1367d59e6SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2367d59e6SBram Moolenaar *
3367d59e6SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4367d59e6SBram Moolenaar *
5367d59e6SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6367d59e6SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7367d59e6SBram Moolenaar * See README.txt for an overview of the Vim source code.
8367d59e6SBram Moolenaar */
9367d59e6SBram Moolenaar
10367d59e6SBram Moolenaar /*
11367d59e6SBram Moolenaar * typval.c: functions that deal with a typval
12367d59e6SBram Moolenaar */
13367d59e6SBram Moolenaar
14367d59e6SBram Moolenaar #include "vim.h"
15367d59e6SBram Moolenaar
16367d59e6SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
17367d59e6SBram Moolenaar
18367d59e6SBram Moolenaar /*
19367d59e6SBram Moolenaar * Allocate memory for a variable type-value, and make it empty (0 or NULL
20367d59e6SBram Moolenaar * value).
21367d59e6SBram Moolenaar */
22367d59e6SBram Moolenaar typval_T *
alloc_tv(void)23367d59e6SBram Moolenaar alloc_tv(void)
24367d59e6SBram Moolenaar {
25367d59e6SBram Moolenaar return ALLOC_CLEAR_ONE(typval_T);
26367d59e6SBram Moolenaar }
27367d59e6SBram Moolenaar
28367d59e6SBram Moolenaar /*
29367d59e6SBram Moolenaar * Allocate memory for a variable type-value, and assign a string to it.
30367d59e6SBram Moolenaar * The string "s" must have been allocated, it is consumed.
31367d59e6SBram Moolenaar * Return NULL for out of memory, the variable otherwise.
32367d59e6SBram Moolenaar */
33367d59e6SBram Moolenaar typval_T *
alloc_string_tv(char_u * s)34367d59e6SBram Moolenaar alloc_string_tv(char_u *s)
35367d59e6SBram Moolenaar {
36367d59e6SBram Moolenaar typval_T *rettv;
37367d59e6SBram Moolenaar
38367d59e6SBram Moolenaar rettv = alloc_tv();
39367d59e6SBram Moolenaar if (rettv != NULL)
40367d59e6SBram Moolenaar {
41367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
42367d59e6SBram Moolenaar rettv->vval.v_string = s;
43367d59e6SBram Moolenaar }
44367d59e6SBram Moolenaar else
45367d59e6SBram Moolenaar vim_free(s);
46367d59e6SBram Moolenaar return rettv;
47367d59e6SBram Moolenaar }
48367d59e6SBram Moolenaar
49367d59e6SBram Moolenaar /*
50367d59e6SBram Moolenaar * Free the memory for a variable type-value.
51367d59e6SBram Moolenaar */
52367d59e6SBram Moolenaar void
free_tv(typval_T * varp)53367d59e6SBram Moolenaar free_tv(typval_T *varp)
54367d59e6SBram Moolenaar {
55367d59e6SBram Moolenaar if (varp != NULL)
56367d59e6SBram Moolenaar {
57367d59e6SBram Moolenaar switch (varp->v_type)
58367d59e6SBram Moolenaar {
59367d59e6SBram Moolenaar case VAR_FUNC:
60367d59e6SBram Moolenaar func_unref(varp->vval.v_string);
61367d59e6SBram Moolenaar // FALLTHROUGH
62367d59e6SBram Moolenaar case VAR_STRING:
63367d59e6SBram Moolenaar vim_free(varp->vval.v_string);
64367d59e6SBram Moolenaar break;
65367d59e6SBram Moolenaar case VAR_PARTIAL:
66367d59e6SBram Moolenaar partial_unref(varp->vval.v_partial);
67367d59e6SBram Moolenaar break;
68367d59e6SBram Moolenaar case VAR_BLOB:
69367d59e6SBram Moolenaar blob_unref(varp->vval.v_blob);
70367d59e6SBram Moolenaar break;
71367d59e6SBram Moolenaar case VAR_LIST:
72367d59e6SBram Moolenaar list_unref(varp->vval.v_list);
73367d59e6SBram Moolenaar break;
74367d59e6SBram Moolenaar case VAR_DICT:
75367d59e6SBram Moolenaar dict_unref(varp->vval.v_dict);
76367d59e6SBram Moolenaar break;
77367d59e6SBram Moolenaar case VAR_JOB:
78367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
79367d59e6SBram Moolenaar job_unref(varp->vval.v_job);
80367d59e6SBram Moolenaar break;
81367d59e6SBram Moolenaar #endif
82367d59e6SBram Moolenaar case VAR_CHANNEL:
83367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
84367d59e6SBram Moolenaar channel_unref(varp->vval.v_channel);
85367d59e6SBram Moolenaar break;
86367d59e6SBram Moolenaar #endif
87367d59e6SBram Moolenaar case VAR_NUMBER:
88367d59e6SBram Moolenaar case VAR_FLOAT:
89367d59e6SBram Moolenaar case VAR_ANY:
90367d59e6SBram Moolenaar case VAR_UNKNOWN:
91367d59e6SBram Moolenaar case VAR_VOID:
92367d59e6SBram Moolenaar case VAR_BOOL:
93367d59e6SBram Moolenaar case VAR_SPECIAL:
94f18332fbSBram Moolenaar case VAR_INSTR:
95367d59e6SBram Moolenaar break;
96367d59e6SBram Moolenaar }
97367d59e6SBram Moolenaar vim_free(varp);
98367d59e6SBram Moolenaar }
99367d59e6SBram Moolenaar }
100367d59e6SBram Moolenaar
101367d59e6SBram Moolenaar /*
102367d59e6SBram Moolenaar * Free the memory for a variable value and set the value to NULL or 0.
103367d59e6SBram Moolenaar */
104367d59e6SBram Moolenaar void
clear_tv(typval_T * varp)105367d59e6SBram Moolenaar clear_tv(typval_T *varp)
106367d59e6SBram Moolenaar {
107367d59e6SBram Moolenaar if (varp != NULL)
108367d59e6SBram Moolenaar {
109367d59e6SBram Moolenaar switch (varp->v_type)
110367d59e6SBram Moolenaar {
111367d59e6SBram Moolenaar case VAR_FUNC:
112367d59e6SBram Moolenaar func_unref(varp->vval.v_string);
113367d59e6SBram Moolenaar // FALLTHROUGH
114367d59e6SBram Moolenaar case VAR_STRING:
115367d59e6SBram Moolenaar VIM_CLEAR(varp->vval.v_string);
116367d59e6SBram Moolenaar break;
117367d59e6SBram Moolenaar case VAR_PARTIAL:
118367d59e6SBram Moolenaar partial_unref(varp->vval.v_partial);
119367d59e6SBram Moolenaar varp->vval.v_partial = NULL;
120367d59e6SBram Moolenaar break;
121367d59e6SBram Moolenaar case VAR_BLOB:
122367d59e6SBram Moolenaar blob_unref(varp->vval.v_blob);
123367d59e6SBram Moolenaar varp->vval.v_blob = NULL;
124367d59e6SBram Moolenaar break;
125367d59e6SBram Moolenaar case VAR_LIST:
126367d59e6SBram Moolenaar list_unref(varp->vval.v_list);
127367d59e6SBram Moolenaar varp->vval.v_list = NULL;
128367d59e6SBram Moolenaar break;
129367d59e6SBram Moolenaar case VAR_DICT:
130367d59e6SBram Moolenaar dict_unref(varp->vval.v_dict);
131367d59e6SBram Moolenaar varp->vval.v_dict = NULL;
132367d59e6SBram Moolenaar break;
133367d59e6SBram Moolenaar case VAR_NUMBER:
134367d59e6SBram Moolenaar case VAR_BOOL:
135367d59e6SBram Moolenaar case VAR_SPECIAL:
136367d59e6SBram Moolenaar varp->vval.v_number = 0;
137367d59e6SBram Moolenaar break;
138367d59e6SBram Moolenaar case VAR_FLOAT:
139367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
140367d59e6SBram Moolenaar varp->vval.v_float = 0.0;
141367d59e6SBram Moolenaar break;
142367d59e6SBram Moolenaar #endif
143367d59e6SBram Moolenaar case VAR_JOB:
144367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
145367d59e6SBram Moolenaar job_unref(varp->vval.v_job);
146367d59e6SBram Moolenaar varp->vval.v_job = NULL;
147367d59e6SBram Moolenaar #endif
148367d59e6SBram Moolenaar break;
149367d59e6SBram Moolenaar case VAR_CHANNEL:
150367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
151367d59e6SBram Moolenaar channel_unref(varp->vval.v_channel);
152367d59e6SBram Moolenaar varp->vval.v_channel = NULL;
153367d59e6SBram Moolenaar #endif
15424f72099SBram Moolenaar break;
15524f72099SBram Moolenaar case VAR_INSTR:
15624f72099SBram Moolenaar VIM_CLEAR(varp->vval.v_instr);
15724f72099SBram Moolenaar break;
158367d59e6SBram Moolenaar case VAR_UNKNOWN:
159367d59e6SBram Moolenaar case VAR_ANY:
160367d59e6SBram Moolenaar case VAR_VOID:
161367d59e6SBram Moolenaar break;
162367d59e6SBram Moolenaar }
163367d59e6SBram Moolenaar varp->v_lock = 0;
164367d59e6SBram Moolenaar }
165367d59e6SBram Moolenaar }
166367d59e6SBram Moolenaar
167367d59e6SBram Moolenaar /*
168367d59e6SBram Moolenaar * Set the value of a variable to NULL without freeing items.
169367d59e6SBram Moolenaar */
170367d59e6SBram Moolenaar void
init_tv(typval_T * varp)171367d59e6SBram Moolenaar init_tv(typval_T *varp)
172367d59e6SBram Moolenaar {
173367d59e6SBram Moolenaar if (varp != NULL)
174367d59e6SBram Moolenaar CLEAR_POINTER(varp);
175367d59e6SBram Moolenaar }
176367d59e6SBram Moolenaar
17736967b32SBram Moolenaar static varnumber_T
tv_get_bool_or_number_chk(typval_T * varp,int * denote,int want_bool)17836967b32SBram Moolenaar tv_get_bool_or_number_chk(typval_T *varp, int *denote, int want_bool)
179367d59e6SBram Moolenaar {
180367d59e6SBram Moolenaar varnumber_T n = 0L;
181367d59e6SBram Moolenaar
182367d59e6SBram Moolenaar switch (varp->v_type)
183367d59e6SBram Moolenaar {
184367d59e6SBram Moolenaar case VAR_NUMBER:
185bade44e5SBram Moolenaar if (in_vim9script() && want_bool && varp->vval.v_number != 0
186d70840edSBram Moolenaar && varp->vval.v_number != 1)
187d70840edSBram Moolenaar {
188d70840edSBram Moolenaar semsg(_(e_using_number_as_bool_nr), varp->vval.v_number);
189d70840edSBram Moolenaar break;
190d70840edSBram Moolenaar }
191367d59e6SBram Moolenaar return varp->vval.v_number;
192367d59e6SBram Moolenaar case VAR_FLOAT:
193367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
194367d59e6SBram Moolenaar emsg(_("E805: Using a Float as a Number"));
195367d59e6SBram Moolenaar break;
196367d59e6SBram Moolenaar #endif
197367d59e6SBram Moolenaar case VAR_FUNC:
198367d59e6SBram Moolenaar case VAR_PARTIAL:
199367d59e6SBram Moolenaar emsg(_("E703: Using a Funcref as a Number"));
200367d59e6SBram Moolenaar break;
201367d59e6SBram Moolenaar case VAR_STRING:
20256acb094SBram Moolenaar if (in_vim9script())
20356acb094SBram Moolenaar {
204ea2d407fSBram Moolenaar emsg_using_string_as(varp, !want_bool);
20556acb094SBram Moolenaar break;
20656acb094SBram Moolenaar }
207367d59e6SBram Moolenaar if (varp->vval.v_string != NULL)
208367d59e6SBram Moolenaar vim_str2nr(varp->vval.v_string, NULL, NULL,
209367d59e6SBram Moolenaar STR2NR_ALL, &n, NULL, 0, FALSE);
210367d59e6SBram Moolenaar return n;
211367d59e6SBram Moolenaar case VAR_LIST:
212367d59e6SBram Moolenaar emsg(_("E745: Using a List as a Number"));
213367d59e6SBram Moolenaar break;
214367d59e6SBram Moolenaar case VAR_DICT:
215367d59e6SBram Moolenaar emsg(_("E728: Using a Dictionary as a Number"));
216367d59e6SBram Moolenaar break;
217367d59e6SBram Moolenaar case VAR_BOOL:
218367d59e6SBram Moolenaar case VAR_SPECIAL:
21936967b32SBram Moolenaar if (!want_bool && in_vim9script())
22056acb094SBram Moolenaar {
221d92cc130SBram Moolenaar if (varp->v_type == VAR_BOOL)
222d92cc130SBram Moolenaar emsg(_(e_using_bool_as_number));
223d92cc130SBram Moolenaar else
22456acb094SBram Moolenaar emsg(_("E611: Using a Special as a Number"));
22556acb094SBram Moolenaar break;
22656acb094SBram Moolenaar }
227367d59e6SBram Moolenaar return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
228367d59e6SBram Moolenaar case VAR_JOB:
229367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
230367d59e6SBram Moolenaar emsg(_("E910: Using a Job as a Number"));
231367d59e6SBram Moolenaar break;
232367d59e6SBram Moolenaar #endif
233367d59e6SBram Moolenaar case VAR_CHANNEL:
234367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
235367d59e6SBram Moolenaar emsg(_("E913: Using a Channel as a Number"));
236367d59e6SBram Moolenaar break;
237367d59e6SBram Moolenaar #endif
238367d59e6SBram Moolenaar case VAR_BLOB:
239367d59e6SBram Moolenaar emsg(_("E974: Using a Blob as a Number"));
240367d59e6SBram Moolenaar break;
241f57b43c2SBram Moolenaar case VAR_VOID:
242f57b43c2SBram Moolenaar emsg(_(e_cannot_use_void_value));
243f57b43c2SBram Moolenaar break;
244367d59e6SBram Moolenaar case VAR_UNKNOWN:
245367d59e6SBram Moolenaar case VAR_ANY:
246f18332fbSBram Moolenaar case VAR_INSTR:
247367d59e6SBram Moolenaar internal_error_no_abort("tv_get_number(UNKNOWN)");
248367d59e6SBram Moolenaar break;
249367d59e6SBram Moolenaar }
250367d59e6SBram Moolenaar if (denote == NULL) // useful for values that must be unsigned
251367d59e6SBram Moolenaar n = -1;
252367d59e6SBram Moolenaar else
253367d59e6SBram Moolenaar *denote = TRUE;
254367d59e6SBram Moolenaar return n;
255367d59e6SBram Moolenaar }
256367d59e6SBram Moolenaar
25736967b32SBram Moolenaar /*
25836967b32SBram Moolenaar * Get the number value of a variable.
25936967b32SBram Moolenaar * If it is a String variable, uses vim_str2nr().
26036967b32SBram Moolenaar * For incompatible types, return 0.
26136967b32SBram Moolenaar * tv_get_number_chk() is similar to tv_get_number(), but informs the
26236967b32SBram Moolenaar * caller of incompatible types: it sets *denote to TRUE if "denote"
26336967b32SBram Moolenaar * is not NULL or returns -1 otherwise.
26436967b32SBram Moolenaar */
26536967b32SBram Moolenaar varnumber_T
tv_get_number(typval_T * varp)26636967b32SBram Moolenaar tv_get_number(typval_T *varp)
26736967b32SBram Moolenaar {
26836967b32SBram Moolenaar int error = FALSE;
26936967b32SBram Moolenaar
27036967b32SBram Moolenaar return tv_get_number_chk(varp, &error); // return 0L on error
27136967b32SBram Moolenaar }
27236967b32SBram Moolenaar
27336967b32SBram Moolenaar varnumber_T
tv_get_number_chk(typval_T * varp,int * denote)27436967b32SBram Moolenaar tv_get_number_chk(typval_T *varp, int *denote)
27536967b32SBram Moolenaar {
27636967b32SBram Moolenaar return tv_get_bool_or_number_chk(varp, denote, FALSE);
27736967b32SBram Moolenaar }
27836967b32SBram Moolenaar
27936967b32SBram Moolenaar /*
28036967b32SBram Moolenaar * Get the boolean value of "varp". This is like tv_get_number_chk(),
281d70840edSBram Moolenaar * but in Vim9 script accepts Number (0 and 1) and Bool/Special.
28236967b32SBram Moolenaar */
28336967b32SBram Moolenaar varnumber_T
tv_get_bool(typval_T * varp)28436967b32SBram Moolenaar tv_get_bool(typval_T *varp)
28536967b32SBram Moolenaar {
28636967b32SBram Moolenaar return tv_get_bool_or_number_chk(varp, NULL, TRUE);
28736967b32SBram Moolenaar }
28836967b32SBram Moolenaar
289e15eebd2SBram Moolenaar /*
290e15eebd2SBram Moolenaar * Get the boolean value of "varp". This is like tv_get_number_chk(),
291e15eebd2SBram Moolenaar * but in Vim9 script accepts Number and Bool.
292e15eebd2SBram Moolenaar */
293e15eebd2SBram Moolenaar varnumber_T
tv_get_bool_chk(typval_T * varp,int * denote)294e15eebd2SBram Moolenaar tv_get_bool_chk(typval_T *varp, int *denote)
295e15eebd2SBram Moolenaar {
296e15eebd2SBram Moolenaar return tv_get_bool_or_number_chk(varp, denote, TRUE);
297e15eebd2SBram Moolenaar }
298e15eebd2SBram Moolenaar
299f57b43c2SBram Moolenaar #if defined(FEAT_FLOAT) || defined(PROTO)
300367d59e6SBram Moolenaar float_T
tv_get_float(typval_T * varp)301367d59e6SBram Moolenaar tv_get_float(typval_T *varp)
302367d59e6SBram Moolenaar {
303367d59e6SBram Moolenaar switch (varp->v_type)
304367d59e6SBram Moolenaar {
305367d59e6SBram Moolenaar case VAR_NUMBER:
306367d59e6SBram Moolenaar return (float_T)(varp->vval.v_number);
307367d59e6SBram Moolenaar case VAR_FLOAT:
308367d59e6SBram Moolenaar return varp->vval.v_float;
309367d59e6SBram Moolenaar case VAR_FUNC:
310367d59e6SBram Moolenaar case VAR_PARTIAL:
311367d59e6SBram Moolenaar emsg(_("E891: Using a Funcref as a Float"));
312367d59e6SBram Moolenaar break;
313367d59e6SBram Moolenaar case VAR_STRING:
314367d59e6SBram Moolenaar emsg(_("E892: Using a String as a Float"));
315367d59e6SBram Moolenaar break;
316367d59e6SBram Moolenaar case VAR_LIST:
317367d59e6SBram Moolenaar emsg(_("E893: Using a List as a Float"));
318367d59e6SBram Moolenaar break;
319367d59e6SBram Moolenaar case VAR_DICT:
320367d59e6SBram Moolenaar emsg(_("E894: Using a Dictionary as a Float"));
321367d59e6SBram Moolenaar break;
322367d59e6SBram Moolenaar case VAR_BOOL:
323367d59e6SBram Moolenaar emsg(_("E362: Using a boolean value as a Float"));
324367d59e6SBram Moolenaar break;
325367d59e6SBram Moolenaar case VAR_SPECIAL:
326367d59e6SBram Moolenaar emsg(_("E907: Using a special value as a Float"));
327367d59e6SBram Moolenaar break;
328367d59e6SBram Moolenaar case VAR_JOB:
329367d59e6SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
330367d59e6SBram Moolenaar emsg(_("E911: Using a Job as a Float"));
331367d59e6SBram Moolenaar break;
332367d59e6SBram Moolenaar # endif
333367d59e6SBram Moolenaar case VAR_CHANNEL:
334367d59e6SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
335367d59e6SBram Moolenaar emsg(_("E914: Using a Channel as a Float"));
336367d59e6SBram Moolenaar break;
337367d59e6SBram Moolenaar # endif
338367d59e6SBram Moolenaar case VAR_BLOB:
339367d59e6SBram Moolenaar emsg(_("E975: Using a Blob as a Float"));
340367d59e6SBram Moolenaar break;
341f57b43c2SBram Moolenaar case VAR_VOID:
342f57b43c2SBram Moolenaar emsg(_(e_cannot_use_void_value));
343f57b43c2SBram Moolenaar break;
344367d59e6SBram Moolenaar case VAR_UNKNOWN:
345367d59e6SBram Moolenaar case VAR_ANY:
346f18332fbSBram Moolenaar case VAR_INSTR:
347367d59e6SBram Moolenaar internal_error_no_abort("tv_get_float(UNKNOWN)");
348367d59e6SBram Moolenaar break;
349367d59e6SBram Moolenaar }
350367d59e6SBram Moolenaar return 0;
351367d59e6SBram Moolenaar }
352367d59e6SBram Moolenaar #endif
353367d59e6SBram Moolenaar
354367d59e6SBram Moolenaar /*
355a9a7c0c6SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string.
3567bb4e74cSBram Moolenaar */
3577bb4e74cSBram Moolenaar int
check_for_string_arg(typval_T * args,int idx)35832105ae8SBram Moolenaar check_for_string_arg(typval_T *args, int idx)
3597bb4e74cSBram Moolenaar {
36032105ae8SBram Moolenaar if (args[idx].v_type != VAR_STRING)
3617bb4e74cSBram Moolenaar {
36232105ae8SBram Moolenaar if (idx >= 0)
36332105ae8SBram Moolenaar semsg(_(e_string_required_for_argument_nr), idx + 1);
364f28f2ac4SBram Moolenaar else
3657bb4e74cSBram Moolenaar emsg(_(e_stringreq));
3667bb4e74cSBram Moolenaar return FAIL;
3677bb4e74cSBram Moolenaar }
3687bb4e74cSBram Moolenaar return OK;
3697bb4e74cSBram Moolenaar }
3707bb4e74cSBram Moolenaar
3717bb4e74cSBram Moolenaar /*
37232105ae8SBram Moolenaar * Give an error and return FAIL unless "args[idx]" is a non-empty string.
3732a9d5d38SBram Moolenaar */
3742a9d5d38SBram Moolenaar int
check_for_nonempty_string_arg(typval_T * args,int idx)37532105ae8SBram Moolenaar check_for_nonempty_string_arg(typval_T *args, int idx)
3762a9d5d38SBram Moolenaar {
37732105ae8SBram Moolenaar if (check_for_string_arg(args, idx) == FAIL)
3782a9d5d38SBram Moolenaar return FAIL;
37932105ae8SBram Moolenaar if (args[idx].vval.v_string == NULL || *args[idx].vval.v_string == NUL)
3802a9d5d38SBram Moolenaar {
38132105ae8SBram Moolenaar semsg(_(e_non_empty_string_required_for_argument_nr), idx + 1);
3822a9d5d38SBram Moolenaar return FAIL;
3832a9d5d38SBram Moolenaar }
3842a9d5d38SBram Moolenaar return OK;
3852a9d5d38SBram Moolenaar }
3862a9d5d38SBram Moolenaar
3872a9d5d38SBram Moolenaar /*
38883494b4aSYegappan Lakshmanan * Check for an optional string argument at 'idx'
38983494b4aSYegappan Lakshmanan */
39083494b4aSYegappan Lakshmanan int
check_for_opt_string_arg(typval_T * args,int idx)39183494b4aSYegappan Lakshmanan check_for_opt_string_arg(typval_T *args, int idx)
39283494b4aSYegappan Lakshmanan {
39383494b4aSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
39483494b4aSYegappan Lakshmanan || check_for_string_arg(args, idx) != FAIL);
39583494b4aSYegappan Lakshmanan }
39683494b4aSYegappan Lakshmanan
39783494b4aSYegappan Lakshmanan /*
398a9a7c0c6SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a number.
3991a71d31bSYegappan Lakshmanan */
4001a71d31bSYegappan Lakshmanan int
check_for_number_arg(typval_T * args,int idx)4011a71d31bSYegappan Lakshmanan check_for_number_arg(typval_T *args, int idx)
4021a71d31bSYegappan Lakshmanan {
4031a71d31bSYegappan Lakshmanan if (args[idx].v_type != VAR_NUMBER)
4041a71d31bSYegappan Lakshmanan {
4051a71d31bSYegappan Lakshmanan if (idx >= 0)
4061a71d31bSYegappan Lakshmanan semsg(_(e_number_required_for_argument_nr), idx + 1);
4071a71d31bSYegappan Lakshmanan else
4081a71d31bSYegappan Lakshmanan emsg(_(e_numberreq));
4091a71d31bSYegappan Lakshmanan return FAIL;
4101a71d31bSYegappan Lakshmanan }
4111a71d31bSYegappan Lakshmanan return OK;
4121a71d31bSYegappan Lakshmanan }
4131a71d31bSYegappan Lakshmanan
4141a71d31bSYegappan Lakshmanan /*
41583494b4aSYegappan Lakshmanan * Check for an optional number argument at 'idx'
41683494b4aSYegappan Lakshmanan */
41783494b4aSYegappan Lakshmanan int
check_for_opt_number_arg(typval_T * args,int idx)41883494b4aSYegappan Lakshmanan check_for_opt_number_arg(typval_T *args, int idx)
41983494b4aSYegappan Lakshmanan {
42083494b4aSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
42183494b4aSYegappan Lakshmanan || check_for_number_arg(args, idx) != FAIL);
42283494b4aSYegappan Lakshmanan }
42383494b4aSYegappan Lakshmanan
42483494b4aSYegappan Lakshmanan /*
425a764e73dSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a float or a number.
426a764e73dSYegappan Lakshmanan */
427a764e73dSYegappan Lakshmanan int
check_for_float_or_nr_arg(typval_T * args,int idx)428a764e73dSYegappan Lakshmanan check_for_float_or_nr_arg(typval_T *args, int idx)
429a764e73dSYegappan Lakshmanan {
430a764e73dSYegappan Lakshmanan if (args[idx].v_type != VAR_FLOAT && args[idx].v_type != VAR_NUMBER)
431a764e73dSYegappan Lakshmanan {
432a764e73dSYegappan Lakshmanan if (idx >= 0)
4334490ec4eSYegappan Lakshmanan semsg(_(e_float_or_number_required_for_argument_nr), idx + 1);
434a764e73dSYegappan Lakshmanan else
435a764e73dSYegappan Lakshmanan emsg(_(e_numberreq));
436a764e73dSYegappan Lakshmanan return FAIL;
437a764e73dSYegappan Lakshmanan }
438a764e73dSYegappan Lakshmanan return OK;
439a764e73dSYegappan Lakshmanan }
440a764e73dSYegappan Lakshmanan
441a764e73dSYegappan Lakshmanan /*
442a9a7c0c6SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a bool.
443a9a7c0c6SYegappan Lakshmanan */
444a9a7c0c6SYegappan Lakshmanan int
check_for_bool_arg(typval_T * args,int idx)445a9a7c0c6SYegappan Lakshmanan check_for_bool_arg(typval_T *args, int idx)
446a9a7c0c6SYegappan Lakshmanan {
447a9a7c0c6SYegappan Lakshmanan if (args[idx].v_type != VAR_BOOL
448a9a7c0c6SYegappan Lakshmanan && !(args[idx].v_type == VAR_NUMBER
449a9a7c0c6SYegappan Lakshmanan && (args[idx].vval.v_number == 0
450a9a7c0c6SYegappan Lakshmanan || args[idx].vval.v_number == 1)))
451a9a7c0c6SYegappan Lakshmanan {
452a9a7c0c6SYegappan Lakshmanan if (idx >= 0)
453a9a7c0c6SYegappan Lakshmanan semsg(_(e_bool_required_for_argument_nr), idx + 1);
454a9a7c0c6SYegappan Lakshmanan else
455a9a7c0c6SYegappan Lakshmanan emsg(_(e_boolreq));
456a9a7c0c6SYegappan Lakshmanan return FAIL;
457a9a7c0c6SYegappan Lakshmanan }
458a9a7c0c6SYegappan Lakshmanan return OK;
459a9a7c0c6SYegappan Lakshmanan }
460a9a7c0c6SYegappan Lakshmanan
461a9a7c0c6SYegappan Lakshmanan /*
462a29856fcSBram Moolenaar * Check for an optional bool argument at 'idx'.
463a29856fcSBram Moolenaar * Return FAIL if the type is wrong.
46483494b4aSYegappan Lakshmanan */
46583494b4aSYegappan Lakshmanan int
check_for_opt_bool_arg(typval_T * args,int idx)46683494b4aSYegappan Lakshmanan check_for_opt_bool_arg(typval_T *args, int idx)
46783494b4aSYegappan Lakshmanan {
468a29856fcSBram Moolenaar if (args[idx].v_type == VAR_UNKNOWN)
469a29856fcSBram Moolenaar return OK;
470a29856fcSBram Moolenaar return check_for_bool_arg(args, idx);
47183494b4aSYegappan Lakshmanan }
47283494b4aSYegappan Lakshmanan
47383494b4aSYegappan Lakshmanan /*
474*5dfe4674SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a blob.
475*5dfe4674SYegappan Lakshmanan */
476*5dfe4674SYegappan Lakshmanan int
check_for_blob_arg(typval_T * args,int idx)477*5dfe4674SYegappan Lakshmanan check_for_blob_arg(typval_T *args, int idx)
478*5dfe4674SYegappan Lakshmanan {
479*5dfe4674SYegappan Lakshmanan if (args[idx].v_type != VAR_BLOB)
480*5dfe4674SYegappan Lakshmanan {
481*5dfe4674SYegappan Lakshmanan if (idx >= 0)
482*5dfe4674SYegappan Lakshmanan semsg(_(e_blob_required_for_argument_nr), idx + 1);
483*5dfe4674SYegappan Lakshmanan else
484*5dfe4674SYegappan Lakshmanan emsg(_(e_blob_required));
485*5dfe4674SYegappan Lakshmanan return FAIL;
486*5dfe4674SYegappan Lakshmanan }
487*5dfe4674SYegappan Lakshmanan return OK;
488*5dfe4674SYegappan Lakshmanan }
489*5dfe4674SYegappan Lakshmanan
490*5dfe4674SYegappan Lakshmanan /*
491a9a7c0c6SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a list.
492a9a7c0c6SYegappan Lakshmanan */
493a9a7c0c6SYegappan Lakshmanan int
check_for_list_arg(typval_T * args,int idx)494a9a7c0c6SYegappan Lakshmanan check_for_list_arg(typval_T *args, int idx)
495a9a7c0c6SYegappan Lakshmanan {
496a9a7c0c6SYegappan Lakshmanan if (args[idx].v_type != VAR_LIST)
497a9a7c0c6SYegappan Lakshmanan {
498a9a7c0c6SYegappan Lakshmanan if (idx >= 0)
499a9a7c0c6SYegappan Lakshmanan semsg(_(e_list_required_for_argument_nr), idx + 1);
500a9a7c0c6SYegappan Lakshmanan else
501a9a7c0c6SYegappan Lakshmanan emsg(_(e_listreq));
502a9a7c0c6SYegappan Lakshmanan return FAIL;
503a9a7c0c6SYegappan Lakshmanan }
504a9a7c0c6SYegappan Lakshmanan return OK;
505a9a7c0c6SYegappan Lakshmanan }
506a9a7c0c6SYegappan Lakshmanan
507a9a7c0c6SYegappan Lakshmanan /*
50883494b4aSYegappan Lakshmanan * Check for an optional list argument at 'idx'
50983494b4aSYegappan Lakshmanan */
51083494b4aSYegappan Lakshmanan int
check_for_opt_list_arg(typval_T * args,int idx)51183494b4aSYegappan Lakshmanan check_for_opt_list_arg(typval_T *args, int idx)
51283494b4aSYegappan Lakshmanan {
51383494b4aSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
51483494b4aSYegappan Lakshmanan || check_for_list_arg(args, idx) != FAIL);
51583494b4aSYegappan Lakshmanan }
51683494b4aSYegappan Lakshmanan
51783494b4aSYegappan Lakshmanan /*
518a9a7c0c6SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a dict.
5195b73992dSYegappan Lakshmanan */
5205b73992dSYegappan Lakshmanan int
check_for_dict_arg(typval_T * args,int idx)5215b73992dSYegappan Lakshmanan check_for_dict_arg(typval_T *args, int idx)
5225b73992dSYegappan Lakshmanan {
5235b73992dSYegappan Lakshmanan if (args[idx].v_type != VAR_DICT)
5245b73992dSYegappan Lakshmanan {
5255b73992dSYegappan Lakshmanan if (idx >= 0)
5265b73992dSYegappan Lakshmanan semsg(_(e_dict_required_for_argument_nr), idx + 1);
5275b73992dSYegappan Lakshmanan else
5285b73992dSYegappan Lakshmanan emsg(_(e_dictreq));
5295b73992dSYegappan Lakshmanan return FAIL;
5305b73992dSYegappan Lakshmanan }
5315b73992dSYegappan Lakshmanan return OK;
5325b73992dSYegappan Lakshmanan }
5335b73992dSYegappan Lakshmanan
5345b73992dSYegappan Lakshmanan /*
53583494b4aSYegappan Lakshmanan * Check for an optional dict argument at 'idx'
53683494b4aSYegappan Lakshmanan */
53783494b4aSYegappan Lakshmanan int
check_for_opt_dict_arg(typval_T * args,int idx)53883494b4aSYegappan Lakshmanan check_for_opt_dict_arg(typval_T *args, int idx)
53983494b4aSYegappan Lakshmanan {
54083494b4aSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
54183494b4aSYegappan Lakshmanan || check_for_dict_arg(args, idx) != FAIL);
54283494b4aSYegappan Lakshmanan }
54383494b4aSYegappan Lakshmanan
54483494b4aSYegappan Lakshmanan /*
54583494b4aSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a channel or a job.
54683494b4aSYegappan Lakshmanan */
54783494b4aSYegappan Lakshmanan int
check_for_chan_or_job_arg(typval_T * args,int idx)54883494b4aSYegappan Lakshmanan check_for_chan_or_job_arg(typval_T *args, int idx)
54983494b4aSYegappan Lakshmanan {
55083494b4aSYegappan Lakshmanan if (args[idx].v_type != VAR_CHANNEL && args[idx].v_type != VAR_JOB)
55183494b4aSYegappan Lakshmanan {
55283494b4aSYegappan Lakshmanan if (idx >= 0)
55383494b4aSYegappan Lakshmanan semsg(_(e_chan_or_job_required_for_argument_nr), idx + 1);
55483494b4aSYegappan Lakshmanan else
55583494b4aSYegappan Lakshmanan emsg(_(e_chan_or_job_req));
55683494b4aSYegappan Lakshmanan return FAIL;
55783494b4aSYegappan Lakshmanan }
55883494b4aSYegappan Lakshmanan return OK;
55983494b4aSYegappan Lakshmanan }
56083494b4aSYegappan Lakshmanan
56183494b4aSYegappan Lakshmanan /*
5627973de35SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is an optional channel or a
5637973de35SYegappan Lakshmanan * job.
5647973de35SYegappan Lakshmanan */
5657973de35SYegappan Lakshmanan int
check_for_opt_chan_or_job_arg(typval_T * args,int idx)5667973de35SYegappan Lakshmanan check_for_opt_chan_or_job_arg(typval_T *args, int idx)
5677973de35SYegappan Lakshmanan {
5687973de35SYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
5697973de35SYegappan Lakshmanan || check_for_chan_or_job_arg(args, idx) != FAIL);
5707973de35SYegappan Lakshmanan }
5717973de35SYegappan Lakshmanan
5727973de35SYegappan Lakshmanan /*
57383494b4aSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a job.
57483494b4aSYegappan Lakshmanan */
57583494b4aSYegappan Lakshmanan int
check_for_job_arg(typval_T * args,int idx)57683494b4aSYegappan Lakshmanan check_for_job_arg(typval_T *args, int idx)
57783494b4aSYegappan Lakshmanan {
57883494b4aSYegappan Lakshmanan if (args[idx].v_type != VAR_JOB)
57983494b4aSYegappan Lakshmanan {
58083494b4aSYegappan Lakshmanan if (idx >= 0)
58183494b4aSYegappan Lakshmanan semsg(_(e_job_required_for_argument_nr), idx + 1);
58283494b4aSYegappan Lakshmanan else
58383494b4aSYegappan Lakshmanan emsg(_(e_jobreq));
58483494b4aSYegappan Lakshmanan return FAIL;
58583494b4aSYegappan Lakshmanan }
58683494b4aSYegappan Lakshmanan return OK;
58783494b4aSYegappan Lakshmanan }
58883494b4aSYegappan Lakshmanan
58983494b4aSYegappan Lakshmanan /*
5904490ec4eSYegappan Lakshmanan * Check for an optional job argument at 'idx'.
5914490ec4eSYegappan Lakshmanan */
5924490ec4eSYegappan Lakshmanan int
check_for_opt_job_arg(typval_T * args,int idx)5934490ec4eSYegappan Lakshmanan check_for_opt_job_arg(typval_T *args, int idx)
5944490ec4eSYegappan Lakshmanan {
5954490ec4eSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
5964490ec4eSYegappan Lakshmanan || check_for_job_arg(args, idx) != FAIL);
5974490ec4eSYegappan Lakshmanan }
5984490ec4eSYegappan Lakshmanan
5994490ec4eSYegappan Lakshmanan /*
60083494b4aSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or
60183494b4aSYegappan Lakshmanan * a number.
60283494b4aSYegappan Lakshmanan */
60383494b4aSYegappan Lakshmanan int
check_for_string_or_number_arg(typval_T * args,int idx)60483494b4aSYegappan Lakshmanan check_for_string_or_number_arg(typval_T *args, int idx)
60583494b4aSYegappan Lakshmanan {
60683494b4aSYegappan Lakshmanan if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_NUMBER)
60783494b4aSYegappan Lakshmanan {
60883494b4aSYegappan Lakshmanan if (idx >= 0)
6094490ec4eSYegappan Lakshmanan semsg(_(e_string_or_number_required_for_argument_nr), idx + 1);
61083494b4aSYegappan Lakshmanan else
61183494b4aSYegappan Lakshmanan emsg(_(e_stringreq));
61283494b4aSYegappan Lakshmanan return FAIL;
61383494b4aSYegappan Lakshmanan }
61483494b4aSYegappan Lakshmanan return OK;
61583494b4aSYegappan Lakshmanan }
61683494b4aSYegappan Lakshmanan
61783494b4aSYegappan Lakshmanan /*
618cd917207SYegappan Lakshmanan * Check for an optional string or number argument at 'idx'.
61983494b4aSYegappan Lakshmanan */
62083494b4aSYegappan Lakshmanan int
check_for_opt_string_or_number_arg(typval_T * args,int idx)62183494b4aSYegappan Lakshmanan check_for_opt_string_or_number_arg(typval_T *args, int idx)
62283494b4aSYegappan Lakshmanan {
62383494b4aSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
62483494b4aSYegappan Lakshmanan || check_for_string_or_number_arg(args, idx) != FAIL);
62583494b4aSYegappan Lakshmanan }
62683494b4aSYegappan Lakshmanan
62783494b4aSYegappan Lakshmanan /*
628cd917207SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a buffer number.
629cd917207SYegappan Lakshmanan * Buffer number can be a number or a string.
630cd917207SYegappan Lakshmanan */
631cd917207SYegappan Lakshmanan int
check_for_buffer_arg(typval_T * args,int idx)632cd917207SYegappan Lakshmanan check_for_buffer_arg(typval_T *args, int idx)
633cd917207SYegappan Lakshmanan {
634cd917207SYegappan Lakshmanan return check_for_string_or_number_arg(args, idx);
635cd917207SYegappan Lakshmanan }
636cd917207SYegappan Lakshmanan
637cd917207SYegappan Lakshmanan /*
638cd917207SYegappan Lakshmanan * Check for an optional buffer argument at 'idx'
639cd917207SYegappan Lakshmanan */
640cd917207SYegappan Lakshmanan int
check_for_opt_buffer_arg(typval_T * args,int idx)641cd917207SYegappan Lakshmanan check_for_opt_buffer_arg(typval_T *args, int idx)
642cd917207SYegappan Lakshmanan {
643cd917207SYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
644cd917207SYegappan Lakshmanan || check_for_buffer_arg(args, idx));
645cd917207SYegappan Lakshmanan }
646cd917207SYegappan Lakshmanan
647cd917207SYegappan Lakshmanan /*
648cd917207SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a line number.
649cd917207SYegappan Lakshmanan * Line number can be a number or a string.
650cd917207SYegappan Lakshmanan */
651cd917207SYegappan Lakshmanan int
check_for_lnum_arg(typval_T * args,int idx)652cd917207SYegappan Lakshmanan check_for_lnum_arg(typval_T *args, int idx)
653cd917207SYegappan Lakshmanan {
654cd917207SYegappan Lakshmanan return check_for_string_or_number_arg(args, idx);
655cd917207SYegappan Lakshmanan }
656cd917207SYegappan Lakshmanan
657cd917207SYegappan Lakshmanan /*
658cd917207SYegappan Lakshmanan * Check for an optional line number argument at 'idx'
659cd917207SYegappan Lakshmanan */
660cd917207SYegappan Lakshmanan int
check_for_opt_lnum_arg(typval_T * args,int idx)661cd917207SYegappan Lakshmanan check_for_opt_lnum_arg(typval_T *args, int idx)
662cd917207SYegappan Lakshmanan {
663cd917207SYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
664cd917207SYegappan Lakshmanan || check_for_lnum_arg(args, idx));
665cd917207SYegappan Lakshmanan }
666cd917207SYegappan Lakshmanan
667cd917207SYegappan Lakshmanan /*
6680ad871dcSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or a blob.
66983494b4aSYegappan Lakshmanan */
67083494b4aSYegappan Lakshmanan int
check_for_string_or_blob_arg(typval_T * args,int idx)67183494b4aSYegappan Lakshmanan check_for_string_or_blob_arg(typval_T *args, int idx)
67283494b4aSYegappan Lakshmanan {
67383494b4aSYegappan Lakshmanan if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_BLOB)
67483494b4aSYegappan Lakshmanan {
67583494b4aSYegappan Lakshmanan if (idx >= 0)
6764490ec4eSYegappan Lakshmanan semsg(_(e_string_or_blob_required_for_argument_nr), idx + 1);
67783494b4aSYegappan Lakshmanan else
67883494b4aSYegappan Lakshmanan emsg(_(e_stringreq));
67983494b4aSYegappan Lakshmanan return FAIL;
68083494b4aSYegappan Lakshmanan }
68183494b4aSYegappan Lakshmanan return OK;
68283494b4aSYegappan Lakshmanan }
68383494b4aSYegappan Lakshmanan
68483494b4aSYegappan Lakshmanan /*
6850ad871dcSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or a list.
686cd917207SYegappan Lakshmanan */
687cd917207SYegappan Lakshmanan int
check_for_string_or_list_arg(typval_T * args,int idx)688cd917207SYegappan Lakshmanan check_for_string_or_list_arg(typval_T *args, int idx)
689cd917207SYegappan Lakshmanan {
690cd917207SYegappan Lakshmanan if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_LIST)
691cd917207SYegappan Lakshmanan {
692cd917207SYegappan Lakshmanan if (idx >= 0)
6934490ec4eSYegappan Lakshmanan semsg(_(e_string_or_list_required_for_argument_nr), idx + 1);
694cd917207SYegappan Lakshmanan else
695cd917207SYegappan Lakshmanan emsg(_(e_stringreq));
696cd917207SYegappan Lakshmanan return FAIL;
697cd917207SYegappan Lakshmanan }
698cd917207SYegappan Lakshmanan return OK;
699cd917207SYegappan Lakshmanan }
700cd917207SYegappan Lakshmanan
701cd917207SYegappan Lakshmanan /*
702a764e73dSYegappan Lakshmanan * Check for an optional string or list argument at 'idx'
703a764e73dSYegappan Lakshmanan */
704a764e73dSYegappan Lakshmanan int
check_for_opt_string_or_list_arg(typval_T * args,int idx)705a764e73dSYegappan Lakshmanan check_for_opt_string_or_list_arg(typval_T *args, int idx)
706a764e73dSYegappan Lakshmanan {
707a764e73dSYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
708a764e73dSYegappan Lakshmanan || check_for_string_or_list_arg(args, idx));
709a764e73dSYegappan Lakshmanan }
710a764e73dSYegappan Lakshmanan
711a764e73dSYegappan Lakshmanan /*
7124490ec4eSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or a dict.
7134490ec4eSYegappan Lakshmanan */
7144490ec4eSYegappan Lakshmanan int
check_for_string_or_dict_arg(typval_T * args,int idx)7154490ec4eSYegappan Lakshmanan check_for_string_or_dict_arg(typval_T *args, int idx)
7164490ec4eSYegappan Lakshmanan {
7174490ec4eSYegappan Lakshmanan if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_DICT)
7184490ec4eSYegappan Lakshmanan {
7194490ec4eSYegappan Lakshmanan if (idx >= 0)
7204490ec4eSYegappan Lakshmanan semsg(_(e_string_or_dict_required_for_argument_nr), idx + 1);
7214490ec4eSYegappan Lakshmanan else
7224490ec4eSYegappan Lakshmanan emsg(_(e_stringreq));
7234490ec4eSYegappan Lakshmanan return FAIL;
7244490ec4eSYegappan Lakshmanan }
7254490ec4eSYegappan Lakshmanan return OK;
7264490ec4eSYegappan Lakshmanan }
7274490ec4eSYegappan Lakshmanan
7284490ec4eSYegappan Lakshmanan /*
7294490ec4eSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or a number
7304490ec4eSYegappan Lakshmanan * or a list.
7314490ec4eSYegappan Lakshmanan */
7324490ec4eSYegappan Lakshmanan int
check_for_string_or_number_or_list_arg(typval_T * args,int idx)7334490ec4eSYegappan Lakshmanan check_for_string_or_number_or_list_arg(typval_T *args, int idx)
7344490ec4eSYegappan Lakshmanan {
7354490ec4eSYegappan Lakshmanan if (args[idx].v_type != VAR_STRING
7364490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_NUMBER
7374490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_LIST)
7384490ec4eSYegappan Lakshmanan {
7394490ec4eSYegappan Lakshmanan if (idx >= 0)
74078db17c6SBram Moolenaar semsg(_(e_string_number_or_list_required_for_argument_nr), idx + 1);
7414490ec4eSYegappan Lakshmanan else
7424490ec4eSYegappan Lakshmanan emsg(_(e_stringreq));
7434490ec4eSYegappan Lakshmanan return FAIL;
7444490ec4eSYegappan Lakshmanan }
7454490ec4eSYegappan Lakshmanan return OK;
7464490ec4eSYegappan Lakshmanan }
7474490ec4eSYegappan Lakshmanan
7484490ec4eSYegappan Lakshmanan /*
7497e6a2a64SYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is an optional string
7507e6a2a64SYegappan Lakshmanan * or number or a list
7517e6a2a64SYegappan Lakshmanan */
7527e6a2a64SYegappan Lakshmanan int
check_for_opt_string_or_number_or_list_arg(typval_T * args,int idx)7537e6a2a64SYegappan Lakshmanan check_for_opt_string_or_number_or_list_arg(typval_T *args, int idx)
7547e6a2a64SYegappan Lakshmanan {
7557e6a2a64SYegappan Lakshmanan return (args[idx].v_type == VAR_UNKNOWN
7567e6a2a64SYegappan Lakshmanan || check_for_string_or_number_or_list_arg(args, idx) != FAIL);
7577e6a2a64SYegappan Lakshmanan }
7587e6a2a64SYegappan Lakshmanan
7597e6a2a64SYegappan Lakshmanan /*
7604490ec4eSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a string or a list
7614490ec4eSYegappan Lakshmanan * or a dict.
7624490ec4eSYegappan Lakshmanan */
7634490ec4eSYegappan Lakshmanan int
check_for_string_or_list_or_dict_arg(typval_T * args,int idx)7644490ec4eSYegappan Lakshmanan check_for_string_or_list_or_dict_arg(typval_T *args, int idx)
7654490ec4eSYegappan Lakshmanan {
7664490ec4eSYegappan Lakshmanan if (args[idx].v_type != VAR_STRING
7674490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_LIST
7684490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_DICT)
7694490ec4eSYegappan Lakshmanan {
7704490ec4eSYegappan Lakshmanan if (idx >= 0)
77178db17c6SBram Moolenaar semsg(_(e_string_list_or_dict_required_for_argument_nr), idx + 1);
7724490ec4eSYegappan Lakshmanan else
7734490ec4eSYegappan Lakshmanan emsg(_(e_stringreq));
7744490ec4eSYegappan Lakshmanan return FAIL;
7754490ec4eSYegappan Lakshmanan }
7764490ec4eSYegappan Lakshmanan return OK;
7774490ec4eSYegappan Lakshmanan }
7784490ec4eSYegappan Lakshmanan
7794490ec4eSYegappan Lakshmanan /*
7800ad871dcSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a list or a blob.
7810ad871dcSYegappan Lakshmanan */
7820ad871dcSYegappan Lakshmanan int
check_for_list_or_blob_arg(typval_T * args,int idx)7830ad871dcSYegappan Lakshmanan check_for_list_or_blob_arg(typval_T *args, int idx)
7840ad871dcSYegappan Lakshmanan {
7850ad871dcSYegappan Lakshmanan if (args[idx].v_type != VAR_LIST && args[idx].v_type != VAR_BLOB)
7860ad871dcSYegappan Lakshmanan {
7870ad871dcSYegappan Lakshmanan if (idx >= 0)
7884490ec4eSYegappan Lakshmanan semsg(_(e_list_or_blob_required_for_argument_nr), idx + 1);
7894490ec4eSYegappan Lakshmanan else
7904490ec4eSYegappan Lakshmanan emsg(_(e_listreq));
7914490ec4eSYegappan Lakshmanan return FAIL;
7924490ec4eSYegappan Lakshmanan }
7934490ec4eSYegappan Lakshmanan return OK;
7944490ec4eSYegappan Lakshmanan }
7954490ec4eSYegappan Lakshmanan
7964490ec4eSYegappan Lakshmanan /*
7974490ec4eSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a list or dict
7984490ec4eSYegappan Lakshmanan */
7994490ec4eSYegappan Lakshmanan int
check_for_list_or_dict_arg(typval_T * args,int idx)8004490ec4eSYegappan Lakshmanan check_for_list_or_dict_arg(typval_T *args, int idx)
8014490ec4eSYegappan Lakshmanan {
8024490ec4eSYegappan Lakshmanan if (args[idx].v_type != VAR_LIST
8034490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_DICT)
8044490ec4eSYegappan Lakshmanan {
8054490ec4eSYegappan Lakshmanan if (idx >= 0)
8064490ec4eSYegappan Lakshmanan semsg(_(e_list_or_dict_required_for_argument_nr), idx + 1);
8070ad871dcSYegappan Lakshmanan else
8080ad871dcSYegappan Lakshmanan emsg(_(e_listreq));
8090ad871dcSYegappan Lakshmanan return FAIL;
8100ad871dcSYegappan Lakshmanan }
8110ad871dcSYegappan Lakshmanan return OK;
8120ad871dcSYegappan Lakshmanan }
8130ad871dcSYegappan Lakshmanan
8140ad871dcSYegappan Lakshmanan /*
8150ad871dcSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is a list or dict or a
8160ad871dcSYegappan Lakshmanan * blob.
8170ad871dcSYegappan Lakshmanan */
8180ad871dcSYegappan Lakshmanan int
check_for_list_or_dict_or_blob_arg(typval_T * args,int idx)8190ad871dcSYegappan Lakshmanan check_for_list_or_dict_or_blob_arg(typval_T *args, int idx)
8200ad871dcSYegappan Lakshmanan {
8210ad871dcSYegappan Lakshmanan if (args[idx].v_type != VAR_LIST
8220ad871dcSYegappan Lakshmanan && args[idx].v_type != VAR_DICT
8230ad871dcSYegappan Lakshmanan && args[idx].v_type != VAR_BLOB)
8240ad871dcSYegappan Lakshmanan {
8250ad871dcSYegappan Lakshmanan if (idx >= 0)
82678db17c6SBram Moolenaar semsg(_(e_list_dict_or_blob_required_for_argument_nr), idx + 1);
8270ad871dcSYegappan Lakshmanan else
8280ad871dcSYegappan Lakshmanan emsg(_(e_listreq));
8290ad871dcSYegappan Lakshmanan return FAIL;
8300ad871dcSYegappan Lakshmanan }
8310ad871dcSYegappan Lakshmanan return OK;
8320ad871dcSYegappan Lakshmanan }
8330ad871dcSYegappan Lakshmanan
8340ad871dcSYegappan Lakshmanan /*
8354490ec4eSYegappan Lakshmanan * Give an error and return FAIL unless "args[idx]" is an optional buffer
8364490ec4eSYegappan Lakshmanan * number or a dict.
837cd917207SYegappan Lakshmanan */
838cd917207SYegappan Lakshmanan int
check_for_opt_buffer_or_dict_arg(typval_T * args,int idx)8394490ec4eSYegappan Lakshmanan check_for_opt_buffer_or_dict_arg(typval_T *args, int idx)
840cd917207SYegappan Lakshmanan {
8414490ec4eSYegappan Lakshmanan if (args[idx].v_type != VAR_UNKNOWN
8424490ec4eSYegappan Lakshmanan && args[idx].v_type != VAR_STRING
843cd917207SYegappan Lakshmanan && args[idx].v_type != VAR_NUMBER
844cd917207SYegappan Lakshmanan && args[idx].v_type != VAR_DICT)
845cd917207SYegappan Lakshmanan {
846cd917207SYegappan Lakshmanan if (idx >= 0)
847cd917207SYegappan Lakshmanan semsg(_(e_string_required_for_argument_nr), idx + 1);
848cd917207SYegappan Lakshmanan else
849cd917207SYegappan Lakshmanan emsg(_(e_stringreq));
850cd917207SYegappan Lakshmanan return FAIL;
851cd917207SYegappan Lakshmanan }
852cd917207SYegappan Lakshmanan return OK;
853cd917207SYegappan Lakshmanan }
854cd917207SYegappan Lakshmanan
855cd917207SYegappan Lakshmanan /*
856367d59e6SBram Moolenaar * Get the string value of a variable.
857367d59e6SBram Moolenaar * If it is a Number variable, the number is converted into a string.
858367d59e6SBram Moolenaar * tv_get_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
859367d59e6SBram Moolenaar * tv_get_string_buf() uses a given buffer.
860367d59e6SBram Moolenaar * If the String variable has never been set, return an empty string.
861367d59e6SBram Moolenaar * Never returns NULL;
862367d59e6SBram Moolenaar * tv_get_string_chk() and tv_get_string_buf_chk() are similar, but return
863367d59e6SBram Moolenaar * NULL on error.
864367d59e6SBram Moolenaar */
865367d59e6SBram Moolenaar char_u *
tv_get_string(typval_T * varp)866367d59e6SBram Moolenaar tv_get_string(typval_T *varp)
867367d59e6SBram Moolenaar {
868367d59e6SBram Moolenaar static char_u mybuf[NUMBUFLEN];
869367d59e6SBram Moolenaar
870367d59e6SBram Moolenaar return tv_get_string_buf(varp, mybuf);
871367d59e6SBram Moolenaar }
872367d59e6SBram Moolenaar
873f2b26bcfSBram Moolenaar /*
874f2b26bcfSBram Moolenaar * Like tv_get_string() but don't allow number to string conversion for Vim9.
875f2b26bcfSBram Moolenaar */
876f2b26bcfSBram Moolenaar char_u *
tv_get_string_strict(typval_T * varp)877f2b26bcfSBram Moolenaar tv_get_string_strict(typval_T *varp)
878f2b26bcfSBram Moolenaar {
879f2b26bcfSBram Moolenaar static char_u mybuf[NUMBUFLEN];
880f2b26bcfSBram Moolenaar char_u *res = tv_get_string_buf_chk_strict(
881f2b26bcfSBram Moolenaar varp, mybuf, in_vim9script());
882f2b26bcfSBram Moolenaar
883f2b26bcfSBram Moolenaar return res != NULL ? res : (char_u *)"";
884f2b26bcfSBram Moolenaar }
885f2b26bcfSBram Moolenaar
886367d59e6SBram Moolenaar char_u *
tv_get_string_buf(typval_T * varp,char_u * buf)887367d59e6SBram Moolenaar tv_get_string_buf(typval_T *varp, char_u *buf)
888367d59e6SBram Moolenaar {
889367d59e6SBram Moolenaar char_u *res = tv_get_string_buf_chk(varp, buf);
890367d59e6SBram Moolenaar
891367d59e6SBram Moolenaar return res != NULL ? res : (char_u *)"";
892367d59e6SBram Moolenaar }
893367d59e6SBram Moolenaar
894367d59e6SBram Moolenaar /*
895367d59e6SBram Moolenaar * Careful: This uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
896367d59e6SBram Moolenaar */
897367d59e6SBram Moolenaar char_u *
tv_get_string_chk(typval_T * varp)898367d59e6SBram Moolenaar tv_get_string_chk(typval_T *varp)
899367d59e6SBram Moolenaar {
900367d59e6SBram Moolenaar static char_u mybuf[NUMBUFLEN];
901367d59e6SBram Moolenaar
902367d59e6SBram Moolenaar return tv_get_string_buf_chk(varp, mybuf);
903367d59e6SBram Moolenaar }
904367d59e6SBram Moolenaar
905367d59e6SBram Moolenaar char_u *
tv_get_string_buf_chk(typval_T * varp,char_u * buf)906367d59e6SBram Moolenaar tv_get_string_buf_chk(typval_T *varp, char_u *buf)
907367d59e6SBram Moolenaar {
908f2b26bcfSBram Moolenaar return tv_get_string_buf_chk_strict(varp, buf, FALSE);
909f2b26bcfSBram Moolenaar }
910f2b26bcfSBram Moolenaar
911f2b26bcfSBram Moolenaar char_u *
tv_get_string_buf_chk_strict(typval_T * varp,char_u * buf,int strict)912f2b26bcfSBram Moolenaar tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
913f2b26bcfSBram Moolenaar {
914367d59e6SBram Moolenaar switch (varp->v_type)
915367d59e6SBram Moolenaar {
916367d59e6SBram Moolenaar case VAR_NUMBER:
917f2b26bcfSBram Moolenaar if (strict)
918f2b26bcfSBram Moolenaar {
919f2b26bcfSBram Moolenaar emsg(_(e_using_number_as_string));
920f2b26bcfSBram Moolenaar break;
921f2b26bcfSBram Moolenaar }
922367d59e6SBram Moolenaar vim_snprintf((char *)buf, NUMBUFLEN, "%lld",
923367d59e6SBram Moolenaar (varnumber_T)varp->vval.v_number);
924367d59e6SBram Moolenaar return buf;
925367d59e6SBram Moolenaar case VAR_FUNC:
926367d59e6SBram Moolenaar case VAR_PARTIAL:
9275b73992dSYegappan Lakshmanan emsg(_("E729: Using a Funcref as a String"));
928367d59e6SBram Moolenaar break;
929367d59e6SBram Moolenaar case VAR_LIST:
9305b73992dSYegappan Lakshmanan emsg(_("E730: Using a List as a String"));
931367d59e6SBram Moolenaar break;
932367d59e6SBram Moolenaar case VAR_DICT:
9335b73992dSYegappan Lakshmanan emsg(_("E731: Using a Dictionary as a String"));
934367d59e6SBram Moolenaar break;
935367d59e6SBram Moolenaar case VAR_FLOAT:
936367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
9377a2217beSBram Moolenaar if (strict)
9387a2217beSBram Moolenaar {
939367d59e6SBram Moolenaar emsg(_(e_float_as_string));
940367d59e6SBram Moolenaar break;
9417a2217beSBram Moolenaar }
9427a2217beSBram Moolenaar vim_snprintf((char *)buf, NUMBUFLEN, "%g", varp->vval.v_float);
9437a2217beSBram Moolenaar return buf;
944367d59e6SBram Moolenaar #endif
945367d59e6SBram Moolenaar case VAR_STRING:
946367d59e6SBram Moolenaar if (varp->vval.v_string != NULL)
947367d59e6SBram Moolenaar return varp->vval.v_string;
948367d59e6SBram Moolenaar return (char_u *)"";
949367d59e6SBram Moolenaar case VAR_BOOL:
950367d59e6SBram Moolenaar case VAR_SPECIAL:
951367d59e6SBram Moolenaar STRCPY(buf, get_var_special_name(varp->vval.v_number));
952367d59e6SBram Moolenaar return buf;
953367d59e6SBram Moolenaar case VAR_BLOB:
9545b73992dSYegappan Lakshmanan emsg(_("E976: Using a Blob as a String"));
955367d59e6SBram Moolenaar break;
956367d59e6SBram Moolenaar case VAR_JOB:
957367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
9581328bde9SBram Moolenaar if (in_vim9script())
959367d59e6SBram Moolenaar {
9601328bde9SBram Moolenaar semsg(_(e_using_invalid_value_as_string_str), "job");
9611328bde9SBram Moolenaar break;
962367d59e6SBram Moolenaar }
9631328bde9SBram Moolenaar return job_to_string_buf(varp, buf);
964367d59e6SBram Moolenaar #endif
965367d59e6SBram Moolenaar break;
966367d59e6SBram Moolenaar case VAR_CHANNEL:
967367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
9681328bde9SBram Moolenaar if (in_vim9script())
969367d59e6SBram Moolenaar {
9701328bde9SBram Moolenaar semsg(_(e_using_invalid_value_as_string_str), "channel");
9711328bde9SBram Moolenaar break;
972367d59e6SBram Moolenaar }
9731328bde9SBram Moolenaar return channel_to_string_buf(varp, buf);
974367d59e6SBram Moolenaar #endif
975367d59e6SBram Moolenaar break;
976f57b43c2SBram Moolenaar case VAR_VOID:
977f57b43c2SBram Moolenaar emsg(_(e_cannot_use_void_value));
978f57b43c2SBram Moolenaar break;
979367d59e6SBram Moolenaar case VAR_UNKNOWN:
980367d59e6SBram Moolenaar case VAR_ANY:
981f18332fbSBram Moolenaar case VAR_INSTR:
98268db996bSBram Moolenaar semsg(_(e_using_invalid_value_as_string_str),
98368db996bSBram Moolenaar vartype_name(varp->v_type));
984367d59e6SBram Moolenaar break;
985367d59e6SBram Moolenaar }
986367d59e6SBram Moolenaar return NULL;
987367d59e6SBram Moolenaar }
988367d59e6SBram Moolenaar
989367d59e6SBram Moolenaar /*
990367d59e6SBram Moolenaar * Turn a typeval into a string. Similar to tv_get_string_buf() but uses
991367d59e6SBram Moolenaar * string() on Dict, List, etc.
992367d59e6SBram Moolenaar */
993367d59e6SBram Moolenaar char_u *
tv_stringify(typval_T * varp,char_u * buf)994367d59e6SBram Moolenaar tv_stringify(typval_T *varp, char_u *buf)
995367d59e6SBram Moolenaar {
996367d59e6SBram Moolenaar if (varp->v_type == VAR_LIST
997367d59e6SBram Moolenaar || varp->v_type == VAR_DICT
998367d59e6SBram Moolenaar || varp->v_type == VAR_BLOB
999367d59e6SBram Moolenaar || varp->v_type == VAR_FUNC
1000367d59e6SBram Moolenaar || varp->v_type == VAR_PARTIAL
1001367d59e6SBram Moolenaar || varp->v_type == VAR_FLOAT)
1002367d59e6SBram Moolenaar {
1003367d59e6SBram Moolenaar typval_T tmp;
1004367d59e6SBram Moolenaar
1005367d59e6SBram Moolenaar f_string(varp, &tmp);
1006367d59e6SBram Moolenaar tv_get_string_buf(&tmp, buf);
1007367d59e6SBram Moolenaar clear_tv(varp);
1008367d59e6SBram Moolenaar *varp = tmp;
1009367d59e6SBram Moolenaar return tmp.vval.v_string;
1010367d59e6SBram Moolenaar }
1011367d59e6SBram Moolenaar return tv_get_string_buf(varp, buf);
1012367d59e6SBram Moolenaar }
1013367d59e6SBram Moolenaar
1014367d59e6SBram Moolenaar /*
1015367d59e6SBram Moolenaar * Return TRUE if typeval "tv" and its value are set to be locked (immutable).
1016367d59e6SBram Moolenaar * Also give an error message, using "name" or _("name") when use_gettext is
1017367d59e6SBram Moolenaar * TRUE.
1018367d59e6SBram Moolenaar */
1019367d59e6SBram Moolenaar int
tv_check_lock(typval_T * tv,char_u * name,int use_gettext)1020367d59e6SBram Moolenaar tv_check_lock(typval_T *tv, char_u *name, int use_gettext)
1021367d59e6SBram Moolenaar {
1022367d59e6SBram Moolenaar int lock = 0;
1023367d59e6SBram Moolenaar
1024367d59e6SBram Moolenaar switch (tv->v_type)
1025367d59e6SBram Moolenaar {
1026367d59e6SBram Moolenaar case VAR_BLOB:
1027367d59e6SBram Moolenaar if (tv->vval.v_blob != NULL)
1028367d59e6SBram Moolenaar lock = tv->vval.v_blob->bv_lock;
1029367d59e6SBram Moolenaar break;
1030367d59e6SBram Moolenaar case VAR_LIST:
1031367d59e6SBram Moolenaar if (tv->vval.v_list != NULL)
1032367d59e6SBram Moolenaar lock = tv->vval.v_list->lv_lock;
1033367d59e6SBram Moolenaar break;
1034367d59e6SBram Moolenaar case VAR_DICT:
1035367d59e6SBram Moolenaar if (tv->vval.v_dict != NULL)
1036367d59e6SBram Moolenaar lock = tv->vval.v_dict->dv_lock;
1037367d59e6SBram Moolenaar break;
1038367d59e6SBram Moolenaar default:
1039367d59e6SBram Moolenaar break;
1040367d59e6SBram Moolenaar }
1041a187c43cSBram Moolenaar return value_check_lock(tv->v_lock, name, use_gettext)
1042a187c43cSBram Moolenaar || (lock != 0 && value_check_lock(lock, name, use_gettext));
1043367d59e6SBram Moolenaar }
1044367d59e6SBram Moolenaar
1045367d59e6SBram Moolenaar /*
1046367d59e6SBram Moolenaar * Copy the values from typval_T "from" to typval_T "to".
1047367d59e6SBram Moolenaar * When needed allocates string or increases reference count.
1048367d59e6SBram Moolenaar * Does not make a copy of a list, blob or dict but copies the reference!
1049367d59e6SBram Moolenaar * It is OK for "from" and "to" to point to the same item. This is used to
1050367d59e6SBram Moolenaar * make a copy later.
1051367d59e6SBram Moolenaar */
1052367d59e6SBram Moolenaar void
copy_tv(typval_T * from,typval_T * to)1053367d59e6SBram Moolenaar copy_tv(typval_T *from, typval_T *to)
1054367d59e6SBram Moolenaar {
1055367d59e6SBram Moolenaar to->v_type = from->v_type;
1056367d59e6SBram Moolenaar to->v_lock = 0;
1057367d59e6SBram Moolenaar switch (from->v_type)
1058367d59e6SBram Moolenaar {
1059367d59e6SBram Moolenaar case VAR_NUMBER:
1060367d59e6SBram Moolenaar case VAR_BOOL:
1061367d59e6SBram Moolenaar case VAR_SPECIAL:
1062367d59e6SBram Moolenaar to->vval.v_number = from->vval.v_number;
1063367d59e6SBram Moolenaar break;
1064367d59e6SBram Moolenaar case VAR_FLOAT:
1065367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
1066367d59e6SBram Moolenaar to->vval.v_float = from->vval.v_float;
1067367d59e6SBram Moolenaar break;
1068367d59e6SBram Moolenaar #endif
1069367d59e6SBram Moolenaar case VAR_JOB:
1070367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
1071367d59e6SBram Moolenaar to->vval.v_job = from->vval.v_job;
1072367d59e6SBram Moolenaar if (to->vval.v_job != NULL)
1073367d59e6SBram Moolenaar ++to->vval.v_job->jv_refcount;
1074367d59e6SBram Moolenaar break;
1075367d59e6SBram Moolenaar #endif
1076367d59e6SBram Moolenaar case VAR_CHANNEL:
1077367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
1078367d59e6SBram Moolenaar to->vval.v_channel = from->vval.v_channel;
1079367d59e6SBram Moolenaar if (to->vval.v_channel != NULL)
1080367d59e6SBram Moolenaar ++to->vval.v_channel->ch_refcount;
1081367d59e6SBram Moolenaar break;
1082367d59e6SBram Moolenaar #endif
1083f18332fbSBram Moolenaar case VAR_INSTR:
1084f18332fbSBram Moolenaar to->vval.v_instr = from->vval.v_instr;
1085f18332fbSBram Moolenaar break;
1086f18332fbSBram Moolenaar
1087367d59e6SBram Moolenaar case VAR_STRING:
1088367d59e6SBram Moolenaar case VAR_FUNC:
1089367d59e6SBram Moolenaar if (from->vval.v_string == NULL)
1090367d59e6SBram Moolenaar to->vval.v_string = NULL;
1091367d59e6SBram Moolenaar else
1092367d59e6SBram Moolenaar {
1093367d59e6SBram Moolenaar to->vval.v_string = vim_strsave(from->vval.v_string);
1094367d59e6SBram Moolenaar if (from->v_type == VAR_FUNC)
1095367d59e6SBram Moolenaar func_ref(to->vval.v_string);
1096367d59e6SBram Moolenaar }
1097367d59e6SBram Moolenaar break;
1098367d59e6SBram Moolenaar case VAR_PARTIAL:
1099367d59e6SBram Moolenaar if (from->vval.v_partial == NULL)
1100367d59e6SBram Moolenaar to->vval.v_partial = NULL;
1101367d59e6SBram Moolenaar else
1102367d59e6SBram Moolenaar {
1103367d59e6SBram Moolenaar to->vval.v_partial = from->vval.v_partial;
1104367d59e6SBram Moolenaar ++to->vval.v_partial->pt_refcount;
1105367d59e6SBram Moolenaar }
1106367d59e6SBram Moolenaar break;
1107367d59e6SBram Moolenaar case VAR_BLOB:
1108367d59e6SBram Moolenaar if (from->vval.v_blob == NULL)
1109367d59e6SBram Moolenaar to->vval.v_blob = NULL;
1110367d59e6SBram Moolenaar else
1111367d59e6SBram Moolenaar {
1112367d59e6SBram Moolenaar to->vval.v_blob = from->vval.v_blob;
1113367d59e6SBram Moolenaar ++to->vval.v_blob->bv_refcount;
1114367d59e6SBram Moolenaar }
1115367d59e6SBram Moolenaar break;
1116367d59e6SBram Moolenaar case VAR_LIST:
1117367d59e6SBram Moolenaar if (from->vval.v_list == NULL)
1118367d59e6SBram Moolenaar to->vval.v_list = NULL;
1119367d59e6SBram Moolenaar else
1120367d59e6SBram Moolenaar {
1121367d59e6SBram Moolenaar to->vval.v_list = from->vval.v_list;
1122367d59e6SBram Moolenaar ++to->vval.v_list->lv_refcount;
1123367d59e6SBram Moolenaar }
1124367d59e6SBram Moolenaar break;
1125367d59e6SBram Moolenaar case VAR_DICT:
1126367d59e6SBram Moolenaar if (from->vval.v_dict == NULL)
1127367d59e6SBram Moolenaar to->vval.v_dict = NULL;
1128367d59e6SBram Moolenaar else
1129367d59e6SBram Moolenaar {
1130367d59e6SBram Moolenaar to->vval.v_dict = from->vval.v_dict;
1131367d59e6SBram Moolenaar ++to->vval.v_dict->dv_refcount;
1132367d59e6SBram Moolenaar }
1133367d59e6SBram Moolenaar break;
113461a417b7SBram Moolenaar case VAR_VOID:
113561a417b7SBram Moolenaar emsg(_(e_cannot_use_void_value));
113661a417b7SBram Moolenaar break;
1137367d59e6SBram Moolenaar case VAR_UNKNOWN:
1138367d59e6SBram Moolenaar case VAR_ANY:
1139367d59e6SBram Moolenaar internal_error_no_abort("copy_tv(UNKNOWN)");
1140367d59e6SBram Moolenaar break;
1141367d59e6SBram Moolenaar }
1142367d59e6SBram Moolenaar }
1143367d59e6SBram Moolenaar
1144367d59e6SBram Moolenaar /*
1145367d59e6SBram Moolenaar * Compare "typ1" and "typ2". Put the result in "typ1".
1146367d59e6SBram Moolenaar */
1147367d59e6SBram Moolenaar int
typval_compare(typval_T * typ1,typval_T * typ2,exprtype_T type,int ic)1148367d59e6SBram Moolenaar typval_compare(
1149367d59e6SBram Moolenaar typval_T *typ1, // first operand
1150367d59e6SBram Moolenaar typval_T *typ2, // second operand
1151657137caSBram Moolenaar exprtype_T type, // operator
1152367d59e6SBram Moolenaar int ic) // ignore case
1153367d59e6SBram Moolenaar {
1154367d59e6SBram Moolenaar int i;
1155367d59e6SBram Moolenaar varnumber_T n1, n2;
1156367d59e6SBram Moolenaar char_u *s1, *s2;
1157367d59e6SBram Moolenaar char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
1158367d59e6SBram Moolenaar int type_is = type == EXPR_IS || type == EXPR_ISNOT;
1159367d59e6SBram Moolenaar
1160367d59e6SBram Moolenaar if (type_is && typ1->v_type != typ2->v_type)
1161367d59e6SBram Moolenaar {
1162367d59e6SBram Moolenaar // For "is" a different type always means FALSE, for "notis"
1163367d59e6SBram Moolenaar // it means TRUE.
1164367d59e6SBram Moolenaar n1 = (type == EXPR_ISNOT);
1165367d59e6SBram Moolenaar }
1166367d59e6SBram Moolenaar else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB)
1167367d59e6SBram Moolenaar {
1168367d59e6SBram Moolenaar if (type_is)
1169367d59e6SBram Moolenaar {
1170367d59e6SBram Moolenaar n1 = (typ1->v_type == typ2->v_type
1171367d59e6SBram Moolenaar && typ1->vval.v_blob == typ2->vval.v_blob);
1172367d59e6SBram Moolenaar if (type == EXPR_ISNOT)
1173367d59e6SBram Moolenaar n1 = !n1;
1174367d59e6SBram Moolenaar }
1175367d59e6SBram Moolenaar else if (typ1->v_type != typ2->v_type
1176367d59e6SBram Moolenaar || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1177367d59e6SBram Moolenaar {
1178367d59e6SBram Moolenaar if (typ1->v_type != typ2->v_type)
1179367d59e6SBram Moolenaar emsg(_("E977: Can only compare Blob with Blob"));
1180367d59e6SBram Moolenaar else
1181367d59e6SBram Moolenaar emsg(_(e_invalblob));
1182367d59e6SBram Moolenaar clear_tv(typ1);
1183367d59e6SBram Moolenaar return FAIL;
1184367d59e6SBram Moolenaar }
1185367d59e6SBram Moolenaar else
1186367d59e6SBram Moolenaar {
1187367d59e6SBram Moolenaar // Compare two Blobs for being equal or unequal.
1188367d59e6SBram Moolenaar n1 = blob_equal(typ1->vval.v_blob, typ2->vval.v_blob);
1189367d59e6SBram Moolenaar if (type == EXPR_NEQUAL)
1190367d59e6SBram Moolenaar n1 = !n1;
1191367d59e6SBram Moolenaar }
1192367d59e6SBram Moolenaar }
1193367d59e6SBram Moolenaar else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
1194367d59e6SBram Moolenaar {
1195367d59e6SBram Moolenaar if (type_is)
1196367d59e6SBram Moolenaar {
1197367d59e6SBram Moolenaar n1 = (typ1->v_type == typ2->v_type
1198367d59e6SBram Moolenaar && typ1->vval.v_list == typ2->vval.v_list);
1199367d59e6SBram Moolenaar if (type == EXPR_ISNOT)
1200367d59e6SBram Moolenaar n1 = !n1;
1201367d59e6SBram Moolenaar }
1202367d59e6SBram Moolenaar else if (typ1->v_type != typ2->v_type
1203367d59e6SBram Moolenaar || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1204367d59e6SBram Moolenaar {
1205367d59e6SBram Moolenaar if (typ1->v_type != typ2->v_type)
1206367d59e6SBram Moolenaar emsg(_("E691: Can only compare List with List"));
1207367d59e6SBram Moolenaar else
1208367d59e6SBram Moolenaar emsg(_("E692: Invalid operation for List"));
1209367d59e6SBram Moolenaar clear_tv(typ1);
1210367d59e6SBram Moolenaar return FAIL;
1211367d59e6SBram Moolenaar }
1212367d59e6SBram Moolenaar else
1213367d59e6SBram Moolenaar {
1214367d59e6SBram Moolenaar // Compare two Lists for being equal or unequal.
1215367d59e6SBram Moolenaar n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list,
1216367d59e6SBram Moolenaar ic, FALSE);
1217367d59e6SBram Moolenaar if (type == EXPR_NEQUAL)
1218367d59e6SBram Moolenaar n1 = !n1;
1219367d59e6SBram Moolenaar }
1220367d59e6SBram Moolenaar }
1221367d59e6SBram Moolenaar
1222367d59e6SBram Moolenaar else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
1223367d59e6SBram Moolenaar {
1224367d59e6SBram Moolenaar if (type_is)
1225367d59e6SBram Moolenaar {
1226367d59e6SBram Moolenaar n1 = (typ1->v_type == typ2->v_type
1227367d59e6SBram Moolenaar && typ1->vval.v_dict == typ2->vval.v_dict);
1228367d59e6SBram Moolenaar if (type == EXPR_ISNOT)
1229367d59e6SBram Moolenaar n1 = !n1;
1230367d59e6SBram Moolenaar }
1231367d59e6SBram Moolenaar else if (typ1->v_type != typ2->v_type
1232367d59e6SBram Moolenaar || (type != EXPR_EQUAL && type != EXPR_NEQUAL))
1233367d59e6SBram Moolenaar {
1234367d59e6SBram Moolenaar if (typ1->v_type != typ2->v_type)
1235367d59e6SBram Moolenaar emsg(_("E735: Can only compare Dictionary with Dictionary"));
1236367d59e6SBram Moolenaar else
1237367d59e6SBram Moolenaar emsg(_("E736: Invalid operation for Dictionary"));
1238367d59e6SBram Moolenaar clear_tv(typ1);
1239367d59e6SBram Moolenaar return FAIL;
1240367d59e6SBram Moolenaar }
1241367d59e6SBram Moolenaar else
1242367d59e6SBram Moolenaar {
1243367d59e6SBram Moolenaar // Compare two Dictionaries for being equal or unequal.
1244367d59e6SBram Moolenaar n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict,
1245367d59e6SBram Moolenaar ic, FALSE);
1246367d59e6SBram Moolenaar if (type == EXPR_NEQUAL)
1247367d59e6SBram Moolenaar n1 = !n1;
1248367d59e6SBram Moolenaar }
1249367d59e6SBram Moolenaar }
1250367d59e6SBram Moolenaar
1251367d59e6SBram Moolenaar else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
1252367d59e6SBram Moolenaar || typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
1253367d59e6SBram Moolenaar {
1254367d59e6SBram Moolenaar if (type != EXPR_EQUAL && type != EXPR_NEQUAL
1255367d59e6SBram Moolenaar && type != EXPR_IS && type != EXPR_ISNOT)
1256367d59e6SBram Moolenaar {
1257367d59e6SBram Moolenaar emsg(_("E694: Invalid operation for Funcrefs"));
1258367d59e6SBram Moolenaar clear_tv(typ1);
1259367d59e6SBram Moolenaar return FAIL;
1260367d59e6SBram Moolenaar }
1261367d59e6SBram Moolenaar if ((typ1->v_type == VAR_PARTIAL
1262367d59e6SBram Moolenaar && typ1->vval.v_partial == NULL)
1263367d59e6SBram Moolenaar || (typ2->v_type == VAR_PARTIAL
1264367d59e6SBram Moolenaar && typ2->vval.v_partial == NULL))
1265367d59e6SBram Moolenaar // When both partials are NULL, then they are equal.
1266367d59e6SBram Moolenaar // Otherwise they are not equal.
1267367d59e6SBram Moolenaar n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
1268367d59e6SBram Moolenaar else if (type_is)
1269367d59e6SBram Moolenaar {
1270367d59e6SBram Moolenaar if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
1271367d59e6SBram Moolenaar // strings are considered the same if their value is
1272367d59e6SBram Moolenaar // the same
1273367d59e6SBram Moolenaar n1 = tv_equal(typ1, typ2, ic, FALSE);
1274367d59e6SBram Moolenaar else if (typ1->v_type == VAR_PARTIAL
1275367d59e6SBram Moolenaar && typ2->v_type == VAR_PARTIAL)
1276367d59e6SBram Moolenaar n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
1277367d59e6SBram Moolenaar else
1278367d59e6SBram Moolenaar n1 = FALSE;
1279367d59e6SBram Moolenaar }
1280367d59e6SBram Moolenaar else
1281367d59e6SBram Moolenaar n1 = tv_equal(typ1, typ2, ic, FALSE);
1282367d59e6SBram Moolenaar if (type == EXPR_NEQUAL || type == EXPR_ISNOT)
1283367d59e6SBram Moolenaar n1 = !n1;
1284367d59e6SBram Moolenaar }
1285367d59e6SBram Moolenaar
1286367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
1287367d59e6SBram Moolenaar // If one of the two variables is a float, compare as a float.
1288367d59e6SBram Moolenaar // When using "=~" or "!~", always compare as string.
1289367d59e6SBram Moolenaar else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
1290367d59e6SBram Moolenaar && type != EXPR_MATCH && type != EXPR_NOMATCH)
1291367d59e6SBram Moolenaar {
1292367d59e6SBram Moolenaar float_T f1, f2;
1293367d59e6SBram Moolenaar
1294367d59e6SBram Moolenaar f1 = tv_get_float(typ1);
1295367d59e6SBram Moolenaar f2 = tv_get_float(typ2);
1296367d59e6SBram Moolenaar n1 = FALSE;
1297367d59e6SBram Moolenaar switch (type)
1298367d59e6SBram Moolenaar {
1299367d59e6SBram Moolenaar case EXPR_IS:
1300367d59e6SBram Moolenaar case EXPR_EQUAL: n1 = (f1 == f2); break;
1301367d59e6SBram Moolenaar case EXPR_ISNOT:
1302367d59e6SBram Moolenaar case EXPR_NEQUAL: n1 = (f1 != f2); break;
1303367d59e6SBram Moolenaar case EXPR_GREATER: n1 = (f1 > f2); break;
1304367d59e6SBram Moolenaar case EXPR_GEQUAL: n1 = (f1 >= f2); break;
1305367d59e6SBram Moolenaar case EXPR_SMALLER: n1 = (f1 < f2); break;
1306367d59e6SBram Moolenaar case EXPR_SEQUAL: n1 = (f1 <= f2); break;
1307367d59e6SBram Moolenaar case EXPR_UNKNOWN:
1308367d59e6SBram Moolenaar case EXPR_MATCH:
1309367d59e6SBram Moolenaar default: break; // avoid gcc warning
1310367d59e6SBram Moolenaar }
1311367d59e6SBram Moolenaar }
1312367d59e6SBram Moolenaar #endif
1313367d59e6SBram Moolenaar
1314367d59e6SBram Moolenaar // If one of the two variables is a number, compare as a number.
1315367d59e6SBram Moolenaar // When using "=~" or "!~", always compare as string.
1316367d59e6SBram Moolenaar else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
1317367d59e6SBram Moolenaar && type != EXPR_MATCH && type != EXPR_NOMATCH)
1318367d59e6SBram Moolenaar {
1319367d59e6SBram Moolenaar n1 = tv_get_number(typ1);
1320367d59e6SBram Moolenaar n2 = tv_get_number(typ2);
1321367d59e6SBram Moolenaar switch (type)
1322367d59e6SBram Moolenaar {
1323367d59e6SBram Moolenaar case EXPR_IS:
1324367d59e6SBram Moolenaar case EXPR_EQUAL: n1 = (n1 == n2); break;
1325367d59e6SBram Moolenaar case EXPR_ISNOT:
1326367d59e6SBram Moolenaar case EXPR_NEQUAL: n1 = (n1 != n2); break;
1327367d59e6SBram Moolenaar case EXPR_GREATER: n1 = (n1 > n2); break;
1328367d59e6SBram Moolenaar case EXPR_GEQUAL: n1 = (n1 >= n2); break;
1329367d59e6SBram Moolenaar case EXPR_SMALLER: n1 = (n1 < n2); break;
1330367d59e6SBram Moolenaar case EXPR_SEQUAL: n1 = (n1 <= n2); break;
1331367d59e6SBram Moolenaar case EXPR_UNKNOWN:
1332367d59e6SBram Moolenaar case EXPR_MATCH:
1333367d59e6SBram Moolenaar default: break; // avoid gcc warning
1334367d59e6SBram Moolenaar }
1335367d59e6SBram Moolenaar }
1336cff40ff9SBram Moolenaar else if (in_vim9script() && (typ1->v_type == VAR_BOOL
13370c35752dSBram Moolenaar || typ2->v_type == VAR_BOOL
13380c35752dSBram Moolenaar || (typ1->v_type == VAR_SPECIAL
13390c35752dSBram Moolenaar && typ2->v_type == VAR_SPECIAL)))
1340cff40ff9SBram Moolenaar {
1341cff40ff9SBram Moolenaar if (typ1->v_type != typ2->v_type)
1342cff40ff9SBram Moolenaar {
1343cff40ff9SBram Moolenaar semsg(_(e_cannot_compare_str_with_str),
1344cff40ff9SBram Moolenaar vartype_name(typ1->v_type), vartype_name(typ2->v_type));
1345cff40ff9SBram Moolenaar clear_tv(typ1);
1346cff40ff9SBram Moolenaar return FAIL;
1347cff40ff9SBram Moolenaar }
1348cff40ff9SBram Moolenaar n1 = typ1->vval.v_number;
1349cff40ff9SBram Moolenaar n2 = typ2->vval.v_number;
1350cff40ff9SBram Moolenaar switch (type)
1351cff40ff9SBram Moolenaar {
1352cff40ff9SBram Moolenaar case EXPR_IS:
1353cff40ff9SBram Moolenaar case EXPR_EQUAL: n1 = (n1 == n2); break;
1354cff40ff9SBram Moolenaar case EXPR_ISNOT:
1355cff40ff9SBram Moolenaar case EXPR_NEQUAL: n1 = (n1 != n2); break;
1356cff40ff9SBram Moolenaar default:
13570c35752dSBram Moolenaar semsg(_(e_invalid_operation_for_str),
13580c35752dSBram Moolenaar vartype_name(typ1->v_type));
1359cff40ff9SBram Moolenaar clear_tv(typ1);
1360cff40ff9SBram Moolenaar return FAIL;
1361cff40ff9SBram Moolenaar }
1362cff40ff9SBram Moolenaar }
1363367d59e6SBram Moolenaar else
1364367d59e6SBram Moolenaar {
13650c35752dSBram Moolenaar if (in_vim9script()
13660c35752dSBram Moolenaar && ((typ1->v_type != VAR_STRING && typ1->v_type != VAR_SPECIAL)
13670c35752dSBram Moolenaar || (typ2->v_type != VAR_STRING && typ2->v_type != VAR_SPECIAL)))
13680c35752dSBram Moolenaar {
13690c35752dSBram Moolenaar semsg(_(e_cannot_compare_str_with_str),
13700c35752dSBram Moolenaar vartype_name(typ1->v_type), vartype_name(typ2->v_type));
13710c35752dSBram Moolenaar clear_tv(typ1);
13720c35752dSBram Moolenaar return FAIL;
13730c35752dSBram Moolenaar }
1374367d59e6SBram Moolenaar s1 = tv_get_string_buf(typ1, buf1);
1375367d59e6SBram Moolenaar s2 = tv_get_string_buf(typ2, buf2);
1376367d59e6SBram Moolenaar if (type != EXPR_MATCH && type != EXPR_NOMATCH)
1377367d59e6SBram Moolenaar i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
1378367d59e6SBram Moolenaar else
1379367d59e6SBram Moolenaar i = 0;
1380367d59e6SBram Moolenaar n1 = FALSE;
1381367d59e6SBram Moolenaar switch (type)
1382367d59e6SBram Moolenaar {
1383367d59e6SBram Moolenaar case EXPR_IS:
1384367d59e6SBram Moolenaar case EXPR_EQUAL: n1 = (i == 0); break;
1385367d59e6SBram Moolenaar case EXPR_ISNOT:
1386367d59e6SBram Moolenaar case EXPR_NEQUAL: n1 = (i != 0); break;
1387367d59e6SBram Moolenaar case EXPR_GREATER: n1 = (i > 0); break;
1388367d59e6SBram Moolenaar case EXPR_GEQUAL: n1 = (i >= 0); break;
1389367d59e6SBram Moolenaar case EXPR_SMALLER: n1 = (i < 0); break;
1390367d59e6SBram Moolenaar case EXPR_SEQUAL: n1 = (i <= 0); break;
1391367d59e6SBram Moolenaar
1392367d59e6SBram Moolenaar case EXPR_MATCH:
1393367d59e6SBram Moolenaar case EXPR_NOMATCH:
1394367d59e6SBram Moolenaar n1 = pattern_match(s2, s1, ic);
1395367d59e6SBram Moolenaar if (type == EXPR_NOMATCH)
1396367d59e6SBram Moolenaar n1 = !n1;
1397367d59e6SBram Moolenaar break;
1398367d59e6SBram Moolenaar
1399367d59e6SBram Moolenaar default: break; // avoid gcc warning
1400367d59e6SBram Moolenaar }
1401367d59e6SBram Moolenaar }
1402367d59e6SBram Moolenaar clear_tv(typ1);
1403c71f36a8SBram Moolenaar if (in_vim9script())
1404c71f36a8SBram Moolenaar {
1405c71f36a8SBram Moolenaar typ1->v_type = VAR_BOOL;
1406c71f36a8SBram Moolenaar typ1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE;
1407c71f36a8SBram Moolenaar }
1408c71f36a8SBram Moolenaar else
1409c71f36a8SBram Moolenaar {
1410367d59e6SBram Moolenaar typ1->v_type = VAR_NUMBER;
1411367d59e6SBram Moolenaar typ1->vval.v_number = n1;
1412c71f36a8SBram Moolenaar }
1413367d59e6SBram Moolenaar
1414367d59e6SBram Moolenaar return OK;
1415367d59e6SBram Moolenaar }
1416367d59e6SBram Moolenaar
141734453208SBram Moolenaar /*
141834453208SBram Moolenaar * Convert any type to a string, never give an error.
141934453208SBram Moolenaar * When "quotes" is TRUE add quotes to a string.
142034453208SBram Moolenaar * Returns an allocated string.
142134453208SBram Moolenaar */
1422367d59e6SBram Moolenaar char_u *
typval_tostring(typval_T * arg,int quotes)142334453208SBram Moolenaar typval_tostring(typval_T *arg, int quotes)
1424367d59e6SBram Moolenaar {
1425367d59e6SBram Moolenaar char_u *tofree;
1426367d59e6SBram Moolenaar char_u numbuf[NUMBUFLEN];
1427367d59e6SBram Moolenaar char_u *ret = NULL;
1428367d59e6SBram Moolenaar
1429367d59e6SBram Moolenaar if (arg == NULL)
1430367d59e6SBram Moolenaar return vim_strsave((char_u *)"(does not exist)");
143134453208SBram Moolenaar if (!quotes && arg->v_type == VAR_STRING)
143234453208SBram Moolenaar {
143334453208SBram Moolenaar ret = vim_strsave(arg->vval.v_string == NULL ? (char_u *)""
143434453208SBram Moolenaar : arg->vval.v_string);
143534453208SBram Moolenaar }
143634453208SBram Moolenaar else
143734453208SBram Moolenaar {
1438367d59e6SBram Moolenaar ret = tv2string(arg, &tofree, numbuf, 0);
1439367d59e6SBram Moolenaar // Make a copy if we have a value but it's not in allocated memory.
1440367d59e6SBram Moolenaar if (ret != NULL && tofree == NULL)
1441367d59e6SBram Moolenaar ret = vim_strsave(ret);
144234453208SBram Moolenaar }
1443367d59e6SBram Moolenaar return ret;
1444367d59e6SBram Moolenaar }
1445367d59e6SBram Moolenaar
1446367d59e6SBram Moolenaar /*
1447367d59e6SBram Moolenaar * Return TRUE if typeval "tv" is locked: Either that value is locked itself
1448367d59e6SBram Moolenaar * or it refers to a List or Dictionary that is locked.
1449367d59e6SBram Moolenaar */
1450367d59e6SBram Moolenaar int
tv_islocked(typval_T * tv)1451367d59e6SBram Moolenaar tv_islocked(typval_T *tv)
1452367d59e6SBram Moolenaar {
1453367d59e6SBram Moolenaar return (tv->v_lock & VAR_LOCKED)
1454367d59e6SBram Moolenaar || (tv->v_type == VAR_LIST
1455367d59e6SBram Moolenaar && tv->vval.v_list != NULL
1456367d59e6SBram Moolenaar && (tv->vval.v_list->lv_lock & VAR_LOCKED))
1457367d59e6SBram Moolenaar || (tv->v_type == VAR_DICT
1458367d59e6SBram Moolenaar && tv->vval.v_dict != NULL
1459367d59e6SBram Moolenaar && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
1460367d59e6SBram Moolenaar }
1461367d59e6SBram Moolenaar
1462367d59e6SBram Moolenaar static int
func_equal(typval_T * tv1,typval_T * tv2,int ic)1463367d59e6SBram Moolenaar func_equal(
1464367d59e6SBram Moolenaar typval_T *tv1,
1465367d59e6SBram Moolenaar typval_T *tv2,
1466367d59e6SBram Moolenaar int ic) // ignore case
1467367d59e6SBram Moolenaar {
1468367d59e6SBram Moolenaar char_u *s1, *s2;
1469367d59e6SBram Moolenaar dict_T *d1, *d2;
1470367d59e6SBram Moolenaar int a1, a2;
1471367d59e6SBram Moolenaar int i;
1472367d59e6SBram Moolenaar
1473367d59e6SBram Moolenaar // empty and NULL function name considered the same
1474367d59e6SBram Moolenaar s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
1475367d59e6SBram Moolenaar : partial_name(tv1->vval.v_partial);
1476367d59e6SBram Moolenaar if (s1 != NULL && *s1 == NUL)
1477367d59e6SBram Moolenaar s1 = NULL;
1478367d59e6SBram Moolenaar s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
1479367d59e6SBram Moolenaar : partial_name(tv2->vval.v_partial);
1480367d59e6SBram Moolenaar if (s2 != NULL && *s2 == NUL)
1481367d59e6SBram Moolenaar s2 = NULL;
1482367d59e6SBram Moolenaar if (s1 == NULL || s2 == NULL)
1483367d59e6SBram Moolenaar {
1484367d59e6SBram Moolenaar if (s1 != s2)
1485367d59e6SBram Moolenaar return FALSE;
1486367d59e6SBram Moolenaar }
1487367d59e6SBram Moolenaar else if (STRCMP(s1, s2) != 0)
1488367d59e6SBram Moolenaar return FALSE;
1489367d59e6SBram Moolenaar
1490367d59e6SBram Moolenaar // empty dict and NULL dict is different
1491367d59e6SBram Moolenaar d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict;
1492367d59e6SBram Moolenaar d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict;
1493367d59e6SBram Moolenaar if (d1 == NULL || d2 == NULL)
1494367d59e6SBram Moolenaar {
1495367d59e6SBram Moolenaar if (d1 != d2)
1496367d59e6SBram Moolenaar return FALSE;
1497367d59e6SBram Moolenaar }
1498367d59e6SBram Moolenaar else if (!dict_equal(d1, d2, ic, TRUE))
1499367d59e6SBram Moolenaar return FALSE;
1500367d59e6SBram Moolenaar
1501367d59e6SBram Moolenaar // empty list and no list considered the same
1502367d59e6SBram Moolenaar a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc;
1503367d59e6SBram Moolenaar a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc;
1504367d59e6SBram Moolenaar if (a1 != a2)
1505367d59e6SBram Moolenaar return FALSE;
1506367d59e6SBram Moolenaar for (i = 0; i < a1; ++i)
1507367d59e6SBram Moolenaar if (!tv_equal(tv1->vval.v_partial->pt_argv + i,
1508367d59e6SBram Moolenaar tv2->vval.v_partial->pt_argv + i, ic, TRUE))
1509367d59e6SBram Moolenaar return FALSE;
1510367d59e6SBram Moolenaar
1511367d59e6SBram Moolenaar return TRUE;
1512367d59e6SBram Moolenaar }
1513367d59e6SBram Moolenaar
1514367d59e6SBram Moolenaar /*
1515367d59e6SBram Moolenaar * Return TRUE if "tv1" and "tv2" have the same value.
1516367d59e6SBram Moolenaar * Compares the items just like "==" would compare them, but strings and
1517367d59e6SBram Moolenaar * numbers are different. Floats and numbers are also different.
1518367d59e6SBram Moolenaar */
1519367d59e6SBram Moolenaar int
tv_equal(typval_T * tv1,typval_T * tv2,int ic,int recursive)1520367d59e6SBram Moolenaar tv_equal(
1521367d59e6SBram Moolenaar typval_T *tv1,
1522367d59e6SBram Moolenaar typval_T *tv2,
1523367d59e6SBram Moolenaar int ic, // ignore case
1524367d59e6SBram Moolenaar int recursive) // TRUE when used recursively
1525367d59e6SBram Moolenaar {
1526367d59e6SBram Moolenaar char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
1527367d59e6SBram Moolenaar char_u *s1, *s2;
1528367d59e6SBram Moolenaar static int recursive_cnt = 0; // catch recursive loops
1529367d59e6SBram Moolenaar int r;
1530367d59e6SBram Moolenaar static int tv_equal_recurse_limit;
1531367d59e6SBram Moolenaar
1532367d59e6SBram Moolenaar // Catch lists and dicts that have an endless loop by limiting
1533367d59e6SBram Moolenaar // recursiveness to a limit. We guess they are equal then.
1534367d59e6SBram Moolenaar // A fixed limit has the problem of still taking an awful long time.
1535367d59e6SBram Moolenaar // Reduce the limit every time running into it. That should work fine for
1536367d59e6SBram Moolenaar // deeply linked structures that are not recursively linked and catch
1537367d59e6SBram Moolenaar // recursiveness quickly.
1538367d59e6SBram Moolenaar if (!recursive)
1539367d59e6SBram Moolenaar tv_equal_recurse_limit = 1000;
1540367d59e6SBram Moolenaar if (recursive_cnt >= tv_equal_recurse_limit)
1541367d59e6SBram Moolenaar {
1542367d59e6SBram Moolenaar --tv_equal_recurse_limit;
1543367d59e6SBram Moolenaar return TRUE;
1544367d59e6SBram Moolenaar }
1545367d59e6SBram Moolenaar
1546367d59e6SBram Moolenaar // For VAR_FUNC and VAR_PARTIAL compare the function name, bound dict and
1547367d59e6SBram Moolenaar // arguments.
1548367d59e6SBram Moolenaar if ((tv1->v_type == VAR_FUNC
1549367d59e6SBram Moolenaar || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))
1550367d59e6SBram Moolenaar && (tv2->v_type == VAR_FUNC
1551367d59e6SBram Moolenaar || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL)))
1552367d59e6SBram Moolenaar {
1553367d59e6SBram Moolenaar ++recursive_cnt;
1554367d59e6SBram Moolenaar r = func_equal(tv1, tv2, ic);
1555367d59e6SBram Moolenaar --recursive_cnt;
1556367d59e6SBram Moolenaar return r;
1557367d59e6SBram Moolenaar }
1558367d59e6SBram Moolenaar
1559418a29f0SBram Moolenaar if (tv1->v_type != tv2->v_type
1560418a29f0SBram Moolenaar && ((tv1->v_type != VAR_BOOL && tv1->v_type != VAR_SPECIAL)
1561418a29f0SBram Moolenaar || (tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL)))
1562367d59e6SBram Moolenaar return FALSE;
1563367d59e6SBram Moolenaar
1564367d59e6SBram Moolenaar switch (tv1->v_type)
1565367d59e6SBram Moolenaar {
1566367d59e6SBram Moolenaar case VAR_LIST:
1567367d59e6SBram Moolenaar ++recursive_cnt;
1568367d59e6SBram Moolenaar r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE);
1569367d59e6SBram Moolenaar --recursive_cnt;
1570367d59e6SBram Moolenaar return r;
1571367d59e6SBram Moolenaar
1572367d59e6SBram Moolenaar case VAR_DICT:
1573367d59e6SBram Moolenaar ++recursive_cnt;
1574367d59e6SBram Moolenaar r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, TRUE);
1575367d59e6SBram Moolenaar --recursive_cnt;
1576367d59e6SBram Moolenaar return r;
1577367d59e6SBram Moolenaar
1578367d59e6SBram Moolenaar case VAR_BLOB:
1579367d59e6SBram Moolenaar return blob_equal(tv1->vval.v_blob, tv2->vval.v_blob);
1580367d59e6SBram Moolenaar
1581367d59e6SBram Moolenaar case VAR_NUMBER:
1582367d59e6SBram Moolenaar case VAR_BOOL:
1583367d59e6SBram Moolenaar case VAR_SPECIAL:
1584367d59e6SBram Moolenaar return tv1->vval.v_number == tv2->vval.v_number;
1585367d59e6SBram Moolenaar
1586367d59e6SBram Moolenaar case VAR_STRING:
1587367d59e6SBram Moolenaar s1 = tv_get_string_buf(tv1, buf1);
1588367d59e6SBram Moolenaar s2 = tv_get_string_buf(tv2, buf2);
1589367d59e6SBram Moolenaar return ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) == 0);
1590367d59e6SBram Moolenaar
1591367d59e6SBram Moolenaar case VAR_FLOAT:
1592367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
1593367d59e6SBram Moolenaar return tv1->vval.v_float == tv2->vval.v_float;
1594367d59e6SBram Moolenaar #endif
1595367d59e6SBram Moolenaar case VAR_JOB:
1596367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
1597367d59e6SBram Moolenaar return tv1->vval.v_job == tv2->vval.v_job;
1598367d59e6SBram Moolenaar #endif
1599367d59e6SBram Moolenaar case VAR_CHANNEL:
1600367d59e6SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
1601367d59e6SBram Moolenaar return tv1->vval.v_channel == tv2->vval.v_channel;
1602367d59e6SBram Moolenaar #endif
1603f18332fbSBram Moolenaar case VAR_INSTR:
1604f18332fbSBram Moolenaar return tv1->vval.v_instr == tv2->vval.v_instr;
1605367d59e6SBram Moolenaar
1606367d59e6SBram Moolenaar case VAR_PARTIAL:
1607367d59e6SBram Moolenaar return tv1->vval.v_partial == tv2->vval.v_partial;
1608367d59e6SBram Moolenaar
1609367d59e6SBram Moolenaar case VAR_FUNC:
1610367d59e6SBram Moolenaar return tv1->vval.v_string == tv2->vval.v_string;
1611367d59e6SBram Moolenaar
1612367d59e6SBram Moolenaar case VAR_UNKNOWN:
1613367d59e6SBram Moolenaar case VAR_ANY:
1614367d59e6SBram Moolenaar case VAR_VOID:
1615367d59e6SBram Moolenaar break;
1616367d59e6SBram Moolenaar }
1617367d59e6SBram Moolenaar
1618367d59e6SBram Moolenaar // VAR_UNKNOWN can be the result of a invalid expression, let's say it
1619367d59e6SBram Moolenaar // does not equal anything, not even itself.
1620367d59e6SBram Moolenaar return FALSE;
1621367d59e6SBram Moolenaar }
1622367d59e6SBram Moolenaar
1623367d59e6SBram Moolenaar /*
1624367d59e6SBram Moolenaar * Get an option value.
1625367d59e6SBram Moolenaar * "arg" points to the '&' or '+' before the option name.
1626367d59e6SBram Moolenaar * "arg" is advanced to character after the option name.
1627367d59e6SBram Moolenaar * Return OK or FAIL.
1628367d59e6SBram Moolenaar */
1629367d59e6SBram Moolenaar int
eval_option(char_u ** arg,typval_T * rettv,int evaluate)16309a78e6dfSBram Moolenaar eval_option(
1631367d59e6SBram Moolenaar char_u **arg,
1632367d59e6SBram Moolenaar typval_T *rettv, // when NULL, only check if option exists
1633367d59e6SBram Moolenaar int evaluate)
1634367d59e6SBram Moolenaar {
1635367d59e6SBram Moolenaar char_u *option_end;
1636367d59e6SBram Moolenaar long numval;
1637367d59e6SBram Moolenaar char_u *stringval;
1638dd1f426bSBram Moolenaar getoption_T opt_type;
1639367d59e6SBram Moolenaar int c;
1640367d59e6SBram Moolenaar int working = (**arg == '+'); // has("+option")
1641367d59e6SBram Moolenaar int ret = OK;
1642367d59e6SBram Moolenaar int opt_flags;
1643367d59e6SBram Moolenaar
1644367d59e6SBram Moolenaar // Isolate the option name and find its value.
1645367d59e6SBram Moolenaar option_end = find_option_end(arg, &opt_flags);
1646367d59e6SBram Moolenaar if (option_end == NULL)
1647367d59e6SBram Moolenaar {
1648367d59e6SBram Moolenaar if (rettv != NULL)
1649367d59e6SBram Moolenaar semsg(_("E112: Option name missing: %s"), *arg);
1650367d59e6SBram Moolenaar return FAIL;
1651367d59e6SBram Moolenaar }
1652367d59e6SBram Moolenaar
1653367d59e6SBram Moolenaar if (!evaluate)
1654367d59e6SBram Moolenaar {
1655367d59e6SBram Moolenaar *arg = option_end;
1656367d59e6SBram Moolenaar return OK;
1657367d59e6SBram Moolenaar }
1658367d59e6SBram Moolenaar
1659367d59e6SBram Moolenaar c = *option_end;
1660367d59e6SBram Moolenaar *option_end = NUL;
1661367d59e6SBram Moolenaar opt_type = get_option_value(*arg, &numval,
1662367d59e6SBram Moolenaar rettv == NULL ? NULL : &stringval, opt_flags);
1663367d59e6SBram Moolenaar
1664dd1f426bSBram Moolenaar if (opt_type == gov_unknown)
1665367d59e6SBram Moolenaar {
1666367d59e6SBram Moolenaar if (rettv != NULL)
1667367d59e6SBram Moolenaar semsg(_(e_unknown_option), *arg);
1668367d59e6SBram Moolenaar ret = FAIL;
1669367d59e6SBram Moolenaar }
1670367d59e6SBram Moolenaar else if (rettv != NULL)
1671367d59e6SBram Moolenaar {
1672a79925a0SBram Moolenaar rettv->v_lock = 0;
1673dd1f426bSBram Moolenaar if (opt_type == gov_hidden_string)
1674367d59e6SBram Moolenaar {
1675367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
1676367d59e6SBram Moolenaar rettv->vval.v_string = NULL;
1677367d59e6SBram Moolenaar }
1678dd1f426bSBram Moolenaar else if (opt_type == gov_hidden_bool || opt_type == gov_hidden_number)
1679367d59e6SBram Moolenaar {
1680dd1f426bSBram Moolenaar rettv->v_type = in_vim9script() && opt_type == gov_hidden_bool
1681dd1f426bSBram Moolenaar ? VAR_BOOL : VAR_NUMBER;
1682367d59e6SBram Moolenaar rettv->vval.v_number = 0;
1683367d59e6SBram Moolenaar }
1684dd1f426bSBram Moolenaar else if (opt_type == gov_bool || opt_type == gov_number)
1685dd1f426bSBram Moolenaar {
1686dd1f426bSBram Moolenaar if (in_vim9script() && opt_type == gov_bool)
1687dd1f426bSBram Moolenaar {
1688dd1f426bSBram Moolenaar rettv->v_type = VAR_BOOL;
1689dd1f426bSBram Moolenaar rettv->vval.v_number = numval ? VVAL_TRUE : VVAL_FALSE;
1690dd1f426bSBram Moolenaar }
1691dd1f426bSBram Moolenaar else
1692367d59e6SBram Moolenaar {
1693367d59e6SBram Moolenaar rettv->v_type = VAR_NUMBER;
1694367d59e6SBram Moolenaar rettv->vval.v_number = numval;
1695367d59e6SBram Moolenaar }
1696dd1f426bSBram Moolenaar }
1697367d59e6SBram Moolenaar else // string option
1698367d59e6SBram Moolenaar {
1699367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
1700367d59e6SBram Moolenaar rettv->vval.v_string = stringval;
1701367d59e6SBram Moolenaar }
1702367d59e6SBram Moolenaar }
1703dd1f426bSBram Moolenaar else if (working && (opt_type == gov_hidden_bool
1704dd1f426bSBram Moolenaar || opt_type == gov_hidden_number
1705dd1f426bSBram Moolenaar || opt_type == gov_hidden_string))
1706367d59e6SBram Moolenaar ret = FAIL;
1707367d59e6SBram Moolenaar
1708367d59e6SBram Moolenaar *option_end = c; // put back for error messages
1709367d59e6SBram Moolenaar *arg = option_end;
1710367d59e6SBram Moolenaar
1711367d59e6SBram Moolenaar return ret;
1712367d59e6SBram Moolenaar }
1713367d59e6SBram Moolenaar
1714367d59e6SBram Moolenaar /*
1715367d59e6SBram Moolenaar * Allocate a variable for a number constant. Also deals with "0z" for blob.
1716367d59e6SBram Moolenaar * Return OK or FAIL.
1717367d59e6SBram Moolenaar */
1718367d59e6SBram Moolenaar int
eval_number(char_u ** arg,typval_T * rettv,int evaluate,int want_string UNUSED)17199a78e6dfSBram Moolenaar eval_number(
1720367d59e6SBram Moolenaar char_u **arg,
1721367d59e6SBram Moolenaar typval_T *rettv,
1722367d59e6SBram Moolenaar int evaluate,
1723367d59e6SBram Moolenaar int want_string UNUSED)
1724367d59e6SBram Moolenaar {
1725367d59e6SBram Moolenaar int len;
1726dd9de50fSBram Moolenaar int skip_quotes = !in_old_script(4);
1727367d59e6SBram Moolenaar #ifdef FEAT_FLOAT
1728367d59e6SBram Moolenaar char_u *p;
1729367d59e6SBram Moolenaar int get_float = FALSE;
1730367d59e6SBram Moolenaar
1731367d59e6SBram Moolenaar // We accept a float when the format matches
1732367d59e6SBram Moolenaar // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
1733367d59e6SBram Moolenaar // strict to avoid backwards compatibility problems.
1734367d59e6SBram Moolenaar // With script version 2 and later the leading digit can be
1735367d59e6SBram Moolenaar // omitted.
1736367d59e6SBram Moolenaar // Don't look for a float after the "." operator, so that
1737367d59e6SBram Moolenaar // ":let vers = 1.2.3" doesn't fail.
1738367d59e6SBram Moolenaar if (**arg == '.')
1739367d59e6SBram Moolenaar p = *arg;
1740367d59e6SBram Moolenaar else
17412950065eSBram Moolenaar {
17422950065eSBram Moolenaar p = *arg + 1;
17432950065eSBram Moolenaar if (skip_quotes)
17442950065eSBram Moolenaar for (;;)
17452950065eSBram Moolenaar {
17462950065eSBram Moolenaar if (*p == '\'')
17472950065eSBram Moolenaar ++p;
17482950065eSBram Moolenaar if (!vim_isdigit(*p))
17492950065eSBram Moolenaar break;
17502950065eSBram Moolenaar p = skipdigits(p);
17512950065eSBram Moolenaar }
17522950065eSBram Moolenaar else
17532950065eSBram Moolenaar p = skipdigits(p);
17542950065eSBram Moolenaar }
1755367d59e6SBram Moolenaar if (!want_string && p[0] == '.' && vim_isdigit(p[1]))
1756367d59e6SBram Moolenaar {
1757367d59e6SBram Moolenaar get_float = TRUE;
1758367d59e6SBram Moolenaar p = skipdigits(p + 2);
1759367d59e6SBram Moolenaar if (*p == 'e' || *p == 'E')
1760367d59e6SBram Moolenaar {
1761367d59e6SBram Moolenaar ++p;
1762367d59e6SBram Moolenaar if (*p == '-' || *p == '+')
1763367d59e6SBram Moolenaar ++p;
1764367d59e6SBram Moolenaar if (!vim_isdigit(*p))
1765367d59e6SBram Moolenaar get_float = FALSE;
1766367d59e6SBram Moolenaar else
1767367d59e6SBram Moolenaar p = skipdigits(p + 1);
1768367d59e6SBram Moolenaar }
1769367d59e6SBram Moolenaar if (ASCII_ISALPHA(*p) || *p == '.')
1770367d59e6SBram Moolenaar get_float = FALSE;
1771367d59e6SBram Moolenaar }
1772367d59e6SBram Moolenaar if (get_float)
1773367d59e6SBram Moolenaar {
1774367d59e6SBram Moolenaar float_T f;
1775367d59e6SBram Moolenaar
17762950065eSBram Moolenaar *arg += string2float(*arg, &f, skip_quotes);
1777367d59e6SBram Moolenaar if (evaluate)
1778367d59e6SBram Moolenaar {
1779367d59e6SBram Moolenaar rettv->v_type = VAR_FLOAT;
1780367d59e6SBram Moolenaar rettv->vval.v_float = f;
1781367d59e6SBram Moolenaar }
1782367d59e6SBram Moolenaar }
1783367d59e6SBram Moolenaar else
1784367d59e6SBram Moolenaar #endif
1785367d59e6SBram Moolenaar if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z'))
1786367d59e6SBram Moolenaar {
1787367d59e6SBram Moolenaar char_u *bp;
1788367d59e6SBram Moolenaar blob_T *blob = NULL; // init for gcc
1789367d59e6SBram Moolenaar
1790367d59e6SBram Moolenaar // Blob constant: 0z0123456789abcdef
1791367d59e6SBram Moolenaar if (evaluate)
1792367d59e6SBram Moolenaar blob = blob_alloc();
1793367d59e6SBram Moolenaar for (bp = *arg + 2; vim_isxdigit(bp[0]); bp += 2)
1794367d59e6SBram Moolenaar {
1795367d59e6SBram Moolenaar if (!vim_isxdigit(bp[1]))
1796367d59e6SBram Moolenaar {
1797367d59e6SBram Moolenaar if (blob != NULL)
1798367d59e6SBram Moolenaar {
1799367d59e6SBram Moolenaar emsg(_("E973: Blob literal should have an even number of hex characters"));
1800367d59e6SBram Moolenaar ga_clear(&blob->bv_ga);
1801367d59e6SBram Moolenaar VIM_CLEAR(blob);
1802367d59e6SBram Moolenaar }
1803367d59e6SBram Moolenaar return FAIL;
1804367d59e6SBram Moolenaar }
1805367d59e6SBram Moolenaar if (blob != NULL)
1806367d59e6SBram Moolenaar ga_append(&blob->bv_ga,
1807367d59e6SBram Moolenaar (hex2nr(*bp) << 4) + hex2nr(*(bp+1)));
1808367d59e6SBram Moolenaar if (bp[2] == '.' && vim_isxdigit(bp[3]))
1809367d59e6SBram Moolenaar ++bp;
1810367d59e6SBram Moolenaar }
1811367d59e6SBram Moolenaar if (blob != NULL)
1812367d59e6SBram Moolenaar rettv_blob_set(rettv, blob);
1813367d59e6SBram Moolenaar *arg = bp;
1814367d59e6SBram Moolenaar }
1815367d59e6SBram Moolenaar else
1816367d59e6SBram Moolenaar {
1817367d59e6SBram Moolenaar varnumber_T n;
1818367d59e6SBram Moolenaar
1819367d59e6SBram Moolenaar // decimal, hex or octal number
18202950065eSBram Moolenaar vim_str2nr(*arg, NULL, &len, skip_quotes
1821367d59e6SBram Moolenaar ? STR2NR_NO_OCT + STR2NR_QUOTE
1822367d59e6SBram Moolenaar : STR2NR_ALL, &n, NULL, 0, TRUE);
1823367d59e6SBram Moolenaar if (len == 0)
1824367d59e6SBram Moolenaar {
1825108010aaSBram Moolenaar semsg(_(e_invalid_expression_str), *arg);
1826367d59e6SBram Moolenaar return FAIL;
1827367d59e6SBram Moolenaar }
1828367d59e6SBram Moolenaar *arg += len;
1829367d59e6SBram Moolenaar if (evaluate)
1830367d59e6SBram Moolenaar {
1831367d59e6SBram Moolenaar rettv->v_type = VAR_NUMBER;
1832367d59e6SBram Moolenaar rettv->vval.v_number = n;
1833367d59e6SBram Moolenaar }
1834367d59e6SBram Moolenaar }
1835367d59e6SBram Moolenaar return OK;
1836367d59e6SBram Moolenaar }
1837367d59e6SBram Moolenaar
1838367d59e6SBram Moolenaar /*
1839367d59e6SBram Moolenaar * Allocate a variable for a string constant.
1840367d59e6SBram Moolenaar * Return OK or FAIL.
1841367d59e6SBram Moolenaar */
1842367d59e6SBram Moolenaar int
eval_string(char_u ** arg,typval_T * rettv,int evaluate)18439a78e6dfSBram Moolenaar eval_string(char_u **arg, typval_T *rettv, int evaluate)
1844367d59e6SBram Moolenaar {
1845367d59e6SBram Moolenaar char_u *p;
18461e0b7b11SBram Moolenaar char_u *end;
1847367d59e6SBram Moolenaar int extra = 0;
1848367d59e6SBram Moolenaar int len;
1849367d59e6SBram Moolenaar
1850367d59e6SBram Moolenaar // Find the end of the string, skipping backslashed characters.
1851367d59e6SBram Moolenaar for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p))
1852367d59e6SBram Moolenaar {
1853367d59e6SBram Moolenaar if (*p == '\\' && p[1] != NUL)
1854367d59e6SBram Moolenaar {
1855367d59e6SBram Moolenaar ++p;
1856367d59e6SBram Moolenaar // A "\<x>" form occupies at least 4 characters, and produces up
1857367d59e6SBram Moolenaar // to 21 characters (3 * 6 for the char and 3 for a modifier):
1858367d59e6SBram Moolenaar // reserve space for 18 extra.
1859367d59e6SBram Moolenaar // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x.
1860367d59e6SBram Moolenaar if (*p == '<')
1861367d59e6SBram Moolenaar extra += 18;
1862367d59e6SBram Moolenaar }
1863367d59e6SBram Moolenaar }
1864367d59e6SBram Moolenaar
1865367d59e6SBram Moolenaar if (*p != '"')
1866367d59e6SBram Moolenaar {
1867367d59e6SBram Moolenaar semsg(_("E114: Missing quote: %s"), *arg);
1868367d59e6SBram Moolenaar return FAIL;
1869367d59e6SBram Moolenaar }
1870367d59e6SBram Moolenaar
1871367d59e6SBram Moolenaar // If only parsing, set *arg and return here
1872367d59e6SBram Moolenaar if (!evaluate)
1873367d59e6SBram Moolenaar {
1874367d59e6SBram Moolenaar *arg = p + 1;
1875367d59e6SBram Moolenaar return OK;
1876367d59e6SBram Moolenaar }
1877367d59e6SBram Moolenaar
1878367d59e6SBram Moolenaar // Copy the string into allocated memory, handling backslashed
1879367d59e6SBram Moolenaar // characters.
1880367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
18811e0b7b11SBram Moolenaar len = (int)(p - *arg + extra);
18821e0b7b11SBram Moolenaar rettv->vval.v_string = alloc(len);
18831e0b7b11SBram Moolenaar if (rettv->vval.v_string == NULL)
18841e0b7b11SBram Moolenaar return FAIL;
18851e0b7b11SBram Moolenaar end = rettv->vval.v_string;
1886367d59e6SBram Moolenaar
1887367d59e6SBram Moolenaar for (p = *arg + 1; *p != NUL && *p != '"'; )
1888367d59e6SBram Moolenaar {
1889367d59e6SBram Moolenaar if (*p == '\\')
1890367d59e6SBram Moolenaar {
1891367d59e6SBram Moolenaar switch (*++p)
1892367d59e6SBram Moolenaar {
18931e0b7b11SBram Moolenaar case 'b': *end++ = BS; ++p; break;
18941e0b7b11SBram Moolenaar case 'e': *end++ = ESC; ++p; break;
18951e0b7b11SBram Moolenaar case 'f': *end++ = FF; ++p; break;
18961e0b7b11SBram Moolenaar case 'n': *end++ = NL; ++p; break;
18971e0b7b11SBram Moolenaar case 'r': *end++ = CAR; ++p; break;
18981e0b7b11SBram Moolenaar case 't': *end++ = TAB; ++p; break;
1899367d59e6SBram Moolenaar
1900367d59e6SBram Moolenaar case 'X': // hex: "\x1", "\x12"
1901367d59e6SBram Moolenaar case 'x':
1902367d59e6SBram Moolenaar case 'u': // Unicode: "\u0023"
1903367d59e6SBram Moolenaar case 'U':
1904367d59e6SBram Moolenaar if (vim_isxdigit(p[1]))
1905367d59e6SBram Moolenaar {
1906367d59e6SBram Moolenaar int n, nr;
1907367d59e6SBram Moolenaar int c = toupper(*p);
1908367d59e6SBram Moolenaar
1909367d59e6SBram Moolenaar if (c == 'X')
1910367d59e6SBram Moolenaar n = 2;
1911367d59e6SBram Moolenaar else if (*p == 'u')
1912367d59e6SBram Moolenaar n = 4;
1913367d59e6SBram Moolenaar else
1914367d59e6SBram Moolenaar n = 8;
1915367d59e6SBram Moolenaar nr = 0;
1916367d59e6SBram Moolenaar while (--n >= 0 && vim_isxdigit(p[1]))
1917367d59e6SBram Moolenaar {
1918367d59e6SBram Moolenaar ++p;
1919367d59e6SBram Moolenaar nr = (nr << 4) + hex2nr(*p);
1920367d59e6SBram Moolenaar }
1921367d59e6SBram Moolenaar ++p;
1922367d59e6SBram Moolenaar // For "\u" store the number according to
1923367d59e6SBram Moolenaar // 'encoding'.
1924367d59e6SBram Moolenaar if (c != 'X')
19251e0b7b11SBram Moolenaar end += (*mb_char2bytes)(nr, end);
1926367d59e6SBram Moolenaar else
19271e0b7b11SBram Moolenaar *end++ = nr;
1928367d59e6SBram Moolenaar }
1929367d59e6SBram Moolenaar break;
1930367d59e6SBram Moolenaar
1931367d59e6SBram Moolenaar // octal: "\1", "\12", "\123"
1932367d59e6SBram Moolenaar case '0':
1933367d59e6SBram Moolenaar case '1':
1934367d59e6SBram Moolenaar case '2':
1935367d59e6SBram Moolenaar case '3':
1936367d59e6SBram Moolenaar case '4':
1937367d59e6SBram Moolenaar case '5':
1938367d59e6SBram Moolenaar case '6':
19391e0b7b11SBram Moolenaar case '7': *end = *p++ - '0';
1940367d59e6SBram Moolenaar if (*p >= '0' && *p <= '7')
1941367d59e6SBram Moolenaar {
19421e0b7b11SBram Moolenaar *end = (*end << 3) + *p++ - '0';
1943367d59e6SBram Moolenaar if (*p >= '0' && *p <= '7')
19441e0b7b11SBram Moolenaar *end = (*end << 3) + *p++ - '0';
1945367d59e6SBram Moolenaar }
19461e0b7b11SBram Moolenaar ++end;
1947367d59e6SBram Moolenaar break;
1948367d59e6SBram Moolenaar
1949fccd93f0SBram Moolenaar // Special key, e.g.: "\<C-W>"
1950ebe9d34aSBram Moolenaar case '<':
1951ebe9d34aSBram Moolenaar {
1952ebe9d34aSBram Moolenaar int flags = FSK_KEYCODE | FSK_IN_STRING;
1953ebe9d34aSBram Moolenaar
1954fccd93f0SBram Moolenaar if (p[1] != '*')
1955ebe9d34aSBram Moolenaar flags |= FSK_SIMPLIFY;
19561e0b7b11SBram Moolenaar extra = trans_special(&p, end, flags, NULL);
1957367d59e6SBram Moolenaar if (extra != 0)
1958367d59e6SBram Moolenaar {
19591e0b7b11SBram Moolenaar end += extra;
19601e0b7b11SBram Moolenaar if (end >= rettv->vval.v_string + len)
19619a78e6dfSBram Moolenaar iemsg("eval_string() used more space than allocated");
1962367d59e6SBram Moolenaar break;
1963367d59e6SBram Moolenaar }
1964ebe9d34aSBram Moolenaar }
1965367d59e6SBram Moolenaar // FALLTHROUGH
1966367d59e6SBram Moolenaar
19671e0b7b11SBram Moolenaar default: MB_COPY_CHAR(p, end);
1968367d59e6SBram Moolenaar break;
1969367d59e6SBram Moolenaar }
1970367d59e6SBram Moolenaar }
1971367d59e6SBram Moolenaar else
19721e0b7b11SBram Moolenaar MB_COPY_CHAR(p, end);
1973367d59e6SBram Moolenaar }
19741e0b7b11SBram Moolenaar *end = NUL;
1975367d59e6SBram Moolenaar if (*p != NUL) // just in case
1976367d59e6SBram Moolenaar ++p;
1977367d59e6SBram Moolenaar *arg = p;
1978367d59e6SBram Moolenaar
1979367d59e6SBram Moolenaar return OK;
1980367d59e6SBram Moolenaar }
1981367d59e6SBram Moolenaar
1982367d59e6SBram Moolenaar /*
1983367d59e6SBram Moolenaar * Allocate a variable for a 'str''ing' constant.
1984367d59e6SBram Moolenaar * Return OK or FAIL.
1985367d59e6SBram Moolenaar */
1986367d59e6SBram Moolenaar int
eval_lit_string(char_u ** arg,typval_T * rettv,int evaluate)19879a78e6dfSBram Moolenaar eval_lit_string(char_u **arg, typval_T *rettv, int evaluate)
1988367d59e6SBram Moolenaar {
1989367d59e6SBram Moolenaar char_u *p;
1990367d59e6SBram Moolenaar char_u *str;
1991367d59e6SBram Moolenaar int reduce = 0;
1992367d59e6SBram Moolenaar
1993367d59e6SBram Moolenaar // Find the end of the string, skipping ''.
1994367d59e6SBram Moolenaar for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p))
1995367d59e6SBram Moolenaar {
1996367d59e6SBram Moolenaar if (*p == '\'')
1997367d59e6SBram Moolenaar {
1998367d59e6SBram Moolenaar if (p[1] != '\'')
1999367d59e6SBram Moolenaar break;
2000367d59e6SBram Moolenaar ++reduce;
2001367d59e6SBram Moolenaar ++p;
2002367d59e6SBram Moolenaar }
2003367d59e6SBram Moolenaar }
2004367d59e6SBram Moolenaar
2005367d59e6SBram Moolenaar if (*p != '\'')
2006367d59e6SBram Moolenaar {
2007367d59e6SBram Moolenaar semsg(_("E115: Missing quote: %s"), *arg);
2008367d59e6SBram Moolenaar return FAIL;
2009367d59e6SBram Moolenaar }
2010367d59e6SBram Moolenaar
2011367d59e6SBram Moolenaar // If only parsing return after setting "*arg"
2012367d59e6SBram Moolenaar if (!evaluate)
2013367d59e6SBram Moolenaar {
2014367d59e6SBram Moolenaar *arg = p + 1;
2015367d59e6SBram Moolenaar return OK;
2016367d59e6SBram Moolenaar }
2017367d59e6SBram Moolenaar
2018367d59e6SBram Moolenaar // Copy the string into allocated memory, handling '' to ' reduction.
2019367d59e6SBram Moolenaar str = alloc((p - *arg) - reduce);
2020367d59e6SBram Moolenaar if (str == NULL)
2021367d59e6SBram Moolenaar return FAIL;
2022367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
2023367d59e6SBram Moolenaar rettv->vval.v_string = str;
2024367d59e6SBram Moolenaar
2025367d59e6SBram Moolenaar for (p = *arg + 1; *p != NUL; )
2026367d59e6SBram Moolenaar {
2027367d59e6SBram Moolenaar if (*p == '\'')
2028367d59e6SBram Moolenaar {
2029367d59e6SBram Moolenaar if (p[1] != '\'')
2030367d59e6SBram Moolenaar break;
2031367d59e6SBram Moolenaar ++p;
2032367d59e6SBram Moolenaar }
2033367d59e6SBram Moolenaar MB_COPY_CHAR(p, str);
2034367d59e6SBram Moolenaar }
2035367d59e6SBram Moolenaar *str = NUL;
2036367d59e6SBram Moolenaar *arg = p + 1;
2037367d59e6SBram Moolenaar
2038367d59e6SBram Moolenaar return OK;
2039367d59e6SBram Moolenaar }
2040367d59e6SBram Moolenaar
2041367d59e6SBram Moolenaar /*
2042367d59e6SBram Moolenaar * Return a string with the string representation of a variable.
2043367d59e6SBram Moolenaar * If the memory is allocated "tofree" is set to it, otherwise NULL.
2044367d59e6SBram Moolenaar * "numbuf" is used for a number.
2045367d59e6SBram Moolenaar * Puts quotes around strings, so that they can be parsed back by eval().
2046367d59e6SBram Moolenaar * May return NULL.
2047367d59e6SBram Moolenaar */
2048367d59e6SBram Moolenaar char_u *
tv2string(typval_T * tv,char_u ** tofree,char_u * numbuf,int copyID)2049367d59e6SBram Moolenaar tv2string(
2050367d59e6SBram Moolenaar typval_T *tv,
2051367d59e6SBram Moolenaar char_u **tofree,
2052367d59e6SBram Moolenaar char_u *numbuf,
2053367d59e6SBram Moolenaar int copyID)
2054367d59e6SBram Moolenaar {
2055367d59e6SBram Moolenaar return echo_string_core(tv, tofree, numbuf, copyID, FALSE, TRUE, FALSE);
2056367d59e6SBram Moolenaar }
2057367d59e6SBram Moolenaar
2058367d59e6SBram Moolenaar /*
2059367d59e6SBram Moolenaar * Get the value of an environment variable.
2060367d59e6SBram Moolenaar * "arg" is pointing to the '$'. It is advanced to after the name.
2061367d59e6SBram Moolenaar * If the environment variable was not set, silently assume it is empty.
2062367d59e6SBram Moolenaar * Return FAIL if the name is invalid.
2063367d59e6SBram Moolenaar */
2064367d59e6SBram Moolenaar int
eval_env_var(char_u ** arg,typval_T * rettv,int evaluate)20659a78e6dfSBram Moolenaar eval_env_var(char_u **arg, typval_T *rettv, int evaluate)
2066367d59e6SBram Moolenaar {
2067367d59e6SBram Moolenaar char_u *string = NULL;
2068367d59e6SBram Moolenaar int len;
2069367d59e6SBram Moolenaar int cc;
2070367d59e6SBram Moolenaar char_u *name;
2071367d59e6SBram Moolenaar int mustfree = FALSE;
2072367d59e6SBram Moolenaar
2073367d59e6SBram Moolenaar ++*arg;
2074367d59e6SBram Moolenaar name = *arg;
2075367d59e6SBram Moolenaar len = get_env_len(arg);
2076367d59e6SBram Moolenaar if (evaluate)
2077367d59e6SBram Moolenaar {
2078367d59e6SBram Moolenaar if (len == 0)
2079367d59e6SBram Moolenaar return FAIL; // invalid empty name
2080367d59e6SBram Moolenaar
2081367d59e6SBram Moolenaar cc = name[len];
2082367d59e6SBram Moolenaar name[len] = NUL;
2083367d59e6SBram Moolenaar // first try vim_getenv(), fast for normal environment vars
2084367d59e6SBram Moolenaar string = vim_getenv(name, &mustfree);
2085367d59e6SBram Moolenaar if (string != NULL && *string != NUL)
2086367d59e6SBram Moolenaar {
2087367d59e6SBram Moolenaar if (!mustfree)
2088367d59e6SBram Moolenaar string = vim_strsave(string);
2089367d59e6SBram Moolenaar }
2090367d59e6SBram Moolenaar else
2091367d59e6SBram Moolenaar {
2092367d59e6SBram Moolenaar if (mustfree)
2093367d59e6SBram Moolenaar vim_free(string);
2094367d59e6SBram Moolenaar
2095367d59e6SBram Moolenaar // next try expanding things like $VIM and ${HOME}
2096367d59e6SBram Moolenaar string = expand_env_save(name - 1);
2097367d59e6SBram Moolenaar if (string != NULL && *string == '$')
2098367d59e6SBram Moolenaar VIM_CLEAR(string);
2099367d59e6SBram Moolenaar }
2100367d59e6SBram Moolenaar name[len] = cc;
2101367d59e6SBram Moolenaar
2102367d59e6SBram Moolenaar rettv->v_type = VAR_STRING;
2103367d59e6SBram Moolenaar rettv->vval.v_string = string;
210416e63e6dSBram Moolenaar rettv->v_lock = 0;
2105367d59e6SBram Moolenaar }
2106367d59e6SBram Moolenaar
2107367d59e6SBram Moolenaar return OK;
2108367d59e6SBram Moolenaar }
2109367d59e6SBram Moolenaar
2110367d59e6SBram Moolenaar /*
2111367d59e6SBram Moolenaar * Get the lnum from the first argument.
2112367d59e6SBram Moolenaar * Also accepts ".", "$", etc., but that only works for the current buffer.
2113367d59e6SBram Moolenaar * Returns -1 on error.
2114367d59e6SBram Moolenaar */
2115367d59e6SBram Moolenaar linenr_T
tv_get_lnum(typval_T * argvars)2116367d59e6SBram Moolenaar tv_get_lnum(typval_T *argvars)
2117367d59e6SBram Moolenaar {
21189a963377SBram Moolenaar linenr_T lnum = -1;
2119367d59e6SBram Moolenaar
212056acb094SBram Moolenaar if (argvars[0].v_type != VAR_STRING || !in_vim9script())
2121367d59e6SBram Moolenaar lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
2122f6bdd82cSBram Moolenaar if (lnum <= 0 && argvars[0].v_type != VAR_NUMBER)
2123367d59e6SBram Moolenaar {
2124367d59e6SBram Moolenaar int fnum;
21256f02b00bSBram Moolenaar pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
2126367d59e6SBram Moolenaar
2127f6bdd82cSBram Moolenaar // no valid number, try using arg like line()
2128367d59e6SBram Moolenaar if (fp != NULL)
2129367d59e6SBram Moolenaar lnum = fp->lnum;
2130367d59e6SBram Moolenaar }
2131367d59e6SBram Moolenaar return lnum;
2132367d59e6SBram Moolenaar }
2133367d59e6SBram Moolenaar
2134367d59e6SBram Moolenaar /*
2135367d59e6SBram Moolenaar * Get the lnum from the first argument.
2136367d59e6SBram Moolenaar * Also accepts "$", then "buf" is used.
2137367d59e6SBram Moolenaar * Returns 0 on error.
2138367d59e6SBram Moolenaar */
2139367d59e6SBram Moolenaar linenr_T
tv_get_lnum_buf(typval_T * argvars,buf_T * buf)2140367d59e6SBram Moolenaar tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
2141367d59e6SBram Moolenaar {
2142367d59e6SBram Moolenaar if (argvars[0].v_type == VAR_STRING
2143367d59e6SBram Moolenaar && argvars[0].vval.v_string != NULL
2144367d59e6SBram Moolenaar && argvars[0].vval.v_string[0] == '$'
2145367d59e6SBram Moolenaar && buf != NULL)
2146367d59e6SBram Moolenaar return buf->b_ml.ml_line_count;
2147367d59e6SBram Moolenaar return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
2148367d59e6SBram Moolenaar }
2149367d59e6SBram Moolenaar
2150367d59e6SBram Moolenaar /*
2151367d59e6SBram Moolenaar * Get buffer by number or pattern.
2152367d59e6SBram Moolenaar */
2153367d59e6SBram Moolenaar buf_T *
tv_get_buf(typval_T * tv,int curtab_only)2154367d59e6SBram Moolenaar tv_get_buf(typval_T *tv, int curtab_only)
2155367d59e6SBram Moolenaar {
2156367d59e6SBram Moolenaar char_u *name = tv->vval.v_string;
2157367d59e6SBram Moolenaar buf_T *buf;
2158367d59e6SBram Moolenaar
2159367d59e6SBram Moolenaar if (tv->v_type == VAR_NUMBER)
2160367d59e6SBram Moolenaar return buflist_findnr((int)tv->vval.v_number);
2161367d59e6SBram Moolenaar if (tv->v_type != VAR_STRING)
2162367d59e6SBram Moolenaar return NULL;
2163367d59e6SBram Moolenaar if (name == NULL || *name == NUL)
2164367d59e6SBram Moolenaar return curbuf;
2165367d59e6SBram Moolenaar if (name[0] == '$' && name[1] == NUL)
2166367d59e6SBram Moolenaar return lastbuf;
2167367d59e6SBram Moolenaar
2168367d59e6SBram Moolenaar buf = buflist_find_by_name(name, curtab_only);
2169367d59e6SBram Moolenaar
2170367d59e6SBram Moolenaar // If not found, try expanding the name, like done for bufexists().
2171367d59e6SBram Moolenaar if (buf == NULL)
2172367d59e6SBram Moolenaar buf = find_buffer(tv);
2173367d59e6SBram Moolenaar
2174367d59e6SBram Moolenaar return buf;
2175367d59e6SBram Moolenaar }
2176367d59e6SBram Moolenaar
21773767e3a3SBram Moolenaar /*
21783767e3a3SBram Moolenaar * Like tv_get_buf() but give an error message is the type is wrong.
21793767e3a3SBram Moolenaar */
21803767e3a3SBram Moolenaar buf_T *
tv_get_buf_from_arg(typval_T * tv)21813767e3a3SBram Moolenaar tv_get_buf_from_arg(typval_T *tv)
21823767e3a3SBram Moolenaar {
21833767e3a3SBram Moolenaar buf_T *buf;
21843767e3a3SBram Moolenaar
21853767e3a3SBram Moolenaar ++emsg_off;
21863767e3a3SBram Moolenaar buf = tv_get_buf(tv, FALSE);
21873767e3a3SBram Moolenaar --emsg_off;
21883767e3a3SBram Moolenaar if (buf == NULL
21893767e3a3SBram Moolenaar && tv->v_type != VAR_NUMBER
21903767e3a3SBram Moolenaar && tv->v_type != VAR_STRING)
21913767e3a3SBram Moolenaar // issue errmsg for type error
21923767e3a3SBram Moolenaar (void)tv_get_number(tv);
21933767e3a3SBram Moolenaar return buf;
21943767e3a3SBram Moolenaar }
21953767e3a3SBram Moolenaar
2196367d59e6SBram Moolenaar #endif // FEAT_EVAL
2197