xref: /vim-8.2.3635/src/typval.c (revision 5dfe4674)
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