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