1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * evalvars.c: functions for dealing with variables
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_EVAL) || defined(PROTO)
17 
18 static dictitem_T	globvars_var;		// variable used for g:
19 static dict_T		globvardict;		// Dictionary with g: variables
20 #define globvarht globvardict.dv_hashtab
21 
22 /*
23  * Old Vim variables such as "v:version" are also available without the "v:".
24  * Also in functions.  We need a special hashtable for them.
25  */
26 static hashtab_T	compat_hashtab;
27 
28 /*
29  * Array to hold the value of v: variables.
30  * The value is in a dictitem, so that it can also be used in the v: scope.
31  * The reason to use this table anyway is for very quick access to the
32  * variables with the VV_ defines.
33  */
34 
35 // values for vv_flags:
36 #define VV_COMPAT	1	// compatible, also used without "v:"
37 #define VV_RO		2	// read-only
38 #define VV_RO_SBX	4	// read-only in the sandbox
39 
40 #define VV_NAME(s, t)	s, {{t, 0, {0}}, 0, {0}}
41 
42 typedef struct vimvar vimvar_T;
43 
44 static struct vimvar
45 {
46     char	*vv_name;	// name of variable, without v:
47     dictitem16_T vv_di;		// value and name for key (max 16 chars!)
48     char	vv_flags;	// VV_COMPAT, VV_RO, VV_RO_SBX
49 } vimvars[VV_LEN] =
50 {
51     // The order here must match the VV_ defines in vim.h!
52     // Initializing a union does not work, leave tv.vval empty to get zero's.
53     {VV_NAME("count",		 VAR_NUMBER), VV_COMPAT+VV_RO},
54     {VV_NAME("count1",		 VAR_NUMBER), VV_RO},
55     {VV_NAME("prevcount",	 VAR_NUMBER), VV_RO},
56     {VV_NAME("errmsg",		 VAR_STRING), VV_COMPAT},
57     {VV_NAME("warningmsg",	 VAR_STRING), 0},
58     {VV_NAME("statusmsg",	 VAR_STRING), 0},
59     {VV_NAME("shell_error",	 VAR_NUMBER), VV_COMPAT+VV_RO},
60     {VV_NAME("this_session",	 VAR_STRING), VV_COMPAT},
61     {VV_NAME("version",		 VAR_NUMBER), VV_COMPAT+VV_RO},
62     {VV_NAME("lnum",		 VAR_NUMBER), VV_RO_SBX},
63     {VV_NAME("termresponse",	 VAR_STRING), VV_RO},
64     {VV_NAME("fname",		 VAR_STRING), VV_RO},
65     {VV_NAME("lang",		 VAR_STRING), VV_RO},
66     {VV_NAME("lc_time",		 VAR_STRING), VV_RO},
67     {VV_NAME("ctype",		 VAR_STRING), VV_RO},
68     {VV_NAME("charconvert_from", VAR_STRING), VV_RO},
69     {VV_NAME("charconvert_to",	 VAR_STRING), VV_RO},
70     {VV_NAME("fname_in",	 VAR_STRING), VV_RO},
71     {VV_NAME("fname_out",	 VAR_STRING), VV_RO},
72     {VV_NAME("fname_new",	 VAR_STRING), VV_RO},
73     {VV_NAME("fname_diff",	 VAR_STRING), VV_RO},
74     {VV_NAME("cmdarg",		 VAR_STRING), VV_RO},
75     {VV_NAME("foldstart",	 VAR_NUMBER), VV_RO_SBX},
76     {VV_NAME("foldend",		 VAR_NUMBER), VV_RO_SBX},
77     {VV_NAME("folddashes",	 VAR_STRING), VV_RO_SBX},
78     {VV_NAME("foldlevel",	 VAR_NUMBER), VV_RO_SBX},
79     {VV_NAME("progname",	 VAR_STRING), VV_RO},
80     {VV_NAME("servername",	 VAR_STRING), VV_RO},
81     {VV_NAME("dying",		 VAR_NUMBER), VV_RO},
82     {VV_NAME("exception",	 VAR_STRING), VV_RO},
83     {VV_NAME("throwpoint",	 VAR_STRING), VV_RO},
84     {VV_NAME("register",	 VAR_STRING), VV_RO},
85     {VV_NAME("cmdbang",		 VAR_NUMBER), VV_RO},
86     {VV_NAME("insertmode",	 VAR_STRING), VV_RO},
87     {VV_NAME("val",		 VAR_UNKNOWN), VV_RO},
88     {VV_NAME("key",		 VAR_UNKNOWN), VV_RO},
89     {VV_NAME("profiling",	 VAR_NUMBER), VV_RO},
90     {VV_NAME("fcs_reason",	 VAR_STRING), VV_RO},
91     {VV_NAME("fcs_choice",	 VAR_STRING), 0},
92     {VV_NAME("beval_bufnr",	 VAR_NUMBER), VV_RO},
93     {VV_NAME("beval_winnr",	 VAR_NUMBER), VV_RO},
94     {VV_NAME("beval_winid",	 VAR_NUMBER), VV_RO},
95     {VV_NAME("beval_lnum",	 VAR_NUMBER), VV_RO},
96     {VV_NAME("beval_col",	 VAR_NUMBER), VV_RO},
97     {VV_NAME("beval_text",	 VAR_STRING), VV_RO},
98     {VV_NAME("scrollstart",	 VAR_STRING), 0},
99     {VV_NAME("swapname",	 VAR_STRING), VV_RO},
100     {VV_NAME("swapchoice",	 VAR_STRING), 0},
101     {VV_NAME("swapcommand",	 VAR_STRING), VV_RO},
102     {VV_NAME("char",		 VAR_STRING), 0},
103     {VV_NAME("mouse_win",	 VAR_NUMBER), 0},
104     {VV_NAME("mouse_winid",	 VAR_NUMBER), 0},
105     {VV_NAME("mouse_lnum",	 VAR_NUMBER), 0},
106     {VV_NAME("mouse_col",	 VAR_NUMBER), 0},
107     {VV_NAME("operator",	 VAR_STRING), VV_RO},
108     {VV_NAME("searchforward",	 VAR_NUMBER), 0},
109     {VV_NAME("hlsearch",	 VAR_NUMBER), 0},
110     {VV_NAME("oldfiles",	 VAR_LIST), 0},
111     {VV_NAME("windowid",	 VAR_NUMBER), VV_RO},
112     {VV_NAME("progpath",	 VAR_STRING), VV_RO},
113     {VV_NAME("completed_item",	 VAR_DICT), VV_RO},
114     {VV_NAME("option_new",	 VAR_STRING), VV_RO},
115     {VV_NAME("option_old",	 VAR_STRING), VV_RO},
116     {VV_NAME("option_oldlocal",	 VAR_STRING), VV_RO},
117     {VV_NAME("option_oldglobal", VAR_STRING), VV_RO},
118     {VV_NAME("option_command",	 VAR_STRING), VV_RO},
119     {VV_NAME("option_type",	 VAR_STRING), VV_RO},
120     {VV_NAME("errors",		 VAR_LIST), 0},
121     {VV_NAME("false",		 VAR_BOOL), VV_RO},
122     {VV_NAME("true",		 VAR_BOOL), VV_RO},
123     {VV_NAME("none",		 VAR_SPECIAL), VV_RO},
124     {VV_NAME("null",		 VAR_SPECIAL), VV_RO},
125     {VV_NAME("numbermax",	 VAR_NUMBER), VV_RO},
126     {VV_NAME("numbermin",	 VAR_NUMBER), VV_RO},
127     {VV_NAME("numbersize",	 VAR_NUMBER), VV_RO},
128     {VV_NAME("vim_did_enter",	 VAR_NUMBER), VV_RO},
129     {VV_NAME("testing",		 VAR_NUMBER), 0},
130     {VV_NAME("t_number",	 VAR_NUMBER), VV_RO},
131     {VV_NAME("t_string",	 VAR_NUMBER), VV_RO},
132     {VV_NAME("t_func",		 VAR_NUMBER), VV_RO},
133     {VV_NAME("t_list",		 VAR_NUMBER), VV_RO},
134     {VV_NAME("t_dict",		 VAR_NUMBER), VV_RO},
135     {VV_NAME("t_float",		 VAR_NUMBER), VV_RO},
136     {VV_NAME("t_bool",		 VAR_NUMBER), VV_RO},
137     {VV_NAME("t_none",		 VAR_NUMBER), VV_RO},
138     {VV_NAME("t_job",		 VAR_NUMBER), VV_RO},
139     {VV_NAME("t_channel",	 VAR_NUMBER), VV_RO},
140     {VV_NAME("t_blob",		 VAR_NUMBER), VV_RO},
141     {VV_NAME("termrfgresp",	 VAR_STRING), VV_RO},
142     {VV_NAME("termrbgresp",	 VAR_STRING), VV_RO},
143     {VV_NAME("termu7resp",	 VAR_STRING), VV_RO},
144     {VV_NAME("termstyleresp",	 VAR_STRING), VV_RO},
145     {VV_NAME("termblinkresp",	 VAR_STRING), VV_RO},
146     {VV_NAME("event",		 VAR_DICT), VV_RO},
147     {VV_NAME("versionlong",	 VAR_NUMBER), VV_RO},
148     {VV_NAME("echospace",	 VAR_NUMBER), VV_RO},
149     {VV_NAME("argv",		 VAR_LIST), VV_RO},
150     {VV_NAME("collate",		 VAR_STRING), VV_RO},
151     {VV_NAME("exiting",		 VAR_SPECIAL), VV_RO},
152     {VV_NAME("colornames",       VAR_DICT), VV_RO},
153     {VV_NAME("sizeofint",	 VAR_NUMBER), VV_RO},
154     {VV_NAME("sizeoflong",	 VAR_NUMBER), VV_RO},
155     {VV_NAME("sizeofpointer",	 VAR_NUMBER), VV_RO},
156 };
157 
158 // shorthand
159 #define vv_type		vv_di.di_tv.v_type
160 #define vv_nr		vv_di.di_tv.vval.v_number
161 #define vv_float	vv_di.di_tv.vval.v_float
162 #define vv_str		vv_di.di_tv.vval.v_string
163 #define vv_list		vv_di.di_tv.vval.v_list
164 #define vv_dict		vv_di.di_tv.vval.v_dict
165 #define vv_blob		vv_di.di_tv.vval.v_blob
166 #define vv_tv		vv_di.di_tv
167 
168 static dictitem_T	vimvars_var;		// variable used for v:
169 static dict_T		vimvardict;		// Dictionary with v: variables
170 #define vimvarht  vimvardict.dv_hashtab
171 
172 // for VIM_VERSION_ defines
173 #include "version.h"
174 
175 static void list_glob_vars(int *first);
176 static void list_buf_vars(int *first);
177 static void list_win_vars(int *first);
178 static void list_tab_vars(int *first);
179 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
180 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags, char_u *endchars, char_u *op, int var_idx);
181 static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
182 static int do_lock_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
183 static void list_one_var(dictitem_T *v, char *prefix, int *first);
184 static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
185 
186 /*
187  * Initialize global and vim special variables
188  */
189     void
evalvars_init(void)190 evalvars_init(void)
191 {
192     int		    i;
193     struct vimvar   *p;
194 
195     init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
196     init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
197     vimvardict.dv_lock = VAR_FIXED;
198     hash_init(&compat_hashtab);
199 
200     for (i = 0; i < VV_LEN; ++i)
201     {
202 	p = &vimvars[i];
203 	if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
204 	{
205 	    iemsg("INTERNAL: name too long, increase size of dictitem16_T");
206 	    getout(1);
207 	}
208 	STRCPY(p->vv_di.di_key, p->vv_name);
209 	if (p->vv_flags & VV_RO)
210 	    p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
211 	else if (p->vv_flags & VV_RO_SBX)
212 	    p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
213 	else
214 	    p->vv_di.di_flags = DI_FLAGS_FIX;
215 
216 	// add to v: scope dict, unless the value is not always available
217 	if (p->vv_type != VAR_UNKNOWN)
218 	    hash_add(&vimvarht, p->vv_di.di_key);
219 	if (p->vv_flags & VV_COMPAT)
220 	    // add to compat scope dict
221 	    hash_add(&compat_hashtab, p->vv_di.di_key);
222     }
223     set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
224     set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
225 
226     set_vim_var_nr(VV_SEARCHFORWARD, 1L);
227     set_vim_var_nr(VV_HLSEARCH, 1L);
228     set_vim_var_nr(VV_EXITING, VVAL_NULL);
229     set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
230     set_vim_var_list(VV_ERRORS, list_alloc());
231     set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
232 
233     set_vim_var_nr(VV_FALSE, VVAL_FALSE);
234     set_vim_var_nr(VV_TRUE, VVAL_TRUE);
235     set_vim_var_nr(VV_NONE, VVAL_NONE);
236     set_vim_var_nr(VV_NULL, VVAL_NULL);
237     set_vim_var_nr(VV_NUMBERMAX, VARNUM_MAX);
238     set_vim_var_nr(VV_NUMBERMIN, VARNUM_MIN);
239     set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
240     set_vim_var_nr(VV_SIZEOFINT, sizeof(int));
241     set_vim_var_nr(VV_SIZEOFLONG, sizeof(long));
242     set_vim_var_nr(VV_SIZEOFPOINTER, sizeof(char *));
243 
244     set_vim_var_nr(VV_TYPE_NUMBER,  VAR_TYPE_NUMBER);
245     set_vim_var_nr(VV_TYPE_STRING,  VAR_TYPE_STRING);
246     set_vim_var_nr(VV_TYPE_FUNC,    VAR_TYPE_FUNC);
247     set_vim_var_nr(VV_TYPE_LIST,    VAR_TYPE_LIST);
248     set_vim_var_nr(VV_TYPE_DICT,    VAR_TYPE_DICT);
249     set_vim_var_nr(VV_TYPE_FLOAT,   VAR_TYPE_FLOAT);
250     set_vim_var_nr(VV_TYPE_BOOL,    VAR_TYPE_BOOL);
251     set_vim_var_nr(VV_TYPE_NONE,    VAR_TYPE_NONE);
252     set_vim_var_nr(VV_TYPE_JOB,     VAR_TYPE_JOB);
253     set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
254     set_vim_var_nr(VV_TYPE_BLOB,    VAR_TYPE_BLOB);
255 
256     set_vim_var_nr(VV_ECHOSPACE,    sc_col - 1);
257 
258     set_vim_var_dict(VV_COLORNAMES, dict_alloc());
259 
260     // Default for v:register is not 0 but '"'.  This is adjusted once the
261     // clipboard has been setup by calling reset_reg_var().
262     set_reg_var(0);
263 }
264 
265 #if defined(EXITFREE) || defined(PROTO)
266 /*
267  * Free all vim variables information on exit
268  */
269     void
evalvars_clear(void)270 evalvars_clear(void)
271 {
272     int		    i;
273     struct vimvar   *p;
274 
275     for (i = 0; i < VV_LEN; ++i)
276     {
277 	p = &vimvars[i];
278 	if (p->vv_di.di_tv.v_type == VAR_STRING)
279 	    VIM_CLEAR(p->vv_str);
280 	else if (p->vv_di.di_tv.v_type == VAR_LIST)
281 	{
282 	    list_unref(p->vv_list);
283 	    p->vv_list = NULL;
284 	}
285     }
286     hash_clear(&vimvarht);
287     hash_init(&vimvarht);  // garbage_collect() will access it
288     hash_clear(&compat_hashtab);
289 
290     // global variables
291     vars_clear(&globvarht);
292 
293     // Script-local variables. Clear all the variables here.
294     // The scriptvar_T is cleared later in free_scriptnames(), because a
295     // variable in one script might hold a reference to the whole scope of
296     // another script.
297     for (i = 1; i <= script_items.ga_len; ++i)
298 	vars_clear(&SCRIPT_VARS(i));
299 }
300 #endif
301 
302     int
garbage_collect_globvars(int copyID)303 garbage_collect_globvars(int copyID)
304 {
305     return set_ref_in_ht(&globvarht, copyID, NULL);
306 }
307 
308     int
garbage_collect_vimvars(int copyID)309 garbage_collect_vimvars(int copyID)
310 {
311     return set_ref_in_ht(&vimvarht, copyID, NULL);
312 }
313 
314     int
garbage_collect_scriptvars(int copyID)315 garbage_collect_scriptvars(int copyID)
316 {
317     int		    i;
318     int		    idx;
319     int		    abort = FALSE;
320     scriptitem_T    *si;
321 
322     for (i = 1; i <= script_items.ga_len; ++i)
323     {
324 	abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
325 
326 	si = SCRIPT_ITEM(i);
327 	for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
328 	{
329 	    svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
330 
331 	    if (sv->sv_name != NULL)
332 		abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL);
333 	}
334     }
335 
336     return abort;
337 }
338 
339 /*
340  * Set an internal variable to a string value. Creates the variable if it does
341  * not already exist.
342  */
343     void
set_internal_string_var(char_u * name,char_u * value)344 set_internal_string_var(char_u *name, char_u *value)
345 {
346     char_u	*val;
347     typval_T	*tvp;
348 
349     val = vim_strsave(value);
350     if (val != NULL)
351     {
352 	tvp = alloc_string_tv(val);
353 	if (tvp != NULL)
354 	{
355 	    set_var(name, tvp, FALSE);
356 	    free_tv(tvp);
357 	}
358     }
359 }
360 
361     int
eval_charconvert(char_u * enc_from,char_u * enc_to,char_u * fname_from,char_u * fname_to)362 eval_charconvert(
363     char_u	*enc_from,
364     char_u	*enc_to,
365     char_u	*fname_from,
366     char_u	*fname_to)
367 {
368     int		err = FALSE;
369 
370     set_vim_var_string(VV_CC_FROM, enc_from, -1);
371     set_vim_var_string(VV_CC_TO, enc_to, -1);
372     set_vim_var_string(VV_FNAME_IN, fname_from, -1);
373     set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
374     if (eval_to_bool(p_ccv, &err, NULL, FALSE))
375 	err = TRUE;
376     set_vim_var_string(VV_CC_FROM, NULL, -1);
377     set_vim_var_string(VV_CC_TO, NULL, -1);
378     set_vim_var_string(VV_FNAME_IN, NULL, -1);
379     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
380 
381     if (err)
382 	return FAIL;
383     return OK;
384 }
385 
386 # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
387     int
eval_printexpr(char_u * fname,char_u * args)388 eval_printexpr(char_u *fname, char_u *args)
389 {
390     int		err = FALSE;
391 
392     set_vim_var_string(VV_FNAME_IN, fname, -1);
393     set_vim_var_string(VV_CMDARG, args, -1);
394     if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
395 	err = TRUE;
396     set_vim_var_string(VV_FNAME_IN, NULL, -1);
397     set_vim_var_string(VV_CMDARG, NULL, -1);
398 
399     if (err)
400     {
401 	mch_remove(fname);
402 	return FAIL;
403     }
404     return OK;
405 }
406 # endif
407 
408 # if defined(FEAT_DIFF) || defined(PROTO)
409     void
eval_diff(char_u * origfile,char_u * newfile,char_u * outfile)410 eval_diff(
411     char_u	*origfile,
412     char_u	*newfile,
413     char_u	*outfile)
414 {
415     int		err = FALSE;
416 
417     set_vim_var_string(VV_FNAME_IN, origfile, -1);
418     set_vim_var_string(VV_FNAME_NEW, newfile, -1);
419     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
420     (void)eval_to_bool(p_dex, &err, NULL, FALSE);
421     set_vim_var_string(VV_FNAME_IN, NULL, -1);
422     set_vim_var_string(VV_FNAME_NEW, NULL, -1);
423     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
424 }
425 
426     void
eval_patch(char_u * origfile,char_u * difffile,char_u * outfile)427 eval_patch(
428     char_u	*origfile,
429     char_u	*difffile,
430     char_u	*outfile)
431 {
432     int		err;
433 
434     set_vim_var_string(VV_FNAME_IN, origfile, -1);
435     set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
436     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
437     (void)eval_to_bool(p_pex, &err, NULL, FALSE);
438     set_vim_var_string(VV_FNAME_IN, NULL, -1);
439     set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
440     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
441 }
442 # endif
443 
444 #if defined(FEAT_SPELL) || defined(PROTO)
445 /*
446  * Evaluate an expression to a list with suggestions.
447  * For the "expr:" part of 'spellsuggest'.
448  * Returns NULL when there is an error.
449  */
450     list_T *
eval_spell_expr(char_u * badword,char_u * expr)451 eval_spell_expr(char_u *badword, char_u *expr)
452 {
453     typval_T	save_val;
454     typval_T	rettv;
455     list_T	*list = NULL;
456     char_u	*p = skipwhite(expr);
457 
458     // Set "v:val" to the bad word.
459     prepare_vimvar(VV_VAL, &save_val);
460     set_vim_var_string(VV_VAL, badword, -1);
461     if (p_verbose == 0)
462 	++emsg_off;
463 
464     if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK)
465     {
466 	if (rettv.v_type != VAR_LIST)
467 	    clear_tv(&rettv);
468 	else
469 	    list = rettv.vval.v_list;
470     }
471 
472     if (p_verbose == 0)
473 	--emsg_off;
474     clear_tv(get_vim_var_tv(VV_VAL));
475     restore_vimvar(VV_VAL, &save_val);
476 
477     return list;
478 }
479 
480 /*
481  * "list" is supposed to contain two items: a word and a number.  Return the
482  * word in "pp" and the number as the return value.
483  * Return -1 if anything isn't right.
484  * Used to get the good word and score from the eval_spell_expr() result.
485  */
486     int
get_spellword(list_T * list,char_u ** pp)487 get_spellword(list_T *list, char_u **pp)
488 {
489     listitem_T	*li;
490 
491     li = list->lv_first;
492     if (li == NULL)
493 	return -1;
494     *pp = tv_get_string(&li->li_tv);
495 
496     li = li->li_next;
497     if (li == NULL)
498 	return -1;
499     return (int)tv_get_number(&li->li_tv);
500 }
501 #endif
502 
503 /*
504  * Prepare v: variable "idx" to be used.
505  * Save the current typeval in "save_tv" and clear it.
506  * When not used yet add the variable to the v: hashtable.
507  */
508     void
prepare_vimvar(int idx,typval_T * save_tv)509 prepare_vimvar(int idx, typval_T *save_tv)
510 {
511     *save_tv = vimvars[idx].vv_tv;
512     vimvars[idx].vv_str = NULL;  // don't free it now
513     if (vimvars[idx].vv_type == VAR_UNKNOWN)
514 	hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
515 }
516 
517 /*
518  * Restore v: variable "idx" to typeval "save_tv".
519  * Note that the v: variable must have been cleared already.
520  * When no longer defined, remove the variable from the v: hashtable.
521  */
522     void
restore_vimvar(int idx,typval_T * save_tv)523 restore_vimvar(int idx, typval_T *save_tv)
524 {
525     hashitem_T	*hi;
526 
527     vimvars[idx].vv_tv = *save_tv;
528     if (vimvars[idx].vv_type == VAR_UNKNOWN)
529     {
530 	hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
531 	if (HASHITEM_EMPTY(hi))
532 	    internal_error("restore_vimvar()");
533 	else
534 	    hash_remove(&vimvarht, hi);
535     }
536 }
537 
538 /*
539  * List Vim variables.
540  */
541     static void
list_vim_vars(int * first)542 list_vim_vars(int *first)
543 {
544     list_hashtable_vars(&vimvarht, "v:", FALSE, first);
545 }
546 
547 /*
548  * List script-local variables, if there is a script.
549  */
550     static void
list_script_vars(int * first)551 list_script_vars(int *first)
552 {
553     if (SCRIPT_ID_VALID(current_sctx.sc_sid))
554 	list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
555 							   "s:", FALSE, first);
556 }
557 
558 /*
559  * Get a list of lines from a HERE document. The here document is a list of
560  * lines surrounded by a marker.
561  *	cmd << {marker}
562  *	  {line1}
563  *	  {line2}
564  *	  ....
565  *	{marker}
566  *
567  * The {marker} is a string. If the optional 'trim' word is supplied before the
568  * marker, then the leading indentation before the lines (matching the
569  * indentation in the 'cmd' line) is stripped.
570  *
571  * When getting lines for an embedded script (e.g. python, lua, perl, ruby,
572  * tcl, mzscheme), script_get is set to TRUE. In this case, if the marker is
573  * missing, then '.' is accepted as a marker.
574  *
575  * Returns a List with {lines} or NULL.
576  */
577     list_T *
heredoc_get(exarg_T * eap,char_u * cmd,int script_get)578 heredoc_get(exarg_T *eap, char_u *cmd, int script_get)
579 {
580     char_u	*theline;
581     char_u	*marker;
582     list_T	*l;
583     char_u	*p;
584     int		marker_indent_len = 0;
585     int		text_indent_len = 0;
586     char_u	*text_indent = NULL;
587     char_u	dot[] = ".";
588     int		comment_char = in_vim9script() ? '#' : '"';
589 
590     if (eap->getline == NULL)
591     {
592 	emsg(_("E991: cannot use =<< here"));
593 	return NULL;
594     }
595 
596     // Check for the optional 'trim' word before the marker
597     cmd = skipwhite(cmd);
598     if (STRNCMP(cmd, "trim", 4) == 0 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
599     {
600 	cmd = skipwhite(cmd + 4);
601 
602 	// Trim the indentation from all the lines in the here document.
603 	// The amount of indentation trimmed is the same as the indentation of
604 	// the first line after the :let command line.  To find the end marker
605 	// the indent of the :let command line is trimmed.
606 	p = *eap->cmdlinep;
607 	while (VIM_ISWHITE(*p))
608 	{
609 	    p++;
610 	    marker_indent_len++;
611 	}
612 	text_indent_len = -1;
613     }
614 
615     // The marker is the next word.
616     if (*cmd != NUL && *cmd != comment_char)
617     {
618 	marker = skipwhite(cmd);
619 	p = skiptowhite(marker);
620 	if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
621 	{
622 	    semsg(_(e_trailing_arg), p);
623 	    return NULL;
624 	}
625 	*p = NUL;
626 	if (!script_get && vim_islower(*marker))
627 	{
628 	    emsg(_("E221: Marker cannot start with lower case letter"));
629 	    return NULL;
630 	}
631     }
632     else
633     {
634 	// When getting lines for an embedded script, if the marker is missing,
635 	// accept '.' as the marker.
636 	if (script_get)
637 	    marker = dot;
638 	else
639 	{
640 	    emsg(_("E172: Missing marker"));
641 	    return NULL;
642 	}
643     }
644 
645     l = list_alloc();
646     if (l == NULL)
647 	return NULL;
648 
649     for (;;)
650     {
651 	int	mi = 0;
652 	int	ti = 0;
653 
654 	theline = eap->getline(NUL, eap->cookie, 0, FALSE);
655 	if (theline == NULL)
656 	{
657 	    semsg(_("E990: Missing end marker '%s'"), marker);
658 	    break;
659 	}
660 
661 	// with "trim": skip the indent matching the :let line to find the
662 	// marker
663 	if (marker_indent_len > 0
664 		&& STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0)
665 	    mi = marker_indent_len;
666 	if (STRCMP(marker, theline + mi) == 0)
667 	{
668 	    vim_free(theline);
669 	    break;
670 	}
671 
672 	if (text_indent_len == -1 && *theline != NUL)
673 	{
674 	    // set the text indent from the first line.
675 	    p = theline;
676 	    text_indent_len = 0;
677 	    while (VIM_ISWHITE(*p))
678 	    {
679 		p++;
680 		text_indent_len++;
681 	    }
682 	    text_indent = vim_strnsave(theline, text_indent_len);
683 	}
684 	// with "trim": skip the indent matching the first line
685 	if (text_indent != NULL)
686 	    for (ti = 0; ti < text_indent_len; ++ti)
687 		if (theline[ti] != text_indent[ti])
688 		    break;
689 
690 	if (list_append_string(l, theline + ti, -1) == FAIL)
691 	    break;
692 	vim_free(theline);
693     }
694     vim_free(text_indent);
695 
696     return l;
697 }
698 
699 /*
700  * Vim9 variable declaration:
701  * ":var name"
702  * ":var name: type"
703  * ":var name = expr"
704  * ":var name: type = expr"
705  * etc.
706  */
707     void
ex_var(exarg_T * eap)708 ex_var(exarg_T *eap)
709 {
710     if (!in_vim9script())
711     {
712 	semsg(_(e_str_cannot_be_used_in_legacy_vim_script), ":var");
713 	return;
714     }
715     ex_let(eap);
716 }
717 
718 /*
719  * ":let"			list all variable values
720  * ":let var1 var2"		list variable values
721  * ":let var = expr"		assignment command.
722  * ":let var += expr"		assignment command.
723  * ":let var -= expr"		assignment command.
724  * ":let var *= expr"		assignment command.
725  * ":let var /= expr"		assignment command.
726  * ":let var %= expr"		assignment command.
727  * ":let var .= expr"		assignment command.
728  * ":let var ..= expr"		assignment command.
729  * ":let [var1, var2] = expr"	unpack list.
730  * ":let var =<< ..."		heredoc
731  * ":let var: string"		Vim9 declaration
732  *
733  * ":final var = expr"		assignment command.
734  * ":final [var1, var2] = expr"	unpack list.
735  *
736  * ":const"			list all variable values
737  * ":const var1 var2"		list variable values
738  * ":const var = expr"		assignment command.
739  * ":const [var1, var2] = expr"	unpack list.
740  */
741     void
ex_let(exarg_T * eap)742 ex_let(exarg_T *eap)
743 {
744     char_u	*arg = eap->arg;
745     char_u	*expr = NULL;
746     typval_T	rettv;
747     int		i;
748     int		var_count = 0;
749     int		semicolon = 0;
750     char_u	op[4];
751     char_u	*argend;
752     int		first = TRUE;
753     int		concat;
754     int		has_assign;
755     int		flags = 0;
756     int		vim9script = in_vim9script();
757 
758     if (eap->cmdidx == CMD_final && !vim9script)
759     {
760 	// In legacy Vim script ":final" is short for ":finally".
761 	ex_finally(eap);
762 	return;
763     }
764     if (eap->cmdidx == CMD_let && vim9script)
765     {
766 	emsg(_(e_cannot_use_let_in_vim9_script));
767 	return;
768     }
769 
770     if (eap->cmdidx == CMD_const)
771 	flags |= ASSIGN_CONST;
772     else if (eap->cmdidx == CMD_final)
773 	flags |= ASSIGN_FINAL;
774 
775     // Vim9 assignment without ":let", ":const" or ":final"
776     if (eap->arg == eap->cmd)
777 	flags |= ASSIGN_NO_DECL;
778 
779     argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
780     if (argend == NULL)
781 	return;
782     if (argend > arg && argend[-1] == '.')  // for var.='str'
783 	--argend;
784     expr = skipwhite(argend);
785     concat = expr[0] == '.'
786 	&& ((expr[1] == '=' && in_old_script(2))
787 		|| (expr[1] == '.' && expr[2] == '='));
788     has_assign =  *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
789 							    && expr[1] == '=');
790     if (!has_assign && !concat)
791     {
792 	// ":let" without "=": list variables
793 	if (*arg == '[')
794 	    emsg(_(e_invarg));
795 	else if (expr[0] == '.' && expr[1] == '=')
796 	    emsg(_("E985: .= is not supported with script version >= 2"));
797 	else if (!ends_excmd2(eap->cmd, arg))
798 	{
799 	    if (vim9script)
800 	    {
801 		if (!ends_excmd2(eap->cmd, skipwhite(argend)))
802 		    semsg(_(e_trailing_arg), argend);
803 		else
804 		    // Vim9 declaration ":var name: type"
805 		    arg = vim9_declare_scriptvar(eap, arg);
806 	    }
807 	    else
808 	    {
809 		// ":let var1 var2" - list values
810 		arg = list_arg_vars(eap, arg, &first);
811 	    }
812 	}
813 	else if (!eap->skip)
814 	{
815 	    // ":let"
816 	    list_glob_vars(&first);
817 	    list_buf_vars(&first);
818 	    list_win_vars(&first);
819 	    list_tab_vars(&first);
820 	    list_script_vars(&first);
821 	    list_func_vars(&first);
822 	    list_vim_vars(&first);
823 	}
824 	set_nextcmd(eap, arg);
825     }
826     else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
827     {
828 	list_T	*l;
829 	long	cur_lnum = SOURCING_LNUM;
830 
831 	// HERE document
832 	l = heredoc_get(eap, expr + 3, FALSE);
833 	if (l != NULL)
834 	{
835 	    rettv_list_set(&rettv, l);
836 	    if (!eap->skip)
837 	    {
838 		// errors are for the assignment, not the end marker
839 		SOURCING_LNUM = cur_lnum;
840 		op[0] = '=';
841 		op[1] = NUL;
842 		(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
843 								flags, op);
844 	    }
845 	    clear_tv(&rettv);
846 	}
847     }
848     else
849     {
850 	evalarg_T   evalarg;
851 	int	    len = 1;
852 
853 	CLEAR_FIELD(rettv);
854 	i = FAIL;
855 	if (has_assign || concat)
856 	{
857 	    int cur_lnum;
858 
859 	    op[0] = '=';
860 	    op[1] = NUL;
861 	    if (*expr != '=')
862 	    {
863 		if (vim9script && (flags & ASSIGN_NO_DECL) == 0)
864 		{
865 		    // +=, /=, etc. require an existing variable
866 		    semsg(_(e_cannot_use_operator_on_new_variable), eap->arg);
867 		    i = FAIL;
868 		}
869 		else if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
870 		{
871 		    op[0] = *expr;   // +=, -=, *=, /=, %= or .=
872 		    ++len;
873 		    if (expr[0] == '.' && expr[1] == '.') // ..=
874 		    {
875 			++expr;
876 			++len;
877 		    }
878 		}
879 		expr += 2;
880 	    }
881 	    else
882 		++expr;
883 
884 	    if (vim9script && !eap->skip && (!VIM_ISWHITE(*argend)
885 						   || !IS_WHITE_OR_NUL(*expr)))
886 	    {
887 		vim_strncpy(op, expr - len, len);
888 		semsg(_(e_white_space_required_before_and_after_str_at_str),
889 								   op, argend);
890 		i = FAIL;
891 	    }
892 
893 	    if (eap->skip)
894 		++emsg_skip;
895 	    fill_evalarg_from_eap(&evalarg, eap, eap->skip);
896 	    expr = skipwhite_and_linebreak(expr, &evalarg);
897 	    cur_lnum = SOURCING_LNUM;
898 	    i = eval0(expr, &rettv, eap, &evalarg);
899 	    if (eap->skip)
900 		--emsg_skip;
901 	    clear_evalarg(&evalarg, eap);
902 
903 	    // Restore the line number so that any type error is given for the
904 	    // declaration, not the expression.
905 	    SOURCING_LNUM = cur_lnum;
906 	}
907 	if (eap->skip)
908 	{
909 	    if (i != FAIL)
910 		clear_tv(&rettv);
911 	}
912 	else if (i != FAIL)
913 	{
914 	    (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
915 								    flags, op);
916 	    clear_tv(&rettv);
917 	}
918     }
919 }
920 
921 /*
922  * Assign the typeval "tv" to the variable or variables at "arg_start".
923  * Handles both "var" with any type and "[var, var; var]" with a list type.
924  * When "op" is not NULL it points to a string with characters that
925  * must appear after the variable(s).  Use "+", "-" or "." for add, subtract
926  * or concatenate.
927  * Returns OK or FAIL;
928  */
929     int
ex_let_vars(char_u * arg_start,typval_T * tv,int copy,int semicolon,int var_count,int flags,char_u * op)930 ex_let_vars(
931     char_u	*arg_start,
932     typval_T	*tv,
933     int		copy,		// copy values from "tv", don't move
934     int		semicolon,	// from skip_var_list()
935     int		var_count,	// from skip_var_list()
936     int		flags,		// ASSIGN_FINAL, ASSIGN_CONST, etc.
937     char_u	*op)
938 {
939     char_u	*arg = arg_start;
940     list_T	*l;
941     int		i;
942     int		var_idx = 0;
943     listitem_T	*item;
944     typval_T	ltv;
945 
946     if (*arg != '[')
947     {
948 	// ":let var = expr" or ":for var in list"
949 	if (ex_let_one(arg, tv, copy, flags, op, op, var_idx) == NULL)
950 	    return FAIL;
951 	return OK;
952     }
953 
954     // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
955     if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
956     {
957 	emsg(_(e_listreq));
958 	return FAIL;
959     }
960 
961     i = list_len(l);
962     if (semicolon == 0 && var_count < i)
963     {
964 	emsg(_("E687: Less targets than List items"));
965 	return FAIL;
966     }
967     if (var_count - semicolon > i)
968     {
969 	emsg(_("E688: More targets than List items"));
970 	return FAIL;
971     }
972 
973     CHECK_LIST_MATERIALIZE(l);
974     item = l->lv_first;
975     while (*arg != ']')
976     {
977 	arg = skipwhite(arg + 1);
978 	++var_idx;
979 	arg = ex_let_one(arg, &item->li_tv, TRUE,
980 			  flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
981 	item = item->li_next;
982 	if (arg == NULL)
983 	    return FAIL;
984 
985 	arg = skipwhite(arg);
986 	if (*arg == ';')
987 	{
988 	    // Put the rest of the list (may be empty) in the var after ';'.
989 	    // Create a new list for this.
990 	    l = list_alloc();
991 	    if (l == NULL)
992 		return FAIL;
993 	    while (item != NULL)
994 	    {
995 		list_append_tv(l, &item->li_tv);
996 		item = item->li_next;
997 	    }
998 
999 	    ltv.v_type = VAR_LIST;
1000 	    ltv.v_lock = 0;
1001 	    ltv.vval.v_list = l;
1002 	    l->lv_refcount = 1;
1003 	    ++var_idx;
1004 
1005 	    arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
1006 			    flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
1007 	    clear_tv(&ltv);
1008 	    if (arg == NULL)
1009 		return FAIL;
1010 	    break;
1011 	}
1012 	else if (*arg != ',' && *arg != ']')
1013 	{
1014 	    internal_error("ex_let_vars()");
1015 	    return FAIL;
1016 	}
1017     }
1018 
1019     return OK;
1020 }
1021 
1022 /*
1023  * Skip over assignable variable "var" or list of variables "[var, var]".
1024  * Used for ":let varvar = expr" and ":for varvar in expr".
1025  * For "[var, var]" increment "*var_count" for each variable.
1026  * for "[var, var; var]" set "semicolon" to 1.
1027  * If "silent" is TRUE do not give an "invalid argument" error message.
1028  * Return NULL for an error.
1029  */
1030     char_u *
skip_var_list(char_u * arg,int include_type,int * var_count,int * semicolon,int silent)1031 skip_var_list(
1032     char_u	*arg,
1033     int		include_type,
1034     int		*var_count,
1035     int		*semicolon,
1036     int		silent)
1037 {
1038     char_u	*p, *s;
1039 
1040     if (*arg == '[')
1041     {
1042 	// "[var, var]": find the matching ']'.
1043 	p = arg;
1044 	for (;;)
1045 	{
1046 	    p = skipwhite(p + 1);	// skip whites after '[', ';' or ','
1047 	    s = skip_var_one(p, include_type);
1048 	    if (s == p)
1049 	    {
1050 		if (!silent)
1051 		    semsg(_(e_invarg2), p);
1052 		return NULL;
1053 	    }
1054 	    ++*var_count;
1055 
1056 	    p = skipwhite(s);
1057 	    if (*p == ']')
1058 		break;
1059 	    else if (*p == ';')
1060 	    {
1061 		if (*semicolon == 1)
1062 		{
1063 		    emsg(_("E452: Double ; in list of variables"));
1064 		    return NULL;
1065 		}
1066 		*semicolon = 1;
1067 	    }
1068 	    else if (*p != ',')
1069 	    {
1070 		if (!silent)
1071 		    semsg(_(e_invarg2), p);
1072 		return NULL;
1073 	    }
1074 	}
1075 	return p + 1;
1076     }
1077     else
1078 	return skip_var_one(arg, include_type);
1079 }
1080 
1081 /*
1082  * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
1083  * l[idx].
1084  * In Vim9 script also skip over ": type" if "include_type" is TRUE.
1085  */
1086     char_u *
skip_var_one(char_u * arg,int include_type)1087 skip_var_one(char_u *arg, int include_type)
1088 {
1089     char_u	*end;
1090     int		vim9 = in_vim9script();
1091 
1092     if (*arg == '@' && arg[1] != NUL)
1093 	return arg + 2;
1094     end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
1095 				   NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1096 
1097     // "a: type" is declaring variable "a" with a type, not "a:".
1098     // Same for "s: type".
1099     if (vim9 && end == arg + 2 && end[-1] == ':')
1100 	--end;
1101 
1102     if (include_type && vim9)
1103     {
1104 	if (*end == ':')
1105 	    end = skip_type(skipwhite(end + 1), FALSE);
1106     }
1107     return end;
1108 }
1109 
1110 /*
1111  * List variables for hashtab "ht" with prefix "prefix".
1112  * If "empty" is TRUE also list NULL strings as empty strings.
1113  */
1114     void
list_hashtable_vars(hashtab_T * ht,char * prefix,int empty,int * first)1115 list_hashtable_vars(
1116     hashtab_T	*ht,
1117     char	*prefix,
1118     int		empty,
1119     int		*first)
1120 {
1121     hashitem_T	*hi;
1122     dictitem_T	*di;
1123     int		todo;
1124     char_u	buf[IOSIZE];
1125 
1126     todo = (int)ht->ht_used;
1127     for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
1128     {
1129 	if (!HASHITEM_EMPTY(hi))
1130 	{
1131 	    --todo;
1132 	    di = HI2DI(hi);
1133 
1134 	    // apply :filter /pat/ to variable name
1135 	    vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
1136 	    vim_strcat((char_u *)buf, di->di_key, IOSIZE);
1137 	    if (message_filtered(buf))
1138 		continue;
1139 
1140 	    if (empty || di->di_tv.v_type != VAR_STRING
1141 					   || di->di_tv.vval.v_string != NULL)
1142 		list_one_var(di, prefix, first);
1143 	}
1144     }
1145 }
1146 
1147 /*
1148  * List global variables.
1149  */
1150     static void
list_glob_vars(int * first)1151 list_glob_vars(int *first)
1152 {
1153     list_hashtable_vars(&globvarht, "", TRUE, first);
1154 }
1155 
1156 /*
1157  * List buffer variables.
1158  */
1159     static void
list_buf_vars(int * first)1160 list_buf_vars(int *first)
1161 {
1162     list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
1163 }
1164 
1165 /*
1166  * List window variables.
1167  */
1168     static void
list_win_vars(int * first)1169 list_win_vars(int *first)
1170 {
1171     list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
1172 }
1173 
1174 /*
1175  * List tab page variables.
1176  */
1177     static void
list_tab_vars(int * first)1178 list_tab_vars(int *first)
1179 {
1180     list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
1181 }
1182 
1183 /*
1184  * List variables in "arg".
1185  */
1186     static char_u *
list_arg_vars(exarg_T * eap,char_u * arg,int * first)1187 list_arg_vars(exarg_T *eap, char_u *arg, int *first)
1188 {
1189     int		error = FALSE;
1190     int		len;
1191     char_u	*name;
1192     char_u	*name_start;
1193     char_u	*arg_subsc;
1194     char_u	*tofree;
1195     typval_T    tv;
1196 
1197     while (!ends_excmd2(eap->cmd, arg) && !got_int)
1198     {
1199 	if (error || eap->skip)
1200 	{
1201 	    arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1202 	    if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
1203 	    {
1204 		emsg_severe = TRUE;
1205 		if (!did_emsg)
1206 		    semsg(_(e_trailing_arg), arg);
1207 		break;
1208 	    }
1209 	}
1210 	else
1211 	{
1212 	    // get_name_len() takes care of expanding curly braces
1213 	    name_start = name = arg;
1214 	    len = get_name_len(&arg, &tofree, TRUE, TRUE);
1215 	    if (len <= 0)
1216 	    {
1217 		// This is mainly to keep test 49 working: when expanding
1218 		// curly braces fails overrule the exception error message.
1219 		if (len < 0 && !aborting())
1220 		{
1221 		    emsg_severe = TRUE;
1222 		    semsg(_(e_invarg2), arg);
1223 		    break;
1224 		}
1225 		error = TRUE;
1226 	    }
1227 	    else
1228 	    {
1229 		arg = skipwhite(arg);
1230 		if (tofree != NULL)
1231 		    name = tofree;
1232 		if (eval_variable(name, len, &tv, NULL,
1233 						     EVAL_VAR_VERBOSE) == FAIL)
1234 		    error = TRUE;
1235 		else
1236 		{
1237 		    // handle d.key, l[idx], f(expr)
1238 		    arg_subsc = arg;
1239 		    if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, TRUE)
1240 								       == FAIL)
1241 			error = TRUE;
1242 		    else
1243 		    {
1244 			if (arg == arg_subsc && len == 2 && name[1] == ':')
1245 			{
1246 			    switch (*name)
1247 			    {
1248 				case 'g': list_glob_vars(first); break;
1249 				case 'b': list_buf_vars(first); break;
1250 				case 'w': list_win_vars(first); break;
1251 				case 't': list_tab_vars(first); break;
1252 				case 'v': list_vim_vars(first); break;
1253 				case 's': list_script_vars(first); break;
1254 				case 'l': list_func_vars(first); break;
1255 				default:
1256 					  semsg(_("E738: Can't list variables for %s"), name);
1257 			    }
1258 			}
1259 			else
1260 			{
1261 			    char_u	numbuf[NUMBUFLEN];
1262 			    char_u	*tf;
1263 			    int		c;
1264 			    char_u	*s;
1265 
1266 			    s = echo_string(&tv, &tf, numbuf, 0);
1267 			    c = *arg;
1268 			    *arg = NUL;
1269 			    list_one_var_a("",
1270 				    arg == arg_subsc ? name : name_start,
1271 				    tv.v_type,
1272 				    s == NULL ? (char_u *)"" : s,
1273 				    first);
1274 			    *arg = c;
1275 			    vim_free(tf);
1276 			}
1277 			clear_tv(&tv);
1278 		    }
1279 		}
1280 	    }
1281 
1282 	    vim_free(tofree);
1283 	}
1284 
1285 	arg = skipwhite(arg);
1286     }
1287 
1288     return arg;
1289 }
1290 
1291 /*
1292  * Set an environment variable, part of ex_let_one().
1293  */
1294     static char_u *
ex_let_env(char_u * arg,typval_T * tv,int flags,char_u * endchars,char_u * op)1295 ex_let_env(
1296     char_u	*arg,
1297     typval_T	*tv,
1298     int		flags,
1299     char_u	*endchars,
1300     char_u	*op)
1301 {
1302     char_u	*arg_end = NULL;
1303     char_u	*name;
1304     int		len;
1305 
1306     if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1307 					 && (flags & ASSIGN_FOR_LOOP) == 0)
1308     {
1309 	emsg(_("E996: Cannot lock an environment variable"));
1310 	return NULL;
1311     }
1312 
1313     // Find the end of the name.
1314     ++arg;
1315     name = arg;
1316     len = get_env_len(&arg);
1317     if (len == 0)
1318 	semsg(_(e_invarg2), name - 1);
1319     else
1320     {
1321 	if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
1322 	    semsg(_(e_letwrong), op);
1323 	else if (endchars != NULL
1324 			      && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1325 	    emsg(_(e_unexpected_characters_in_let));
1326 	else if (!check_secure())
1327 	{
1328 	    char_u	*tofree = NULL;
1329 	    int		c1 = name[len];
1330 	    char_u	*p;
1331 
1332 	    name[len] = NUL;
1333 	    p = tv_get_string_chk(tv);
1334 	    if (p != NULL && op != NULL && *op == '.')
1335 	    {
1336 		int	mustfree = FALSE;
1337 		char_u  *s = vim_getenv(name, &mustfree);
1338 
1339 		if (s != NULL)
1340 		{
1341 		    p = tofree = concat_str(s, p);
1342 		    if (mustfree)
1343 			vim_free(s);
1344 		}
1345 	    }
1346 	    if (p != NULL)
1347 	    {
1348 		vim_setenv_ext(name, p);
1349 		arg_end = arg;
1350 	    }
1351 	    name[len] = c1;
1352 	    vim_free(tofree);
1353 	}
1354     }
1355     return arg_end;
1356 }
1357 
1358 /*
1359  * Set an option, part of ex_let_one().
1360  */
1361     static char_u *
ex_let_option(char_u * arg,typval_T * tv,int flags,char_u * endchars,char_u * op)1362 ex_let_option(
1363     char_u	*arg,
1364     typval_T	*tv,
1365     int		flags,
1366     char_u	*endchars,
1367     char_u	*op)
1368 {
1369     char_u	*p;
1370     int		opt_flags;
1371     char_u	*arg_end = NULL;
1372 
1373     if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1374 					 && (flags & ASSIGN_FOR_LOOP) == 0)
1375     {
1376 	emsg(_(e_const_option));
1377 	return NULL;
1378     }
1379 
1380     // Find the end of the name.
1381     p = find_option_end(&arg, &opt_flags);
1382     if (p == NULL || (endchars != NULL
1383 			       && vim_strchr(endchars, *skipwhite(p)) == NULL))
1384 	emsg(_(e_unexpected_characters_in_let));
1385     else
1386     {
1387 	int	    c1;
1388 	long	    n = 0;
1389 	getoption_T opt_type;
1390 	long	    numval;
1391 	char_u	    *stringval = NULL;
1392 	char_u	    *s = NULL;
1393 	int	    failed = FALSE;
1394 
1395 	c1 = *p;
1396 	*p = NUL;
1397 
1398 	opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
1399 	if ((opt_type == gov_bool
1400 		    || opt_type == gov_number
1401 		    || opt_type == gov_hidden_bool
1402 		    || opt_type == gov_hidden_number)
1403 			 && (tv->v_type != VAR_STRING || !in_vim9script()))
1404 	{
1405 	    if (opt_type == gov_bool || opt_type == gov_hidden_bool)
1406 		// bool, possibly hidden
1407 		n = (long)tv_get_bool(tv);
1408 	    else
1409 		// number, possibly hidden
1410 		n = (long)tv_get_number(tv);
1411 	}
1412 
1413 	// Avoid setting a string option to the text "v:false" or similar.
1414 	// In Vim9 script also don't convert a number to string.
1415 	if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
1416 			 && (!in_vim9script() || tv->v_type != VAR_NUMBER))
1417 	    s = tv_get_string_chk(tv);
1418 
1419 	if (op != NULL && *op != '=')
1420 	{
1421 	    if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
1422 		    || (opt_type == gov_string && *op != '.'))
1423 	    {
1424 		semsg(_(e_letwrong), op);
1425 		failed = TRUE;  // don't set the value
1426 
1427 	    }
1428 	    else
1429 	    {
1430 		// number, in legacy script also bool
1431 		if (opt_type == gov_number
1432 			     || (opt_type == gov_bool && !in_vim9script()))
1433 		{
1434 		    switch (*op)
1435 		    {
1436 			case '+': n = numval + n; break;
1437 			case '-': n = numval - n; break;
1438 			case '*': n = numval * n; break;
1439 			case '/': n = (long)num_divide(numval, n,
1440 							       &failed); break;
1441 			case '%': n = (long)num_modulus(numval, n,
1442 							       &failed); break;
1443 		    }
1444 		    s = NULL;
1445 		}
1446 		else if (opt_type == gov_string
1447 					 && stringval != NULL && s != NULL)
1448 		{
1449 		    // string
1450 		    s = concat_str(stringval, s);
1451 		    vim_free(stringval);
1452 		    stringval = s;
1453 		}
1454 	    }
1455 	}
1456 
1457 	if (!failed)
1458 	{
1459 	    if (opt_type != gov_string || s != NULL)
1460 	    {
1461 		set_option_value(arg, n, s, opt_flags);
1462 		arg_end = p;
1463 	    }
1464 	    else
1465 		emsg(_(e_stringreq));
1466 	}
1467 	*p = c1;
1468 	vim_free(stringval);
1469     }
1470     return arg_end;
1471 }
1472 
1473 /*
1474  * Set a register, part of ex_let_one().
1475  */
1476     static char_u *
ex_let_register(char_u * arg,typval_T * tv,int flags,char_u * endchars,char_u * op)1477 ex_let_register(
1478     char_u	*arg,
1479     typval_T	*tv,
1480     int		flags,
1481     char_u	*endchars,
1482     char_u	*op)
1483 {
1484     char_u	*arg_end = NULL;
1485 
1486     if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1487 					 && (flags & ASSIGN_FOR_LOOP) == 0)
1488     {
1489 	emsg(_("E996: Cannot lock a register"));
1490 	return NULL;
1491     }
1492     ++arg;
1493     if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
1494 	semsg(_(e_letwrong), op);
1495     else if (endchars != NULL
1496 			  && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1497 	emsg(_(e_unexpected_characters_in_let));
1498     else
1499     {
1500 	char_u	*ptofree = NULL;
1501 	char_u	*p;
1502 
1503 	p = tv_get_string_chk(tv);
1504 	if (p != NULL && op != NULL && *op == '.')
1505 	{
1506 	    char_u  *s = get_reg_contents(*arg == '@'
1507 						  ? '"' : *arg, GREG_EXPR_SRC);
1508 
1509 	    if (s != NULL)
1510 	    {
1511 		p = ptofree = concat_str(s, p);
1512 		vim_free(s);
1513 	    }
1514 	}
1515 	if (p != NULL)
1516 	{
1517 	    write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
1518 	    arg_end = arg + 1;
1519 	}
1520 	vim_free(ptofree);
1521     }
1522     return arg_end;
1523 }
1524 
1525 /*
1526  * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
1527  * Returns a pointer to the char just after the var name.
1528  * Returns NULL if there is an error.
1529  */
1530     static char_u *
ex_let_one(char_u * arg,typval_T * tv,int copy,int flags,char_u * endchars,char_u * op,int var_idx)1531 ex_let_one(
1532     char_u	*arg,		// points to variable name
1533     typval_T	*tv,		// value to assign to variable
1534     int		copy,		// copy value from "tv"
1535     int		flags,		// ASSIGN_CONST, ASSIGN_FINAL, etc.
1536     char_u	*endchars,	// valid chars after variable name  or NULL
1537     char_u	*op,		// "+", "-", "."  or NULL
1538     int		var_idx)	// variable index for "let [a, b] = list"
1539 {
1540     char_u	*arg_end = NULL;
1541 
1542     if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
1543 			&& (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
1544 				  && vim_strchr((char_u *)"$@&", *arg) != NULL)
1545     {
1546 	vim9_declare_error(arg);
1547 	return NULL;
1548     }
1549 
1550     if (*arg == '$')
1551     {
1552 	// ":let $VAR = expr": Set environment variable.
1553 	return ex_let_env(arg, tv, flags, endchars, op);
1554     }
1555     else if (*arg == '&')
1556     {
1557 	// ":let &option = expr": Set option value.
1558 	// ":let &l:option = expr": Set local option value.
1559 	// ":let &g:option = expr": Set global option value.
1560 	// ":for &ts in range(8)": Set option value for for loop
1561 	return ex_let_option(arg, tv, flags, endchars, op);
1562     }
1563     else if (*arg == '@')
1564     {
1565 	// ":let @r = expr": Set register contents.
1566 	return ex_let_register(arg, tv, flags, endchars, op);
1567     }
1568     else if (eval_isnamec1(*arg) || *arg == '{')
1569     {
1570 	lval_T	lv;
1571 	char_u	*p;
1572 
1573 	// ":let var = expr": Set internal variable.
1574 	// ":let var: type = expr": Set internal variable with type.
1575 	// ":let {expr} = expr": Idem, name made with curly braces
1576 	p = get_lval(arg, tv, &lv, FALSE, FALSE,
1577 		(flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
1578 					   ? GLV_NO_DECL : 0, FNE_CHECK_START);
1579 	if (p != NULL && lv.ll_name != NULL)
1580 	{
1581 	    if (endchars != NULL && vim_strchr(endchars,
1582 					   *skipwhite(lv.ll_name_end)) == NULL)
1583 	    {
1584 		emsg(_(e_unexpected_characters_in_let));
1585 	    }
1586 	    else
1587 	    {
1588 		set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
1589 		arg_end = lv.ll_name_end;
1590 	    }
1591 	}
1592 	clear_lval(&lv);
1593     }
1594     else
1595 	semsg(_(e_invarg2), arg);
1596 
1597     return arg_end;
1598 }
1599 
1600 /*
1601  * ":unlet[!] var1 ... " command.
1602  */
1603     void
ex_unlet(exarg_T * eap)1604 ex_unlet(exarg_T *eap)
1605 {
1606     ex_unletlock(eap, eap->arg, 0, 0, do_unlet_var, NULL);
1607 }
1608 
1609 /*
1610  * ":lockvar" and ":unlockvar" commands
1611  */
1612     void
ex_lockvar(exarg_T * eap)1613 ex_lockvar(exarg_T *eap)
1614 {
1615     char_u	*arg = eap->arg;
1616     int		deep = 2;
1617 
1618     if (eap->forceit)
1619 	deep = -1;
1620     else if (vim_isdigit(*arg))
1621     {
1622 	deep = getdigits(&arg);
1623 	arg = skipwhite(arg);
1624     }
1625 
1626     ex_unletlock(eap, arg, deep, 0, do_lock_var, NULL);
1627 }
1628 
1629 /*
1630  * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
1631  * Also used for Vim9 script.  "callback" is invoked as:
1632  *	callback(&lv, name_end, eap, deep, cookie)
1633  */
1634     void
ex_unletlock(exarg_T * eap,char_u * argstart,int deep,int glv_flags,int (* callback)(lval_T *,char_u *,exarg_T *,int,void *),void * cookie)1635 ex_unletlock(
1636     exarg_T	*eap,
1637     char_u	*argstart,
1638     int		deep,
1639     int		glv_flags,
1640     int		(*callback)(lval_T *, char_u *, exarg_T *, int, void *),
1641     void	*cookie)
1642 {
1643     char_u	*arg = argstart;
1644     char_u	*name_end;
1645     int		error = FALSE;
1646     lval_T	lv;
1647 
1648     do
1649     {
1650 	if (*arg == '$')
1651 	{
1652 	    lv.ll_name = arg;
1653 	    lv.ll_tv = NULL;
1654 	    ++arg;
1655 	    if (get_env_len(&arg) == 0)
1656 	    {
1657 		semsg(_(e_invarg2), arg - 1);
1658 		return;
1659 	    }
1660 	    if (!error && !eap->skip
1661 			      && callback(&lv, arg, eap, deep, cookie) == FAIL)
1662 		error = TRUE;
1663 	    name_end = arg;
1664 	}
1665 	else
1666 	{
1667 	    // Parse the name and find the end.
1668 	    name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error,
1669 				     glv_flags | GLV_NO_DECL, FNE_CHECK_START);
1670 	    if (lv.ll_name == NULL)
1671 		error = TRUE;	    // error but continue parsing
1672 	    if (name_end == NULL || (!VIM_ISWHITE(*name_end)
1673 						    && !ends_excmd(*name_end)))
1674 	    {
1675 		if (name_end != NULL)
1676 		{
1677 		    emsg_severe = TRUE;
1678 		    semsg(_(e_trailing_arg), name_end);
1679 		}
1680 		if (!(eap->skip || error))
1681 		    clear_lval(&lv);
1682 		break;
1683 	    }
1684 
1685 	    if (!error && !eap->skip
1686 			 && callback(&lv, name_end, eap, deep, cookie) == FAIL)
1687 		error = TRUE;
1688 
1689 	    if (!eap->skip)
1690 		clear_lval(&lv);
1691 	}
1692 
1693 	arg = skipwhite(name_end);
1694     } while (!ends_excmd2(name_end, arg));
1695 
1696     set_nextcmd(eap, arg);
1697 }
1698 
1699     static int
do_unlet_var(lval_T * lp,char_u * name_end,exarg_T * eap,int deep UNUSED,void * cookie UNUSED)1700 do_unlet_var(
1701     lval_T	*lp,
1702     char_u	*name_end,
1703     exarg_T	*eap,
1704     int		deep UNUSED,
1705     void	*cookie UNUSED)
1706 {
1707     int		forceit = eap->forceit;
1708     int		ret = OK;
1709     int		cc;
1710 
1711     if (lp->ll_tv == NULL)
1712     {
1713 	cc = *name_end;
1714 	*name_end = NUL;
1715 
1716 	// Environment variable, normal name or expanded name.
1717 	if (*lp->ll_name == '$')
1718 	    vim_unsetenv(lp->ll_name + 1);
1719 	else if (do_unlet(lp->ll_name, forceit) == FAIL)
1720 	    ret = FAIL;
1721 	*name_end = cc;
1722     }
1723     else if ((lp->ll_list != NULL
1724 		 && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
1725 	    || (lp->ll_dict != NULL
1726 		&& value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
1727 	return FAIL;
1728     else if (lp->ll_range)
1729     {
1730 	if (list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_name, lp->ll_n1,
1731 					   !lp->ll_empty2, lp->ll_n2) == FAIL)
1732 	    return FAIL;
1733     }
1734     else
1735     {
1736 	if (lp->ll_list != NULL)
1737 	    // unlet a List item.
1738 	    listitem_remove(lp->ll_list, lp->ll_li);
1739 	else
1740 	    // unlet a Dictionary item.
1741 	    dictitem_remove(lp->ll_dict, lp->ll_di);
1742     }
1743 
1744     return ret;
1745 }
1746 
1747 /*
1748  * Unlet one item or a range of items from a list.
1749  * Return OK or FAIL.
1750  */
1751     int
list_unlet_range(list_T * l,listitem_T * li_first,char_u * name,long n1_arg,int has_n2,long n2)1752 list_unlet_range(
1753 	list_T	    *l,
1754 	listitem_T  *li_first,
1755 	char_u	    *name,
1756 	long	    n1_arg,
1757 	int	    has_n2,
1758 	long	    n2)
1759 {
1760     listitem_T  *li = li_first;
1761     int		n1 = n1_arg;
1762 
1763     while (li != NULL && (!has_n2 || n2 >= n1))
1764     {
1765 	if (value_check_lock(li->li_tv.v_lock, name, FALSE))
1766 	    return FAIL;
1767 	li = li->li_next;
1768 	++n1;
1769     }
1770 
1771     // Delete a range of List items.
1772     li = li_first;
1773     n1 = n1_arg;
1774     while (li != NULL && (!has_n2 || n2 >= n1))
1775     {
1776 	listitem_T *next = li->li_next;
1777 
1778 	listitem_remove(l, li);
1779 	li = next;
1780 	++n1;
1781     }
1782     return OK;
1783 }
1784 /*
1785  * "unlet" a variable.  Return OK if it existed, FAIL if not.
1786  * When "forceit" is TRUE don't complain if the variable doesn't exist.
1787  */
1788     int
do_unlet(char_u * name,int forceit)1789 do_unlet(char_u *name, int forceit)
1790 {
1791     hashtab_T	*ht;
1792     hashitem_T	*hi;
1793     char_u	*varname;
1794     dict_T	*d;
1795     dictitem_T	*di;
1796 
1797     // can't :unlet a script variable in Vim9 script
1798     if (in_vim9script() && check_vim9_unlet(name) == FAIL)
1799 	return FAIL;
1800 
1801     ht = find_var_ht(name, &varname);
1802 
1803     // can't :unlet a script variable in Vim9 script from a function
1804     if (ht == get_script_local_ht()
1805 	    && SCRIPT_ID_VALID(current_sctx.sc_sid)
1806 	    && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
1807 							 == SCRIPT_VERSION_VIM9
1808 	    && check_vim9_unlet(name) == FAIL)
1809 	return FAIL;
1810 
1811     if (ht != NULL && *varname != NUL)
1812     {
1813 	d = get_current_funccal_dict(ht);
1814 	if (d == NULL)
1815 	{
1816 	    if (ht == &globvarht)
1817 		d = &globvardict;
1818 	    else if (ht == &compat_hashtab)
1819 		d = &vimvardict;
1820 	    else
1821 	    {
1822 		di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
1823 		d = di == NULL ? NULL : di->di_tv.vval.v_dict;
1824 	    }
1825 	    if (d == NULL)
1826 	    {
1827 		internal_error("do_unlet()");
1828 		return FAIL;
1829 	    }
1830 	}
1831 	hi = hash_find(ht, varname);
1832 	if (HASHITEM_EMPTY(hi))
1833 	    hi = find_hi_in_scoped_ht(name, &ht);
1834 	if (hi != NULL && !HASHITEM_EMPTY(hi))
1835 	{
1836 	    di = HI2DI(hi);
1837 	    if (var_check_fixed(di->di_flags, name, FALSE)
1838 		    || var_check_ro(di->di_flags, name, FALSE)
1839 		    || value_check_lock(d->dv_lock, name, FALSE))
1840 		return FAIL;
1841 
1842 	    delete_var(ht, hi);
1843 	    return OK;
1844 	}
1845     }
1846     if (forceit)
1847 	return OK;
1848     semsg(_("E108: No such variable: \"%s\""), name);
1849     return FAIL;
1850 }
1851 
1852 /*
1853  * Lock or unlock variable indicated by "lp".
1854  * "deep" is the levels to go (-1 for unlimited);
1855  * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
1856  */
1857     static int
do_lock_var(lval_T * lp,char_u * name_end,exarg_T * eap,int deep,void * cookie UNUSED)1858 do_lock_var(
1859     lval_T	*lp,
1860     char_u	*name_end,
1861     exarg_T	*eap,
1862     int		deep,
1863     void	*cookie UNUSED)
1864 {
1865     int		lock = eap->cmdidx == CMD_lockvar;
1866     int		ret = OK;
1867     int		cc;
1868     dictitem_T	*di;
1869 
1870     if (lp->ll_tv == NULL)
1871     {
1872 	cc = *name_end;
1873 	*name_end = NUL;
1874 	if (*lp->ll_name == '$')
1875 	{
1876 	    semsg(_(e_lock_unlock), lp->ll_name);
1877 	    ret = FAIL;
1878 	}
1879 	else
1880 	{
1881 	    // Normal name or expanded name.
1882 	    di = find_var(lp->ll_name, NULL, TRUE);
1883 	    if (di == NULL)
1884 	    {
1885 		if (in_vim9script())
1886 		    semsg(_(e_cannot_find_variable_to_unlock_str),
1887 								  lp->ll_name);
1888 		ret = FAIL;
1889 	    }
1890 	    else if ((di->di_flags & DI_FLAGS_FIX)
1891 			    && di->di_tv.v_type != VAR_DICT
1892 			    && di->di_tv.v_type != VAR_LIST)
1893 	    {
1894 		// For historic reasons this error is not given for a list or
1895 		// dict.  E.g., the b: dict could be locked/unlocked.
1896 		semsg(_(e_lock_unlock), lp->ll_name);
1897 		ret = FAIL;
1898 	    }
1899 	    else
1900 	    {
1901 		if (lock)
1902 		    di->di_flags |= DI_FLAGS_LOCK;
1903 		else
1904 		    di->di_flags &= ~DI_FLAGS_LOCK;
1905 		if (deep != 0)
1906 		    item_lock(&di->di_tv, deep, lock, FALSE);
1907 	    }
1908 	}
1909 	*name_end = cc;
1910     }
1911     else if (deep == 0)
1912     {
1913 	// nothing to do
1914     }
1915     else if (lp->ll_range)
1916     {
1917 	listitem_T    *li = lp->ll_li;
1918 
1919 	// (un)lock a range of List items.
1920 	while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
1921 	{
1922 	    item_lock(&li->li_tv, deep, lock, FALSE);
1923 	    li = li->li_next;
1924 	    ++lp->ll_n1;
1925 	}
1926     }
1927     else if (lp->ll_list != NULL)
1928 	// (un)lock a List item.
1929 	item_lock(&lp->ll_li->li_tv, deep, lock, FALSE);
1930     else
1931 	// (un)lock a Dictionary item.
1932 	item_lock(&lp->ll_di->di_tv, deep, lock, FALSE);
1933 
1934     return ret;
1935 }
1936 
1937 /*
1938  * Lock or unlock an item.  "deep" is nr of levels to go.
1939  * When "check_refcount" is TRUE do not lock a list or dict with a reference
1940  * count larger than 1.
1941  */
1942     void
item_lock(typval_T * tv,int deep,int lock,int check_refcount)1943 item_lock(typval_T *tv, int deep, int lock, int check_refcount)
1944 {
1945     static int	recurse = 0;
1946     list_T	*l;
1947     listitem_T	*li;
1948     dict_T	*d;
1949     blob_T	*b;
1950     hashitem_T	*hi;
1951     int		todo;
1952 
1953     if (recurse >= DICT_MAXNEST)
1954     {
1955 	emsg(_("E743: variable nested too deep for (un)lock"));
1956 	return;
1957     }
1958     if (deep == 0)
1959 	return;
1960     ++recurse;
1961 
1962     // lock/unlock the item itself
1963     if (lock)
1964 	tv->v_lock |= VAR_LOCKED;
1965     else
1966 	tv->v_lock &= ~VAR_LOCKED;
1967 
1968     switch (tv->v_type)
1969     {
1970 	case VAR_UNKNOWN:
1971 	case VAR_ANY:
1972 	case VAR_VOID:
1973 	case VAR_NUMBER:
1974 	case VAR_BOOL:
1975 	case VAR_STRING:
1976 	case VAR_FUNC:
1977 	case VAR_PARTIAL:
1978 	case VAR_FLOAT:
1979 	case VAR_SPECIAL:
1980 	case VAR_JOB:
1981 	case VAR_CHANNEL:
1982 	case VAR_INSTR:
1983 	    break;
1984 
1985 	case VAR_BLOB:
1986 	    if ((b = tv->vval.v_blob) != NULL
1987 				    && !(check_refcount && b->bv_refcount > 1))
1988 	    {
1989 		if (lock)
1990 		    b->bv_lock |= VAR_LOCKED;
1991 		else
1992 		    b->bv_lock &= ~VAR_LOCKED;
1993 	    }
1994 	    break;
1995 	case VAR_LIST:
1996 	    if ((l = tv->vval.v_list) != NULL
1997 				    && !(check_refcount && l->lv_refcount > 1))
1998 	    {
1999 		if (lock)
2000 		    l->lv_lock |= VAR_LOCKED;
2001 		else
2002 		    l->lv_lock &= ~VAR_LOCKED;
2003 		if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item)
2004 		    // recursive: lock/unlock the items the List contains
2005 		    FOR_ALL_LIST_ITEMS(l, li)
2006 			item_lock(&li->li_tv, deep - 1, lock, check_refcount);
2007 	    }
2008 	    break;
2009 	case VAR_DICT:
2010 	    if ((d = tv->vval.v_dict) != NULL
2011 				    && !(check_refcount && d->dv_refcount > 1))
2012 	    {
2013 		if (lock)
2014 		    d->dv_lock |= VAR_LOCKED;
2015 		else
2016 		    d->dv_lock &= ~VAR_LOCKED;
2017 		if (deep < 0 || deep > 1)
2018 		{
2019 		    // recursive: lock/unlock the items the List contains
2020 		    todo = (int)d->dv_hashtab.ht_used;
2021 		    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2022 		    {
2023 			if (!HASHITEM_EMPTY(hi))
2024 			{
2025 			    --todo;
2026 			    item_lock(&HI2DI(hi)->di_tv, deep - 1, lock,
2027 							       check_refcount);
2028 			}
2029 		    }
2030 		}
2031 	    }
2032     }
2033     --recurse;
2034 }
2035 
2036 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
2037 /*
2038  * Delete all "menutrans_" variables.
2039  */
2040     void
del_menutrans_vars(void)2041 del_menutrans_vars(void)
2042 {
2043     hashitem_T	*hi;
2044     int		todo;
2045 
2046     hash_lock(&globvarht);
2047     todo = (int)globvarht.ht_used;
2048     for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
2049     {
2050 	if (!HASHITEM_EMPTY(hi))
2051 	{
2052 	    --todo;
2053 	    if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
2054 		delete_var(&globvarht, hi);
2055 	}
2056     }
2057     hash_unlock(&globvarht);
2058 }
2059 #endif
2060 
2061 /*
2062  * Local string buffer for the next two functions to store a variable name
2063  * with its prefix. Allocated in cat_prefix_varname(), freed later in
2064  * get_user_var_name().
2065  */
2066 
2067 static char_u	*varnamebuf = NULL;
2068 static int	varnamebuflen = 0;
2069 
2070 /*
2071  * Function to concatenate a prefix and a variable name.
2072  */
2073     char_u *
cat_prefix_varname(int prefix,char_u * name)2074 cat_prefix_varname(int prefix, char_u *name)
2075 {
2076     int		len;
2077 
2078     len = (int)STRLEN(name) + 3;
2079     if (len > varnamebuflen)
2080     {
2081 	vim_free(varnamebuf);
2082 	len += 10;			// some additional space
2083 	varnamebuf = alloc(len);
2084 	if (varnamebuf == NULL)
2085 	{
2086 	    varnamebuflen = 0;
2087 	    return NULL;
2088 	}
2089 	varnamebuflen = len;
2090     }
2091     *varnamebuf = prefix;
2092     varnamebuf[1] = ':';
2093     STRCPY(varnamebuf + 2, name);
2094     return varnamebuf;
2095 }
2096 
2097 /*
2098  * Function given to ExpandGeneric() to obtain the list of user defined
2099  * (global/buffer/window/built-in) variable names.
2100  */
2101     char_u *
get_user_var_name(expand_T * xp,int idx)2102 get_user_var_name(expand_T *xp, int idx)
2103 {
2104     static long_u	gdone;
2105     static long_u	bdone;
2106     static long_u	wdone;
2107     static long_u	tdone;
2108     static int		vidx;
2109     static hashitem_T	*hi;
2110     hashtab_T		*ht;
2111 
2112     if (idx == 0)
2113     {
2114 	gdone = bdone = wdone = vidx = 0;
2115 	tdone = 0;
2116     }
2117 
2118     // Global variables
2119     if (gdone < globvarht.ht_used)
2120     {
2121 	if (gdone++ == 0)
2122 	    hi = globvarht.ht_array;
2123 	else
2124 	    ++hi;
2125 	while (HASHITEM_EMPTY(hi))
2126 	    ++hi;
2127 	if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
2128 	    return cat_prefix_varname('g', hi->hi_key);
2129 	return hi->hi_key;
2130     }
2131 
2132     // b: variables
2133     ht =
2134 #ifdef FEAT_CMDWIN
2135 	// In cmdwin, the alternative buffer should be used.
2136 	is_in_cmdwin() ? &prevwin->w_buffer->b_vars->dv_hashtab :
2137 #endif
2138 	&curbuf->b_vars->dv_hashtab;
2139     if (bdone < ht->ht_used)
2140     {
2141 	if (bdone++ == 0)
2142 	    hi = ht->ht_array;
2143 	else
2144 	    ++hi;
2145 	while (HASHITEM_EMPTY(hi))
2146 	    ++hi;
2147 	return cat_prefix_varname('b', hi->hi_key);
2148     }
2149 
2150     // w: variables
2151     ht =
2152 #ifdef FEAT_CMDWIN
2153 	// In cmdwin, the alternative window should be used.
2154 	is_in_cmdwin() ? &prevwin->w_vars->dv_hashtab :
2155 #endif
2156 	&curwin->w_vars->dv_hashtab;
2157     if (wdone < ht->ht_used)
2158     {
2159 	if (wdone++ == 0)
2160 	    hi = ht->ht_array;
2161 	else
2162 	    ++hi;
2163 	while (HASHITEM_EMPTY(hi))
2164 	    ++hi;
2165 	return cat_prefix_varname('w', hi->hi_key);
2166     }
2167 
2168     // t: variables
2169     ht = &curtab->tp_vars->dv_hashtab;
2170     if (tdone < ht->ht_used)
2171     {
2172 	if (tdone++ == 0)
2173 	    hi = ht->ht_array;
2174 	else
2175 	    ++hi;
2176 	while (HASHITEM_EMPTY(hi))
2177 	    ++hi;
2178 	return cat_prefix_varname('t', hi->hi_key);
2179     }
2180 
2181     // v: variables
2182     if (vidx < VV_LEN)
2183 	return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
2184 
2185     VIM_CLEAR(varnamebuf);
2186     varnamebuflen = 0;
2187     return NULL;
2188 }
2189 
2190     char *
get_var_special_name(int nr)2191 get_var_special_name(int nr)
2192 {
2193     switch (nr)
2194     {
2195 	case VVAL_FALSE: return in_vim9script() ? "false" : "v:false";
2196 	case VVAL_TRUE:  return in_vim9script() ? "true" : "v:true";
2197 	case VVAL_NULL:  return in_vim9script() ? "null" : "v:null";
2198 	case VVAL_NONE:  return "v:none";
2199     }
2200     internal_error("get_var_special_name()");
2201     return "42";
2202 }
2203 
2204 /*
2205  * Returns the global variable dictionary
2206  */
2207     dict_T *
get_globvar_dict(void)2208 get_globvar_dict(void)
2209 {
2210     return &globvardict;
2211 }
2212 
2213 /*
2214  * Returns the global variable hash table
2215  */
2216     hashtab_T *
get_globvar_ht(void)2217 get_globvar_ht(void)
2218 {
2219     return &globvarht;
2220 }
2221 
2222 /*
2223  * Returns the v: variable dictionary
2224  */
2225     dict_T *
get_vimvar_dict(void)2226 get_vimvar_dict(void)
2227 {
2228     return &vimvardict;
2229 }
2230 
2231 /*
2232  * Returns the index of a v:variable.  Negative if not found.
2233  * Returns DI_ flags in "di_flags".
2234  */
2235     int
find_vim_var(char_u * name,int * di_flags)2236 find_vim_var(char_u *name, int *di_flags)
2237 {
2238     dictitem_T	    *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
2239     struct vimvar   *vv;
2240 
2241     if (di == NULL)
2242 	return -1;
2243     *di_flags = di->di_flags;
2244     vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
2245     return (int)(vv - vimvars);
2246 }
2247 
2248 
2249 /*
2250  * Set type of v: variable to "type".
2251  */
2252     void
set_vim_var_type(int idx,vartype_T type)2253 set_vim_var_type(int idx, vartype_T type)
2254 {
2255     vimvars[idx].vv_type = type;
2256 }
2257 
2258 /*
2259  * Set number v: variable to "val".
2260  * Note that this does not set the type, use set_vim_var_type() for that.
2261  */
2262     void
set_vim_var_nr(int idx,varnumber_T val)2263 set_vim_var_nr(int idx, varnumber_T val)
2264 {
2265     vimvars[idx].vv_nr = val;
2266 }
2267 
2268     char *
get_vim_var_name(int idx)2269 get_vim_var_name(int idx)
2270 {
2271     return vimvars[idx].vv_name;
2272 }
2273 
2274 /*
2275  * Get typval_T v: variable value.
2276  */
2277     typval_T *
get_vim_var_tv(int idx)2278 get_vim_var_tv(int idx)
2279 {
2280     return &vimvars[idx].vv_tv;
2281 }
2282 
2283 /*
2284  * Set v: variable to "tv".  Only accepts the same type.
2285  * Takes over the value of "tv".
2286  */
2287     int
set_vim_var_tv(int idx,typval_T * tv)2288 set_vim_var_tv(int idx, typval_T *tv)
2289 {
2290     if (vimvars[idx].vv_type != tv->v_type)
2291     {
2292 	emsg(_(e_type_mismatch_for_v_variable));
2293 	clear_tv(tv);
2294 	return FAIL;
2295     }
2296     // VV_RO is also checked when compiling, but let's check here as well.
2297     if (vimvars[idx].vv_flags & VV_RO)
2298     {
2299 	semsg(_(e_cannot_change_readonly_variable_str), vimvars[idx].vv_name);
2300 	return FAIL;
2301     }
2302     if (sandbox && (vimvars[idx].vv_flags & VV_RO_SBX))
2303     {
2304 	semsg(_(e_readonlysbx), vimvars[idx].vv_name);
2305 	return FAIL;
2306     }
2307     clear_tv(&vimvars[idx].vv_di.di_tv);
2308     vimvars[idx].vv_di.di_tv = *tv;
2309     return OK;
2310 }
2311 
2312 /*
2313  * Get number v: variable value.
2314  */
2315     varnumber_T
get_vim_var_nr(int idx)2316 get_vim_var_nr(int idx)
2317 {
2318     return vimvars[idx].vv_nr;
2319 }
2320 
2321 /*
2322  * Get string v: variable value.  Uses a static buffer, can only be used once.
2323  * If the String variable has never been set, return an empty string.
2324  * Never returns NULL;
2325  */
2326     char_u *
get_vim_var_str(int idx)2327 get_vim_var_str(int idx)
2328 {
2329     return tv_get_string(&vimvars[idx].vv_tv);
2330 }
2331 
2332 /*
2333  * Get List v: variable value.  Caller must take care of reference count when
2334  * needed.
2335  */
2336     list_T *
get_vim_var_list(int idx)2337 get_vim_var_list(int idx)
2338 {
2339     return vimvars[idx].vv_list;
2340 }
2341 
2342 /*
2343  * Get Dict v: variable value.  Caller must take care of reference count when
2344  * needed.
2345  */
2346     dict_T *
get_vim_var_dict(int idx)2347 get_vim_var_dict(int idx)
2348 {
2349     return vimvars[idx].vv_dict;
2350 }
2351 
2352 /*
2353  * Set v:char to character "c".
2354  */
2355     void
set_vim_var_char(int c)2356 set_vim_var_char(int c)
2357 {
2358     char_u	buf[MB_MAXBYTES + 1];
2359 
2360     if (has_mbyte)
2361 	buf[(*mb_char2bytes)(c, buf)] = NUL;
2362     else
2363     {
2364 	buf[0] = c;
2365 	buf[1] = NUL;
2366     }
2367     set_vim_var_string(VV_CHAR, buf, -1);
2368 }
2369 
2370 /*
2371  * Set v:count to "count" and v:count1 to "count1".
2372  * When "set_prevcount" is TRUE first set v:prevcount from v:count.
2373  */
2374     void
set_vcount(long count,long count1,int set_prevcount)2375 set_vcount(
2376     long	count,
2377     long	count1,
2378     int		set_prevcount)
2379 {
2380     if (set_prevcount)
2381 	vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
2382     vimvars[VV_COUNT].vv_nr = count;
2383     vimvars[VV_COUNT1].vv_nr = count1;
2384 }
2385 
2386 /*
2387  * Save variables that might be changed as a side effect.  Used when executing
2388  * a timer callback.
2389  */
2390     void
save_vimvars(vimvars_save_T * vvsave)2391 save_vimvars(vimvars_save_T *vvsave)
2392 {
2393     vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
2394     vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
2395     vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
2396 }
2397 
2398 /*
2399  * Restore variables saved by save_vimvars().
2400  */
2401     void
restore_vimvars(vimvars_save_T * vvsave)2402 restore_vimvars(vimvars_save_T *vvsave)
2403 {
2404     vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
2405     vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
2406     vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
2407 }
2408 
2409 /*
2410  * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
2411  * value.
2412  */
2413     void
set_vim_var_string(int idx,char_u * val,int len)2414 set_vim_var_string(
2415     int		idx,
2416     char_u	*val,
2417     int		len)	    // length of "val" to use or -1 (whole string)
2418 {
2419     clear_tv(&vimvars[idx].vv_di.di_tv);
2420     vimvars[idx].vv_type = VAR_STRING;
2421     if (val == NULL)
2422 	vimvars[idx].vv_str = NULL;
2423     else if (len == -1)
2424 	vimvars[idx].vv_str = vim_strsave(val);
2425     else
2426 	vimvars[idx].vv_str = vim_strnsave(val, len);
2427 }
2428 
2429 /*
2430  * Set List v: variable to "val".
2431  */
2432     void
set_vim_var_list(int idx,list_T * val)2433 set_vim_var_list(int idx, list_T *val)
2434 {
2435     clear_tv(&vimvars[idx].vv_di.di_tv);
2436     vimvars[idx].vv_type = VAR_LIST;
2437     vimvars[idx].vv_list = val;
2438     if (val != NULL)
2439 	++val->lv_refcount;
2440 }
2441 
2442 /*
2443  * Set Dictionary v: variable to "val".
2444  */
2445     void
set_vim_var_dict(int idx,dict_T * val)2446 set_vim_var_dict(int idx, dict_T *val)
2447 {
2448     clear_tv(&vimvars[idx].vv_di.di_tv);
2449     vimvars[idx].vv_type = VAR_DICT;
2450     vimvars[idx].vv_dict = val;
2451     if (val != NULL)
2452     {
2453 	++val->dv_refcount;
2454 	dict_set_items_ro(val);
2455     }
2456 }
2457 
2458 /*
2459  * Set the v:argv list.
2460  */
2461     void
set_argv_var(char ** argv,int argc)2462 set_argv_var(char **argv, int argc)
2463 {
2464     list_T	*l = list_alloc();
2465     int		i;
2466 
2467     if (l == NULL)
2468 	getout(1);
2469     l->lv_lock = VAR_FIXED;
2470     for (i = 0; i < argc; ++i)
2471     {
2472 	if (list_append_string(l, (char_u *)argv[i], -1) == FAIL)
2473 	    getout(1);
2474 	l->lv_u.mat.lv_last->li_tv.v_lock = VAR_FIXED;
2475     }
2476     set_vim_var_list(VV_ARGV, l);
2477 }
2478 
2479 /*
2480  * Reset v:register, taking the 'clipboard' setting into account.
2481  */
2482     void
reset_reg_var(void)2483 reset_reg_var(void)
2484 {
2485     int regname = 0;
2486 
2487     // Adjust the register according to 'clipboard', so that when
2488     // "unnamed" is present it becomes '*' or '+' instead of '"'.
2489 #ifdef FEAT_CLIPBOARD
2490     adjust_clip_reg(&regname);
2491 #endif
2492     set_reg_var(regname);
2493 }
2494 
2495 /*
2496  * Set v:register if needed.
2497  */
2498     void
set_reg_var(int c)2499 set_reg_var(int c)
2500 {
2501     char_u	regname;
2502 
2503     if (c == 0 || c == ' ')
2504 	regname = '"';
2505     else
2506 	regname = c;
2507     // Avoid free/alloc when the value is already right.
2508     if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
2509 	set_vim_var_string(VV_REG, &regname, 1);
2510 }
2511 
2512 /*
2513  * Get or set v:exception.  If "oldval" == NULL, return the current value.
2514  * Otherwise, restore the value to "oldval" and return NULL.
2515  * Must always be called in pairs to save and restore v:exception!  Does not
2516  * take care of memory allocations.
2517  */
2518     char_u *
v_exception(char_u * oldval)2519 v_exception(char_u *oldval)
2520 {
2521     if (oldval == NULL)
2522 	return vimvars[VV_EXCEPTION].vv_str;
2523 
2524     vimvars[VV_EXCEPTION].vv_str = oldval;
2525     return NULL;
2526 }
2527 
2528 /*
2529  * Get or set v:throwpoint.  If "oldval" == NULL, return the current value.
2530  * Otherwise, restore the value to "oldval" and return NULL.
2531  * Must always be called in pairs to save and restore v:throwpoint!  Does not
2532  * take care of memory allocations.
2533  */
2534     char_u *
v_throwpoint(char_u * oldval)2535 v_throwpoint(char_u *oldval)
2536 {
2537     if (oldval == NULL)
2538 	return vimvars[VV_THROWPOINT].vv_str;
2539 
2540     vimvars[VV_THROWPOINT].vv_str = oldval;
2541     return NULL;
2542 }
2543 
2544 /*
2545  * Set v:cmdarg.
2546  * If "eap" != NULL, use "eap" to generate the value and return the old value.
2547  * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
2548  * Must always be called in pairs!
2549  */
2550     char_u *
set_cmdarg(exarg_T * eap,char_u * oldarg)2551 set_cmdarg(exarg_T *eap, char_u *oldarg)
2552 {
2553     char_u	*oldval;
2554     char_u	*newval;
2555     unsigned	len;
2556 
2557     oldval = vimvars[VV_CMDARG].vv_str;
2558     if (eap == NULL)
2559     {
2560 	vim_free(oldval);
2561 	vimvars[VV_CMDARG].vv_str = oldarg;
2562 	return NULL;
2563     }
2564 
2565     if (eap->force_bin == FORCE_BIN)
2566 	len = 6;
2567     else if (eap->force_bin == FORCE_NOBIN)
2568 	len = 8;
2569     else
2570 	len = 0;
2571 
2572     if (eap->read_edit)
2573 	len += 7;
2574 
2575     if (eap->force_ff != 0)
2576 	len += 10; // " ++ff=unix"
2577     if (eap->force_enc != 0)
2578 	len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
2579     if (eap->bad_char != 0)
2580 	len += 7 + 4;  // " ++bad=" + "keep" or "drop"
2581 
2582     newval = alloc(len + 1);
2583     if (newval == NULL)
2584 	return NULL;
2585 
2586     if (eap->force_bin == FORCE_BIN)
2587 	sprintf((char *)newval, " ++bin");
2588     else if (eap->force_bin == FORCE_NOBIN)
2589 	sprintf((char *)newval, " ++nobin");
2590     else
2591 	*newval = NUL;
2592 
2593     if (eap->read_edit)
2594 	STRCAT(newval, " ++edit");
2595 
2596     if (eap->force_ff != 0)
2597 	sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
2598 						eap->force_ff == 'u' ? "unix"
2599 						: eap->force_ff == 'd' ? "dos"
2600 						: "mac");
2601     if (eap->force_enc != 0)
2602 	sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
2603 					       eap->cmd + eap->force_enc);
2604     if (eap->bad_char == BAD_KEEP)
2605 	STRCPY(newval + STRLEN(newval), " ++bad=keep");
2606     else if (eap->bad_char == BAD_DROP)
2607 	STRCPY(newval + STRLEN(newval), " ++bad=drop");
2608     else if (eap->bad_char != 0)
2609 	sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
2610     vimvars[VV_CMDARG].vv_str = newval;
2611     return oldval;
2612 }
2613 
2614 /*
2615  * Get the value of internal variable "name".
2616  * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
2617  * imported script ID.
2618  * Return OK or FAIL.  If OK is returned "rettv" must be cleared.
2619  */
2620     int
eval_variable(char_u * name,int len,typval_T * rettv,dictitem_T ** dip,int flags)2621 eval_variable(
2622     char_u	*name,
2623     int		len,		// length of "name"
2624     typval_T	*rettv,		// NULL when only checking existence
2625     dictitem_T	**dip,		// non-NULL when typval's dict item is needed
2626     int		flags)		// EVAL_VAR_ flags
2627 {
2628     int		ret = OK;
2629     typval_T	*tv = NULL;
2630     int		found = FALSE;
2631     hashtab_T	*ht = NULL;
2632     int		cc;
2633     type_T	*type = NULL;
2634 
2635     // truncate the name, so that we can use strcmp()
2636     cc = name[len];
2637     name[len] = NUL;
2638 
2639     // Check for local variable when debugging.
2640     if ((tv = lookup_debug_var(name)) == NULL)
2641     {
2642 	// Check for user-defined variables.
2643 	dictitem_T	*v = find_var(name, &ht, flags & EVAL_VAR_NOAUTOLOAD);
2644 
2645 	if (v != NULL)
2646 	{
2647 	    tv = &v->di_tv;
2648 	    if (dip != NULL)
2649 		*dip = v;
2650 	}
2651 	else
2652 	    ht = NULL;
2653     }
2654 
2655     if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
2656     {
2657 	imported_T  *import;
2658 	char_u	    *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
2659 
2660 	import = find_imported(p, 0, NULL);
2661 
2662 	// imported variable from another script
2663 	if (import != NULL)
2664 	{
2665 	    if (import->imp_funcname != NULL)
2666 	    {
2667 		found = TRUE;
2668 		if (rettv != NULL)
2669 		{
2670 		    rettv->v_type = VAR_FUNC;
2671 		    rettv->vval.v_string = vim_strsave(import->imp_funcname);
2672 		}
2673 	    }
2674 	    else if (import->imp_flags & IMP_FLAGS_STAR)
2675 	    {
2676 		if ((flags & EVAL_VAR_IMPORT) == 0)
2677 		{
2678 		    if (flags & EVAL_VAR_VERBOSE)
2679 			emsg(_(e_import_as_name_not_supported_here));
2680 		    ret = FAIL;
2681 		}
2682 		else
2683 		{
2684 		    if (rettv != NULL)
2685 		    {
2686 			rettv->v_type = VAR_ANY;
2687 			rettv->vval.v_number = import->imp_sid;
2688 		    }
2689 		    found = TRUE;
2690 		}
2691 	    }
2692 	    else
2693 	    {
2694 		scriptitem_T    *si = SCRIPT_ITEM(import->imp_sid);
2695 		svar_T		*sv = ((svar_T *)si->sn_var_vals.ga_data)
2696 						    + import->imp_var_vals_idx;
2697 		tv = sv->sv_tv;
2698 		type = sv->sv_type;
2699 	    }
2700 	}
2701 	else if (in_vim9script())
2702 	{
2703 	    ufunc_T *ufunc = find_func(name, FALSE, NULL);
2704 
2705 	    // In Vim9 script we can get a function reference by using the
2706 	    // function name.
2707 	    if (ufunc != NULL)
2708 	    {
2709 		found = TRUE;
2710 		if (rettv != NULL)
2711 		{
2712 		    rettv->v_type = VAR_FUNC;
2713 		    rettv->vval.v_string = vim_strsave(ufunc->uf_name);
2714 		    if (rettv->vval.v_string != NULL)
2715 			func_ref(ufunc->uf_name);
2716 		}
2717 	    }
2718 	}
2719     }
2720 
2721     if (!found)
2722     {
2723 	if (tv == NULL)
2724 	{
2725 	    if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
2726 		semsg(_(e_undefined_variable_str), name);
2727 	    ret = FAIL;
2728 	}
2729 	else if (rettv != NULL)
2730 	{
2731 	    if (ht != NULL && ht == get_script_local_ht()
2732 		    && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
2733 	    {
2734 		svar_T *sv = find_typval_in_script(tv);
2735 
2736 		if (sv != NULL)
2737 		    type = sv->sv_type;
2738 	    }
2739 
2740 	    // If a list or dict variable wasn't initialized, do it now.
2741 	    if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL)
2742 	    {
2743 		tv->vval.v_dict = dict_alloc();
2744 		if (tv->vval.v_dict != NULL)
2745 		{
2746 		    ++tv->vval.v_dict->dv_refcount;
2747 		    tv->vval.v_dict->dv_type = alloc_type(type);
2748 		}
2749 	    }
2750 	    else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL)
2751 	    {
2752 		tv->vval.v_list = list_alloc();
2753 		if (tv->vval.v_list != NULL)
2754 		{
2755 		    ++tv->vval.v_list->lv_refcount;
2756 		    tv->vval.v_list->lv_type = alloc_type(type);
2757 		}
2758 	    }
2759 	    else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL)
2760 	    {
2761 		tv->vval.v_blob = blob_alloc();
2762 		if (tv->vval.v_blob != NULL)
2763 		    ++tv->vval.v_blob->bv_refcount;
2764 	    }
2765 	    copy_tv(tv, rettv);
2766 	}
2767     }
2768 
2769     name[len] = cc;
2770 
2771     return ret;
2772 }
2773 
2774 /*
2775  * Check if variable "name[len]" is a local variable or an argument.
2776  * If so, "*eval_lavars_used" is set to TRUE.
2777  */
2778     void
check_vars(char_u * name,int len)2779 check_vars(char_u *name, int len)
2780 {
2781     int		cc;
2782     char_u	*varname;
2783     hashtab_T	*ht;
2784 
2785     if (eval_lavars_used == NULL)
2786 	return;
2787 
2788     // truncate the name, so that we can use strcmp()
2789     cc = name[len];
2790     name[len] = NUL;
2791 
2792     ht = find_var_ht(name, &varname);
2793     if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
2794     {
2795 	if (find_var(name, NULL, TRUE) != NULL)
2796 	    *eval_lavars_used = TRUE;
2797     }
2798 
2799     name[len] = cc;
2800 }
2801 
2802 /*
2803  * Find variable "name" in the list of variables.
2804  * Return a pointer to it if found, NULL if not found.
2805  * Careful: "a:0" variables don't have a name.
2806  * When "htp" is not NULL  set "htp" to the hashtab_T used.
2807  */
2808     dictitem_T *
find_var(char_u * name,hashtab_T ** htp,int no_autoload)2809 find_var(char_u *name, hashtab_T **htp, int no_autoload)
2810 {
2811     char_u	*varname;
2812     hashtab_T	*ht;
2813     dictitem_T	*ret = NULL;
2814 
2815     ht = find_var_ht(name, &varname);
2816     if (htp != NULL)
2817 	*htp = ht;
2818     if (ht == NULL)
2819 	return NULL;
2820     ret = find_var_in_ht(ht, *name, varname, no_autoload);
2821     if (ret != NULL)
2822 	return ret;
2823 
2824     // Search in parent scope for lambda
2825     ret = find_var_in_scoped_ht(name, no_autoload);
2826     if (ret != NULL)
2827 	return ret;
2828 
2829     // in Vim9 script items without a scope can be script-local
2830     if (in_vim9script() && name[0] != NUL && name[1] != ':')
2831     {
2832 	ht = get_script_local_ht();
2833 	if (ht != NULL)
2834 	{
2835 	    ret = find_var_in_ht(ht, *name, varname, no_autoload);
2836 	    if (ret != NULL)
2837 	    {
2838 		if (htp != NULL)
2839 		    *htp = ht;
2840 		return ret;
2841 	    }
2842 	}
2843     }
2844 
2845     return NULL;
2846 }
2847 
2848 /*
2849  * Find variable "varname" in hashtab "ht" with name "htname".
2850  * When "varname" is empty returns curwin/curtab/etc vars dictionary.
2851  * Returns NULL if not found.
2852  */
2853     dictitem_T *
find_var_in_ht(hashtab_T * ht,int htname,char_u * varname,int no_autoload)2854 find_var_in_ht(
2855     hashtab_T	*ht,
2856     int		htname,
2857     char_u	*varname,
2858     int		no_autoload)
2859 {
2860     hashitem_T	*hi;
2861 
2862     if (*varname == NUL)
2863     {
2864 	// Must be something like "s:", otherwise "ht" would be NULL.
2865 	switch (htname)
2866 	{
2867 	    case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
2868 	    case 'g': return &globvars_var;
2869 	    case 'v': return &vimvars_var;
2870 	    case 'b': return &curbuf->b_bufvar;
2871 	    case 'w': return &curwin->w_winvar;
2872 	    case 't': return &curtab->tp_winvar;
2873 	    case 'l': return get_funccal_local_var();
2874 	    case 'a': return get_funccal_args_var();
2875 	}
2876 	return NULL;
2877     }
2878 
2879     hi = hash_find(ht, varname);
2880     if (HASHITEM_EMPTY(hi))
2881     {
2882 	// For global variables we may try auto-loading the script.  If it
2883 	// worked find the variable again.  Don't auto-load a script if it was
2884 	// loaded already, otherwise it would be loaded every time when
2885 	// checking if a function name is a Funcref variable.
2886 	if (ht == &globvarht && !no_autoload)
2887 	{
2888 	    // Note: script_autoload() may make "hi" invalid. It must either
2889 	    // be obtained again or not used.
2890 	    if (!script_autoload(varname, FALSE) || aborting())
2891 		return NULL;
2892 	    hi = hash_find(ht, varname);
2893 	}
2894 	if (HASHITEM_EMPTY(hi))
2895 	    return NULL;
2896     }
2897     return HI2DI(hi);
2898 }
2899 
2900 /*
2901  * Get the script-local hashtab.  NULL if not in a script context.
2902  */
2903     hashtab_T *
get_script_local_ht(void)2904 get_script_local_ht(void)
2905 {
2906     scid_T sid = current_sctx.sc_sid;
2907 
2908     if (SCRIPT_ID_VALID(sid))
2909 	return &SCRIPT_VARS(sid);
2910     return NULL;
2911 }
2912 
2913 /*
2914  * Look for "name[len]" in script-local variables and functions.
2915  * When "cmd" is TRUE it must look like a command, a function must be followed
2916  * by "(" or "->".
2917  * Return OK when found, FAIL when not found.
2918  */
2919     int
lookup_scriptitem(char_u * name,size_t len,int cmd,cctx_T * dummy UNUSED)2920 lookup_scriptitem(
2921 	char_u	*name,
2922 	size_t	len,
2923 	int	cmd,
2924 	cctx_T	*dummy UNUSED)
2925 {
2926     hashtab_T	*ht = get_script_local_ht();
2927     char_u	buffer[30];
2928     char_u	*p;
2929     int		res;
2930     hashitem_T	*hi;
2931     int		is_global = FALSE;
2932     char_u	*fname = name;
2933 
2934     if (ht == NULL)
2935 	return FAIL;
2936     if (len < sizeof(buffer) - 1)
2937     {
2938 	// avoid an alloc/free for short names
2939 	vim_strncpy(buffer, name, len);
2940 	p = buffer;
2941     }
2942     else
2943     {
2944 	p = vim_strnsave(name, len);
2945 	if (p == NULL)
2946 	    return FAIL;
2947     }
2948 
2949     hi = hash_find(ht, p);
2950     res = HASHITEM_EMPTY(hi) ? FAIL : OK;
2951 
2952     // if not script-local, then perhaps imported
2953     if (res == FAIL && find_imported(p, 0, NULL) != NULL)
2954 	res = OK;
2955     if (p != buffer)
2956 	vim_free(p);
2957 
2958     // Find a function, so that a following "->" works.
2959     // When used as a command require "(" or "->" to follow, "Cmd" is a user
2960     // command while "Cmd()" is a function call.
2961     if (res != OK)
2962     {
2963 	p = skipwhite(name + len);
2964 
2965 	if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
2966 	{
2967 	    // Do not check for an internal function, since it might also be a
2968 	    // valid command, such as ":split" versus "split()".
2969 	    // Skip "g:" before a function name.
2970 	    if (name[0] == 'g' && name[1] == ':')
2971 	    {
2972 		is_global = TRUE;
2973 		fname = name + 2;
2974 	    }
2975 	    if (find_func(fname, is_global, NULL) != NULL)
2976 		res = OK;
2977 	}
2978     }
2979 
2980     return res;
2981 }
2982 
2983 /*
2984  * Find the hashtab used for a variable name.
2985  * Return NULL if the name is not valid.
2986  * Set "varname" to the start of name without ':'.
2987  */
2988     hashtab_T *
find_var_ht(char_u * name,char_u ** varname)2989 find_var_ht(char_u *name, char_u **varname)
2990 {
2991     hashitem_T	*hi;
2992     hashtab_T	*ht;
2993 
2994     if (name[0] == NUL)
2995 	return NULL;
2996     if (name[1] != ':')
2997     {
2998 	// The name must not start with a colon or #.
2999 	if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
3000 	    return NULL;
3001 	*varname = name;
3002 
3003 	// "version" is "v:version" in all scopes if scriptversion < 3.
3004 	// Same for a few other variables marked with VV_COMPAT.
3005 	if (in_old_script(3))
3006 	{
3007 	    hi = hash_find(&compat_hashtab, name);
3008 	    if (!HASHITEM_EMPTY(hi))
3009 		return &compat_hashtab;
3010 	}
3011 
3012 	ht = get_funccal_local_ht();
3013 	if (ht != NULL)
3014 	    return ht;				// local variable
3015 
3016 	// In Vim9 script items at the script level are script-local, except
3017 	// for autoload names.
3018 	if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL)
3019 	{
3020 	    ht = get_script_local_ht();
3021 	    if (ht != NULL)
3022 		return ht;
3023 	}
3024 
3025 	return &globvarht;			// global variable
3026     }
3027     *varname = name + 2;
3028     if (*name == 'g')				// global variable
3029 	return &globvarht;
3030     // There must be no ':' or '#' in the rest of the name, unless g: is used
3031     if (vim_strchr(name + 2, ':') != NULL
3032 			       || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
3033 	return NULL;
3034     if (*name == 'b')				// buffer variable
3035 	return &curbuf->b_vars->dv_hashtab;
3036     if (*name == 'w')				// window variable
3037 	return &curwin->w_vars->dv_hashtab;
3038     if (*name == 't')				// tab page variable
3039 	return &curtab->tp_vars->dv_hashtab;
3040     if (*name == 'v')				// v: variable
3041 	return &vimvarht;
3042     if (get_current_funccal() != NULL
3043 	       && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
3044     {
3045 	// a: and l: are only used in functions defined with ":function"
3046 	if (*name == 'a')			// a: function argument
3047 	    return get_funccal_args_ht();
3048 	if (*name == 'l')			// l: local function variable
3049 	    return get_funccal_local_ht();
3050     }
3051     if (*name == 's')				// script variable
3052     {
3053 	ht = get_script_local_ht();
3054 	if (ht != NULL)
3055 	    return ht;
3056     }
3057     return NULL;
3058 }
3059 
3060 /*
3061  * Get the string value of a (global/local) variable.
3062  * Note: see tv_get_string() for how long the pointer remains valid.
3063  * Returns NULL when it doesn't exist.
3064  */
3065     char_u *
get_var_value(char_u * name)3066 get_var_value(char_u *name)
3067 {
3068     dictitem_T	*v;
3069 
3070     v = find_var(name, NULL, FALSE);
3071     if (v == NULL)
3072 	return NULL;
3073     return tv_get_string(&v->di_tv);
3074 }
3075 
3076 /*
3077  * Allocate a new hashtab for a sourced script.  It will be used while
3078  * sourcing this script and when executing functions defined in the script.
3079  */
3080     void
new_script_vars(scid_T id)3081 new_script_vars(scid_T id)
3082 {
3083     scriptvar_T *sv;
3084 
3085     sv = ALLOC_CLEAR_ONE(scriptvar_T);
3086     if (sv == NULL)
3087 	return;
3088     init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
3089     SCRIPT_ITEM(id)->sn_vars = sv;
3090 }
3091 
3092 /*
3093  * Initialize dictionary "dict" as a scope and set variable "dict_var" to
3094  * point to it.
3095  */
3096     void
init_var_dict(dict_T * dict,dictitem_T * dict_var,int scope)3097 init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
3098 {
3099     hash_init(&dict->dv_hashtab);
3100     dict->dv_lock = 0;
3101     dict->dv_scope = scope;
3102     dict->dv_refcount = DO_NOT_FREE_CNT;
3103     dict->dv_copyID = 0;
3104     dict_var->di_tv.vval.v_dict = dict;
3105     dict_var->di_tv.v_type = VAR_DICT;
3106     dict_var->di_tv.v_lock = VAR_FIXED;
3107     dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
3108     dict_var->di_key[0] = NUL;
3109 }
3110 
3111 /*
3112  * Unreference a dictionary initialized by init_var_dict().
3113  */
3114     void
unref_var_dict(dict_T * dict)3115 unref_var_dict(dict_T *dict)
3116 {
3117     // Now the dict needs to be freed if no one else is using it, go back to
3118     // normal reference counting.
3119     dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
3120     dict_unref(dict);
3121 }
3122 
3123 /*
3124  * Clean up a list of internal variables.
3125  * Frees all allocated variables and the value they contain.
3126  * Clears hashtab "ht", does not free it.
3127  */
3128     void
vars_clear(hashtab_T * ht)3129 vars_clear(hashtab_T *ht)
3130 {
3131     vars_clear_ext(ht, TRUE);
3132 }
3133 
3134 /*
3135  * Like vars_clear(), but only free the value if "free_val" is TRUE.
3136  */
3137     void
vars_clear_ext(hashtab_T * ht,int free_val)3138 vars_clear_ext(hashtab_T *ht, int free_val)
3139 {
3140     int		todo;
3141     hashitem_T	*hi;
3142     dictitem_T	*v;
3143 
3144     hash_lock(ht);
3145     todo = (int)ht->ht_used;
3146     for (hi = ht->ht_array; todo > 0; ++hi)
3147     {
3148 	if (!HASHITEM_EMPTY(hi))
3149 	{
3150 	    --todo;
3151 
3152 	    // Free the variable.  Don't remove it from the hashtab,
3153 	    // ht_array might change then.  hash_clear() takes care of it
3154 	    // later.
3155 	    v = HI2DI(hi);
3156 	    if (free_val)
3157 		clear_tv(&v->di_tv);
3158 	    if (v->di_flags & DI_FLAGS_ALLOC)
3159 		vim_free(v);
3160 	}
3161     }
3162     hash_clear(ht);
3163     hash_init(ht);
3164 }
3165 
3166 /*
3167  * Delete a variable from hashtab "ht" at item "hi".
3168  * Clear the variable value and free the dictitem.
3169  */
3170     void
delete_var(hashtab_T * ht,hashitem_T * hi)3171 delete_var(hashtab_T *ht, hashitem_T *hi)
3172 {
3173     dictitem_T	*di = HI2DI(hi);
3174 
3175     hash_remove(ht, hi);
3176     clear_tv(&di->di_tv);
3177     vim_free(di);
3178 }
3179 
3180 /*
3181  * List the value of one internal variable.
3182  */
3183     static void
list_one_var(dictitem_T * v,char * prefix,int * first)3184 list_one_var(dictitem_T *v, char *prefix, int *first)
3185 {
3186     char_u	*tofree;
3187     char_u	*s;
3188     char_u	numbuf[NUMBUFLEN];
3189 
3190     s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
3191     list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
3192 					 s == NULL ? (char_u *)"" : s, first);
3193     vim_free(tofree);
3194 }
3195 
3196     static void
list_one_var_a(char * prefix,char_u * name,int type,char_u * string,int * first)3197 list_one_var_a(
3198     char	*prefix,
3199     char_u	*name,
3200     int		type,
3201     char_u	*string,
3202     int		*first)  // when TRUE clear rest of screen and set to FALSE
3203 {
3204     // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
3205     msg_start();
3206     msg_puts(prefix);
3207     if (name != NULL)	// "a:" vars don't have a name stored
3208 	msg_puts((char *)name);
3209     msg_putchar(' ');
3210     msg_advance(22);
3211     if (type == VAR_NUMBER)
3212 	msg_putchar('#');
3213     else if (type == VAR_FUNC || type == VAR_PARTIAL)
3214 	msg_putchar('*');
3215     else if (type == VAR_LIST)
3216     {
3217 	msg_putchar('[');
3218 	if (*string == '[')
3219 	    ++string;
3220     }
3221     else if (type == VAR_DICT)
3222     {
3223 	msg_putchar('{');
3224 	if (*string == '{')
3225 	    ++string;
3226     }
3227     else
3228 	msg_putchar(' ');
3229 
3230     msg_outtrans(string);
3231 
3232     if (type == VAR_FUNC || type == VAR_PARTIAL)
3233 	msg_puts("()");
3234     if (*first)
3235     {
3236 	msg_clr_eos();
3237 	*first = FALSE;
3238     }
3239 }
3240 
3241 /*
3242  * Set variable "name" to value in "tv".
3243  * If the variable already exists, the value is updated.
3244  * Otherwise the variable is created.
3245  */
3246     void
set_var(char_u * name,typval_T * tv,int copy)3247 set_var(
3248     char_u	*name,
3249     typval_T	*tv,
3250     int		copy)	    // make copy of value in "tv"
3251 {
3252     set_var_const(name, NULL, tv, copy, ASSIGN_DECL, 0);
3253 }
3254 
3255 /*
3256  * Set variable "name" to value in "tv".
3257  * If the variable already exists and "is_const" is FALSE the value is updated.
3258  * Otherwise the variable is created.
3259  */
3260     void
set_var_const(char_u * name,type_T * type_arg,typval_T * tv_arg,int copy,int flags_arg,int var_idx)3261 set_var_const(
3262     char_u	*name,
3263     type_T	*type_arg,
3264     typval_T	*tv_arg,
3265     int		copy,	    // make copy of value in "tv"
3266     int		flags_arg,  // ASSIGN_CONST, ASSIGN_FINAL, etc.
3267     int		var_idx)    // index for ":let [a, b] = list"
3268 {
3269     typval_T	*tv = tv_arg;
3270     type_T	*type = type_arg;
3271     typval_T	bool_tv;
3272     dictitem_T	*di;
3273     typval_T	*dest_tv = NULL;
3274     char_u	*varname;
3275     hashtab_T	*ht;
3276     int		is_script_local;
3277     int		vim9script = in_vim9script();
3278     int		var_in_vim9script;
3279     int		flags = flags_arg;
3280 
3281     ht = find_var_ht(name, &varname);
3282     if (ht == NULL || *varname == NUL)
3283     {
3284 	semsg(_(e_illvar), name);
3285 	goto failed;
3286     }
3287     is_script_local = ht == get_script_local_ht();
3288 
3289     if (vim9script
3290 	    && !is_script_local
3291 	    && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
3292 	    && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
3293 	    && name[1] == ':')
3294     {
3295 	vim9_declare_error(name);
3296 	goto failed;
3297     }
3298     if ((flags & ASSIGN_FOR_LOOP) && name[1] == ':'
3299 			      && vim_strchr((char_u *)"gwbt", name[0]) != NULL)
3300 	// Do not make g:var, w:var, b:var or t:var final.
3301 	flags &= ~ASSIGN_FINAL;
3302 
3303     var_in_vim9script = is_script_local && current_script_is_vim9();
3304     if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
3305     {
3306 	// For "[a, _] = list" the underscore is ignored.
3307 	if ((flags & ASSIGN_UNPACK) == 0)
3308 	    emsg(_(e_cannot_use_underscore_here));
3309 	goto failed;
3310     }
3311 
3312     di = find_var_in_ht(ht, 0, varname, TRUE);
3313 
3314     if (di == NULL && var_in_vim9script)
3315     {
3316 	imported_T  *import = find_imported(varname, 0, NULL);
3317 
3318 	if (import != NULL)
3319 	{
3320 	    scriptitem_T    *si = SCRIPT_ITEM(import->imp_sid);
3321 	    svar_T	    *sv;
3322 	    where_T	    where = WHERE_INIT;
3323 
3324 	    // imported variable from another script
3325 	    if ((flags & ASSIGN_NO_DECL) == 0)
3326 	    {
3327 		semsg(_(e_redefining_imported_item_str), name);
3328 		goto failed;
3329 	    }
3330 	    if (import->imp_flags & IMP_FLAGS_STAR)
3331 	    {
3332 		semsg(_(e_cannot_use_str_itself_it_is_imported_with_star),
3333 									 name);
3334 		goto failed;
3335 	    }
3336 	    sv = ((svar_T *)si->sn_var_vals.ga_data) + import->imp_var_vals_idx;
3337 
3338 	    where.wt_variable = TRUE;
3339 	    if (check_typval_type(sv->sv_type, tv, where) == FAIL
3340 		    || value_check_lock(sv->sv_tv->v_lock, name, FALSE))
3341 	    {
3342 		goto failed;
3343 	    }
3344 
3345 	    dest_tv = sv->sv_tv;
3346 	    clear_tv(dest_tv);
3347 	}
3348     }
3349 
3350     if (dest_tv == NULL)
3351     {
3352 	// Search in parent scope which is possible to reference from lambda
3353 	if (di == NULL)
3354 	    di = find_var_in_scoped_ht(name, TRUE);
3355 
3356 	if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
3357 				      && var_wrong_func_name(name, di == NULL))
3358 	    goto failed;
3359 
3360 	if (need_convert_to_bool(type, tv))
3361 	{
3362 	    // Destination is a bool and the value is not, but it can be
3363 	    // converted.
3364 	    CLEAR_FIELD(bool_tv);
3365 	    bool_tv.v_type = VAR_BOOL;
3366 	    bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
3367 	    tv = &bool_tv;
3368 	}
3369 
3370 	if (di != NULL)
3371 	{
3372 	    // Item already exists.  Allowed to replace when reloading.
3373 	    if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
3374 	    {
3375 		if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
3376 					     && (flags & ASSIGN_FOR_LOOP) == 0)
3377 		{
3378 		    emsg(_(e_cannot_mod));
3379 		    goto failed;
3380 		}
3381 
3382 		if (is_script_local && vim9script
3383 			      && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
3384 		{
3385 		    semsg(_(e_redefining_script_item_str), name);
3386 		    goto failed;
3387 		}
3388 
3389 		if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
3390 		{
3391 		    where_T where = WHERE_INIT;
3392 		    svar_T  *sv = find_typval_in_script(&di->di_tv);
3393 
3394 		    if (sv != NULL)
3395 		    {
3396 			// check the type and adjust to bool if needed
3397 			where.wt_index = var_idx;
3398 			where.wt_variable = TRUE;
3399 			if (check_script_var_type(sv, tv, name, where) == FAIL)
3400 			    goto failed;
3401 			if (type == NULL)
3402 			    type = sv->sv_type;
3403 		    }
3404 		}
3405 
3406 		if ((flags & ASSIGN_FOR_LOOP) == 0
3407 				     && var_check_permission(di, name) == FAIL)
3408 		    goto failed;
3409 	    }
3410 	    else
3411 	    {
3412 		// can only redefine once
3413 		di->di_flags &= ~DI_FLAGS_RELOAD;
3414 
3415 		// A Vim9 script-local variable is also present in sn_all_vars
3416 		// and sn_var_vals.  It may set "type" from "tv".
3417 		if (var_in_vim9script)
3418 		    update_vim9_script_var(FALSE, di, flags, tv, &type,
3419 					 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3420 	    }
3421 
3422 	    // existing variable, need to clear the value
3423 
3424 	    // Handle setting internal di: variables separately where needed to
3425 	    // prevent changing the type.
3426 	    if (ht == &vimvarht)
3427 	    {
3428 		if (di->di_tv.v_type == VAR_STRING)
3429 		{
3430 		    VIM_CLEAR(di->di_tv.vval.v_string);
3431 		    if (copy || tv->v_type != VAR_STRING)
3432 		    {
3433 			char_u *val = tv_get_string(tv);
3434 
3435 			// Careful: when assigning to v:errmsg and
3436 			// tv_get_string() causes an error message the variable
3437 			// will already be set.
3438 			if (di->di_tv.vval.v_string == NULL)
3439 			    di->di_tv.vval.v_string = vim_strsave(val);
3440 		    }
3441 		    else
3442 		    {
3443 			// Take over the string to avoid an extra alloc/free.
3444 			di->di_tv.vval.v_string = tv->vval.v_string;
3445 			tv->vval.v_string = NULL;
3446 		    }
3447 		    goto failed;
3448 		}
3449 		else if (di->di_tv.v_type == VAR_NUMBER)
3450 		{
3451 		    di->di_tv.vval.v_number = tv_get_number(tv);
3452 		    if (STRCMP(varname, "searchforward") == 0)
3453 			set_search_direction(di->di_tv.vval.v_number
3454 								  ? '/' : '?');
3455 #ifdef FEAT_SEARCH_EXTRA
3456 		    else if (STRCMP(varname, "hlsearch") == 0)
3457 		    {
3458 			no_hlsearch = !di->di_tv.vval.v_number;
3459 			redraw_all_later(SOME_VALID);
3460 		    }
3461 #endif
3462 		    goto failed;
3463 		}
3464 		else if (di->di_tv.v_type != tv->v_type)
3465 		{
3466 		    semsg(_("E963: setting %s to value with wrong type"), name);
3467 		    goto failed;
3468 		}
3469 	    }
3470 
3471 	    clear_tv(&di->di_tv);
3472 	}
3473 	else
3474 	{
3475 	    // Item not found, check if a function already exists.
3476 	    if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
3477 		   && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
3478 	    {
3479 		semsg(_(e_redefining_script_item_str), name);
3480 		goto failed;
3481 	    }
3482 
3483 	    // add a new variable
3484 	    if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
3485 	    {
3486 		semsg(_(e_unknown_variable_str), name);
3487 		goto failed;
3488 	    }
3489 
3490 	    // Can't add "v:" or "a:" variable.
3491 	    if (ht == &vimvarht || ht == get_funccal_args_ht())
3492 	    {
3493 		semsg(_(e_illvar), name);
3494 		goto failed;
3495 	    }
3496 
3497 	    // Make sure the variable name is valid.  In Vim9 script an autoload
3498 	    // variable must be prefixed with "g:".
3499 	    if (!valid_varname(varname, -1, !vim9script
3500 					       || STRNCMP(name, "g:", 2) == 0))
3501 		goto failed;
3502 
3503 	    di = alloc(sizeof(dictitem_T) + STRLEN(varname));
3504 	    if (di == NULL)
3505 		goto failed;
3506 	    STRCPY(di->di_key, varname);
3507 	    if (hash_add(ht, DI2HIKEY(di)) == FAIL)
3508 	    {
3509 		vim_free(di);
3510 		goto failed;
3511 	    }
3512 	    di->di_flags = DI_FLAGS_ALLOC;
3513 	    if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
3514 		di->di_flags |= DI_FLAGS_LOCK;
3515 
3516 	    // A Vim9 script-local variable is also added to sn_all_vars and
3517 	    // sn_var_vals. It may set "type" from "tv".
3518 	    if (var_in_vim9script)
3519 		update_vim9_script_var(TRUE, di, flags, tv, &type,
3520 					 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3521 	}
3522 
3523 	dest_tv = &di->di_tv;
3524     }
3525 
3526     if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
3527 	copy_tv(tv, dest_tv);
3528     else
3529     {
3530 	*dest_tv = *tv;
3531 	dest_tv->v_lock = 0;
3532 	init_tv(tv);
3533     }
3534 
3535     if (vim9script && type != NULL)
3536     {
3537 	if (type->tt_type == VAR_DICT && dest_tv->vval.v_dict != NULL)
3538 	{
3539 	    if (dest_tv->vval.v_dict->dv_type != type)
3540 	    {
3541 		free_type(dest_tv->vval.v_dict->dv_type);
3542 		dest_tv->vval.v_dict->dv_type = alloc_type(type);
3543 	    }
3544 	}
3545 	else if (type->tt_type == VAR_LIST && dest_tv->vval.v_list != NULL)
3546 	{
3547 	    if (dest_tv->vval.v_list->lv_type != type)
3548 	    {
3549 		free_type(dest_tv->vval.v_list->lv_type);
3550 		dest_tv->vval.v_list->lv_type = alloc_type(type);
3551 	    }
3552 	}
3553     }
3554 
3555     // ":const var = value" locks the value
3556     // ":final var = value" locks "var"
3557     if (flags & ASSIGN_CONST)
3558 	// Like :lockvar! name: lock the value and what it contains, but only
3559 	// if the reference count is up to one.  That locks only literal
3560 	// values.
3561 	item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
3562     return;
3563 
3564 failed:
3565     if (!copy)
3566 	clear_tv(tv_arg);
3567 }
3568 
3569 /*
3570  * Check in this order for backwards compatibility:
3571  * - Whether the variable is read-only
3572  * - Whether the variable value is locked
3573  * - Whether the variable is locked
3574  */
3575     int
var_check_permission(dictitem_T * di,char_u * name)3576 var_check_permission(dictitem_T *di, char_u *name)
3577 {
3578     if (var_check_ro(di->di_flags, name, FALSE)
3579 		    || value_check_lock(di->di_tv.v_lock, name, FALSE)
3580 		    || var_check_lock(di->di_flags, name, FALSE))
3581 	return FAIL;
3582     return OK;
3583 }
3584 
3585 /*
3586  * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
3587  * Also give an error message.
3588  */
3589     int
var_check_ro(int flags,char_u * name,int use_gettext)3590 var_check_ro(int flags, char_u *name, int use_gettext)
3591 {
3592     if (flags & DI_FLAGS_RO)
3593     {
3594 	semsg(_(e_cannot_change_readonly_variable_str),
3595 				       use_gettext ? (char_u *)_(name) : name);
3596 	return TRUE;
3597     }
3598     if ((flags & DI_FLAGS_RO_SBX) && sandbox)
3599     {
3600 	semsg(_(e_readonlysbx), use_gettext ? (char_u *)_(name) : name);
3601 	return TRUE;
3602     }
3603     return FALSE;
3604 }
3605 
3606 /*
3607  * Return TRUE if di_flags "flags" indicates variable "name" is locked.
3608  * Also give an error message.
3609  */
3610     int
var_check_lock(int flags,char_u * name,int use_gettext)3611 var_check_lock(int flags, char_u *name, int use_gettext)
3612 {
3613     if (flags & DI_FLAGS_LOCK)
3614     {
3615 	semsg(_(e_variable_is_locked_str),
3616 				       use_gettext ? (char_u *)_(name) : name);
3617 	return TRUE;
3618     }
3619     return FALSE;
3620 }
3621 
3622 /*
3623  * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
3624  * Also give an error message.
3625  */
3626     int
var_check_fixed(int flags,char_u * name,int use_gettext)3627 var_check_fixed(int flags, char_u *name, int use_gettext)
3628 {
3629     if (flags & DI_FLAGS_FIX)
3630     {
3631 	semsg(_("E795: Cannot delete variable %s"),
3632 				      use_gettext ? (char_u *)_(name) : name);
3633 	return TRUE;
3634     }
3635     return FALSE;
3636 }
3637 
3638 /*
3639  * Check if a funcref is assigned to a valid variable name.
3640  * Return TRUE and give an error if not.
3641  */
3642     int
var_wrong_func_name(char_u * name,int new_var)3643 var_wrong_func_name(
3644     char_u *name,    // points to start of variable name
3645     int    new_var)  // TRUE when creating the variable
3646 {
3647     // Allow for w: b: s: and t:.  In Vim9 script s: is not allowed, because
3648     // the name can be used without the s: prefix.
3649     if (!((vim_strchr((char_u *)"wbt", name[0]) != NULL
3650 		    || (!in_vim9script() && name[0] == 's')) && name[1] == ':')
3651 	    && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
3652 						     ? name[2] : name[0]))
3653     {
3654 	semsg(_("E704: Funcref variable name must start with a capital: %s"),
3655 									name);
3656 	return TRUE;
3657     }
3658     // Don't allow hiding a function.  When "v" is not NULL we might be
3659     // assigning another function to the same var, the type is checked
3660     // below.
3661     if (new_var && function_exists(name, FALSE))
3662     {
3663 	semsg(_("E705: Variable name conflicts with existing function: %s"),
3664 								    name);
3665 	return TRUE;
3666     }
3667     return FALSE;
3668 }
3669 
3670 /*
3671  * Return TRUE if "flags" indicates variable "name" has a locked (immutable)
3672  * value.  Also give an error message, using "name" or _("name") when
3673  * "use_gettext" is TRUE.
3674  */
3675     int
value_check_lock(int lock,char_u * name,int use_gettext)3676 value_check_lock(int lock, char_u *name, int use_gettext)
3677 {
3678     if (lock & VAR_LOCKED)
3679     {
3680 	semsg(_("E741: Value is locked: %s"),
3681 				name == NULL ? (char_u *)_("Unknown")
3682 					     : use_gettext ? (char_u *)_(name)
3683 					     : name);
3684 	return TRUE;
3685     }
3686     if (lock & VAR_FIXED)
3687     {
3688 	semsg(_("E742: Cannot change value of %s"),
3689 				name == NULL ? (char_u *)_("Unknown")
3690 					     : use_gettext ? (char_u *)_(name)
3691 					     : name);
3692 	return TRUE;
3693     }
3694     return FALSE;
3695 }
3696 
3697 /*
3698  * Check if a variable name is valid.  When "autoload" is true "#" is allowed.
3699  * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
3700  * Return FALSE and give an error if not.
3701  */
3702     int
valid_varname(char_u * varname,int len,int autoload)3703 valid_varname(char_u *varname, int len, int autoload)
3704 {
3705     char_u *p;
3706 
3707     for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
3708 	if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
3709 					 && !(autoload && *p == AUTOLOAD_CHAR))
3710 	{
3711 	    semsg(_(e_illvar), varname);
3712 	    return FALSE;
3713 	}
3714     return TRUE;
3715 }
3716 
3717 /*
3718  * getwinvar() and gettabwinvar()
3719  */
3720     static void
getwinvar(typval_T * argvars,typval_T * rettv,int off)3721 getwinvar(
3722     typval_T	*argvars,
3723     typval_T	*rettv,
3724     int		off)	    // 1 for gettabwinvar()
3725 {
3726     win_T	*win;
3727     char_u	*varname;
3728     dictitem_T	*v;
3729     tabpage_T	*tp = NULL;
3730     int		done = FALSE;
3731     win_T	*oldcurwin;
3732     tabpage_T	*oldtabpage;
3733     int		need_switch_win;
3734 
3735     if (off == 1)
3736 	tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
3737     else
3738 	tp = curtab;
3739     win = find_win_by_nr(&argvars[off], tp);
3740     varname = tv_get_string_chk(&argvars[off + 1]);
3741     ++emsg_off;
3742 
3743     rettv->v_type = VAR_STRING;
3744     rettv->vval.v_string = NULL;
3745 
3746     if (win != NULL && varname != NULL)
3747     {
3748 	// Set curwin to be our win, temporarily.  Also set the tabpage,
3749 	// otherwise the window is not valid. Only do this when needed,
3750 	// autocommands get blocked.
3751 	need_switch_win = !(tp == curtab && win == curwin);
3752 	if (!need_switch_win
3753 		  || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK)
3754 	{
3755 	    if (*varname == '&')
3756 	    {
3757 		if (varname[1] == NUL)
3758 		{
3759 		    // get all window-local options in a dict
3760 		    dict_T	*opts = get_winbuf_options(FALSE);
3761 
3762 		    if (opts != NULL)
3763 		    {
3764 			rettv_dict_set(rettv, opts);
3765 			done = TRUE;
3766 		    }
3767 		}
3768 		else if (eval_option(&varname, rettv, 1) == OK)
3769 		    // window-local-option
3770 		    done = TRUE;
3771 	    }
3772 	    else
3773 	    {
3774 		// Look up the variable.
3775 		// Let getwinvar({nr}, "") return the "w:" dictionary.
3776 		v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
3777 							      varname, FALSE);
3778 		if (v != NULL)
3779 		{
3780 		    copy_tv(&v->di_tv, rettv);
3781 		    done = TRUE;
3782 		}
3783 	    }
3784 	}
3785 
3786 	if (need_switch_win)
3787 	    // restore previous notion of curwin
3788 	    restore_win(oldcurwin, oldtabpage, TRUE);
3789     }
3790 
3791     if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
3792 	// use the default return value
3793 	copy_tv(&argvars[off + 2], rettv);
3794 
3795     --emsg_off;
3796 }
3797 
3798 /*
3799  * Set option "varname" to the value of "varp" for the current buffer/window.
3800  */
3801     static void
set_option_from_tv(char_u * varname,typval_T * varp)3802 set_option_from_tv(char_u *varname, typval_T *varp)
3803 {
3804     long	numval = 0;
3805     char_u	*strval;
3806     char_u	nbuf[NUMBUFLEN];
3807     int		error = FALSE;
3808 
3809     if (varp->v_type == VAR_BOOL)
3810     {
3811 	numval = (long)varp->vval.v_number;
3812 	strval = (char_u *)"0";  // avoid using "false"
3813     }
3814     else
3815     {
3816 	if (!in_vim9script() || varp->v_type != VAR_STRING)
3817 	    numval = (long)tv_get_number_chk(varp, &error);
3818 	strval = tv_get_string_buf_chk(varp, nbuf);
3819     }
3820     if (!error && strval != NULL)
3821 	set_option_value(varname, numval, strval, OPT_LOCAL);
3822 }
3823 
3824 /*
3825  * "setwinvar()" and "settabwinvar()" functions
3826  */
3827     static void
setwinvar(typval_T * argvars,int off)3828 setwinvar(typval_T *argvars, int off)
3829 {
3830     win_T	*win;
3831     win_T	*save_curwin;
3832     tabpage_T	*save_curtab;
3833     int		need_switch_win;
3834     char_u	*varname, *winvarname;
3835     typval_T	*varp;
3836     tabpage_T	*tp = NULL;
3837 
3838     if (check_secure())
3839 	return;
3840 
3841     if (off == 1)
3842 	tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
3843     else
3844 	tp = curtab;
3845     win = find_win_by_nr(&argvars[off], tp);
3846     varname = tv_get_string_chk(&argvars[off + 1]);
3847     varp = &argvars[off + 2];
3848 
3849     if (win != NULL && varname != NULL && varp != NULL)
3850     {
3851 	need_switch_win = !(tp == curtab && win == curwin);
3852 	if (!need_switch_win
3853 	       || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK)
3854 	{
3855 	    if (*varname == '&')
3856 		set_option_from_tv(varname + 1, varp);
3857 	    else
3858 	    {
3859 		winvarname = alloc(STRLEN(varname) + 3);
3860 		if (winvarname != NULL)
3861 		{
3862 		    STRCPY(winvarname, "w:");
3863 		    STRCPY(winvarname + 2, varname);
3864 		    set_var(winvarname, varp, TRUE);
3865 		    vim_free(winvarname);
3866 		}
3867 	    }
3868 	}
3869 	if (need_switch_win)
3870 	    restore_win(save_curwin, save_curtab, TRUE);
3871     }
3872 }
3873 
3874 /*
3875  * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
3876  * v:option_type, and v:option_command.
3877  */
3878     void
reset_v_option_vars(void)3879 reset_v_option_vars(void)
3880 {
3881     set_vim_var_string(VV_OPTION_NEW,  NULL, -1);
3882     set_vim_var_string(VV_OPTION_OLD,  NULL, -1);
3883     set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
3884     set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
3885     set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
3886     set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
3887 }
3888 
3889 /*
3890  * Add an assert error to v:errors.
3891  */
3892     void
assert_error(garray_T * gap)3893 assert_error(garray_T *gap)
3894 {
3895     struct vimvar   *vp = &vimvars[VV_ERRORS];
3896 
3897     if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
3898 	// Make sure v:errors is a list.
3899 	set_vim_var_list(VV_ERRORS, list_alloc());
3900     list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
3901 }
3902 
3903     int
var_exists(char_u * var)3904 var_exists(char_u *var)
3905 {
3906     char_u	*arg = var;
3907     char_u	*name;
3908     char_u	*tofree;
3909     typval_T    tv;
3910     int		len = 0;
3911     int		n = FALSE;
3912 
3913     // get_name_len() takes care of expanding curly braces
3914     name = var;
3915     len = get_name_len(&arg, &tofree, TRUE, FALSE);
3916     if (len > 0)
3917     {
3918 	if (tofree != NULL)
3919 	    name = tofree;
3920 	n = (eval_variable(name, len, &tv, NULL,
3921 				 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
3922 	if (n)
3923 	{
3924 	    // handle d.key, l[idx], f(expr)
3925 	    arg = skipwhite(arg);
3926 	    n = (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, FALSE) == OK);
3927 	    if (n)
3928 		clear_tv(&tv);
3929 	}
3930     }
3931     if (*arg != NUL)
3932 	n = FALSE;
3933 
3934     vim_free(tofree);
3935     return n;
3936 }
3937 
3938 static lval_T	*redir_lval = NULL;
3939 #define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
3940 static garray_T redir_ga;	// only valid when redir_lval is not NULL
3941 static char_u	*redir_endp = NULL;
3942 static char_u	*redir_varname = NULL;
3943 
3944     int
alloc_redir_lval(void)3945 alloc_redir_lval(void)
3946 {
3947     redir_lval = ALLOC_CLEAR_ONE(lval_T);
3948     if (redir_lval == NULL)
3949 	return FAIL;
3950     return OK;
3951 }
3952 
3953     void
clear_redir_lval(void)3954 clear_redir_lval(void)
3955 {
3956     VIM_CLEAR(redir_lval);
3957 }
3958 
3959     void
init_redir_ga(void)3960 init_redir_ga(void)
3961 {
3962     ga_init2(&redir_ga, (int)sizeof(char), 500);
3963 }
3964 
3965 /*
3966  * Start recording command output to a variable
3967  * When "append" is TRUE append to an existing variable.
3968  * Returns OK if successfully completed the setup.  FAIL otherwise.
3969  */
3970     int
var_redir_start(char_u * name,int append)3971 var_redir_start(char_u *name, int append)
3972 {
3973     int		called_emsg_before;
3974     typval_T	tv;
3975 
3976     // Catch a bad name early.
3977     if (!eval_isnamec1(*name))
3978     {
3979 	emsg(_(e_invarg));
3980 	return FAIL;
3981     }
3982 
3983     // Make a copy of the name, it is used in redir_lval until redir ends.
3984     redir_varname = vim_strsave(name);
3985     if (redir_varname == NULL)
3986 	return FAIL;
3987 
3988     if (alloc_redir_lval() == FAIL)
3989     {
3990 	var_redir_stop();
3991 	return FAIL;
3992     }
3993 
3994     // The output is stored in growarray "redir_ga" until redirection ends.
3995     init_redir_ga();
3996 
3997     // Parse the variable name (can be a dict or list entry).
3998     redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
3999 							     FNE_CHECK_START);
4000     if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
4001     {
4002 	clear_lval(redir_lval);
4003 	if (redir_endp != NULL && *redir_endp != NUL)
4004 	    // Trailing characters are present after the variable name
4005 	    semsg(_(e_trailing_arg), redir_endp);
4006 	else
4007 	    semsg(_(e_invarg2), name);
4008 	redir_endp = NULL;  // don't store a value, only cleanup
4009 	var_redir_stop();
4010 	return FAIL;
4011     }
4012 
4013     // check if we can write to the variable: set it to or append an empty
4014     // string
4015     called_emsg_before = called_emsg;
4016     tv.v_type = VAR_STRING;
4017     tv.vval.v_string = (char_u *)"";
4018     if (append)
4019 	set_var_lval(redir_lval, redir_endp, &tv, TRUE,
4020 					     ASSIGN_NO_DECL, (char_u *)".", 0);
4021     else
4022 	set_var_lval(redir_lval, redir_endp, &tv, TRUE,
4023 					     ASSIGN_NO_DECL, (char_u *)"=", 0);
4024     clear_lval(redir_lval);
4025     if (called_emsg > called_emsg_before)
4026     {
4027 	redir_endp = NULL;  // don't store a value, only cleanup
4028 	var_redir_stop();
4029 	return FAIL;
4030     }
4031 
4032     return OK;
4033 }
4034 
4035 /*
4036  * Append "value[value_len]" to the variable set by var_redir_start().
4037  * The actual appending is postponed until redirection ends, because the value
4038  * appended may in fact be the string we write to, changing it may cause freed
4039  * memory to be used:
4040  *   :redir => foo
4041  *   :let foo
4042  *   :redir END
4043  */
4044     void
var_redir_str(char_u * value,int value_len)4045 var_redir_str(char_u *value, int value_len)
4046 {
4047     int		len;
4048 
4049     if (redir_lval == NULL)
4050 	return;
4051 
4052     if (value_len == -1)
4053 	len = (int)STRLEN(value);	// Append the entire string
4054     else
4055 	len = value_len;		// Append only "value_len" characters
4056 
4057     if (ga_grow(&redir_ga, len) == OK)
4058     {
4059 	mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
4060 	redir_ga.ga_len += len;
4061     }
4062     else
4063 	var_redir_stop();
4064 }
4065 
4066 /*
4067  * Stop redirecting command output to a variable.
4068  * Frees the allocated memory.
4069  */
4070     void
var_redir_stop(void)4071 var_redir_stop(void)
4072 {
4073     typval_T	tv;
4074 
4075     if (EVALCMD_BUSY)
4076     {
4077 	redir_lval = NULL;
4078 	return;
4079     }
4080 
4081     if (redir_lval != NULL)
4082     {
4083 	// If there was no error: assign the text to the variable.
4084 	if (redir_endp != NULL)
4085 	{
4086 	    ga_append(&redir_ga, NUL);  // Append the trailing NUL.
4087 	    tv.v_type = VAR_STRING;
4088 	    tv.vval.v_string = redir_ga.ga_data;
4089 	    // Call get_lval() again, if it's inside a Dict or List it may
4090 	    // have changed.
4091 	    redir_endp = get_lval(redir_varname, NULL, redir_lval,
4092 					FALSE, FALSE, 0, FNE_CHECK_START);
4093 	    if (redir_endp != NULL && redir_lval->ll_name != NULL)
4094 		set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
4095 							     (char_u *)".", 0);
4096 	    clear_lval(redir_lval);
4097 	}
4098 
4099 	// free the collected output
4100 	VIM_CLEAR(redir_ga.ga_data);
4101 
4102 	VIM_CLEAR(redir_lval);
4103     }
4104     VIM_CLEAR(redir_varname);
4105 }
4106 
4107 /*
4108  * Get the collected redirected text and clear redir_ga.
4109  */
4110     char_u *
get_clear_redir_ga(void)4111 get_clear_redir_ga(void)
4112 {
4113     char_u *res;
4114 
4115     ga_append(&redir_ga, NUL);  // Append the trailing NUL.
4116     res = redir_ga.ga_data;
4117     redir_ga.ga_data = NULL;
4118     return res;
4119 }
4120 
4121 /*
4122  * "gettabvar()" function
4123  */
4124     void
f_gettabvar(typval_T * argvars,typval_T * rettv)4125 f_gettabvar(typval_T *argvars, typval_T *rettv)
4126 {
4127     win_T	*oldcurwin;
4128     tabpage_T	*tp, *oldtabpage;
4129     dictitem_T	*v;
4130     char_u	*varname;
4131     int		done = FALSE;
4132 
4133     rettv->v_type = VAR_STRING;
4134     rettv->vval.v_string = NULL;
4135 
4136     if (in_vim9script()
4137 	    && (check_for_number_arg(argvars, 0) == FAIL
4138 		|| check_for_string_arg(argvars, 1) == FAIL))
4139 	return;
4140 
4141     varname = tv_get_string_chk(&argvars[1]);
4142     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4143     if (tp != NULL && varname != NULL)
4144     {
4145 	// Set tp to be our tabpage, temporarily.  Also set the window to the
4146 	// first window in the tabpage, otherwise the window is not valid.
4147 	if (switch_win(&oldcurwin, &oldtabpage,
4148 		tp == curtab || tp->tp_firstwin == NULL ? firstwin
4149 					    : tp->tp_firstwin, tp, TRUE) == OK)
4150 	{
4151 	    // look up the variable
4152 	    // Let gettabvar({nr}, "") return the "t:" dictionary.
4153 	    v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
4154 	    if (v != NULL)
4155 	    {
4156 		copy_tv(&v->di_tv, rettv);
4157 		done = TRUE;
4158 	    }
4159 	}
4160 
4161 	// restore previous notion of curwin
4162 	restore_win(oldcurwin, oldtabpage, TRUE);
4163     }
4164 
4165     if (!done && argvars[2].v_type != VAR_UNKNOWN)
4166 	copy_tv(&argvars[2], rettv);
4167 }
4168 
4169 /*
4170  * "gettabwinvar()" function
4171  */
4172     void
f_gettabwinvar(typval_T * argvars,typval_T * rettv)4173 f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4174 {
4175     if (in_vim9script()
4176 	    && (check_for_number_arg(argvars, 0) == FAIL
4177 		|| check_for_number_arg(argvars, 1) == FAIL
4178 		|| check_for_string_arg(argvars, 2) == FAIL))
4179 	return;
4180 
4181     getwinvar(argvars, rettv, 1);
4182 }
4183 
4184 /*
4185  * "getwinvar()" function
4186  */
4187     void
f_getwinvar(typval_T * argvars,typval_T * rettv)4188 f_getwinvar(typval_T *argvars, typval_T *rettv)
4189 {
4190     if (in_vim9script()
4191 	    && (check_for_number_arg(argvars, 0) == FAIL
4192 		|| check_for_string_arg(argvars, 1) == FAIL))
4193 	return;
4194 
4195     getwinvar(argvars, rettv, 0);
4196 }
4197 
4198 /*
4199  * "getbufvar()" function
4200  */
4201     void
f_getbufvar(typval_T * argvars,typval_T * rettv)4202 f_getbufvar(typval_T *argvars, typval_T *rettv)
4203 {
4204     buf_T	*buf;
4205     char_u	*varname;
4206     dictitem_T	*v;
4207     int		done = FALSE;
4208 
4209     if (in_vim9script()
4210 	    && (check_for_buffer_arg(argvars, 0) == FAIL
4211 		|| check_for_string_arg(argvars, 1) == FAIL))
4212 	return;
4213 
4214     varname = tv_get_string_chk(&argvars[1]);
4215     buf = tv_get_buf_from_arg(&argvars[0]);
4216 
4217     rettv->v_type = VAR_STRING;
4218     rettv->vval.v_string = NULL;
4219 
4220     if (buf != NULL && varname != NULL)
4221     {
4222 	if (*varname == '&')
4223 	{
4224 	    buf_T	*save_curbuf = curbuf;
4225 
4226 	    // set curbuf to be our buf, temporarily
4227 	    curbuf = buf;
4228 
4229 	    if (varname[1] == NUL)
4230 	    {
4231 		// get all buffer-local options in a dict
4232 		dict_T	*opts = get_winbuf_options(TRUE);
4233 
4234 		if (opts != NULL)
4235 		{
4236 		    rettv_dict_set(rettv, opts);
4237 		    done = TRUE;
4238 		}
4239 	    }
4240 	    else if (eval_option(&varname, rettv, TRUE) == OK)
4241 		// buffer-local-option
4242 		done = TRUE;
4243 
4244 	    // restore previous notion of curbuf
4245 	    curbuf = save_curbuf;
4246 	}
4247 	else
4248 	{
4249 	    // Look up the variable.
4250 	    if (*varname == NUL)
4251 		// Let getbufvar({nr}, "") return the "b:" dictionary.
4252 		v = &buf->b_bufvar;
4253 	    else
4254 		v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
4255 							       varname, FALSE);
4256 	    if (v != NULL)
4257 	    {
4258 		copy_tv(&v->di_tv, rettv);
4259 		done = TRUE;
4260 	    }
4261 	}
4262     }
4263 
4264     if (!done && argvars[2].v_type != VAR_UNKNOWN)
4265 	// use the default value
4266 	copy_tv(&argvars[2], rettv);
4267 }
4268 
4269 /*
4270  * "settabvar()" function
4271  */
4272     void
f_settabvar(typval_T * argvars,typval_T * rettv UNUSED)4273 f_settabvar(typval_T *argvars, typval_T *rettv UNUSED)
4274 {
4275     tabpage_T	*save_curtab;
4276     tabpage_T	*tp;
4277     char_u	*varname, *tabvarname;
4278     typval_T	*varp;
4279 
4280     if (check_secure())
4281 	return;
4282 
4283     if (in_vim9script()
4284 	    && (check_for_number_arg(argvars, 0) == FAIL
4285 		|| check_for_string_arg(argvars, 1) == FAIL))
4286 	return;
4287 
4288     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4289     varname = tv_get_string_chk(&argvars[1]);
4290     varp = &argvars[2];
4291 
4292     if (varname != NULL && varp != NULL && tp != NULL)
4293     {
4294 	save_curtab = curtab;
4295 	goto_tabpage_tp(tp, FALSE, FALSE);
4296 
4297 	tabvarname = alloc(STRLEN(varname) + 3);
4298 	if (tabvarname != NULL)
4299 	{
4300 	    STRCPY(tabvarname, "t:");
4301 	    STRCPY(tabvarname + 2, varname);
4302 	    set_var(tabvarname, varp, TRUE);
4303 	    vim_free(tabvarname);
4304 	}
4305 
4306 	// Restore current tabpage
4307 	if (valid_tabpage(save_curtab))
4308 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
4309     }
4310 }
4311 
4312 /*
4313  * "settabwinvar()" function
4314  */
4315     void
f_settabwinvar(typval_T * argvars,typval_T * rettv UNUSED)4316 f_settabwinvar(typval_T *argvars, typval_T *rettv UNUSED)
4317 {
4318     if (in_vim9script()
4319 	    && (check_for_number_arg(argvars, 0) == FAIL
4320 		|| check_for_number_arg(argvars, 1) == FAIL
4321 		|| check_for_string_arg(argvars, 2) == FAIL))
4322 	return;
4323 
4324     setwinvar(argvars, 1);
4325 }
4326 
4327 /*
4328  * "setwinvar()" function
4329  */
4330     void
f_setwinvar(typval_T * argvars,typval_T * rettv UNUSED)4331 f_setwinvar(typval_T *argvars, typval_T *rettv UNUSED)
4332 {
4333     if (in_vim9script()
4334 	    && (check_for_number_arg(argvars, 0) == FAIL
4335 		|| check_for_string_arg(argvars, 1) == FAIL))
4336 	return;
4337 
4338     setwinvar(argvars, 0);
4339 }
4340 
4341 /*
4342  * "setbufvar()" function
4343  */
4344     void
f_setbufvar(typval_T * argvars,typval_T * rettv UNUSED)4345 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
4346 {
4347     buf_T	*buf;
4348     char_u	*varname, *bufvarname;
4349     typval_T	*varp;
4350 
4351     if (check_secure())
4352 	return;
4353 
4354     if (in_vim9script()
4355 	    && (check_for_buffer_arg(argvars, 0) == FAIL
4356 		|| check_for_string_arg(argvars, 1) == FAIL))
4357 	return;
4358 
4359     varname = tv_get_string_chk(&argvars[1]);
4360     buf = tv_get_buf_from_arg(&argvars[0]);
4361     varp = &argvars[2];
4362 
4363     if (buf != NULL && varname != NULL && varp != NULL)
4364     {
4365 	if (*varname == '&')
4366 	{
4367 	    aco_save_T	aco;
4368 
4369 	    // set curbuf to be our buf, temporarily
4370 	    aucmd_prepbuf(&aco, buf);
4371 
4372 	    set_option_from_tv(varname + 1, varp);
4373 
4374 	    // reset notion of buffer
4375 	    aucmd_restbuf(&aco);
4376 	}
4377 	else
4378 	{
4379 	    bufvarname = alloc(STRLEN(varname) + 3);
4380 	    if (bufvarname != NULL)
4381 	    {
4382 		buf_T *save_curbuf = curbuf;
4383 
4384 		curbuf = buf;
4385 		STRCPY(bufvarname, "b:");
4386 		STRCPY(bufvarname + 2, varname);
4387 		set_var(bufvarname, varp, TRUE);
4388 		vim_free(bufvarname);
4389 		curbuf = save_curbuf;
4390 	    }
4391 	}
4392     }
4393 }
4394 
4395 /*
4396  * Get a callback from "arg".  It can be a Funcref or a function name.
4397  * When "arg" is zero return an empty string.
4398  * "cb_name" is not allocated.
4399  * "cb_name" is set to NULL for an invalid argument.
4400  */
4401     callback_T
get_callback(typval_T * arg)4402 get_callback(typval_T *arg)
4403 {
4404     callback_T  res;
4405     int		r = OK;
4406 
4407     res.cb_free_name = FALSE;
4408     if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
4409     {
4410 	res.cb_partial = arg->vval.v_partial;
4411 	++res.cb_partial->pt_refcount;
4412 	res.cb_name = partial_name(res.cb_partial);
4413     }
4414     else
4415     {
4416 	res.cb_partial = NULL;
4417 	if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
4418 					       && isdigit(*arg->vval.v_string))
4419 	    r = FAIL;
4420 	else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
4421 	{
4422 	    // Note that we don't make a copy of the string.
4423 	    res.cb_name = arg->vval.v_string;
4424 	    func_ref(res.cb_name);
4425 	}
4426 	else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
4427 	    res.cb_name = (char_u *)"";
4428 	else
4429 	    r = FAIL;
4430 
4431 	if (r == FAIL)
4432 	{
4433 	    emsg(_("E921: Invalid callback argument"));
4434 	    res.cb_name = NULL;
4435 	}
4436     }
4437     return res;
4438 }
4439 
4440 /*
4441  * Copy a callback into a typval_T.
4442  */
4443     void
put_callback(callback_T * cb,typval_T * tv)4444 put_callback(callback_T *cb, typval_T *tv)
4445 {
4446     if (cb->cb_partial != NULL)
4447     {
4448 	tv->v_type = VAR_PARTIAL;
4449 	tv->vval.v_partial = cb->cb_partial;
4450 	++tv->vval.v_partial->pt_refcount;
4451     }
4452     else
4453     {
4454 	tv->v_type = VAR_FUNC;
4455 	tv->vval.v_string = vim_strsave(cb->cb_name);
4456 	func_ref(cb->cb_name);
4457     }
4458 }
4459 
4460 /*
4461  * Make a copy of "src" into "dest", allocating the function name if needed,
4462  * without incrementing the refcount.
4463  */
4464     void
set_callback(callback_T * dest,callback_T * src)4465 set_callback(callback_T *dest, callback_T *src)
4466 {
4467     if (src->cb_partial == NULL)
4468     {
4469 	// just a function name, make a copy
4470 	dest->cb_name = vim_strsave(src->cb_name);
4471 	dest->cb_free_name = TRUE;
4472     }
4473     else
4474     {
4475 	// cb_name is a pointer into cb_partial
4476 	dest->cb_name = src->cb_name;
4477 	dest->cb_free_name = FALSE;
4478     }
4479     dest->cb_partial = src->cb_partial;
4480 }
4481 
4482 /*
4483  * Copy callback from "src" to "dest", incrementing the refcounts.
4484  */
4485     void
copy_callback(callback_T * dest,callback_T * src)4486 copy_callback(callback_T *dest, callback_T *src)
4487 {
4488     dest->cb_partial = src->cb_partial;
4489     if (dest->cb_partial != NULL)
4490     {
4491 	dest->cb_name = src->cb_name;
4492 	dest->cb_free_name = FALSE;
4493 	++dest->cb_partial->pt_refcount;
4494     }
4495     else
4496     {
4497 	dest->cb_name = vim_strsave(src->cb_name);
4498 	dest->cb_free_name = TRUE;
4499 	func_ref(src->cb_name);
4500     }
4501 }
4502 
4503 /*
4504  * Unref/free "callback" returned by get_callback() or set_callback().
4505  */
4506     void
free_callback(callback_T * callback)4507 free_callback(callback_T *callback)
4508 {
4509     if (callback->cb_partial != NULL)
4510     {
4511 	partial_unref(callback->cb_partial);
4512 	callback->cb_partial = NULL;
4513     }
4514     else if (callback->cb_name != NULL)
4515 	func_unref(callback->cb_name);
4516     if (callback->cb_free_name)
4517     {
4518 	vim_free(callback->cb_name);
4519 	callback->cb_free_name = FALSE;
4520     }
4521     callback->cb_name = NULL;
4522 }
4523 
4524 #endif // FEAT_EVAL
4525