blob: 196d4d42297a4ec790b0fb4489b72687f4a2af96 [file] [log] [blame]
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001/* 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
Bram Moolenaare5cdf152019-08-29 22:09:46 +020018static dictitem_T globvars_var; // variable used for g:
Bram Moolenaarda6c0332019-09-01 16:01:30 +020019static dict_T globvardict; // Dictionary with g: variables
20#define globvarht globvardict.dv_hashtab
Bram Moolenaare5cdf152019-08-29 22:09:46 +020021
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 */
26static 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
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010042typedef struct vimvar vimvar_T;
43
Bram Moolenaare5cdf152019-08-29 22:09:46 +020044static 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!)
Bram Moolenaard787e402021-12-24 21:36:12 +000048 type_T *vv_type; // type or NULL
Bram Moolenaare5cdf152019-08-29 22:09:46 +020049 char vv_flags; // VV_COMPAT, VV_RO, VV_RO_SBX
50} vimvars[VV_LEN] =
51{
Bram Moolenaar8d71b542019-08-30 15:46:30 +020052 // The order here must match the VV_ defines in vim.h!
53 // Initializing a union does not work, leave tv.vval empty to get zero's.
Bram Moolenaard787e402021-12-24 21:36:12 +000054 {VV_NAME("count", VAR_NUMBER), NULL, VV_COMPAT+VV_RO},
55 {VV_NAME("count1", VAR_NUMBER), NULL, VV_RO},
56 {VV_NAME("prevcount", VAR_NUMBER), NULL, VV_RO},
57 {VV_NAME("errmsg", VAR_STRING), NULL, VV_COMPAT},
58 {VV_NAME("warningmsg", VAR_STRING), NULL, 0},
59 {VV_NAME("statusmsg", VAR_STRING), NULL, 0},
60 {VV_NAME("shell_error", VAR_NUMBER), NULL, VV_COMPAT+VV_RO},
61 {VV_NAME("this_session", VAR_STRING), NULL, VV_COMPAT},
62 {VV_NAME("version", VAR_NUMBER), NULL, VV_COMPAT+VV_RO},
63 {VV_NAME("lnum", VAR_NUMBER), NULL, VV_RO_SBX},
64 {VV_NAME("termresponse", VAR_STRING), NULL, VV_RO},
65 {VV_NAME("fname", VAR_STRING), NULL, VV_RO},
66 {VV_NAME("lang", VAR_STRING), NULL, VV_RO},
67 {VV_NAME("lc_time", VAR_STRING), NULL, VV_RO},
68 {VV_NAME("ctype", VAR_STRING), NULL, VV_RO},
69 {VV_NAME("charconvert_from", VAR_STRING), NULL, VV_RO},
70 {VV_NAME("charconvert_to", VAR_STRING), NULL, VV_RO},
71 {VV_NAME("fname_in", VAR_STRING), NULL, VV_RO},
72 {VV_NAME("fname_out", VAR_STRING), NULL, VV_RO},
73 {VV_NAME("fname_new", VAR_STRING), NULL, VV_RO},
74 {VV_NAME("fname_diff", VAR_STRING), NULL, VV_RO},
75 {VV_NAME("cmdarg", VAR_STRING), NULL, VV_RO},
76 {VV_NAME("foldstart", VAR_NUMBER), NULL, VV_RO_SBX},
77 {VV_NAME("foldend", VAR_NUMBER), NULL, VV_RO_SBX},
78 {VV_NAME("folddashes", VAR_STRING), NULL, VV_RO_SBX},
79 {VV_NAME("foldlevel", VAR_NUMBER), NULL, VV_RO_SBX},
80 {VV_NAME("progname", VAR_STRING), NULL, VV_RO},
81 {VV_NAME("servername", VAR_STRING), NULL, VV_RO},
82 {VV_NAME("dying", VAR_NUMBER), NULL, VV_RO},
83 {VV_NAME("exception", VAR_STRING), NULL, VV_RO},
84 {VV_NAME("throwpoint", VAR_STRING), NULL, VV_RO},
85 {VV_NAME("register", VAR_STRING), NULL, VV_RO},
86 {VV_NAME("cmdbang", VAR_NUMBER), NULL, VV_RO},
87 {VV_NAME("insertmode", VAR_STRING), NULL, VV_RO},
88 {VV_NAME("val", VAR_UNKNOWN), NULL, VV_RO},
89 {VV_NAME("key", VAR_UNKNOWN), NULL, VV_RO},
90 {VV_NAME("profiling", VAR_NUMBER), NULL, VV_RO},
91 {VV_NAME("fcs_reason", VAR_STRING), NULL, VV_RO},
92 {VV_NAME("fcs_choice", VAR_STRING), NULL, 0},
93 {VV_NAME("beval_bufnr", VAR_NUMBER), NULL, VV_RO},
94 {VV_NAME("beval_winnr", VAR_NUMBER), NULL, VV_RO},
95 {VV_NAME("beval_winid", VAR_NUMBER), NULL, VV_RO},
96 {VV_NAME("beval_lnum", VAR_NUMBER), NULL, VV_RO},
97 {VV_NAME("beval_col", VAR_NUMBER), NULL, VV_RO},
98 {VV_NAME("beval_text", VAR_STRING), NULL, VV_RO},
99 {VV_NAME("scrollstart", VAR_STRING), NULL, 0},
100 {VV_NAME("swapname", VAR_STRING), NULL, VV_RO},
101 {VV_NAME("swapchoice", VAR_STRING), NULL, 0},
102 {VV_NAME("swapcommand", VAR_STRING), NULL, VV_RO},
103 {VV_NAME("char", VAR_STRING), NULL, 0},
104 {VV_NAME("mouse_win", VAR_NUMBER), NULL, 0},
105 {VV_NAME("mouse_winid", VAR_NUMBER), NULL, 0},
106 {VV_NAME("mouse_lnum", VAR_NUMBER), NULL, 0},
107 {VV_NAME("mouse_col", VAR_NUMBER), NULL, 0},
108 {VV_NAME("operator", VAR_STRING), NULL, VV_RO},
109 {VV_NAME("searchforward", VAR_NUMBER), NULL, 0},
110 {VV_NAME("hlsearch", VAR_NUMBER), NULL, 0},
111 {VV_NAME("oldfiles", VAR_LIST), &t_list_string, 0},
112 {VV_NAME("windowid", VAR_NUMBER), NULL, VV_RO},
113 {VV_NAME("progpath", VAR_STRING), NULL, VV_RO},
114 {VV_NAME("completed_item", VAR_DICT), &t_dict_string, VV_RO},
115 {VV_NAME("option_new", VAR_STRING), NULL, VV_RO},
116 {VV_NAME("option_old", VAR_STRING), NULL, VV_RO},
117 {VV_NAME("option_oldlocal", VAR_STRING), NULL, VV_RO},
118 {VV_NAME("option_oldglobal", VAR_STRING), NULL, VV_RO},
119 {VV_NAME("option_command", VAR_STRING), NULL, VV_RO},
120 {VV_NAME("option_type", VAR_STRING), NULL, VV_RO},
121 {VV_NAME("errors", VAR_LIST), &t_list_string, 0},
122 {VV_NAME("false", VAR_BOOL), NULL, VV_RO},
123 {VV_NAME("true", VAR_BOOL), NULL, VV_RO},
124 {VV_NAME("none", VAR_SPECIAL), NULL, VV_RO},
125 {VV_NAME("null", VAR_SPECIAL), NULL, VV_RO},
126 {VV_NAME("numbermax", VAR_NUMBER), NULL, VV_RO},
127 {VV_NAME("numbermin", VAR_NUMBER), NULL, VV_RO},
128 {VV_NAME("numbersize", VAR_NUMBER), NULL, VV_RO},
129 {VV_NAME("vim_did_enter", VAR_NUMBER), NULL, VV_RO},
130 {VV_NAME("testing", VAR_NUMBER), NULL, 0},
131 {VV_NAME("t_number", VAR_NUMBER), NULL, VV_RO},
132 {VV_NAME("t_string", VAR_NUMBER), NULL, VV_RO},
133 {VV_NAME("t_func", VAR_NUMBER), NULL, VV_RO},
134 {VV_NAME("t_list", VAR_NUMBER), NULL, VV_RO},
135 {VV_NAME("t_dict", VAR_NUMBER), NULL, VV_RO},
136 {VV_NAME("t_float", VAR_NUMBER), NULL, VV_RO},
137 {VV_NAME("t_bool", VAR_NUMBER), NULL, VV_RO},
138 {VV_NAME("t_none", VAR_NUMBER), NULL, VV_RO},
139 {VV_NAME("t_job", VAR_NUMBER), NULL, VV_RO},
140 {VV_NAME("t_channel", VAR_NUMBER), NULL, VV_RO},
141 {VV_NAME("t_blob", VAR_NUMBER), NULL, VV_RO},
142 {VV_NAME("termrfgresp", VAR_STRING), NULL, VV_RO},
143 {VV_NAME("termrbgresp", VAR_STRING), NULL, VV_RO},
144 {VV_NAME("termu7resp", VAR_STRING), NULL, VV_RO},
145 {VV_NAME("termstyleresp", VAR_STRING), NULL, VV_RO},
146 {VV_NAME("termblinkresp", VAR_STRING), NULL, VV_RO},
147 {VV_NAME("event", VAR_DICT), NULL, VV_RO},
148 {VV_NAME("versionlong", VAR_NUMBER), NULL, VV_RO},
149 {VV_NAME("echospace", VAR_NUMBER), NULL, VV_RO},
150 {VV_NAME("argv", VAR_LIST), &t_list_string, VV_RO},
151 {VV_NAME("collate", VAR_STRING), NULL, VV_RO},
152 {VV_NAME("exiting", VAR_SPECIAL), NULL, VV_RO},
153 {VV_NAME("colornames", VAR_DICT), &t_dict_string, VV_RO},
154 {VV_NAME("sizeofint", VAR_NUMBER), NULL, VV_RO},
155 {VV_NAME("sizeoflong", VAR_NUMBER), NULL, VV_RO},
156 {VV_NAME("sizeofpointer", VAR_NUMBER), NULL, VV_RO},
naohiro ono56200ee2022-01-01 14:59:44 +0000157 {VV_NAME("maxcol", VAR_NUMBER), NULL, VV_RO},
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200158};
159
160// shorthand
Bram Moolenaard787e402021-12-24 21:36:12 +0000161#define vv_tv_type vv_di.di_tv.v_type
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200162#define vv_nr vv_di.di_tv.vval.v_number
163#define vv_float vv_di.di_tv.vval.v_float
164#define vv_str vv_di.di_tv.vval.v_string
165#define vv_list vv_di.di_tv.vval.v_list
166#define vv_dict vv_di.di_tv.vval.v_dict
167#define vv_blob vv_di.di_tv.vval.v_blob
168#define vv_tv vv_di.di_tv
169
170static dictitem_T vimvars_var; // variable used for v:
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200171static dict_T vimvardict; // Dictionary with v: variables
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200172#define vimvarht vimvardict.dv_hashtab
173
174// for VIM_VERSION_ defines
175#include "version.h"
176
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200177static void list_glob_vars(int *first);
178static void list_buf_vars(int *first);
179static void list_win_vars(int *first);
180static void list_tab_vars(int *first);
181static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100182static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags, char_u *endchars, char_u *op, int var_idx);
Bram Moolenaard72c1bf2020-04-19 16:28:59 +0200183static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
184static int do_lock_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200185static void list_one_var(dictitem_T *v, char *prefix, int *first);
186static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
187
188/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200189 * Initialize global and vim special variables
190 */
191 void
192evalvars_init(void)
193{
194 int i;
195 struct vimvar *p;
196
197 init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
198 init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
199 vimvardict.dv_lock = VAR_FIXED;
200 hash_init(&compat_hashtab);
201
202 for (i = 0; i < VV_LEN; ++i)
203 {
204 p = &vimvars[i];
205 if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
206 {
207 iemsg("INTERNAL: name too long, increase size of dictitem16_T");
208 getout(1);
209 }
210 STRCPY(p->vv_di.di_key, p->vv_name);
211 if (p->vv_flags & VV_RO)
212 p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
213 else if (p->vv_flags & VV_RO_SBX)
214 p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
215 else
216 p->vv_di.di_flags = DI_FLAGS_FIX;
217
218 // add to v: scope dict, unless the value is not always available
Bram Moolenaard787e402021-12-24 21:36:12 +0000219 if (p->vv_tv_type != VAR_UNKNOWN)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200220 hash_add(&vimvarht, p->vv_di.di_key);
221 if (p->vv_flags & VV_COMPAT)
222 // add to compat scope dict
223 hash_add(&compat_hashtab, p->vv_di.di_key);
224 }
Bram Moolenaar016faaa2020-10-03 12:57:27 +0200225 set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
226 set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200227
228 set_vim_var_nr(VV_SEARCHFORWARD, 1L);
229 set_vim_var_nr(VV_HLSEARCH, 1L);
Bram Moolenaarf0068c52020-11-30 17:42:10 +0100230 set_vim_var_nr(VV_EXITING, VVAL_NULL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200231 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
232 set_vim_var_list(VV_ERRORS, list_alloc());
233 set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
234
235 set_vim_var_nr(VV_FALSE, VVAL_FALSE);
236 set_vim_var_nr(VV_TRUE, VVAL_TRUE);
237 set_vim_var_nr(VV_NONE, VVAL_NONE);
238 set_vim_var_nr(VV_NULL, VVAL_NULL);
Bram Moolenaar57d5a012021-01-21 21:42:31 +0100239 set_vim_var_nr(VV_NUMBERMAX, VARNUM_MAX);
240 set_vim_var_nr(VV_NUMBERMIN, VARNUM_MIN);
Bram Moolenaarf9706e92020-02-22 14:27:04 +0100241 set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
Bram Moolenaar69b30722021-11-02 21:39:49 +0000242 set_vim_var_nr(VV_SIZEOFINT, sizeof(int));
243 set_vim_var_nr(VV_SIZEOFLONG, sizeof(long));
244 set_vim_var_nr(VV_SIZEOFPOINTER, sizeof(char *));
naohiro ono56200ee2022-01-01 14:59:44 +0000245 set_vim_var_nr(VV_MAXCOL, MAXCOL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200246
247 set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
248 set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
249 set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
250 set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
251 set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
252 set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
253 set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
254 set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
255 set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
256 set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
257 set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
258
259 set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
260
Drew Vogele30d1022021-10-24 20:35:07 +0100261 set_vim_var_dict(VV_COLORNAMES, dict_alloc());
262
Bram Moolenaar439c0362020-06-06 15:58:03 +0200263 // Default for v:register is not 0 but '"'. This is adjusted once the
264 // clipboard has been setup by calling reset_reg_var().
265 set_reg_var(0);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200266}
267
268#if defined(EXITFREE) || defined(PROTO)
269/*
270 * Free all vim variables information on exit
271 */
272 void
273evalvars_clear(void)
274{
275 int i;
276 struct vimvar *p;
277
278 for (i = 0; i < VV_LEN; ++i)
279 {
280 p = &vimvars[i];
281 if (p->vv_di.di_tv.v_type == VAR_STRING)
282 VIM_CLEAR(p->vv_str);
283 else if (p->vv_di.di_tv.v_type == VAR_LIST)
284 {
285 list_unref(p->vv_list);
286 p->vv_list = NULL;
287 }
288 }
289 hash_clear(&vimvarht);
290 hash_init(&vimvarht); // garbage_collect() will access it
291 hash_clear(&compat_hashtab);
292
293 // global variables
294 vars_clear(&globvarht);
295
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100296 // Script-local variables. Clear all the variables here.
297 // The scriptvar_T is cleared later in free_scriptnames(), because a
298 // variable in one script might hold a reference to the whole scope of
299 // another script.
300 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200301 vars_clear(&SCRIPT_VARS(i));
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200302}
303#endif
304
305 int
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200306garbage_collect_globvars(int copyID)
307{
308 return set_ref_in_ht(&globvarht, copyID, NULL);
309}
310
311 int
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200312garbage_collect_vimvars(int copyID)
313{
314 return set_ref_in_ht(&vimvarht, copyID, NULL);
315}
316
317 int
318garbage_collect_scriptvars(int copyID)
319{
Bram Moolenaared234f22020-10-15 20:42:20 +0200320 int i;
321 int idx;
322 int abort = FALSE;
323 scriptitem_T *si;
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200324
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100325 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaared234f22020-10-15 20:42:20 +0200326 {
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200327 abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
328
Bram Moolenaared234f22020-10-15 20:42:20 +0200329 si = SCRIPT_ITEM(i);
330 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
331 {
332 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
333
Bram Moolenaard00a7fb2021-03-08 20:47:14 +0100334 if (sv->sv_name != NULL)
335 abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL);
Bram Moolenaared234f22020-10-15 20:42:20 +0200336 }
337 }
338
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200339 return abort;
340}
341
342/*
343 * Set an internal variable to a string value. Creates the variable if it does
344 * not already exist.
345 */
346 void
347set_internal_string_var(char_u *name, char_u *value)
348{
349 char_u *val;
350 typval_T *tvp;
351
352 val = vim_strsave(value);
353 if (val != NULL)
354 {
355 tvp = alloc_string_tv(val);
356 if (tvp != NULL)
357 {
358 set_var(name, tvp, FALSE);
359 free_tv(tvp);
360 }
361 }
362}
363
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200364 int
365eval_charconvert(
366 char_u *enc_from,
367 char_u *enc_to,
368 char_u *fname_from,
369 char_u *fname_to)
370{
371 int err = FALSE;
372
373 set_vim_var_string(VV_CC_FROM, enc_from, -1);
374 set_vim_var_string(VV_CC_TO, enc_to, -1);
375 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
376 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
377 if (eval_to_bool(p_ccv, &err, NULL, FALSE))
378 err = TRUE;
379 set_vim_var_string(VV_CC_FROM, NULL, -1);
380 set_vim_var_string(VV_CC_TO, NULL, -1);
381 set_vim_var_string(VV_FNAME_IN, NULL, -1);
382 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
383
384 if (err)
385 return FAIL;
386 return OK;
387}
388
389# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
390 int
391eval_printexpr(char_u *fname, char_u *args)
392{
393 int err = FALSE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000394 sctx_T saved_sctx = current_sctx;
395 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200396
397 set_vim_var_string(VV_FNAME_IN, fname, -1);
398 set_vim_var_string(VV_CMDARG, args, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000399 ctx = get_option_sctx("printexpr");
400 if (ctx != NULL)
401 current_sctx = *ctx;
402
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200403 if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
404 err = TRUE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000405
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200406 set_vim_var_string(VV_FNAME_IN, NULL, -1);
407 set_vim_var_string(VV_CMDARG, NULL, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000408 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200409
410 if (err)
411 {
412 mch_remove(fname);
413 return FAIL;
414 }
415 return OK;
416}
417# endif
418
419# if defined(FEAT_DIFF) || defined(PROTO)
420 void
421eval_diff(
422 char_u *origfile,
423 char_u *newfile,
424 char_u *outfile)
425{
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000426 sctx_T saved_sctx = current_sctx;
427 sctx_T *ctx;
428 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200429
430 set_vim_var_string(VV_FNAME_IN, origfile, -1);
431 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
432 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000433
434 ctx = get_option_sctx("diffexpr");
435 if (ctx != NULL)
436 current_sctx = *ctx;
437
438 // errors are ignored
439 tv = eval_expr(p_dex, NULL);
Bram Moolenaar39b89442022-01-22 18:21:36 +0000440 free_tv(tv);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000441
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200442 set_vim_var_string(VV_FNAME_IN, NULL, -1);
443 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
444 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000445 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200446}
447
448 void
449eval_patch(
450 char_u *origfile,
451 char_u *difffile,
452 char_u *outfile)
453{
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000454 sctx_T saved_sctx = current_sctx;
455 sctx_T *ctx;
456 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200457
458 set_vim_var_string(VV_FNAME_IN, origfile, -1);
459 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
460 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000461
462 ctx = get_option_sctx("patchexpr");
463 if (ctx != NULL)
464 current_sctx = *ctx;
465
466 // errors are ignored
467 tv = eval_expr(p_pex, NULL);
468 free_tv(tv);
469
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200470 set_vim_var_string(VV_FNAME_IN, NULL, -1);
471 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
472 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000473 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200474}
475# endif
476
477#if defined(FEAT_SPELL) || defined(PROTO)
478/*
479 * Evaluate an expression to a list with suggestions.
480 * For the "expr:" part of 'spellsuggest'.
481 * Returns NULL when there is an error.
482 */
483 list_T *
484eval_spell_expr(char_u *badword, char_u *expr)
485{
486 typval_T save_val;
487 typval_T rettv;
488 list_T *list = NULL;
489 char_u *p = skipwhite(expr);
490
491 // Set "v:val" to the bad word.
492 prepare_vimvar(VV_VAL, &save_val);
493 set_vim_var_string(VV_VAL, badword, -1);
494 if (p_verbose == 0)
495 ++emsg_off;
496
Bram Moolenaar5409f5d2020-06-24 18:37:35 +0200497 if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK)
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200498 {
499 if (rettv.v_type != VAR_LIST)
500 clear_tv(&rettv);
501 else
502 list = rettv.vval.v_list;
503 }
504
505 if (p_verbose == 0)
506 --emsg_off;
507 clear_tv(get_vim_var_tv(VV_VAL));
508 restore_vimvar(VV_VAL, &save_val);
509
510 return list;
511}
512
513/*
514 * "list" is supposed to contain two items: a word and a number. Return the
515 * word in "pp" and the number as the return value.
516 * Return -1 if anything isn't right.
517 * Used to get the good word and score from the eval_spell_expr() result.
518 */
519 int
520get_spellword(list_T *list, char_u **pp)
521{
522 listitem_T *li;
523
524 li = list->lv_first;
525 if (li == NULL)
526 return -1;
527 *pp = tv_get_string(&li->li_tv);
528
529 li = li->li_next;
530 if (li == NULL)
531 return -1;
532 return (int)tv_get_number(&li->li_tv);
533}
534#endif
535
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200536/*
537 * Prepare v: variable "idx" to be used.
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200538 * Save the current typeval in "save_tv" and clear it.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200539 * When not used yet add the variable to the v: hashtable.
540 */
541 void
542prepare_vimvar(int idx, typval_T *save_tv)
543{
544 *save_tv = vimvars[idx].vv_tv;
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200545 vimvars[idx].vv_str = NULL; // don't free it now
Bram Moolenaard787e402021-12-24 21:36:12 +0000546 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200547 hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
548}
549
550/*
551 * Restore v: variable "idx" to typeval "save_tv".
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200552 * Note that the v: variable must have been cleared already.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200553 * When no longer defined, remove the variable from the v: hashtable.
554 */
555 void
556restore_vimvar(int idx, typval_T *save_tv)
557{
558 hashitem_T *hi;
559
560 vimvars[idx].vv_tv = *save_tv;
Bram Moolenaard787e402021-12-24 21:36:12 +0000561 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200562 {
563 hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
564 if (HASHITEM_EMPTY(hi))
565 internal_error("restore_vimvar()");
566 else
567 hash_remove(&vimvarht, hi);
568 }
569}
570
571/*
572 * List Vim variables.
573 */
574 static void
575list_vim_vars(int *first)
576{
577 list_hashtable_vars(&vimvarht, "v:", FALSE, first);
578}
579
580/*
581 * List script-local variables, if there is a script.
582 */
583 static void
584list_script_vars(int *first)
585{
Bram Moolenaare3d46852020-08-29 13:39:17 +0200586 if (SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200587 list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
588 "s:", FALSE, first);
589}
590
591/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200592 * Get a list of lines from a HERE document. The here document is a list of
593 * lines surrounded by a marker.
594 * cmd << {marker}
595 * {line1}
596 * {line2}
597 * ....
598 * {marker}
599 *
600 * The {marker} is a string. If the optional 'trim' word is supplied before the
601 * marker, then the leading indentation before the lines (matching the
602 * indentation in the 'cmd' line) is stripped.
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200603 *
604 * When getting lines for an embedded script (e.g. python, lua, perl, ruby,
605 * tcl, mzscheme), script_get is set to TRUE. In this case, if the marker is
606 * missing, then '.' is accepted as a marker.
607 *
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200608 * Returns a List with {lines} or NULL.
609 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100610 list_T *
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200611heredoc_get(exarg_T *eap, char_u *cmd, int script_get)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200612{
613 char_u *theline;
614 char_u *marker;
615 list_T *l;
616 char_u *p;
617 int marker_indent_len = 0;
618 int text_indent_len = 0;
619 char_u *text_indent = NULL;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200620 char_u dot[] = ".";
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200621 int comment_char = in_vim9script() ? '#' : '"';
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200622
623 if (eap->getline == NULL)
624 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000625 emsg(_(e_cannot_use_heredoc_here));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200626 return NULL;
627 }
628
629 // Check for the optional 'trim' word before the marker
630 cmd = skipwhite(cmd);
631 if (STRNCMP(cmd, "trim", 4) == 0 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
632 {
633 cmd = skipwhite(cmd + 4);
634
635 // Trim the indentation from all the lines in the here document.
636 // The amount of indentation trimmed is the same as the indentation of
637 // the first line after the :let command line. To find the end marker
638 // the indent of the :let command line is trimmed.
639 p = *eap->cmdlinep;
640 while (VIM_ISWHITE(*p))
641 {
642 p++;
643 marker_indent_len++;
644 }
645 text_indent_len = -1;
646 }
647
648 // The marker is the next word.
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200649 if (*cmd != NUL && *cmd != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200650 {
651 marker = skipwhite(cmd);
652 p = skiptowhite(marker);
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200653 if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200654 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000655 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200656 return NULL;
657 }
658 *p = NUL;
Bram Moolenaar6ab09532020-05-01 14:10:13 +0200659 if (!script_get && vim_islower(*marker))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200660 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000661 emsg(_(e_marker_cannot_start_with_lower_case_letter));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200662 return NULL;
663 }
664 }
665 else
666 {
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200667 // When getting lines for an embedded script, if the marker is missing,
668 // accept '.' as the marker.
669 if (script_get)
670 marker = dot;
671 else
672 {
Bram Moolenaar1a992222021-12-31 17:25:48 +0000673 emsg(_(e_missing_marker));
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200674 return NULL;
675 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200676 }
677
678 l = list_alloc();
679 if (l == NULL)
680 return NULL;
681
682 for (;;)
683 {
684 int mi = 0;
685 int ti = 0;
686
687 theline = eap->getline(NUL, eap->cookie, 0, FALSE);
688 if (theline == NULL)
689 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000690 semsg(_(e_missing_end_marker_str), marker);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200691 break;
692 }
693
694 // with "trim": skip the indent matching the :let line to find the
695 // marker
696 if (marker_indent_len > 0
697 && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0)
698 mi = marker_indent_len;
699 if (STRCMP(marker, theline + mi) == 0)
700 {
701 vim_free(theline);
702 break;
703 }
704
705 if (text_indent_len == -1 && *theline != NUL)
706 {
707 // set the text indent from the first line.
708 p = theline;
709 text_indent_len = 0;
710 while (VIM_ISWHITE(*p))
711 {
712 p++;
713 text_indent_len++;
714 }
715 text_indent = vim_strnsave(theline, text_indent_len);
716 }
717 // with "trim": skip the indent matching the first line
718 if (text_indent != NULL)
719 for (ti = 0; ti < text_indent_len; ++ti)
720 if (theline[ti] != text_indent[ti])
721 break;
722
723 if (list_append_string(l, theline + ti, -1) == FAIL)
724 break;
725 vim_free(theline);
726 }
727 vim_free(text_indent);
728
729 return l;
730}
731
732/*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200733 * Vim9 variable declaration:
734 * ":var name"
735 * ":var name: type"
736 * ":var name = expr"
737 * ":var name: type = expr"
738 * etc.
739 */
740 void
741ex_var(exarg_T *eap)
742{
743 if (!in_vim9script())
744 {
745 semsg(_(e_str_cannot_be_used_in_legacy_vim_script), ":var");
746 return;
747 }
748 ex_let(eap);
749}
750
751/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200752 * ":let" list all variable values
753 * ":let var1 var2" list variable values
754 * ":let var = expr" assignment command.
755 * ":let var += expr" assignment command.
756 * ":let var -= expr" assignment command.
757 * ":let var *= expr" assignment command.
758 * ":let var /= expr" assignment command.
759 * ":let var %= expr" assignment command.
760 * ":let var .= expr" assignment command.
761 * ":let var ..= expr" assignment command.
762 * ":let [var1, var2] = expr" unpack list.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100763 * ":let var =<< ..." heredoc
Bram Moolenaard672dde2020-02-26 13:43:51 +0100764 * ":let var: string" Vim9 declaration
Bram Moolenaar2eec3792020-05-25 20:33:55 +0200765 *
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200766 * ":final var = expr" assignment command.
767 * ":final [var1, var2] = expr" unpack list.
768 *
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200769 * ":const" list all variable values
770 * ":const var1 var2" list variable values
771 * ":const var = expr" assignment command.
772 * ":const [var1, var2] = expr" unpack list.
773 */
774 void
Bram Moolenaar2eec3792020-05-25 20:33:55 +0200775ex_let(exarg_T *eap)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200776{
777 char_u *arg = eap->arg;
778 char_u *expr = NULL;
779 typval_T rettv;
780 int i;
781 int var_count = 0;
782 int semicolon = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200783 char_u op[4];
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200784 char_u *argend;
785 int first = TRUE;
786 int concat;
Bram Moolenaar32e35112020-05-14 22:41:15 +0200787 int has_assign;
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100788 int flags = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200789 int vim9script = in_vim9script();
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200790
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200791 if (eap->cmdidx == CMD_final && !vim9script)
792 {
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100793 // In legacy Vim script ":final" is short for ":finally".
794 ex_finally(eap);
795 return;
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200796 }
Bram Moolenaarc58f5452020-10-21 20:58:52 +0200797 if (eap->cmdidx == CMD_let && vim9script)
Bram Moolenaarcfcd0112020-09-27 15:19:27 +0200798 {
799 emsg(_(e_cannot_use_let_in_vim9_script));
800 return;
801 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200802
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100803 if (eap->cmdidx == CMD_const)
804 flags |= ASSIGN_CONST;
805 else if (eap->cmdidx == CMD_final)
806 flags |= ASSIGN_FINAL;
807
808 // Vim9 assignment without ":let", ":const" or ":final"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100809 if (eap->arg == eap->cmd)
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200810 flags |= ASSIGN_NO_DECL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100811
Bram Moolenaar47a519a2020-06-14 23:05:10 +0200812 argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200813 if (argend == NULL)
814 return;
815 if (argend > arg && argend[-1] == '.') // for var.='str'
816 --argend;
817 expr = skipwhite(argend);
818 concat = expr[0] == '.'
Bram Moolenaardd9de502021-08-15 13:49:42 +0200819 && ((expr[1] == '=' && in_old_script(2))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200820 || (expr[1] == '.' && expr[2] == '='));
Bram Moolenaar32e35112020-05-14 22:41:15 +0200821 has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
822 && expr[1] == '=');
Bram Moolenaar822ba242020-05-24 23:00:18 +0200823 if (!has_assign && !concat)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200824 {
825 // ":let" without "=": list variables
826 if (*arg == '[')
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000827 emsg(_(e_invalid_argument));
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200828 else if (expr[0] == '.' && expr[1] == '=')
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000829 emsg(_(e_dot_equal_not_supported_with_script_version_two));
Bram Moolenaarfaac4102020-04-20 17:46:14 +0200830 else if (!ends_excmd2(eap->cmd, arg))
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200831 {
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200832 if (vim9script)
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200833 {
Bram Moolenaarccc25aa2021-03-26 21:27:52 +0100834 if (!ends_excmd2(eap->cmd, skipwhite(argend)))
Bram Moolenaar74409f62022-01-01 15:58:22 +0000835 semsg(_(e_trailing_characters_str), argend);
Bram Moolenaarccc25aa2021-03-26 21:27:52 +0100836 else
837 // Vim9 declaration ":var name: type"
838 arg = vim9_declare_scriptvar(eap, arg);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200839 }
840 else
841 {
842 // ":let var1 var2" - list values
843 arg = list_arg_vars(eap, arg, &first);
844 }
845 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200846 else if (!eap->skip)
847 {
848 // ":let"
849 list_glob_vars(&first);
850 list_buf_vars(&first);
851 list_win_vars(&first);
852 list_tab_vars(&first);
853 list_script_vars(&first);
854 list_func_vars(&first);
855 list_vim_vars(&first);
856 }
Bram Moolenaar63b91732021-08-05 20:40:03 +0200857 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200858 }
859 else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
860 {
861 list_T *l;
Bram Moolenaar81530e32021-07-28 21:25:49 +0200862 long cur_lnum = SOURCING_LNUM;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200863
864 // HERE document
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200865 l = heredoc_get(eap, expr + 3, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200866 if (l != NULL)
867 {
868 rettv_list_set(&rettv, l);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +0200869 if (!eap->skip)
870 {
Bram Moolenaar81530e32021-07-28 21:25:49 +0200871 // errors are for the assignment, not the end marker
872 SOURCING_LNUM = cur_lnum;
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +0200873 op[0] = '=';
874 op[1] = NUL;
875 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100876 flags, op);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +0200877 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200878 clear_tv(&rettv);
879 }
880 }
881 else
882 {
Bram Moolenaar5409f5d2020-06-24 18:37:35 +0200883 evalarg_T evalarg;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200884 int len = 1;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200885
Bram Moolenaarc1ec0422020-09-09 22:27:58 +0200886 CLEAR_FIELD(rettv);
Bram Moolenaar32e35112020-05-14 22:41:15 +0200887 i = FAIL;
888 if (has_assign || concat)
889 {
Bram Moolenaar9a562c12021-01-23 13:39:14 +0100890 int cur_lnum;
891
Bram Moolenaar32e35112020-05-14 22:41:15 +0200892 op[0] = '=';
893 op[1] = NUL;
894 if (*expr != '=')
895 {
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200896 if (vim9script && (flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar122616d2020-08-21 21:32:50 +0200897 {
898 // +=, /=, etc. require an existing variable
899 semsg(_(e_cannot_use_operator_on_new_variable), eap->arg);
900 i = FAIL;
901 }
902 else if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
Bram Moolenaar32e35112020-05-14 22:41:15 +0200903 {
904 op[0] = *expr; // +=, -=, *=, /=, %= or .=
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200905 ++len;
Bram Moolenaar32e35112020-05-14 22:41:15 +0200906 if (expr[0] == '.' && expr[1] == '.') // ..=
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200907 {
Bram Moolenaar32e35112020-05-14 22:41:15 +0200908 ++expr;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200909 ++len;
910 }
Bram Moolenaar32e35112020-05-14 22:41:15 +0200911 }
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200912 expr += 2;
Bram Moolenaar32e35112020-05-14 22:41:15 +0200913 }
914 else
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200915 ++expr;
916
Bram Moolenaar7f2c3412021-11-29 16:01:49 +0000917 if (vim9script && !eap->skip && (!VIM_ISWHITE(*argend)
Bram Moolenaarc7e44a72020-07-29 21:37:43 +0200918 || !IS_WHITE_OR_NUL(*expr)))
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200919 {
920 vim_strncpy(op, expr - len, len);
Bram Moolenaare7a73e02021-01-01 19:17:55 +0100921 semsg(_(e_white_space_required_before_and_after_str_at_str),
922 op, argend);
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200923 i = FAIL;
924 }
Bram Moolenaar32e35112020-05-14 22:41:15 +0200925
926 if (eap->skip)
927 ++emsg_skip;
Bram Moolenaar2eb6fc32021-07-25 14:13:53 +0200928 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
Bram Moolenaarc7e44a72020-07-29 21:37:43 +0200929 expr = skipwhite_and_linebreak(expr, &evalarg);
Bram Moolenaar9a562c12021-01-23 13:39:14 +0100930 cur_lnum = SOURCING_LNUM;
Bram Moolenaarb171fb12020-06-24 20:34:03 +0200931 i = eval0(expr, &rettv, eap, &evalarg);
Bram Moolenaar5409f5d2020-06-24 18:37:35 +0200932 if (eap->skip)
933 --emsg_skip;
Bram Moolenaarfaf86262020-06-27 23:07:36 +0200934 clear_evalarg(&evalarg, eap);
Bram Moolenaar9a562c12021-01-23 13:39:14 +0100935
936 // Restore the line number so that any type error is given for the
937 // declaration, not the expression.
938 SOURCING_LNUM = cur_lnum;
Bram Moolenaar32e35112020-05-14 22:41:15 +0200939 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200940 if (eap->skip)
941 {
942 if (i != FAIL)
943 clear_tv(&rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200944 }
Bram Moolenaar822ba242020-05-24 23:00:18 +0200945 else if (i != FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200946 {
947 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200948 flags, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200949 clear_tv(&rettv);
950 }
951 }
952}
953
954/*
Bram Moolenaar6c3843c2021-03-04 12:38:21 +0100955 * Assign the typeval "tv" to the variable or variables at "arg_start".
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200956 * Handles both "var" with any type and "[var, var; var]" with a list type.
957 * When "op" is not NULL it points to a string with characters that
958 * must appear after the variable(s). Use "+", "-" or "." for add, subtract
959 * or concatenate.
960 * Returns OK or FAIL;
961 */
962 int
963ex_let_vars(
964 char_u *arg_start,
965 typval_T *tv,
966 int copy, // copy values from "tv", don't move
967 int semicolon, // from skip_var_list()
968 int var_count, // from skip_var_list()
Bram Moolenaar3862ea32021-01-01 21:05:55 +0100969 int flags, // ASSIGN_FINAL, ASSIGN_CONST, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200970 char_u *op)
971{
972 char_u *arg = arg_start;
973 list_T *l;
974 int i;
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100975 int var_idx = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200976 listitem_T *item;
977 typval_T ltv;
978
979 if (*arg != '[')
980 {
981 // ":let var = expr" or ":for var in list"
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100982 if (ex_let_one(arg, tv, copy, flags, op, op, var_idx) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200983 return FAIL;
984 return OK;
985 }
986
987 // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
988 if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
989 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000990 emsg(_(e_list_required));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200991 return FAIL;
992 }
993
994 i = list_len(l);
995 if (semicolon == 0 && var_count < i)
996 {
Bram Moolenaara6f79292022-01-04 21:30:47 +0000997 emsg(_(e_less_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200998 return FAIL;
999 }
1000 if (var_count - semicolon > i)
1001 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00001002 emsg(_(e_more_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001003 return FAIL;
1004 }
1005
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02001006 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001007 item = l->lv_first;
1008 while (*arg != ']')
1009 {
1010 arg = skipwhite(arg + 1);
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001011 ++var_idx;
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001012 arg = ex_let_one(arg, &item->li_tv, TRUE,
1013 flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001014 item = item->li_next;
1015 if (arg == NULL)
1016 return FAIL;
1017
1018 arg = skipwhite(arg);
1019 if (*arg == ';')
1020 {
1021 // Put the rest of the list (may be empty) in the var after ';'.
1022 // Create a new list for this.
1023 l = list_alloc();
1024 if (l == NULL)
1025 return FAIL;
1026 while (item != NULL)
1027 {
1028 list_append_tv(l, &item->li_tv);
1029 item = item->li_next;
1030 }
1031
1032 ltv.v_type = VAR_LIST;
1033 ltv.v_lock = 0;
1034 ltv.vval.v_list = l;
1035 l->lv_refcount = 1;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001036 ++var_idx;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001037
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001038 arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
1039 flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001040 clear_tv(&ltv);
1041 if (arg == NULL)
1042 return FAIL;
1043 break;
1044 }
1045 else if (*arg != ',' && *arg != ']')
1046 {
1047 internal_error("ex_let_vars()");
1048 return FAIL;
1049 }
1050 }
1051
1052 return OK;
1053}
1054
1055/*
1056 * Skip over assignable variable "var" or list of variables "[var, var]".
1057 * Used for ":let varvar = expr" and ":for varvar in expr".
1058 * For "[var, var]" increment "*var_count" for each variable.
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001059 * for "[var, var; var]" set "semicolon" to 1.
1060 * If "silent" is TRUE do not give an "invalid argument" error message.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001061 * Return NULL for an error.
1062 */
1063 char_u *
1064skip_var_list(
1065 char_u *arg,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001066 int include_type,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001067 int *var_count,
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001068 int *semicolon,
1069 int silent)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001070{
1071 char_u *p, *s;
1072
1073 if (*arg == '[')
1074 {
1075 // "[var, var]": find the matching ']'.
1076 p = arg;
1077 for (;;)
1078 {
1079 p = skipwhite(p + 1); // skip whites after '[', ';' or ','
Bram Moolenaar036d0712021-01-17 20:23:38 +01001080 s = skip_var_one(p, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001081 if (s == p)
1082 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001083 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001084 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001085 return NULL;
1086 }
1087 ++*var_count;
1088
1089 p = skipwhite(s);
1090 if (*p == ']')
1091 break;
1092 else if (*p == ';')
1093 {
1094 if (*semicolon == 1)
1095 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00001096 emsg(_(e_double_semicolon_in_list_of_variables));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001097 return NULL;
1098 }
1099 *semicolon = 1;
1100 }
1101 else if (*p != ',')
1102 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001103 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001104 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001105 return NULL;
1106 }
1107 }
1108 return p + 1;
1109 }
1110 else
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001111 return skip_var_one(arg, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001112}
1113
1114/*
1115 * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
1116 * l[idx].
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001117 * In Vim9 script also skip over ": type" if "include_type" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001118 */
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001119 char_u *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001120skip_var_one(char_u *arg, int include_type)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001121{
Bram Moolenaar585587d2021-01-17 20:52:13 +01001122 char_u *end;
1123 int vim9 = in_vim9script();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001124
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001125 if (*arg == '@' && arg[1] != NUL)
1126 return arg + 2;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001127 end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001128 NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
Bram Moolenaar036d0712021-01-17 20:23:38 +01001129
1130 // "a: type" is declaring variable "a" with a type, not "a:".
1131 // Same for "s: type".
Bram Moolenaar585587d2021-01-17 20:52:13 +01001132 if (vim9 && end == arg + 2 && end[-1] == ':')
Bram Moolenaar036d0712021-01-17 20:23:38 +01001133 --end;
1134
Bram Moolenaar585587d2021-01-17 20:52:13 +01001135 if (include_type && vim9)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001136 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001137 if (*end == ':')
Bram Moolenaar4fc224c2020-07-26 17:56:25 +02001138 end = skip_type(skipwhite(end + 1), FALSE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001139 }
1140 return end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001141}
1142
1143/*
1144 * List variables for hashtab "ht" with prefix "prefix".
1145 * If "empty" is TRUE also list NULL strings as empty strings.
1146 */
1147 void
1148list_hashtable_vars(
1149 hashtab_T *ht,
1150 char *prefix,
1151 int empty,
1152 int *first)
1153{
1154 hashitem_T *hi;
1155 dictitem_T *di;
1156 int todo;
1157 char_u buf[IOSIZE];
1158
1159 todo = (int)ht->ht_used;
1160 for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
1161 {
1162 if (!HASHITEM_EMPTY(hi))
1163 {
1164 --todo;
1165 di = HI2DI(hi);
1166
1167 // apply :filter /pat/ to variable name
1168 vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
1169 vim_strcat((char_u *)buf, di->di_key, IOSIZE);
1170 if (message_filtered(buf))
1171 continue;
1172
1173 if (empty || di->di_tv.v_type != VAR_STRING
1174 || di->di_tv.vval.v_string != NULL)
1175 list_one_var(di, prefix, first);
1176 }
1177 }
1178}
1179
1180/*
1181 * List global variables.
1182 */
1183 static void
1184list_glob_vars(int *first)
1185{
1186 list_hashtable_vars(&globvarht, "", TRUE, first);
1187}
1188
1189/*
1190 * List buffer variables.
1191 */
1192 static void
1193list_buf_vars(int *first)
1194{
1195 list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
1196}
1197
1198/*
1199 * List window variables.
1200 */
1201 static void
1202list_win_vars(int *first)
1203{
1204 list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
1205}
1206
1207/*
1208 * List tab page variables.
1209 */
1210 static void
1211list_tab_vars(int *first)
1212{
1213 list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
1214}
1215
1216/*
1217 * List variables in "arg".
1218 */
1219 static char_u *
1220list_arg_vars(exarg_T *eap, char_u *arg, int *first)
1221{
1222 int error = FALSE;
1223 int len;
1224 char_u *name;
1225 char_u *name_start;
1226 char_u *arg_subsc;
1227 char_u *tofree;
1228 typval_T tv;
1229
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001230 while (!ends_excmd2(eap->cmd, arg) && !got_int)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001231 {
1232 if (error || eap->skip)
1233 {
1234 arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1235 if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
1236 {
1237 emsg_severe = TRUE;
Bram Moolenaar4830c212021-08-14 14:59:27 +02001238 if (!did_emsg)
Bram Moolenaar74409f62022-01-01 15:58:22 +00001239 semsg(_(e_trailing_characters_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001240 break;
1241 }
1242 }
1243 else
1244 {
1245 // get_name_len() takes care of expanding curly braces
1246 name_start = name = arg;
1247 len = get_name_len(&arg, &tofree, TRUE, TRUE);
1248 if (len <= 0)
1249 {
1250 // This is mainly to keep test 49 working: when expanding
1251 // curly braces fails overrule the exception error message.
1252 if (len < 0 && !aborting())
1253 {
1254 emsg_severe = TRUE;
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001255 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001256 break;
1257 }
1258 error = TRUE;
1259 }
1260 else
1261 {
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02001262 arg = skipwhite(arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001263 if (tofree != NULL)
1264 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00001265 if (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01001266 EVAL_VAR_VERBOSE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001267 error = TRUE;
1268 else
1269 {
1270 // handle d.key, l[idx], f(expr)
1271 arg_subsc = arg;
Bram Moolenaar32884ad2022-01-07 12:45:29 +00001272 if (handle_subscript(&arg, name_start, &tv,
1273 &EVALARG_EVALUATE, TRUE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001274 error = TRUE;
1275 else
1276 {
1277 if (arg == arg_subsc && len == 2 && name[1] == ':')
1278 {
1279 switch (*name)
1280 {
1281 case 'g': list_glob_vars(first); break;
1282 case 'b': list_buf_vars(first); break;
1283 case 'w': list_win_vars(first); break;
1284 case 't': list_tab_vars(first); break;
1285 case 'v': list_vim_vars(first); break;
1286 case 's': list_script_vars(first); break;
1287 case 'l': list_func_vars(first); break;
1288 default:
Bram Moolenaara6f79292022-01-04 21:30:47 +00001289 semsg(_(e_cant_list_variables_for_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001290 }
1291 }
1292 else
1293 {
1294 char_u numbuf[NUMBUFLEN];
1295 char_u *tf;
1296 int c;
1297 char_u *s;
1298
1299 s = echo_string(&tv, &tf, numbuf, 0);
1300 c = *arg;
1301 *arg = NUL;
1302 list_one_var_a("",
1303 arg == arg_subsc ? name : name_start,
1304 tv.v_type,
1305 s == NULL ? (char_u *)"" : s,
1306 first);
1307 *arg = c;
1308 vim_free(tf);
1309 }
1310 clear_tv(&tv);
1311 }
1312 }
1313 }
1314
1315 vim_free(tofree);
1316 }
1317
1318 arg = skipwhite(arg);
1319 }
1320
1321 return arg;
1322}
1323
1324/*
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001325 * Set an environment variable, part of ex_let_one().
1326 */
1327 static char_u *
1328ex_let_env(
1329 char_u *arg,
1330 typval_T *tv,
1331 int flags,
1332 char_u *endchars,
1333 char_u *op)
1334{
1335 char_u *arg_end = NULL;
1336 char_u *name;
1337 int len;
1338
1339 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1340 && (flags & ASSIGN_FOR_LOOP) == 0)
1341 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001342 emsg(_(e_cannot_lock_environment_variable));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001343 return NULL;
1344 }
1345
1346 // Find the end of the name.
1347 ++arg;
1348 name = arg;
1349 len = get_env_len(&arg);
1350 if (len == 0)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001351 semsg(_(e_invalid_argument_str), name - 1);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001352 else
1353 {
1354 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001355 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001356 else if (endchars != NULL
1357 && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1358 emsg(_(e_unexpected_characters_in_let));
1359 else if (!check_secure())
1360 {
1361 char_u *tofree = NULL;
1362 int c1 = name[len];
1363 char_u *p;
1364
1365 name[len] = NUL;
1366 p = tv_get_string_chk(tv);
1367 if (p != NULL && op != NULL && *op == '.')
1368 {
1369 int mustfree = FALSE;
1370 char_u *s = vim_getenv(name, &mustfree);
1371
1372 if (s != NULL)
1373 {
1374 p = tofree = concat_str(s, p);
1375 if (mustfree)
1376 vim_free(s);
1377 }
1378 }
1379 if (p != NULL)
1380 {
1381 vim_setenv_ext(name, p);
1382 arg_end = arg;
1383 }
1384 name[len] = c1;
1385 vim_free(tofree);
1386 }
1387 }
1388 return arg_end;
1389}
1390
1391/*
1392 * Set an option, part of ex_let_one().
1393 */
1394 static char_u *
1395ex_let_option(
1396 char_u *arg,
1397 typval_T *tv,
1398 int flags,
1399 char_u *endchars,
1400 char_u *op)
1401{
1402 char_u *p;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001403 int scope;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001404 char_u *arg_end = NULL;
1405
1406 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1407 && (flags & ASSIGN_FOR_LOOP) == 0)
1408 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001409 emsg(_(e_cannot_lock_option));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001410 return NULL;
1411 }
1412
1413 // Find the end of the name.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001414 p = find_option_end(&arg, &scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001415 if (p == NULL || (endchars != NULL
1416 && vim_strchr(endchars, *skipwhite(p)) == NULL))
1417 emsg(_(e_unexpected_characters_in_let));
1418 else
1419 {
1420 int c1;
1421 long n = 0;
1422 getoption_T opt_type;
1423 long numval;
1424 char_u *stringval = NULL;
1425 char_u *s = NULL;
1426 int failed = FALSE;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001427 int opt_p_flags;
1428 char_u *tofree = NULL;
Bram Moolenaar92c33eb2021-12-07 11:03:39 +00001429 char_u numbuf[NUMBUFLEN];
1430
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001431 c1 = *p;
1432 *p = NUL;
1433
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001434 opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags,
1435 scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001436 if ((opt_type == gov_bool
1437 || opt_type == gov_number
1438 || opt_type == gov_hidden_bool
1439 || opt_type == gov_hidden_number)
1440 && (tv->v_type != VAR_STRING || !in_vim9script()))
1441 {
1442 if (opt_type == gov_bool || opt_type == gov_hidden_bool)
1443 // bool, possibly hidden
1444 n = (long)tv_get_bool(tv);
1445 else
1446 // number, possibly hidden
1447 n = (long)tv_get_number(tv);
1448 }
1449
Bram Moolenaaref082e12021-12-12 21:02:03 +00001450 if ((opt_p_flags & P_FUNC) && (tv->v_type == VAR_PARTIAL
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001451 || tv->v_type == VAR_FUNC))
1452 {
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001453 // If the option can be set to a function reference or a lambda
1454 // and the passed value is a function reference, then convert it to
1455 // the name (string) of the function reference.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001456 s = tv2string(tv, &tofree, numbuf, 0);
1457 }
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001458 // Avoid setting a string option to the text "v:false" or similar.
1459 // In Vim9 script also don't convert a number to string.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001460 else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001461 && (!in_vim9script() || tv->v_type != VAR_NUMBER))
1462 s = tv_get_string_chk(tv);
1463
1464 if (op != NULL && *op != '=')
1465 {
1466 if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
1467 || (opt_type == gov_string && *op != '.'))
1468 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001469 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001470 failed = TRUE; // don't set the value
1471
1472 }
1473 else
1474 {
1475 // number, in legacy script also bool
1476 if (opt_type == gov_number
1477 || (opt_type == gov_bool && !in_vim9script()))
1478 {
1479 switch (*op)
1480 {
1481 case '+': n = numval + n; break;
1482 case '-': n = numval - n; break;
1483 case '*': n = numval * n; break;
1484 case '/': n = (long)num_divide(numval, n,
1485 &failed); break;
1486 case '%': n = (long)num_modulus(numval, n,
1487 &failed); break;
1488 }
1489 s = NULL;
1490 }
1491 else if (opt_type == gov_string
1492 && stringval != NULL && s != NULL)
1493 {
1494 // string
1495 s = concat_str(stringval, s);
1496 vim_free(stringval);
1497 stringval = s;
1498 }
1499 }
1500 }
1501
1502 if (!failed)
1503 {
1504 if (opt_type != gov_string || s != NULL)
1505 {
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001506 set_option_value(arg, n, s, scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001507 arg_end = p;
1508 }
1509 else
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001510 emsg(_(e_string_required));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001511 }
1512 *p = c1;
1513 vim_free(stringval);
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001514 vim_free(tofree);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001515 }
1516 return arg_end;
1517}
1518
1519/*
1520 * Set a register, part of ex_let_one().
1521 */
1522 static char_u *
1523ex_let_register(
1524 char_u *arg,
1525 typval_T *tv,
1526 int flags,
1527 char_u *endchars,
1528 char_u *op)
1529{
1530 char_u *arg_end = NULL;
1531
1532 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1533 && (flags & ASSIGN_FOR_LOOP) == 0)
1534 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001535 emsg(_(e_cannot_lock_register));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001536 return NULL;
1537 }
1538 ++arg;
1539 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001540 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001541 else if (endchars != NULL
1542 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1543 emsg(_(e_unexpected_characters_in_let));
1544 else
1545 {
1546 char_u *ptofree = NULL;
1547 char_u *p;
1548
1549 p = tv_get_string_chk(tv);
1550 if (p != NULL && op != NULL && *op == '.')
1551 {
1552 char_u *s = get_reg_contents(*arg == '@'
1553 ? '"' : *arg, GREG_EXPR_SRC);
1554
1555 if (s != NULL)
1556 {
1557 p = ptofree = concat_str(s, p);
1558 vim_free(s);
1559 }
1560 }
1561 if (p != NULL)
1562 {
1563 write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
1564 arg_end = arg + 1;
1565 }
1566 vim_free(ptofree);
1567 }
1568 return arg_end;
1569}
1570
1571/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001572 * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
1573 * Returns a pointer to the char just after the var name.
1574 * Returns NULL if there is an error.
1575 */
1576 static char_u *
1577ex_let_one(
1578 char_u *arg, // points to variable name
1579 typval_T *tv, // value to assign to variable
1580 int copy, // copy value from "tv"
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001581 int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001582 char_u *endchars, // valid chars after variable name or NULL
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001583 char_u *op, // "+", "-", "." or NULL
1584 int var_idx) // variable index for "let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001585{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001586 char_u *arg_end = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001587
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001588 if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001589 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaarc2ee44c2020-08-02 16:59:00 +02001590 && vim_strchr((char_u *)"$@&", *arg) != NULL)
1591 {
1592 vim9_declare_error(arg);
1593 return NULL;
1594 }
1595
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001596 if (*arg == '$')
1597 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001598 // ":let $VAR = expr": Set environment variable.
1599 return ex_let_env(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001600 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001601 else if (*arg == '&')
1602 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001603 // ":let &option = expr": Set option value.
1604 // ":let &l:option = expr": Set local option value.
1605 // ":let &g:option = expr": Set global option value.
1606 // ":for &ts in range(8)": Set option value for for loop
1607 return ex_let_option(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001608 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001609 else if (*arg == '@')
1610 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001611 // ":let @r = expr": Set register contents.
1612 return ex_let_register(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001613 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001614 else if (eval_isnamec1(*arg) || *arg == '{')
1615 {
1616 lval_T lv;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001617 char_u *p;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001618
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001619 // ":let var = expr": Set internal variable.
1620 // ":let var: type = expr": Set internal variable with type.
1621 // ":let {expr} = expr": Idem, name made with curly braces
Bram Moolenaar8f22f5c2020-12-19 22:10:13 +01001622 p = get_lval(arg, tv, &lv, FALSE, FALSE,
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001623 (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
1624 ? GLV_NO_DECL : 0, FNE_CHECK_START);
Bram Moolenaar822ba242020-05-24 23:00:18 +02001625 if (p != NULL && lv.ll_name != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001626 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001627 if (endchars != NULL && vim_strchr(endchars,
1628 *skipwhite(lv.ll_name_end)) == NULL)
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001629 {
Bram Moolenaar108010a2021-06-27 22:03:33 +02001630 emsg(_(e_unexpected_characters_in_let));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001631 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001632 else
1633 {
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001634 set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
Bram Moolenaara3589a02021-04-14 13:30:46 +02001635 arg_end = lv.ll_name_end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001636 }
1637 }
1638 clear_lval(&lv);
1639 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001640 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001641 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001642
1643 return arg_end;
1644}
1645
1646/*
1647 * ":unlet[!] var1 ... " command.
1648 */
1649 void
1650ex_unlet(exarg_T *eap)
1651{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001652 ex_unletlock(eap, eap->arg, 0, 0, do_unlet_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001653}
1654
1655/*
1656 * ":lockvar" and ":unlockvar" commands
1657 */
1658 void
1659ex_lockvar(exarg_T *eap)
1660{
1661 char_u *arg = eap->arg;
1662 int deep = 2;
1663
1664 if (eap->forceit)
1665 deep = -1;
1666 else if (vim_isdigit(*arg))
1667 {
1668 deep = getdigits(&arg);
1669 arg = skipwhite(arg);
1670 }
1671
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001672 ex_unletlock(eap, arg, deep, 0, do_lock_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001673}
1674
1675/*
1676 * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001677 * Also used for Vim9 script. "callback" is invoked as:
1678 * callback(&lv, name_end, eap, deep, cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001679 */
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001680 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001681ex_unletlock(
1682 exarg_T *eap,
1683 char_u *argstart,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001684 int deep,
1685 int glv_flags,
1686 int (*callback)(lval_T *, char_u *, exarg_T *, int, void *),
1687 void *cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001688{
1689 char_u *arg = argstart;
1690 char_u *name_end;
1691 int error = FALSE;
1692 lval_T lv;
1693
1694 do
1695 {
1696 if (*arg == '$')
1697 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001698 lv.ll_name = arg;
1699 lv.ll_tv = NULL;
1700 ++arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001701 if (get_env_len(&arg) == 0)
1702 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001703 semsg(_(e_invalid_argument_str), arg - 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001704 return;
1705 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001706 if (!error && !eap->skip
1707 && callback(&lv, arg, eap, deep, cookie) == FAIL)
1708 error = TRUE;
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001709 name_end = arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001710 }
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001711 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001712 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001713 // Parse the name and find the end.
1714 name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error,
Bram Moolenaarc3689572021-01-01 19:40:02 +01001715 glv_flags | GLV_NO_DECL, FNE_CHECK_START);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001716 if (lv.ll_name == NULL)
1717 error = TRUE; // error but continue parsing
1718 if (name_end == NULL || (!VIM_ISWHITE(*name_end)
1719 && !ends_excmd(*name_end)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001720 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001721 if (name_end != NULL)
1722 {
1723 emsg_severe = TRUE;
Bram Moolenaar74409f62022-01-01 15:58:22 +00001724 semsg(_(e_trailing_characters_str), name_end);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001725 }
1726 if (!(eap->skip || error))
1727 clear_lval(&lv);
1728 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001729 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001730
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001731 if (!error && !eap->skip
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001732 && callback(&lv, name_end, eap, deep, cookie) == FAIL)
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001733 error = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001734
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001735 if (!eap->skip)
1736 clear_lval(&lv);
1737 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001738
1739 arg = skipwhite(name_end);
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001740 } while (!ends_excmd2(name_end, arg));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001741
Bram Moolenaar63b91732021-08-05 20:40:03 +02001742 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001743}
1744
1745 static int
1746do_unlet_var(
1747 lval_T *lp,
1748 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001749 exarg_T *eap,
1750 int deep UNUSED,
1751 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001752{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001753 int forceit = eap->forceit;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001754 int ret = OK;
1755 int cc;
1756
1757 if (lp->ll_tv == NULL)
1758 {
1759 cc = *name_end;
1760 *name_end = NUL;
1761
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001762 // Environment variable, normal name or expanded name.
1763 if (*lp->ll_name == '$')
1764 vim_unsetenv(lp->ll_name + 1);
1765 else if (do_unlet(lp->ll_name, forceit) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001766 ret = FAIL;
1767 *name_end = cc;
1768 }
1769 else if ((lp->ll_list != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02001770 && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001771 || (lp->ll_dict != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02001772 && value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001773 return FAIL;
1774 else if (lp->ll_range)
1775 {
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001776 if (list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_name, lp->ll_n1,
1777 !lp->ll_empty2, lp->ll_n2) == FAIL)
1778 return FAIL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001779 }
1780 else
1781 {
1782 if (lp->ll_list != NULL)
1783 // unlet a List item.
1784 listitem_remove(lp->ll_list, lp->ll_li);
1785 else
1786 // unlet a Dictionary item.
1787 dictitem_remove(lp->ll_dict, lp->ll_di);
1788 }
1789
1790 return ret;
1791}
1792
1793/*
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001794 * Unlet one item or a range of items from a list.
1795 * Return OK or FAIL.
1796 */
1797 int
1798list_unlet_range(
1799 list_T *l,
1800 listitem_T *li_first,
1801 char_u *name,
1802 long n1_arg,
1803 int has_n2,
1804 long n2)
1805{
1806 listitem_T *li = li_first;
1807 int n1 = n1_arg;
1808
1809 while (li != NULL && (!has_n2 || n2 >= n1))
1810 {
1811 if (value_check_lock(li->li_tv.v_lock, name, FALSE))
1812 return FAIL;
1813 li = li->li_next;
1814 ++n1;
1815 }
1816
1817 // Delete a range of List items.
1818 li = li_first;
1819 n1 = n1_arg;
1820 while (li != NULL && (!has_n2 || n2 >= n1))
1821 {
1822 listitem_T *next = li->li_next;
1823
1824 listitem_remove(l, li);
1825 li = next;
1826 ++n1;
1827 }
1828 return OK;
1829}
1830/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001831 * "unlet" a variable. Return OK if it existed, FAIL if not.
1832 * When "forceit" is TRUE don't complain if the variable doesn't exist.
1833 */
1834 int
1835do_unlet(char_u *name, int forceit)
1836{
1837 hashtab_T *ht;
1838 hashitem_T *hi;
1839 char_u *varname;
1840 dict_T *d;
1841 dictitem_T *di;
1842
Bram Moolenaar9aed7292020-12-18 15:38:00 +01001843 // can't :unlet a script variable in Vim9 script
Bram Moolenaareb6880b2020-07-12 17:07:05 +02001844 if (in_vim9script() && check_vim9_unlet(name) == FAIL)
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001845 return FAIL;
1846
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001847 ht = find_var_ht(name, &varname);
Bram Moolenaar9aed7292020-12-18 15:38:00 +01001848
1849 // can't :unlet a script variable in Vim9 script from a function
1850 if (ht == get_script_local_ht()
1851 && SCRIPT_ID_VALID(current_sctx.sc_sid)
1852 && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
1853 == SCRIPT_VERSION_VIM9
1854 && check_vim9_unlet(name) == FAIL)
1855 return FAIL;
1856
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001857 if (ht != NULL && *varname != NUL)
1858 {
1859 d = get_current_funccal_dict(ht);
1860 if (d == NULL)
1861 {
1862 if (ht == &globvarht)
1863 d = &globvardict;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02001864 else if (ht == &compat_hashtab)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001865 d = &vimvardict;
1866 else
1867 {
1868 di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
1869 d = di == NULL ? NULL : di->di_tv.vval.v_dict;
1870 }
1871 if (d == NULL)
1872 {
1873 internal_error("do_unlet()");
1874 return FAIL;
1875 }
1876 }
1877 hi = hash_find(ht, varname);
1878 if (HASHITEM_EMPTY(hi))
1879 hi = find_hi_in_scoped_ht(name, &ht);
1880 if (hi != NULL && !HASHITEM_EMPTY(hi))
1881 {
1882 di = HI2DI(hi);
1883 if (var_check_fixed(di->di_flags, name, FALSE)
1884 || var_check_ro(di->di_flags, name, FALSE)
Bram Moolenaara187c432020-09-16 21:08:28 +02001885 || value_check_lock(d->dv_lock, name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001886 return FAIL;
1887
1888 delete_var(ht, hi);
1889 return OK;
1890 }
1891 }
1892 if (forceit)
1893 return OK;
Bram Moolenaare1242042021-12-16 20:56:57 +00001894 semsg(_(e_no_such_variable_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001895 return FAIL;
1896}
1897
1898/*
1899 * Lock or unlock variable indicated by "lp".
1900 * "deep" is the levels to go (-1 for unlimited);
1901 * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
1902 */
1903 static int
1904do_lock_var(
1905 lval_T *lp,
1906 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001907 exarg_T *eap,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001908 int deep,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001909 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001910{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001911 int lock = eap->cmdidx == CMD_lockvar;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001912 int ret = OK;
1913 int cc;
1914 dictitem_T *di;
1915
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001916 if (lp->ll_tv == NULL)
1917 {
1918 cc = *name_end;
1919 *name_end = NUL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001920 if (*lp->ll_name == '$')
1921 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00001922 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001923 ret = FAIL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001924 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001925 else
1926 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001927 // Normal name or expanded name.
1928 di = find_var(lp->ll_name, NULL, TRUE);
1929 if (di == NULL)
Bram Moolenaar04b568b2021-11-22 21:58:41 +00001930 {
1931 if (in_vim9script())
1932 semsg(_(e_cannot_find_variable_to_unlock_str),
1933 lp->ll_name);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001934 ret = FAIL;
Bram Moolenaar04b568b2021-11-22 21:58:41 +00001935 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001936 else if ((di->di_flags & DI_FLAGS_FIX)
1937 && di->di_tv.v_type != VAR_DICT
1938 && di->di_tv.v_type != VAR_LIST)
1939 {
1940 // For historic reasons this error is not given for a list or
1941 // dict. E.g., the b: dict could be locked/unlocked.
Bram Moolenaar3a846e62022-01-01 16:21:00 +00001942 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001943 ret = FAIL;
1944 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001945 else
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001946 {
1947 if (lock)
1948 di->di_flags |= DI_FLAGS_LOCK;
1949 else
1950 di->di_flags &= ~DI_FLAGS_LOCK;
Bram Moolenaara187c432020-09-16 21:08:28 +02001951 if (deep != 0)
1952 item_lock(&di->di_tv, deep, lock, FALSE);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001953 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001954 }
1955 *name_end = cc;
1956 }
Bram Moolenaara187c432020-09-16 21:08:28 +02001957 else if (deep == 0)
1958 {
1959 // nothing to do
1960 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001961 else if (lp->ll_range)
1962 {
1963 listitem_T *li = lp->ll_li;
1964
1965 // (un)lock a range of List items.
1966 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
1967 {
Bram Moolenaar021bda52020-08-17 21:07:22 +02001968 item_lock(&li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001969 li = li->li_next;
1970 ++lp->ll_n1;
1971 }
1972 }
1973 else if (lp->ll_list != NULL)
1974 // (un)lock a List item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02001975 item_lock(&lp->ll_li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001976 else
1977 // (un)lock a Dictionary item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02001978 item_lock(&lp->ll_di->di_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001979
1980 return ret;
1981}
1982
1983/*
1984 * Lock or unlock an item. "deep" is nr of levels to go.
Bram Moolenaar021bda52020-08-17 21:07:22 +02001985 * When "check_refcount" is TRUE do not lock a list or dict with a reference
1986 * count larger than 1.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001987 */
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02001988 void
Bram Moolenaar021bda52020-08-17 21:07:22 +02001989item_lock(typval_T *tv, int deep, int lock, int check_refcount)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001990{
1991 static int recurse = 0;
1992 list_T *l;
1993 listitem_T *li;
1994 dict_T *d;
1995 blob_T *b;
1996 hashitem_T *hi;
1997 int todo;
1998
1999 if (recurse >= DICT_MAXNEST)
2000 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002001 emsg(_(e_variable_nested_too_deep_for_unlock));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002002 return;
2003 }
2004 if (deep == 0)
2005 return;
2006 ++recurse;
2007
2008 // lock/unlock the item itself
2009 if (lock)
2010 tv->v_lock |= VAR_LOCKED;
2011 else
2012 tv->v_lock &= ~VAR_LOCKED;
2013
2014 switch (tv->v_type)
2015 {
2016 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002017 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002018 case VAR_VOID:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002019 case VAR_NUMBER:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002020 case VAR_BOOL:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002021 case VAR_STRING:
2022 case VAR_FUNC:
2023 case VAR_PARTIAL:
2024 case VAR_FLOAT:
2025 case VAR_SPECIAL:
2026 case VAR_JOB:
2027 case VAR_CHANNEL:
Bram Moolenaarf18332f2021-05-07 17:55:55 +02002028 case VAR_INSTR:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002029 break;
2030
2031 case VAR_BLOB:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002032 if ((b = tv->vval.v_blob) != NULL
2033 && !(check_refcount && b->bv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002034 {
2035 if (lock)
2036 b->bv_lock |= VAR_LOCKED;
2037 else
2038 b->bv_lock &= ~VAR_LOCKED;
2039 }
2040 break;
2041 case VAR_LIST:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002042 if ((l = tv->vval.v_list) != NULL
2043 && !(check_refcount && l->lv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002044 {
2045 if (lock)
2046 l->lv_lock |= VAR_LOCKED;
2047 else
2048 l->lv_lock &= ~VAR_LOCKED;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002049 if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002050 // recursive: lock/unlock the items the List contains
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002051 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar021bda52020-08-17 21:07:22 +02002052 item_lock(&li->li_tv, deep - 1, lock, check_refcount);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002053 }
2054 break;
2055 case VAR_DICT:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002056 if ((d = tv->vval.v_dict) != NULL
2057 && !(check_refcount && d->dv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002058 {
2059 if (lock)
2060 d->dv_lock |= VAR_LOCKED;
2061 else
2062 d->dv_lock &= ~VAR_LOCKED;
2063 if (deep < 0 || deep > 1)
2064 {
2065 // recursive: lock/unlock the items the List contains
2066 todo = (int)d->dv_hashtab.ht_used;
2067 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2068 {
2069 if (!HASHITEM_EMPTY(hi))
2070 {
2071 --todo;
Bram Moolenaar021bda52020-08-17 21:07:22 +02002072 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock,
2073 check_refcount);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002074 }
2075 }
2076 }
2077 }
2078 }
2079 --recurse;
2080}
2081
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002082#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
2083/*
2084 * Delete all "menutrans_" variables.
2085 */
2086 void
2087del_menutrans_vars(void)
2088{
2089 hashitem_T *hi;
2090 int todo;
2091
2092 hash_lock(&globvarht);
2093 todo = (int)globvarht.ht_used;
2094 for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
2095 {
2096 if (!HASHITEM_EMPTY(hi))
2097 {
2098 --todo;
2099 if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
2100 delete_var(&globvarht, hi);
2101 }
2102 }
2103 hash_unlock(&globvarht);
2104}
2105#endif
2106
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002107/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002108 * Local string buffer for the next two functions to store a variable name
2109 * with its prefix. Allocated in cat_prefix_varname(), freed later in
2110 * get_user_var_name().
2111 */
2112
2113static char_u *varnamebuf = NULL;
2114static int varnamebuflen = 0;
2115
2116/*
2117 * Function to concatenate a prefix and a variable name.
2118 */
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01002119 char_u *
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002120cat_prefix_varname(int prefix, char_u *name)
2121{
2122 int len;
2123
2124 len = (int)STRLEN(name) + 3;
2125 if (len > varnamebuflen)
2126 {
2127 vim_free(varnamebuf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002128 len += 10; // some additional space
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002129 varnamebuf = alloc(len);
2130 if (varnamebuf == NULL)
2131 {
2132 varnamebuflen = 0;
2133 return NULL;
2134 }
2135 varnamebuflen = len;
2136 }
2137 *varnamebuf = prefix;
2138 varnamebuf[1] = ':';
2139 STRCPY(varnamebuf + 2, name);
2140 return varnamebuf;
2141}
2142
2143/*
2144 * Function given to ExpandGeneric() to obtain the list of user defined
2145 * (global/buffer/window/built-in) variable names.
2146 */
2147 char_u *
2148get_user_var_name(expand_T *xp, int idx)
2149{
2150 static long_u gdone;
2151 static long_u bdone;
2152 static long_u wdone;
2153 static long_u tdone;
2154 static int vidx;
2155 static hashitem_T *hi;
2156 hashtab_T *ht;
2157
2158 if (idx == 0)
2159 {
2160 gdone = bdone = wdone = vidx = 0;
2161 tdone = 0;
2162 }
2163
2164 // Global variables
2165 if (gdone < globvarht.ht_used)
2166 {
2167 if (gdone++ == 0)
2168 hi = globvarht.ht_array;
2169 else
2170 ++hi;
2171 while (HASHITEM_EMPTY(hi))
2172 ++hi;
2173 if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
2174 return cat_prefix_varname('g', hi->hi_key);
2175 return hi->hi_key;
2176 }
2177
2178 // b: variables
Bram Moolenaar4ff2f2f2020-10-25 13:22:42 +01002179 ht =
2180#ifdef FEAT_CMDWIN
2181 // In cmdwin, the alternative buffer should be used.
mityua1198122021-11-20 19:13:39 +00002182 is_in_cmdwin() ? &prevwin->w_buffer->b_vars->dv_hashtab :
Bram Moolenaar4ff2f2f2020-10-25 13:22:42 +01002183#endif
2184 &curbuf->b_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002185 if (bdone < ht->ht_used)
2186 {
2187 if (bdone++ == 0)
2188 hi = ht->ht_array;
2189 else
2190 ++hi;
2191 while (HASHITEM_EMPTY(hi))
2192 ++hi;
2193 return cat_prefix_varname('b', hi->hi_key);
2194 }
2195
2196 // w: variables
Bram Moolenaar4ff2f2f2020-10-25 13:22:42 +01002197 ht =
2198#ifdef FEAT_CMDWIN
2199 // In cmdwin, the alternative window should be used.
mityua1198122021-11-20 19:13:39 +00002200 is_in_cmdwin() ? &prevwin->w_vars->dv_hashtab :
Bram Moolenaar4ff2f2f2020-10-25 13:22:42 +01002201#endif
2202 &curwin->w_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002203 if (wdone < ht->ht_used)
2204 {
2205 if (wdone++ == 0)
2206 hi = ht->ht_array;
2207 else
2208 ++hi;
2209 while (HASHITEM_EMPTY(hi))
2210 ++hi;
2211 return cat_prefix_varname('w', hi->hi_key);
2212 }
2213
2214 // t: variables
2215 ht = &curtab->tp_vars->dv_hashtab;
2216 if (tdone < ht->ht_used)
2217 {
2218 if (tdone++ == 0)
2219 hi = ht->ht_array;
2220 else
2221 ++hi;
2222 while (HASHITEM_EMPTY(hi))
2223 ++hi;
2224 return cat_prefix_varname('t', hi->hi_key);
2225 }
2226
2227 // v: variables
2228 if (vidx < VV_LEN)
2229 return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
2230
2231 VIM_CLEAR(varnamebuf);
2232 varnamebuflen = 0;
2233 return NULL;
2234}
2235
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002236 char *
2237get_var_special_name(int nr)
2238{
2239 switch (nr)
2240 {
Bram Moolenaara8b8af12021-01-01 15:11:04 +01002241 case VVAL_FALSE: return in_vim9script() ? "false" : "v:false";
2242 case VVAL_TRUE: return in_vim9script() ? "true" : "v:true";
Bram Moolenaar67977822021-01-03 21:53:53 +01002243 case VVAL_NULL: return in_vim9script() ? "null" : "v:null";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002244 case VVAL_NONE: return "v:none";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002245 }
2246 internal_error("get_var_special_name()");
2247 return "42";
2248}
2249
2250/*
2251 * Returns the global variable dictionary
2252 */
2253 dict_T *
2254get_globvar_dict(void)
2255{
2256 return &globvardict;
2257}
2258
2259/*
2260 * Returns the global variable hash table
2261 */
2262 hashtab_T *
2263get_globvar_ht(void)
2264{
2265 return &globvarht;
2266}
2267
2268/*
2269 * Returns the v: variable dictionary
2270 */
2271 dict_T *
2272get_vimvar_dict(void)
2273{
2274 return &vimvardict;
2275}
2276
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002277/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002278 * Returns the index of a v:variable. Negative if not found.
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002279 * Returns DI_ flags in "di_flags".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002280 */
2281 int
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002282find_vim_var(char_u *name, int *di_flags)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002283{
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002284 dictitem_T *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
2285 struct vimvar *vv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002286
2287 if (di == NULL)
2288 return -1;
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002289 *di_flags = di->di_flags;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002290 vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
2291 return (int)(vv - vimvars);
2292}
2293
2294
2295/*
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002296 * Set type of v: variable to "type".
2297 */
2298 void
2299set_vim_var_type(int idx, vartype_T type)
2300{
Bram Moolenaard787e402021-12-24 21:36:12 +00002301 vimvars[idx].vv_tv_type = type;
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002302}
2303
2304/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002305 * Set number v: variable to "val".
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002306 * Note that this does not set the type, use set_vim_var_type() for that.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002307 */
2308 void
2309set_vim_var_nr(int idx, varnumber_T val)
2310{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002311 vimvars[idx].vv_nr = val;
2312}
2313
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002314 char *
2315get_vim_var_name(int idx)
2316{
2317 return vimvars[idx].vv_name;
2318}
2319
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002320/*
2321 * Get typval_T v: variable value.
2322 */
2323 typval_T *
2324get_vim_var_tv(int idx)
2325{
2326 return &vimvars[idx].vv_tv;
2327}
2328
Bram Moolenaard787e402021-12-24 21:36:12 +00002329 type_T *
2330get_vim_var_type(int idx, garray_T *type_list)
2331{
2332 if (vimvars[idx].vv_type != NULL)
2333 return vimvars[idx].vv_type;
2334 return typval2type_vimvar(&vimvars[idx].vv_tv, type_list);
2335}
2336
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002337/*
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002338 * Set v: variable to "tv". Only accepts the same type.
2339 * Takes over the value of "tv".
2340 */
2341 int
2342set_vim_var_tv(int idx, typval_T *tv)
2343{
Bram Moolenaard787e402021-12-24 21:36:12 +00002344 if (vimvars[idx].vv_tv_type != tv->v_type)
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002345 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002346 emsg(_(e_type_mismatch_for_v_variable));
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002347 clear_tv(tv);
2348 return FAIL;
2349 }
Bram Moolenaarcab27672020-04-09 20:10:55 +02002350 // VV_RO is also checked when compiling, but let's check here as well.
2351 if (vimvars[idx].vv_flags & VV_RO)
2352 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02002353 semsg(_(e_cannot_change_readonly_variable_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002354 return FAIL;
2355 }
2356 if (sandbox && (vimvars[idx].vv_flags & VV_RO_SBX))
2357 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00002358 semsg(_(e_cannot_set_variable_in_sandbox_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002359 return FAIL;
2360 }
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002361 clear_tv(&vimvars[idx].vv_di.di_tv);
2362 vimvars[idx].vv_di.di_tv = *tv;
2363 return OK;
2364}
2365
2366/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002367 * Get number v: variable value.
2368 */
2369 varnumber_T
2370get_vim_var_nr(int idx)
2371{
2372 return vimvars[idx].vv_nr;
2373}
2374
2375/*
2376 * Get string v: variable value. Uses a static buffer, can only be used once.
2377 * If the String variable has never been set, return an empty string.
2378 * Never returns NULL;
2379 */
2380 char_u *
2381get_vim_var_str(int idx)
2382{
2383 return tv_get_string(&vimvars[idx].vv_tv);
2384}
2385
2386/*
2387 * Get List v: variable value. Caller must take care of reference count when
2388 * needed.
2389 */
2390 list_T *
2391get_vim_var_list(int idx)
2392{
2393 return vimvars[idx].vv_list;
2394}
2395
2396/*
2397 * Get Dict v: variable value. Caller must take care of reference count when
2398 * needed.
2399 */
2400 dict_T *
2401get_vim_var_dict(int idx)
2402{
2403 return vimvars[idx].vv_dict;
2404}
2405
2406/*
2407 * Set v:char to character "c".
2408 */
2409 void
2410set_vim_var_char(int c)
2411{
2412 char_u buf[MB_MAXBYTES + 1];
2413
2414 if (has_mbyte)
2415 buf[(*mb_char2bytes)(c, buf)] = NUL;
2416 else
2417 {
2418 buf[0] = c;
2419 buf[1] = NUL;
2420 }
2421 set_vim_var_string(VV_CHAR, buf, -1);
2422}
2423
2424/*
2425 * Set v:count to "count" and v:count1 to "count1".
2426 * When "set_prevcount" is TRUE first set v:prevcount from v:count.
2427 */
2428 void
2429set_vcount(
2430 long count,
2431 long count1,
2432 int set_prevcount)
2433{
2434 if (set_prevcount)
2435 vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
2436 vimvars[VV_COUNT].vv_nr = count;
2437 vimvars[VV_COUNT1].vv_nr = count1;
2438}
2439
2440/*
2441 * Save variables that might be changed as a side effect. Used when executing
2442 * a timer callback.
2443 */
2444 void
2445save_vimvars(vimvars_save_T *vvsave)
2446{
2447 vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
2448 vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
2449 vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
2450}
2451
2452/*
2453 * Restore variables saved by save_vimvars().
2454 */
2455 void
2456restore_vimvars(vimvars_save_T *vvsave)
2457{
2458 vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
2459 vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
2460 vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
2461}
2462
2463/*
2464 * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
2465 * value.
2466 */
2467 void
2468set_vim_var_string(
2469 int idx,
2470 char_u *val,
2471 int len) // length of "val" to use or -1 (whole string)
2472{
2473 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002474 vimvars[idx].vv_tv_type = VAR_STRING;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002475 if (val == NULL)
2476 vimvars[idx].vv_str = NULL;
2477 else if (len == -1)
2478 vimvars[idx].vv_str = vim_strsave(val);
2479 else
2480 vimvars[idx].vv_str = vim_strnsave(val, len);
2481}
2482
2483/*
2484 * Set List v: variable to "val".
2485 */
2486 void
2487set_vim_var_list(int idx, list_T *val)
2488{
2489 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002490 vimvars[idx].vv_tv_type = VAR_LIST;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002491 vimvars[idx].vv_list = val;
2492 if (val != NULL)
2493 ++val->lv_refcount;
2494}
2495
2496/*
2497 * Set Dictionary v: variable to "val".
2498 */
2499 void
2500set_vim_var_dict(int idx, dict_T *val)
2501{
2502 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002503 vimvars[idx].vv_tv_type = VAR_DICT;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002504 vimvars[idx].vv_dict = val;
2505 if (val != NULL)
2506 {
2507 ++val->dv_refcount;
2508 dict_set_items_ro(val);
2509 }
2510}
2511
2512/*
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002513 * Set the v:argv list.
2514 */
2515 void
2516set_argv_var(char **argv, int argc)
2517{
2518 list_T *l = list_alloc();
2519 int i;
2520
2521 if (l == NULL)
2522 getout(1);
2523 l->lv_lock = VAR_FIXED;
2524 for (i = 0; i < argc; ++i)
2525 {
2526 if (list_append_string(l, (char_u *)argv[i], -1) == FAIL)
2527 getout(1);
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01002528 l->lv_u.mat.lv_last->li_tv.v_lock = VAR_FIXED;
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002529 }
2530 set_vim_var_list(VV_ARGV, l);
2531}
2532
2533/*
Bram Moolenaar439c0362020-06-06 15:58:03 +02002534 * Reset v:register, taking the 'clipboard' setting into account.
2535 */
2536 void
2537reset_reg_var(void)
2538{
2539 int regname = 0;
2540
2541 // Adjust the register according to 'clipboard', so that when
2542 // "unnamed" is present it becomes '*' or '+' instead of '"'.
2543#ifdef FEAT_CLIPBOARD
2544 adjust_clip_reg(&regname);
2545#endif
2546 set_reg_var(regname);
2547}
2548
2549/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002550 * Set v:register if needed.
2551 */
2552 void
2553set_reg_var(int c)
2554{
2555 char_u regname;
2556
2557 if (c == 0 || c == ' ')
2558 regname = '"';
2559 else
2560 regname = c;
2561 // Avoid free/alloc when the value is already right.
2562 if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
2563 set_vim_var_string(VV_REG, &regname, 1);
2564}
2565
2566/*
2567 * Get or set v:exception. If "oldval" == NULL, return the current value.
2568 * Otherwise, restore the value to "oldval" and return NULL.
2569 * Must always be called in pairs to save and restore v:exception! Does not
2570 * take care of memory allocations.
2571 */
2572 char_u *
2573v_exception(char_u *oldval)
2574{
2575 if (oldval == NULL)
2576 return vimvars[VV_EXCEPTION].vv_str;
2577
2578 vimvars[VV_EXCEPTION].vv_str = oldval;
2579 return NULL;
2580}
2581
2582/*
2583 * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
2584 * Otherwise, restore the value to "oldval" and return NULL.
2585 * Must always be called in pairs to save and restore v:throwpoint! Does not
2586 * take care of memory allocations.
2587 */
2588 char_u *
2589v_throwpoint(char_u *oldval)
2590{
2591 if (oldval == NULL)
2592 return vimvars[VV_THROWPOINT].vv_str;
2593
2594 vimvars[VV_THROWPOINT].vv_str = oldval;
2595 return NULL;
2596}
2597
2598/*
2599 * Set v:cmdarg.
2600 * If "eap" != NULL, use "eap" to generate the value and return the old value.
2601 * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
2602 * Must always be called in pairs!
2603 */
2604 char_u *
2605set_cmdarg(exarg_T *eap, char_u *oldarg)
2606{
2607 char_u *oldval;
2608 char_u *newval;
2609 unsigned len;
2610
2611 oldval = vimvars[VV_CMDARG].vv_str;
2612 if (eap == NULL)
2613 {
2614 vim_free(oldval);
2615 vimvars[VV_CMDARG].vv_str = oldarg;
2616 return NULL;
2617 }
2618
2619 if (eap->force_bin == FORCE_BIN)
2620 len = 6;
2621 else if (eap->force_bin == FORCE_NOBIN)
2622 len = 8;
2623 else
2624 len = 0;
2625
2626 if (eap->read_edit)
2627 len += 7;
2628
2629 if (eap->force_ff != 0)
2630 len += 10; // " ++ff=unix"
2631 if (eap->force_enc != 0)
2632 len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
2633 if (eap->bad_char != 0)
2634 len += 7 + 4; // " ++bad=" + "keep" or "drop"
2635
2636 newval = alloc(len + 1);
2637 if (newval == NULL)
2638 return NULL;
2639
2640 if (eap->force_bin == FORCE_BIN)
2641 sprintf((char *)newval, " ++bin");
2642 else if (eap->force_bin == FORCE_NOBIN)
2643 sprintf((char *)newval, " ++nobin");
2644 else
2645 *newval = NUL;
2646
2647 if (eap->read_edit)
2648 STRCAT(newval, " ++edit");
2649
2650 if (eap->force_ff != 0)
2651 sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
2652 eap->force_ff == 'u' ? "unix"
2653 : eap->force_ff == 'd' ? "dos"
2654 : "mac");
2655 if (eap->force_enc != 0)
2656 sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
2657 eap->cmd + eap->force_enc);
2658 if (eap->bad_char == BAD_KEEP)
2659 STRCPY(newval + STRLEN(newval), " ++bad=keep");
2660 else if (eap->bad_char == BAD_DROP)
2661 STRCPY(newval + STRLEN(newval), " ++bad=drop");
2662 else if (eap->bad_char != 0)
2663 sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
2664 vimvars[VV_CMDARG].vv_str = newval;
2665 return oldval;
2666}
2667
2668/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002669 * Get the value of internal variable "name".
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002670 * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
2671 * imported script ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002672 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
2673 */
2674 int
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02002675eval_variable(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002676 char_u *name,
2677 int len, // length of "name"
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002678 scid_T sid, // script ID for imported item or zero
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002679 typval_T *rettv, // NULL when only checking existence
2680 dictitem_T **dip, // non-NULL when typval's dict item is needed
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002681 int flags) // EVAL_VAR_ flags
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002682{
2683 int ret = OK;
2684 typval_T *tv = NULL;
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002685 int found = FALSE;
Bram Moolenaarf055d452021-07-08 20:57:24 +02002686 hashtab_T *ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002687 int cc;
Bram Moolenaarc967d572021-07-08 21:38:50 +02002688 type_T *type = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002689
2690 // truncate the name, so that we can use strcmp()
2691 cc = name[len];
2692 name[len] = NUL;
2693
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002694 // Check for local variable when debugging.
2695 if ((tv = lookup_debug_var(name)) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002696 {
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002697 // Check for user-defined variables.
Bram Moolenaarc967d572021-07-08 21:38:50 +02002698 dictitem_T *v = find_var(name, &ht, flags & EVAL_VAR_NOAUTOLOAD);
2699
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002700 if (v != NULL)
2701 {
2702 tv = &v->di_tv;
2703 if (dip != NULL)
2704 *dip = v;
2705 }
Bram Moolenaarc967d572021-07-08 21:38:50 +02002706 else
2707 ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002708 }
2709
Bram Moolenaareb6880b2020-07-12 17:07:05 +02002710 if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002711 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002712 imported_T *import = NULL;
Bram Moolenaar9721fb42020-06-11 23:10:46 +02002713 char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
2714
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002715 if (sid == 0)
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002716 import = find_imported(p, 0, TRUE, NULL);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002717
2718 // imported variable from another script
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002719 if (import != NULL || sid != 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002720 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002721 if ((flags & EVAL_VAR_IMPORT) == 0)
Bram Moolenaarc620c052020-07-08 15:16:19 +02002722 {
Bram Moolenaar71f21932022-01-07 18:20:55 +00002723 if (SCRIPT_ID_VALID(sid))
Bram Moolenaarc620c052020-07-08 15:16:19 +02002724 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002725 ht = &SCRIPT_VARS(sid);
2726 if (ht != NULL)
2727 {
2728 dictitem_T *v = find_var_in_ht(ht, 0, name,
2729 flags & EVAL_VAR_NOAUTOLOAD);
2730
2731 if (v != NULL)
2732 {
2733 tv = &v->di_tv;
2734 if (dip != NULL)
2735 *dip = v;
2736 }
2737 else
2738 ht = NULL;
2739 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02002740 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002741 else
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002742 {
2743 if (flags & EVAL_VAR_VERBOSE)
Bram Moolenaardd5893b2022-01-20 21:32:54 +00002744 semsg(_(e_expected_dot_after_name_str), name);
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002745 ret = FAIL;
2746 }
Bram Moolenaarf6a44f72020-09-27 13:51:14 +02002747 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02002748 else
2749 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002750 if (rettv != NULL)
2751 {
2752 rettv->v_type = VAR_ANY;
2753 rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
2754 }
2755 found = TRUE;
Bram Moolenaarc620c052020-07-08 15:16:19 +02002756 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002757 }
Bram Moolenaar052ff292021-12-11 13:54:46 +00002758 else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002759 {
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00002760 ufunc_T *ufunc = find_func(name, FALSE);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002761
Bram Moolenaarb033ee22021-08-15 16:08:36 +02002762 // In Vim9 script we can get a function reference by using the
2763 // function name.
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002764 if (ufunc != NULL)
2765 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002766 found = TRUE;
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002767 if (rettv != NULL)
2768 {
2769 rettv->v_type = VAR_FUNC;
Bram Moolenaaref082e12021-12-12 21:02:03 +00002770 if (STRNCMP(name, "g:", 2) == 0)
2771 // Keep the "g:", otherwise script-local may be
2772 // assumed.
2773 rettv->vval.v_string = vim_strsave(name);
2774 else
2775 rettv->vval.v_string = vim_strsave(ufunc->uf_name);
Bram Moolenaarb033ee22021-08-15 16:08:36 +02002776 if (rettv->vval.v_string != NULL)
2777 func_ref(ufunc->uf_name);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002778 }
2779 }
2780 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002781 }
2782
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002783 if (!found)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002784 {
Bram Moolenaarc620c052020-07-08 15:16:19 +02002785 if (tv == NULL)
2786 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002787 if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002788 semsg(_(e_undefined_variable_str), name);
Bram Moolenaarc620c052020-07-08 15:16:19 +02002789 ret = FAIL;
2790 }
2791 else if (rettv != NULL)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002792 {
Bram Moolenaar11005b02021-07-11 20:59:00 +02002793 if (ht != NULL && ht == get_script_local_ht()
2794 && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
Bram Moolenaarf055d452021-07-08 20:57:24 +02002795 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002796 svar_T *sv = find_typval_in_script(tv, 0);
Bram Moolenaarf055d452021-07-08 20:57:24 +02002797
Bram Moolenaarf055d452021-07-08 20:57:24 +02002798 if (sv != NULL)
2799 type = sv->sv_type;
2800 }
2801
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002802 // If a list or dict variable wasn't initialized, do it now.
2803 if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL)
2804 {
2805 tv->vval.v_dict = dict_alloc();
2806 if (tv->vval.v_dict != NULL)
Bram Moolenaarf055d452021-07-08 20:57:24 +02002807 {
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002808 ++tv->vval.v_dict->dv_refcount;
Bram Moolenaarf055d452021-07-08 20:57:24 +02002809 tv->vval.v_dict->dv_type = alloc_type(type);
2810 }
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002811 }
2812 else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL)
2813 {
2814 tv->vval.v_list = list_alloc();
2815 if (tv->vval.v_list != NULL)
Bram Moolenaarf055d452021-07-08 20:57:24 +02002816 {
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002817 ++tv->vval.v_list->lv_refcount;
Bram Moolenaarf055d452021-07-08 20:57:24 +02002818 tv->vval.v_list->lv_type = alloc_type(type);
2819 }
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002820 }
Bram Moolenaarb7c21af2021-04-18 14:12:31 +02002821 else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL)
2822 {
2823 tv->vval.v_blob = blob_alloc();
2824 if (tv->vval.v_blob != NULL)
2825 ++tv->vval.v_blob->bv_refcount;
2826 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02002827 copy_tv(tv, rettv);
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002828 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002829 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002830
2831 name[len] = cc;
2832
2833 return ret;
2834}
2835
2836/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002837 * Check if variable "name[len]" is a local variable or an argument.
2838 * If so, "*eval_lavars_used" is set to TRUE.
2839 */
2840 void
2841check_vars(char_u *name, int len)
2842{
2843 int cc;
2844 char_u *varname;
2845 hashtab_T *ht;
2846
2847 if (eval_lavars_used == NULL)
2848 return;
2849
2850 // truncate the name, so that we can use strcmp()
2851 cc = name[len];
2852 name[len] = NUL;
2853
2854 ht = find_var_ht(name, &varname);
2855 if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
2856 {
2857 if (find_var(name, NULL, TRUE) != NULL)
2858 *eval_lavars_used = TRUE;
2859 }
2860
2861 name[len] = cc;
2862}
2863
2864/*
2865 * Find variable "name" in the list of variables.
2866 * Return a pointer to it if found, NULL if not found.
2867 * Careful: "a:0" variables don't have a name.
Bram Moolenaar32b3f822021-01-06 21:59:39 +01002868 * When "htp" is not NULL set "htp" to the hashtab_T used.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002869 */
2870 dictitem_T *
2871find_var(char_u *name, hashtab_T **htp, int no_autoload)
2872{
2873 char_u *varname;
2874 hashtab_T *ht;
2875 dictitem_T *ret = NULL;
2876
2877 ht = find_var_ht(name, &varname);
2878 if (htp != NULL)
2879 *htp = ht;
2880 if (ht == NULL)
2881 return NULL;
Bram Moolenaar32b3f822021-01-06 21:59:39 +01002882 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002883 if (ret != NULL)
2884 return ret;
2885
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002886 // Search in parent scope for lambda
Bram Moolenaar32b3f822021-01-06 21:59:39 +01002887 ret = find_var_in_scoped_ht(name, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01002888 if (ret != NULL)
2889 return ret;
2890
2891 // in Vim9 script items without a scope can be script-local
2892 if (in_vim9script() && name[0] != NUL && name[1] != ':')
2893 {
2894 ht = get_script_local_ht();
2895 if (ht != NULL)
2896 {
Bram Moolenaar32b3f822021-01-06 21:59:39 +01002897 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01002898 if (ret != NULL)
2899 {
2900 if (htp != NULL)
2901 *htp = ht;
2902 return ret;
2903 }
2904 }
2905 }
2906
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00002907 // When using "vim9script autoload" script-local items are prefixed but can
2908 // be used with s:name.
2909 if (SCRIPT_ID_VALID(current_sctx.sc_sid)
2910 && name[0] == 's' && name[1] == ':')
2911 {
2912 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
2913
2914 if (si->sn_autoload_prefix != NULL)
2915 {
2916 char_u *auto_name = concat_str(si->sn_autoload_prefix, name + 2);
2917
2918 if (auto_name != NULL)
2919 {
2920 ht = &globvarht;
2921 ret = find_var_in_ht(ht, *name, auto_name, TRUE);
Bram Moolenaar130f65d2022-01-13 20:39:41 +00002922 vim_free(auto_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00002923 if (ret != NULL)
2924 {
2925 if (htp != NULL)
2926 *htp = ht;
2927 return ret;
2928 }
2929 }
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00002930 }
2931 }
2932
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01002933 return NULL;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002934}
2935
2936/*
Bram Moolenaar71f21932022-01-07 18:20:55 +00002937 * Like find_var() but if the name starts with <SNR>99_ then look in the
2938 * referenced script (used for a funcref).
2939 */
2940 dictitem_T *
2941find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload)
2942{
2943 if (STRNCMP(name, "<SNR>", 5) == 0 && isdigit(name[5]))
2944 {
2945 char_u *p = name + 5;
2946 int sid = getdigits(&p);
2947
2948 if (SCRIPT_ID_VALID(sid) && *p == '_')
2949 {
2950 hashtab_T *ht = &SCRIPT_VARS(sid);
2951
2952 if (ht != NULL)
2953 {
2954 dictitem_T *di = find_var_in_ht(ht, 0, p + 1, no_autoload);
2955
2956 if (di != NULL)
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00002957 {
2958 if (htp != NULL)
2959 *htp = ht;
Bram Moolenaar71f21932022-01-07 18:20:55 +00002960 return di;
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00002961 }
Bram Moolenaar71f21932022-01-07 18:20:55 +00002962 }
2963 }
2964 }
2965
2966 return find_var(name, htp, no_autoload);
2967}
2968
2969/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002970 * Find variable "varname" in hashtab "ht" with name "htname".
Bram Moolenaar52592752020-04-03 18:43:35 +02002971 * When "varname" is empty returns curwin/curtab/etc vars dictionary.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002972 * Returns NULL if not found.
2973 */
2974 dictitem_T *
2975find_var_in_ht(
2976 hashtab_T *ht,
2977 int htname,
2978 char_u *varname,
2979 int no_autoload)
2980{
2981 hashitem_T *hi;
2982
2983 if (*varname == NUL)
2984 {
2985 // Must be something like "s:", otherwise "ht" would be NULL.
2986 switch (htname)
2987 {
2988 case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
2989 case 'g': return &globvars_var;
2990 case 'v': return &vimvars_var;
2991 case 'b': return &curbuf->b_bufvar;
2992 case 'w': return &curwin->w_winvar;
2993 case 't': return &curtab->tp_winvar;
2994 case 'l': return get_funccal_local_var();
2995 case 'a': return get_funccal_args_var();
2996 }
2997 return NULL;
2998 }
2999
3000 hi = hash_find(ht, varname);
3001 if (HASHITEM_EMPTY(hi))
3002 {
3003 // For global variables we may try auto-loading the script. If it
3004 // worked find the variable again. Don't auto-load a script if it was
3005 // loaded already, otherwise it would be loaded every time when
3006 // checking if a function name is a Funcref variable.
3007 if (ht == &globvarht && !no_autoload)
3008 {
3009 // Note: script_autoload() may make "hi" invalid. It must either
3010 // be obtained again or not used.
3011 if (!script_autoload(varname, FALSE) || aborting())
3012 return NULL;
3013 hi = hash_find(ht, varname);
3014 }
3015 if (HASHITEM_EMPTY(hi))
3016 return NULL;
3017 }
3018 return HI2DI(hi);
3019}
3020
3021/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003022 * Get the script-local hashtab. NULL if not in a script context.
3023 */
Bram Moolenaar922acbd2020-10-08 21:30:40 +02003024 hashtab_T *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003025get_script_local_ht(void)
3026{
3027 scid_T sid = current_sctx.sc_sid;
3028
Bram Moolenaare3d46852020-08-29 13:39:17 +02003029 if (SCRIPT_ID_VALID(sid))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003030 return &SCRIPT_VARS(sid);
3031 return NULL;
3032}
3033
3034/*
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003035 * Look for "name[len]" in script-local variables and functions.
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003036 * When "cmd" is TRUE it must look like a command, a function must be followed
3037 * by "(" or "->".
Bram Moolenaar709664c2020-12-12 14:33:41 +01003038 * Return OK when found, FAIL when not found.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003039 */
Bram Moolenaar709664c2020-12-12 14:33:41 +01003040 int
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003041lookup_scriptitem(
Bram Moolenaar709664c2020-12-12 14:33:41 +01003042 char_u *name,
3043 size_t len,
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003044 int cmd,
Bram Moolenaar709664c2020-12-12 14:33:41 +01003045 cctx_T *dummy UNUSED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003046{
3047 hashtab_T *ht = get_script_local_ht();
3048 char_u buffer[30];
3049 char_u *p;
Bram Moolenaar709664c2020-12-12 14:33:41 +01003050 int res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003051 hashitem_T *hi;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003052 int is_global = FALSE;
3053 char_u *fname = name;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003054
3055 if (ht == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003056 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003057 if (len < sizeof(buffer) - 1)
3058 {
Bram Moolenaar7d3664d2020-05-09 13:06:24 +02003059 // avoid an alloc/free for short names
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003060 vim_strncpy(buffer, name, len);
3061 p = buffer;
3062 }
3063 else
3064 {
Bram Moolenaar71ccd032020-06-12 22:59:11 +02003065 p = vim_strnsave(name, len);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003066 if (p == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003067 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003068 }
3069
3070 hi = hash_find(ht, p);
Bram Moolenaar709664c2020-12-12 14:33:41 +01003071 res = HASHITEM_EMPTY(hi) ? FAIL : OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003072
3073 // if not script-local, then perhaps imported
Bram Moolenaardc4451d2022-01-09 21:36:37 +00003074 if (res == FAIL && find_imported(p, 0, FALSE, NULL) != NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003075 res = OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003076 if (p != buffer)
3077 vim_free(p);
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003078
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003079 // Find a function, so that a following "->" works.
3080 // When used as a command require "(" or "->" to follow, "Cmd" is a user
3081 // command while "Cmd()" is a function call.
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003082 if (res != OK)
3083 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003084 p = skipwhite(name + len);
3085
3086 if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003087 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003088 // Do not check for an internal function, since it might also be a
3089 // valid command, such as ":split" versus "split()".
3090 // Skip "g:" before a function name.
3091 if (name[0] == 'g' && name[1] == ':')
3092 {
3093 is_global = TRUE;
3094 fname = name + 2;
3095 }
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003096 if (find_func(fname, is_global) != NULL)
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003097 res = OK;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003098 }
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003099 }
3100
Bram Moolenaar709664c2020-12-12 14:33:41 +01003101 return res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003102}
3103
3104/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003105 * Find the hashtab used for a variable name.
3106 * Return NULL if the name is not valid.
3107 * Set "varname" to the start of name without ':'.
3108 */
3109 hashtab_T *
3110find_var_ht(char_u *name, char_u **varname)
3111{
3112 hashitem_T *hi;
3113 hashtab_T *ht;
3114
3115 if (name[0] == NUL)
3116 return NULL;
3117 if (name[1] != ':')
3118 {
3119 // The name must not start with a colon or #.
3120 if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
3121 return NULL;
3122 *varname = name;
3123
3124 // "version" is "v:version" in all scopes if scriptversion < 3.
3125 // Same for a few other variables marked with VV_COMPAT.
Bram Moolenaardd9de502021-08-15 13:49:42 +02003126 if (in_old_script(3))
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003127 {
3128 hi = hash_find(&compat_hashtab, name);
3129 if (!HASHITEM_EMPTY(hi))
3130 return &compat_hashtab;
3131 }
3132
3133 ht = get_funccal_local_ht();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003134 if (ht != NULL)
3135 return ht; // local variable
3136
Bram Moolenaarf0a40692021-06-11 22:05:47 +02003137 // In Vim9 script items at the script level are script-local, except
3138 // for autoload names.
3139 if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003140 {
3141 ht = get_script_local_ht();
3142 if (ht != NULL)
3143 return ht;
3144 }
3145
3146 return &globvarht; // global variable
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003147 }
3148 *varname = name + 2;
3149 if (*name == 'g') // global variable
3150 return &globvarht;
3151 // There must be no ':' or '#' in the rest of the name, unless g: is used
3152 if (vim_strchr(name + 2, ':') != NULL
3153 || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
3154 return NULL;
3155 if (*name == 'b') // buffer variable
3156 return &curbuf->b_vars->dv_hashtab;
3157 if (*name == 'w') // window variable
3158 return &curwin->w_vars->dv_hashtab;
3159 if (*name == 't') // tab page variable
3160 return &curtab->tp_vars->dv_hashtab;
3161 if (*name == 'v') // v: variable
3162 return &vimvarht;
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003163 if (get_current_funccal() != NULL
Bram Moolenaar0cb5bcf2020-06-20 18:19:09 +02003164 && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003165 {
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003166 // a: and l: are only used in functions defined with ":function"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003167 if (*name == 'a') // a: function argument
3168 return get_funccal_args_ht();
3169 if (*name == 'l') // l: local function variable
3170 return get_funccal_local_ht();
3171 }
3172 if (*name == 's') // script variable
3173 {
3174 ht = get_script_local_ht();
3175 if (ht != NULL)
3176 return ht;
3177 }
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003178 return NULL;
3179}
3180
3181/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003182 * Get the string value of a (global/local) variable.
3183 * Note: see tv_get_string() for how long the pointer remains valid.
3184 * Returns NULL when it doesn't exist.
3185 */
3186 char_u *
3187get_var_value(char_u *name)
3188{
3189 dictitem_T *v;
3190
3191 v = find_var(name, NULL, FALSE);
3192 if (v == NULL)
3193 return NULL;
3194 return tv_get_string(&v->di_tv);
3195}
3196
3197/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003198 * Allocate a new hashtab for a sourced script. It will be used while
3199 * sourcing this script and when executing functions defined in the script.
3200 */
3201 void
3202new_script_vars(scid_T id)
3203{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003204 scriptvar_T *sv;
3205
Bram Moolenaar7ebcba62020-01-12 17:42:55 +01003206 sv = ALLOC_CLEAR_ONE(scriptvar_T);
3207 if (sv == NULL)
3208 return;
3209 init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
Bram Moolenaar21b9e972020-01-26 19:26:46 +01003210 SCRIPT_ITEM(id)->sn_vars = sv;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003211}
3212
3213/*
3214 * Initialize dictionary "dict" as a scope and set variable "dict_var" to
3215 * point to it.
3216 */
3217 void
3218init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
3219{
3220 hash_init(&dict->dv_hashtab);
3221 dict->dv_lock = 0;
3222 dict->dv_scope = scope;
3223 dict->dv_refcount = DO_NOT_FREE_CNT;
3224 dict->dv_copyID = 0;
3225 dict_var->di_tv.vval.v_dict = dict;
3226 dict_var->di_tv.v_type = VAR_DICT;
3227 dict_var->di_tv.v_lock = VAR_FIXED;
3228 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
3229 dict_var->di_key[0] = NUL;
3230}
3231
3232/*
3233 * Unreference a dictionary initialized by init_var_dict().
3234 */
3235 void
3236unref_var_dict(dict_T *dict)
3237{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003238 // Now the dict needs to be freed if no one else is using it, go back to
3239 // normal reference counting.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003240 dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
3241 dict_unref(dict);
3242}
3243
3244/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003245 * Clean up a list of internal variables.
3246 * Frees all allocated variables and the value they contain.
3247 * Clears hashtab "ht", does not free it.
3248 */
3249 void
3250vars_clear(hashtab_T *ht)
3251{
3252 vars_clear_ext(ht, TRUE);
3253}
3254
3255/*
3256 * Like vars_clear(), but only free the value if "free_val" is TRUE.
3257 */
3258 void
3259vars_clear_ext(hashtab_T *ht, int free_val)
3260{
3261 int todo;
3262 hashitem_T *hi;
3263 dictitem_T *v;
3264
3265 hash_lock(ht);
3266 todo = (int)ht->ht_used;
3267 for (hi = ht->ht_array; todo > 0; ++hi)
3268 {
3269 if (!HASHITEM_EMPTY(hi))
3270 {
3271 --todo;
3272
3273 // Free the variable. Don't remove it from the hashtab,
3274 // ht_array might change then. hash_clear() takes care of it
3275 // later.
3276 v = HI2DI(hi);
3277 if (free_val)
3278 clear_tv(&v->di_tv);
3279 if (v->di_flags & DI_FLAGS_ALLOC)
3280 vim_free(v);
3281 }
3282 }
3283 hash_clear(ht);
Bram Moolenaar8d739de2020-10-14 19:39:19 +02003284 hash_init(ht);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003285}
3286
3287/*
3288 * Delete a variable from hashtab "ht" at item "hi".
3289 * Clear the variable value and free the dictitem.
3290 */
Bram Moolenaarfcdc5d82020-10-10 19:07:09 +02003291 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003292delete_var(hashtab_T *ht, hashitem_T *hi)
3293{
3294 dictitem_T *di = HI2DI(hi);
3295
3296 hash_remove(ht, hi);
3297 clear_tv(&di->di_tv);
3298 vim_free(di);
3299}
3300
3301/*
3302 * List the value of one internal variable.
3303 */
3304 static void
3305list_one_var(dictitem_T *v, char *prefix, int *first)
3306{
3307 char_u *tofree;
3308 char_u *s;
3309 char_u numbuf[NUMBUFLEN];
3310
3311 s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
3312 list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
3313 s == NULL ? (char_u *)"" : s, first);
3314 vim_free(tofree);
3315}
3316
3317 static void
3318list_one_var_a(
3319 char *prefix,
3320 char_u *name,
3321 int type,
3322 char_u *string,
3323 int *first) // when TRUE clear rest of screen and set to FALSE
3324{
3325 // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
3326 msg_start();
3327 msg_puts(prefix);
3328 if (name != NULL) // "a:" vars don't have a name stored
3329 msg_puts((char *)name);
3330 msg_putchar(' ');
3331 msg_advance(22);
3332 if (type == VAR_NUMBER)
3333 msg_putchar('#');
3334 else if (type == VAR_FUNC || type == VAR_PARTIAL)
3335 msg_putchar('*');
3336 else if (type == VAR_LIST)
3337 {
3338 msg_putchar('[');
3339 if (*string == '[')
3340 ++string;
3341 }
3342 else if (type == VAR_DICT)
3343 {
3344 msg_putchar('{');
3345 if (*string == '{')
3346 ++string;
3347 }
3348 else
3349 msg_putchar(' ');
3350
3351 msg_outtrans(string);
3352
3353 if (type == VAR_FUNC || type == VAR_PARTIAL)
3354 msg_puts("()");
3355 if (*first)
3356 {
3357 msg_clr_eos();
3358 *first = FALSE;
3359 }
3360}
3361
3362/*
3363 * Set variable "name" to value in "tv".
3364 * If the variable already exists, the value is updated.
3365 * Otherwise the variable is created.
3366 */
3367 void
3368set_var(
3369 char_u *name,
3370 typval_T *tv,
3371 int copy) // make copy of value in "tv"
3372{
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003373 set_var_const(name, 0, NULL, tv, copy, ASSIGN_DECL, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003374}
3375
3376/*
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003377 * Set variable "name" to value in "tv_arg".
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003378 * When "sid" is non-zero "name" is in the script with this ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003379 * If the variable already exists and "is_const" is FALSE the value is updated.
3380 * Otherwise the variable is created.
3381 */
3382 void
3383set_var_const(
3384 char_u *name,
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003385 scid_T sid,
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003386 type_T *type_arg,
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003387 typval_T *tv_arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003388 int copy, // make copy of value in "tv"
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003389 int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaarf785aa12021-02-11 21:19:34 +01003390 int var_idx) // index for ":let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003391{
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003392 typval_T *tv = tv_arg;
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003393 type_T *type = type_arg;
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003394 typval_T bool_tv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003395 dictitem_T *di;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003396 typval_T *dest_tv = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003397 char_u *varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003398 char_u *name_tofree = NULL;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003399 hashtab_T *ht = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003400 int is_script_local;
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003401 int vim9script = in_vim9script();
Bram Moolenaare535db82021-03-31 21:07:24 +02003402 int var_in_vim9script;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003403 int var_in_autoload = FALSE;
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003404 int flags = flags_arg;
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003405 int free_tv_arg = !copy; // free tv_arg if not used
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003406
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003407 if (sid != 0)
3408 {
3409 if (SCRIPT_ID_VALID(sid))
3410 ht = &SCRIPT_VARS(sid);
3411 varname = name;
3412 }
3413 else
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003414 {
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003415 scriptitem_T *si;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003416
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003417 if (in_vim9script() && is_export
3418 && SCRIPT_ID_VALID(current_sctx.sc_sid)
3419 && (si = SCRIPT_ITEM(current_sctx.sc_sid))
3420 ->sn_autoload_prefix != NULL)
3421 {
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003422 // In a vim9 autoload script an exported variable is put in the
3423 // global namespace with the autoload prefix.
3424 var_in_autoload = TRUE;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003425 varname = concat_str(si->sn_autoload_prefix, name);
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003426 if (varname == NULL)
3427 goto failed;
3428 name_tofree = varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003429 ht = &globvarht;
3430 }
3431 else
3432 ht = find_var_ht(name, &varname);
3433 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003434 if (ht == NULL || *varname == NUL)
3435 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003436 semsg(_(e_illegal_variable_name_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003437 goto failed;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003438 }
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003439 is_script_local = ht == get_script_local_ht() || sid != 0 || var_in_autoload;
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003440
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003441 if (vim9script
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003442 && !is_script_local
Bram Moolenaar3862ea32021-01-01 21:05:55 +01003443 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01003444 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003445 && name[1] == ':')
Bram Moolenaar67979662020-06-20 22:50:47 +02003446 {
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003447 vim9_declare_error(name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003448 goto failed;
Bram Moolenaar67979662020-06-20 22:50:47 +02003449 }
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003450 if ((flags & ASSIGN_FOR_LOOP) && name[1] == ':'
3451 && vim_strchr((char_u *)"gwbt", name[0]) != NULL)
3452 // Do not make g:var, w:var, b:var or t:var final.
3453 flags &= ~ASSIGN_FINAL;
3454
Bram Moolenaare535db82021-03-31 21:07:24 +02003455 var_in_vim9script = is_script_local && current_script_is_vim9();
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003456 if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
3457 {
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02003458 // For "[a, _] = list" the underscore is ignored.
3459 if ((flags & ASSIGN_UNPACK) == 0)
3460 emsg(_(e_cannot_use_underscore_here));
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003461 goto failed;
3462 }
Bram Moolenaar67979662020-06-20 22:50:47 +02003463
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003464 di = find_var_in_ht(ht, 0, varname, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003465
Bram Moolenaar24e93162021-07-18 20:40:33 +02003466 if (di == NULL && var_in_vim9script)
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003467 {
Bram Moolenaardc4451d2022-01-09 21:36:37 +00003468 imported_T *import = find_imported(varname, 0, FALSE, NULL);
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003469
Bram Moolenaar24e93162021-07-18 20:40:33 +02003470 if (import != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003471 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003472 // imported name space cannot be used
Bram Moolenaar24e93162021-07-18 20:40:33 +02003473 if ((flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003474 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003475 semsg(_(e_redefining_imported_item_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003476 goto failed;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003477 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003478 semsg(_(e_cannot_use_str_itself_it_is_imported), name);
3479 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003480 }
3481 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003482
Bram Moolenaar24e93162021-07-18 20:40:33 +02003483 if (dest_tv == NULL)
3484 {
3485 // Search in parent scope which is possible to reference from lambda
3486 if (di == NULL)
3487 di = find_var_in_scoped_ht(name, TRUE);
3488
3489 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
Bram Moolenaarf6488542021-07-18 21:24:50 +02003490 && var_wrong_func_name(name, di == NULL))
Bram Moolenaar24e93162021-07-18 20:40:33 +02003491 goto failed;
3492
3493 if (need_convert_to_bool(type, tv))
3494 {
Bram Moolenaarf6488542021-07-18 21:24:50 +02003495 // Destination is a bool and the value is not, but it can be
3496 // converted.
Bram Moolenaar24e93162021-07-18 20:40:33 +02003497 CLEAR_FIELD(bool_tv);
3498 bool_tv.v_type = VAR_BOOL;
3499 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
3500 tv = &bool_tv;
3501 }
3502
3503 if (di != NULL)
3504 {
3505 // Item already exists. Allowed to replace when reloading.
3506 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
3507 {
3508 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
Bram Moolenaarf6488542021-07-18 21:24:50 +02003509 && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003510 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003511 emsg(_(e_cannot_modify_existing_variable));
Bram Moolenaar24e93162021-07-18 20:40:33 +02003512 goto failed;
3513 }
3514
3515 if (is_script_local && vim9script
Bram Moolenaarf6488542021-07-18 21:24:50 +02003516 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003517 {
3518 semsg(_(e_redefining_script_item_str), name);
3519 goto failed;
3520 }
3521
Bram Moolenaara06758d2021-10-15 00:18:37 +01003522 if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003523 {
Bram Moolenaar2b59df02021-07-22 15:14:25 +02003524 where_T where = WHERE_INIT;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003525 svar_T *sv = find_typval_in_script(&di->di_tv, sid);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003526
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003527 if (sv != NULL)
3528 {
3529 // check the type and adjust to bool if needed
3530 where.wt_index = var_idx;
3531 where.wt_variable = TRUE;
3532 if (check_script_var_type(sv, tv, name, where) == FAIL)
3533 goto failed;
3534 if (type == NULL)
3535 type = sv->sv_type;
3536 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003537 }
3538
Bram Moolenaara06758d2021-10-15 00:18:37 +01003539 if ((flags & ASSIGN_FOR_LOOP) == 0
3540 && var_check_permission(di, name) == FAIL)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003541 goto failed;
3542 }
3543 else
3544 {
3545 // can only redefine once
3546 di->di_flags &= ~DI_FLAGS_RELOAD;
3547
Bram Moolenaarf6488542021-07-18 21:24:50 +02003548 // A Vim9 script-local variable is also present in sn_all_vars
3549 // and sn_var_vals. It may set "type" from "tv".
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003550 if (var_in_vim9script || var_in_autoload)
3551 update_vim9_script_var(FALSE, di,
3552 var_in_autoload ? name : di->di_key, flags,
3553 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003554 }
3555
3556 // existing variable, need to clear the value
3557
3558 // Handle setting internal di: variables separately where needed to
3559 // prevent changing the type.
3560 if (ht == &vimvarht)
3561 {
3562 if (di->di_tv.v_type == VAR_STRING)
3563 {
3564 VIM_CLEAR(di->di_tv.vval.v_string);
3565 if (copy || tv->v_type != VAR_STRING)
3566 {
3567 char_u *val = tv_get_string(tv);
3568
Bram Moolenaarf6488542021-07-18 21:24:50 +02003569 // Careful: when assigning to v:errmsg and
3570 // tv_get_string() causes an error message the variable
3571 // will already be set.
Bram Moolenaar24e93162021-07-18 20:40:33 +02003572 if (di->di_tv.vval.v_string == NULL)
3573 di->di_tv.vval.v_string = vim_strsave(val);
3574 }
3575 else
3576 {
3577 // Take over the string to avoid an extra alloc/free.
3578 di->di_tv.vval.v_string = tv->vval.v_string;
3579 tv->vval.v_string = NULL;
3580 }
3581 goto failed;
3582 }
3583 else if (di->di_tv.v_type == VAR_NUMBER)
3584 {
3585 di->di_tv.vval.v_number = tv_get_number(tv);
3586 if (STRCMP(varname, "searchforward") == 0)
Bram Moolenaarf6488542021-07-18 21:24:50 +02003587 set_search_direction(di->di_tv.vval.v_number
3588 ? '/' : '?');
Bram Moolenaar24e93162021-07-18 20:40:33 +02003589#ifdef FEAT_SEARCH_EXTRA
3590 else if (STRCMP(varname, "hlsearch") == 0)
3591 {
3592 no_hlsearch = !di->di_tv.vval.v_number;
3593 redraw_all_later(SOME_VALID);
3594 }
3595#endif
3596 goto failed;
3597 }
3598 else if (di->di_tv.v_type != tv->v_type)
3599 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00003600 semsg(_(e_setting_str_to_value_with_wrong_type), name);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003601 goto failed;
3602 }
3603 }
3604
3605 clear_tv(&di->di_tv);
3606 }
3607 else
3608 {
3609 // Item not found, check if a function already exists.
3610 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaarf6488542021-07-18 21:24:50 +02003611 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
Bram Moolenaar12be7342021-03-31 21:47:33 +02003612 {
3613 semsg(_(e_redefining_script_item_str), name);
3614 goto failed;
3615 }
3616
Bram Moolenaar24e93162021-07-18 20:40:33 +02003617 // add a new variable
3618 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
3619 {
3620 semsg(_(e_unknown_variable_str), name);
3621 goto failed;
3622 }
3623
3624 // Can't add "v:" or "a:" variable.
3625 if (ht == &vimvarht || ht == get_funccal_args_ht())
3626 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003627 semsg(_(e_illegal_variable_name_str), name);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003628 goto failed;
3629 }
3630
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003631 // Make sure the variable name is valid. In Vim9 script an
3632 // autoload variable must be prefixed with "g:" unless in an
3633 // autoload script.
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00003634 if (!valid_varname(varname, -1, !vim9script
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003635 || STRNCMP(name, "g:", 2) == 0 || var_in_autoload))
Bram Moolenaar24e93162021-07-18 20:40:33 +02003636 goto failed;
3637
3638 di = alloc(sizeof(dictitem_T) + STRLEN(varname));
3639 if (di == NULL)
3640 goto failed;
3641 STRCPY(di->di_key, varname);
3642 if (hash_add(ht, DI2HIKEY(di)) == FAIL)
3643 {
3644 vim_free(di);
3645 goto failed;
3646 }
3647 di->di_flags = DI_FLAGS_ALLOC;
3648 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
3649 di->di_flags |= DI_FLAGS_LOCK;
3650
3651 // A Vim9 script-local variable is also added to sn_all_vars and
3652 // sn_var_vals. It may set "type" from "tv".
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003653 if (var_in_vim9script || var_in_autoload)
3654 update_vim9_script_var(TRUE, di,
3655 var_in_autoload ? name : di->di_key, flags,
3656 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar07a65d22020-12-26 20:09:15 +01003657 }
3658
Bram Moolenaar24e93162021-07-18 20:40:33 +02003659 dest_tv = &di->di_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003660 }
3661
3662 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003663 copy_tv(tv, dest_tv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003664 else
3665 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003666 *dest_tv = *tv;
3667 dest_tv->v_lock = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003668 init_tv(tv);
3669 }
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003670 free_tv_arg = FALSE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003671
Bram Moolenaaraa210a32021-01-02 15:41:03 +01003672 if (vim9script && type != NULL)
3673 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003674 if (type->tt_type == VAR_DICT && dest_tv->vval.v_dict != NULL)
Bram Moolenaar464393a2021-09-11 23:07:44 +02003675 {
3676 if (dest_tv->vval.v_dict->dv_type != type)
3677 {
3678 free_type(dest_tv->vval.v_dict->dv_type);
3679 dest_tv->vval.v_dict->dv_type = alloc_type(type);
3680 }
3681 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003682 else if (type->tt_type == VAR_LIST && dest_tv->vval.v_list != NULL)
Bram Moolenaar464393a2021-09-11 23:07:44 +02003683 {
3684 if (dest_tv->vval.v_list->lv_type != type)
3685 {
3686 free_type(dest_tv->vval.v_list->lv_type);
3687 dest_tv->vval.v_list->lv_type = alloc_type(type);
3688 }
3689 }
Bram Moolenaaraa210a32021-01-02 15:41:03 +01003690 }
3691
Bram Moolenaar1dcf55d2020-12-22 22:07:30 +01003692 // ":const var = value" locks the value
3693 // ":final var = value" locks "var"
Bram Moolenaar30fd8202020-09-26 15:09:30 +02003694 if (flags & ASSIGN_CONST)
Bram Moolenaar021bda52020-08-17 21:07:22 +02003695 // Like :lockvar! name: lock the value and what it contains, but only
3696 // if the reference count is up to one. That locks only literal
3697 // values.
Bram Moolenaar24e93162021-07-18 20:40:33 +02003698 item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003699
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003700failed:
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003701 vim_free(name_tofree);
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003702 if (free_tv_arg)
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003703 clear_tv(tv_arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003704}
3705
3706/*
Bram Moolenaar3bdc90b2020-12-22 20:35:40 +01003707 * Check in this order for backwards compatibility:
3708 * - Whether the variable is read-only
3709 * - Whether the variable value is locked
3710 * - Whether the variable is locked
3711 */
3712 int
3713var_check_permission(dictitem_T *di, char_u *name)
3714{
3715 if (var_check_ro(di->di_flags, name, FALSE)
3716 || value_check_lock(di->di_tv.v_lock, name, FALSE)
3717 || var_check_lock(di->di_flags, name, FALSE))
3718 return FAIL;
3719 return OK;
3720}
3721
3722/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003723 * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
3724 * Also give an error message.
3725 */
3726 int
3727var_check_ro(int flags, char_u *name, int use_gettext)
3728{
3729 if (flags & DI_FLAGS_RO)
3730 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003731 if (name == NULL)
3732 emsg(_(e_cannot_change_readonly_variable));
3733 else
3734 semsg(_(e_cannot_change_readonly_variable_str),
Bram Moolenaard8e44472021-07-21 22:20:33 +02003735 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003736 return TRUE;
3737 }
3738 if ((flags & DI_FLAGS_RO_SBX) && sandbox)
3739 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003740 if (name == NULL)
3741 emsg(_(e_cannot_set_variable_in_sandbox));
3742 else
3743 semsg(_(e_cannot_set_variable_in_sandbox_str),
3744 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003745 return TRUE;
3746 }
3747 return FALSE;
3748}
3749
3750/*
Bram Moolenaara187c432020-09-16 21:08:28 +02003751 * Return TRUE if di_flags "flags" indicates variable "name" is locked.
3752 * Also give an error message.
3753 */
3754 int
3755var_check_lock(int flags, char_u *name, int use_gettext)
3756{
3757 if (flags & DI_FLAGS_LOCK)
3758 {
3759 semsg(_(e_variable_is_locked_str),
3760 use_gettext ? (char_u *)_(name) : name);
3761 return TRUE;
3762 }
3763 return FALSE;
3764}
3765
3766/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003767 * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
3768 * Also give an error message.
3769 */
3770 int
3771var_check_fixed(int flags, char_u *name, int use_gettext)
3772{
3773 if (flags & DI_FLAGS_FIX)
3774 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003775 if (name == NULL)
3776 emsg(_(e_cannot_delete_variable));
3777 else
3778 semsg(_(e_cannot_delete_variable_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003779 use_gettext ? (char_u *)_(name) : name);
3780 return TRUE;
3781 }
3782 return FALSE;
3783}
3784
3785/*
3786 * Check if a funcref is assigned to a valid variable name.
3787 * Return TRUE and give an error if not.
3788 */
3789 int
Bram Moolenaar98b4f142020-08-08 15:46:01 +02003790var_wrong_func_name(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003791 char_u *name, // points to start of variable name
3792 int new_var) // TRUE when creating the variable
3793{
Bram Moolenaar32154662021-03-28 21:14:06 +02003794 // Allow for w: b: s: and t:. In Vim9 script s: is not allowed, because
3795 // the name can be used without the s: prefix.
3796 if (!((vim_strchr((char_u *)"wbt", name[0]) != NULL
3797 || (!in_vim9script() && name[0] == 's')) && name[1] == ':')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003798 && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
3799 ? name[2] : name[0]))
3800 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00003801 semsg(_(e_funcref_variable_name_must_start_with_capital_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003802 return TRUE;
3803 }
3804 // Don't allow hiding a function. When "v" is not NULL we might be
3805 // assigning another function to the same var, the type is checked
3806 // below.
3807 if (new_var && function_exists(name, FALSE))
3808 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00003809 semsg(_(e_variable_name_conflicts_with_existing_function_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003810 name);
3811 return TRUE;
3812 }
3813 return FALSE;
3814}
3815
3816/*
Bram Moolenaara187c432020-09-16 21:08:28 +02003817 * Return TRUE if "flags" indicates variable "name" has a locked (immutable)
3818 * value. Also give an error message, using "name" or _("name") when
3819 * "use_gettext" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003820 */
3821 int
Bram Moolenaara187c432020-09-16 21:08:28 +02003822value_check_lock(int lock, char_u *name, int use_gettext)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003823{
3824 if (lock & VAR_LOCKED)
3825 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003826 if (name == NULL)
3827 emsg(_(e_value_is_locked));
3828 else
3829 semsg(_(e_value_is_locked_str),
3830 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003831 return TRUE;
3832 }
3833 if (lock & VAR_FIXED)
3834 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003835 if (name == NULL)
3836 emsg(_(e_cannot_change_value));
3837 else
3838 semsg(_(e_cannot_change_value_of_str),
3839 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003840 return TRUE;
3841 }
3842 return FALSE;
3843}
3844
3845/*
Bram Moolenaar03290b82020-12-19 16:30:44 +01003846 * Check if a variable name is valid. When "autoload" is true "#" is allowed.
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00003847 * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003848 * Return FALSE and give an error if not.
3849 */
3850 int
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00003851valid_varname(char_u *varname, int len, int autoload)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003852{
3853 char_u *p;
3854
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00003855 for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003856 if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
Bram Moolenaar03290b82020-12-19 16:30:44 +01003857 && !(autoload && *p == AUTOLOAD_CHAR))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003858 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003859 semsg(_(e_illegal_variable_name_str), varname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003860 return FALSE;
3861 }
3862 return TRUE;
3863}
3864
3865/*
3866 * getwinvar() and gettabwinvar()
3867 */
3868 static void
3869getwinvar(
3870 typval_T *argvars,
3871 typval_T *rettv,
3872 int off) // 1 for gettabwinvar()
3873{
3874 win_T *win;
3875 char_u *varname;
3876 dictitem_T *v;
3877 tabpage_T *tp = NULL;
3878 int done = FALSE;
Bram Moolenaar18f47402022-01-06 13:24:51 +00003879 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003880 int need_switch_win;
3881
3882 if (off == 1)
3883 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
3884 else
3885 tp = curtab;
3886 win = find_win_by_nr(&argvars[off], tp);
3887 varname = tv_get_string_chk(&argvars[off + 1]);
3888 ++emsg_off;
3889
3890 rettv->v_type = VAR_STRING;
3891 rettv->vval.v_string = NULL;
3892
3893 if (win != NULL && varname != NULL)
3894 {
3895 // Set curwin to be our win, temporarily. Also set the tabpage,
3896 // otherwise the window is not valid. Only do this when needed,
3897 // autocommands get blocked.
3898 need_switch_win = !(tp == curtab && win == curwin);
3899 if (!need_switch_win
Bram Moolenaar18f47402022-01-06 13:24:51 +00003900 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003901 {
3902 if (*varname == '&')
3903 {
3904 if (varname[1] == NUL)
3905 {
3906 // get all window-local options in a dict
3907 dict_T *opts = get_winbuf_options(FALSE);
3908
3909 if (opts != NULL)
3910 {
3911 rettv_dict_set(rettv, opts);
3912 done = TRUE;
3913 }
3914 }
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02003915 else if (eval_option(&varname, rettv, 1) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003916 // window-local-option
3917 done = TRUE;
3918 }
3919 else
3920 {
3921 // Look up the variable.
3922 // Let getwinvar({nr}, "") return the "w:" dictionary.
3923 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
3924 varname, FALSE);
3925 if (v != NULL)
3926 {
3927 copy_tv(&v->di_tv, rettv);
3928 done = TRUE;
3929 }
3930 }
3931 }
3932
3933 if (need_switch_win)
3934 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00003935 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003936 }
3937
3938 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
3939 // use the default return value
3940 copy_tv(&argvars[off + 2], rettv);
3941
3942 --emsg_off;
3943}
3944
3945/*
Bram Moolenaar191929b2020-08-19 21:20:49 +02003946 * Set option "varname" to the value of "varp" for the current buffer/window.
3947 */
3948 static void
3949set_option_from_tv(char_u *varname, typval_T *varp)
3950{
3951 long numval = 0;
3952 char_u *strval;
3953 char_u nbuf[NUMBUFLEN];
3954 int error = FALSE;
3955
Bram Moolenaar31a201a2021-01-03 14:47:25 +01003956 if (varp->v_type == VAR_BOOL)
Bram Moolenaarb0d81822021-01-03 15:55:10 +01003957 {
Bram Moolenaar31a201a2021-01-03 14:47:25 +01003958 numval = (long)varp->vval.v_number;
Bram Moolenaarb0d81822021-01-03 15:55:10 +01003959 strval = (char_u *)"0"; // avoid using "false"
3960 }
3961 else
3962 {
3963 if (!in_vim9script() || varp->v_type != VAR_STRING)
3964 numval = (long)tv_get_number_chk(varp, &error);
3965 strval = tv_get_string_buf_chk(varp, nbuf);
3966 }
Bram Moolenaar191929b2020-08-19 21:20:49 +02003967 if (!error && strval != NULL)
3968 set_option_value(varname, numval, strval, OPT_LOCAL);
3969}
3970
3971/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003972 * "setwinvar()" and "settabwinvar()" functions
3973 */
3974 static void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01003975setwinvar(typval_T *argvars, int off)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003976{
3977 win_T *win;
Bram Moolenaar18f47402022-01-06 13:24:51 +00003978 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003979 int need_switch_win;
3980 char_u *varname, *winvarname;
3981 typval_T *varp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003982 tabpage_T *tp = NULL;
3983
3984 if (check_secure())
3985 return;
3986
3987 if (off == 1)
3988 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
3989 else
3990 tp = curtab;
3991 win = find_win_by_nr(&argvars[off], tp);
3992 varname = tv_get_string_chk(&argvars[off + 1]);
3993 varp = &argvars[off + 2];
3994
3995 if (win != NULL && varname != NULL && varp != NULL)
3996 {
3997 need_switch_win = !(tp == curtab && win == curwin);
3998 if (!need_switch_win
Bram Moolenaar18f47402022-01-06 13:24:51 +00003999 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004000 {
4001 if (*varname == '&')
Bram Moolenaar191929b2020-08-19 21:20:49 +02004002 set_option_from_tv(varname + 1, varp);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004003 else
4004 {
4005 winvarname = alloc(STRLEN(varname) + 3);
4006 if (winvarname != NULL)
4007 {
4008 STRCPY(winvarname, "w:");
4009 STRCPY(winvarname + 2, varname);
4010 set_var(winvarname, varp, TRUE);
4011 vim_free(winvarname);
4012 }
4013 }
4014 }
4015 if (need_switch_win)
Bram Moolenaar18f47402022-01-06 13:24:51 +00004016 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004017 }
4018}
4019
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004020/*
4021 * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
4022 * v:option_type, and v:option_command.
4023 */
4024 void
4025reset_v_option_vars(void)
4026{
4027 set_vim_var_string(VV_OPTION_NEW, NULL, -1);
4028 set_vim_var_string(VV_OPTION_OLD, NULL, -1);
4029 set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
4030 set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
4031 set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
4032 set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
4033}
4034
4035/*
4036 * Add an assert error to v:errors.
4037 */
4038 void
4039assert_error(garray_T *gap)
4040{
4041 struct vimvar *vp = &vimvars[VV_ERRORS];
4042
Bram Moolenaard787e402021-12-24 21:36:12 +00004043 if (vp->vv_tv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004044 // Make sure v:errors is a list.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004045 set_vim_var_list(VV_ERRORS, list_alloc());
4046 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
4047}
4048
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004049 int
4050var_exists(char_u *var)
4051{
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004052 char_u *arg = var;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004053 char_u *name;
4054 char_u *tofree;
4055 typval_T tv;
4056 int len = 0;
4057 int n = FALSE;
4058
4059 // get_name_len() takes care of expanding curly braces
4060 name = var;
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004061 len = get_name_len(&arg, &tofree, TRUE, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004062 if (len > 0)
4063 {
4064 if (tofree != NULL)
4065 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004066 n = (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01004067 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004068 if (n)
4069 {
4070 // handle d.key, l[idx], f(expr)
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004071 arg = skipwhite(arg);
Bram Moolenaar32884ad2022-01-07 12:45:29 +00004072 n = (handle_subscript(&arg, name, &tv, &EVALARG_EVALUATE,
4073 FALSE) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004074 if (n)
4075 clear_tv(&tv);
4076 }
4077 }
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004078 if (*arg != NUL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004079 n = FALSE;
4080
4081 vim_free(tofree);
4082 return n;
4083}
4084
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004085static lval_T *redir_lval = NULL;
4086#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
4087static garray_T redir_ga; // only valid when redir_lval is not NULL
4088static char_u *redir_endp = NULL;
4089static char_u *redir_varname = NULL;
4090
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004091 int
4092alloc_redir_lval(void)
4093{
4094 redir_lval = ALLOC_CLEAR_ONE(lval_T);
4095 if (redir_lval == NULL)
4096 return FAIL;
4097 return OK;
4098}
4099
4100 void
4101clear_redir_lval(void)
4102{
4103 VIM_CLEAR(redir_lval);
4104}
4105
4106 void
4107init_redir_ga(void)
4108{
Bram Moolenaar04935fb2022-01-08 16:19:22 +00004109 ga_init2(&redir_ga, sizeof(char), 500);
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004110}
4111
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004112/*
4113 * Start recording command output to a variable
4114 * When "append" is TRUE append to an existing variable.
4115 * Returns OK if successfully completed the setup. FAIL otherwise.
4116 */
4117 int
4118var_redir_start(char_u *name, int append)
4119{
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004120 int called_emsg_before;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004121 typval_T tv;
4122
4123 // Catch a bad name early.
4124 if (!eval_isnamec1(*name))
4125 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004126 emsg(_(e_invalid_argument));
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004127 return FAIL;
4128 }
4129
4130 // Make a copy of the name, it is used in redir_lval until redir ends.
4131 redir_varname = vim_strsave(name);
4132 if (redir_varname == NULL)
4133 return FAIL;
4134
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004135 if (alloc_redir_lval() == FAIL)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004136 {
4137 var_redir_stop();
4138 return FAIL;
4139 }
4140
4141 // The output is stored in growarray "redir_ga" until redirection ends.
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004142 init_redir_ga();
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004143
4144 // Parse the variable name (can be a dict or list entry).
4145 redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
4146 FNE_CHECK_START);
4147 if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
4148 {
4149 clear_lval(redir_lval);
4150 if (redir_endp != NULL && *redir_endp != NUL)
4151 // Trailing characters are present after the variable name
Bram Moolenaar74409f62022-01-01 15:58:22 +00004152 semsg(_(e_trailing_characters_str), redir_endp);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004153 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004154 semsg(_(e_invalid_argument_str), name);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004155 redir_endp = NULL; // don't store a value, only cleanup
4156 var_redir_stop();
4157 return FAIL;
4158 }
4159
4160 // check if we can write to the variable: set it to or append an empty
4161 // string
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004162 called_emsg_before = called_emsg;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004163 tv.v_type = VAR_STRING;
4164 tv.vval.v_string = (char_u *)"";
4165 if (append)
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004166 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004167 ASSIGN_NO_DECL, (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004168 else
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004169 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004170 ASSIGN_NO_DECL, (char_u *)"=", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004171 clear_lval(redir_lval);
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004172 if (called_emsg > called_emsg_before)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004173 {
4174 redir_endp = NULL; // don't store a value, only cleanup
4175 var_redir_stop();
4176 return FAIL;
4177 }
4178
4179 return OK;
4180}
4181
4182/*
4183 * Append "value[value_len]" to the variable set by var_redir_start().
4184 * The actual appending is postponed until redirection ends, because the value
4185 * appended may in fact be the string we write to, changing it may cause freed
4186 * memory to be used:
4187 * :redir => foo
4188 * :let foo
4189 * :redir END
4190 */
4191 void
4192var_redir_str(char_u *value, int value_len)
4193{
4194 int len;
4195
4196 if (redir_lval == NULL)
4197 return;
4198
4199 if (value_len == -1)
4200 len = (int)STRLEN(value); // Append the entire string
4201 else
4202 len = value_len; // Append only "value_len" characters
4203
4204 if (ga_grow(&redir_ga, len) == OK)
4205 {
4206 mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
4207 redir_ga.ga_len += len;
4208 }
4209 else
4210 var_redir_stop();
4211}
4212
4213/*
4214 * Stop redirecting command output to a variable.
4215 * Frees the allocated memory.
4216 */
4217 void
4218var_redir_stop(void)
4219{
4220 typval_T tv;
4221
4222 if (EVALCMD_BUSY)
4223 {
4224 redir_lval = NULL;
4225 return;
4226 }
4227
4228 if (redir_lval != NULL)
4229 {
4230 // If there was no error: assign the text to the variable.
4231 if (redir_endp != NULL)
4232 {
4233 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4234 tv.v_type = VAR_STRING;
4235 tv.vval.v_string = redir_ga.ga_data;
4236 // Call get_lval() again, if it's inside a Dict or List it may
4237 // have changed.
4238 redir_endp = get_lval(redir_varname, NULL, redir_lval,
4239 FALSE, FALSE, 0, FNE_CHECK_START);
4240 if (redir_endp != NULL && redir_lval->ll_name != NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004241 set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004242 (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004243 clear_lval(redir_lval);
4244 }
4245
4246 // free the collected output
4247 VIM_CLEAR(redir_ga.ga_data);
4248
4249 VIM_CLEAR(redir_lval);
4250 }
4251 VIM_CLEAR(redir_varname);
4252}
4253
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004254/*
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004255 * Get the collected redirected text and clear redir_ga.
4256 */
4257 char_u *
4258get_clear_redir_ga(void)
4259{
4260 char_u *res;
4261
4262 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4263 res = redir_ga.ga_data;
4264 redir_ga.ga_data = NULL;
4265 return res;
4266}
4267
4268/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004269 * "gettabvar()" function
4270 */
4271 void
4272f_gettabvar(typval_T *argvars, typval_T *rettv)
4273{
Bram Moolenaar18f47402022-01-06 13:24:51 +00004274 switchwin_T switchwin;
4275 tabpage_T *tp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004276 dictitem_T *v;
4277 char_u *varname;
4278 int done = FALSE;
4279
4280 rettv->v_type = VAR_STRING;
4281 rettv->vval.v_string = NULL;
4282
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004283 if (in_vim9script()
4284 && (check_for_number_arg(argvars, 0) == FAIL
4285 || check_for_string_arg(argvars, 1) == FAIL))
4286 return;
4287
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004288 varname = tv_get_string_chk(&argvars[1]);
4289 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4290 if (tp != NULL && varname != NULL)
4291 {
4292 // Set tp to be our tabpage, temporarily. Also set the window to the
4293 // first window in the tabpage, otherwise the window is not valid.
Bram Moolenaar18f47402022-01-06 13:24:51 +00004294 if (switch_win(&switchwin,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004295 tp == curtab || tp->tp_firstwin == NULL ? firstwin
4296 : tp->tp_firstwin, tp, TRUE) == OK)
4297 {
4298 // look up the variable
4299 // Let gettabvar({nr}, "") return the "t:" dictionary.
4300 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
4301 if (v != NULL)
4302 {
4303 copy_tv(&v->di_tv, rettv);
4304 done = TRUE;
4305 }
4306 }
4307
4308 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00004309 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004310 }
4311
4312 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4313 copy_tv(&argvars[2], rettv);
4314}
4315
4316/*
4317 * "gettabwinvar()" function
4318 */
4319 void
4320f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4321{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004322 if (in_vim9script()
4323 && (check_for_number_arg(argvars, 0) == FAIL
4324 || check_for_number_arg(argvars, 1) == FAIL
4325 || check_for_string_arg(argvars, 2) == FAIL))
4326 return;
4327
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004328 getwinvar(argvars, rettv, 1);
4329}
4330
4331/*
4332 * "getwinvar()" function
4333 */
4334 void
4335f_getwinvar(typval_T *argvars, typval_T *rettv)
4336{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004337 if (in_vim9script()
4338 && (check_for_number_arg(argvars, 0) == FAIL
4339 || check_for_string_arg(argvars, 1) == FAIL))
4340 return;
4341
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004342 getwinvar(argvars, rettv, 0);
4343}
4344
4345/*
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004346 * "getbufvar()" function
4347 */
4348 void
4349f_getbufvar(typval_T *argvars, typval_T *rettv)
4350{
4351 buf_T *buf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004352 char_u *varname;
4353 dictitem_T *v;
4354 int done = FALSE;
4355
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004356 if (in_vim9script()
4357 && (check_for_buffer_arg(argvars, 0) == FAIL
4358 || check_for_string_arg(argvars, 1) == FAIL))
4359 return;
4360
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004361 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004362 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004363
4364 rettv->v_type = VAR_STRING;
4365 rettv->vval.v_string = NULL;
4366
4367 if (buf != NULL && varname != NULL)
4368 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004369 if (*varname == '&')
4370 {
Bram Moolenaar86015452020-03-29 15:12:15 +02004371 buf_T *save_curbuf = curbuf;
4372
4373 // set curbuf to be our buf, temporarily
4374 curbuf = buf;
4375
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004376 if (varname[1] == NUL)
4377 {
4378 // get all buffer-local options in a dict
4379 dict_T *opts = get_winbuf_options(TRUE);
4380
4381 if (opts != NULL)
4382 {
4383 rettv_dict_set(rettv, opts);
4384 done = TRUE;
4385 }
4386 }
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02004387 else if (eval_option(&varname, rettv, TRUE) == OK)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004388 // buffer-local-option
4389 done = TRUE;
Bram Moolenaar86015452020-03-29 15:12:15 +02004390
4391 // restore previous notion of curbuf
4392 curbuf = save_curbuf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004393 }
4394 else
4395 {
4396 // Look up the variable.
Bram Moolenaar52592752020-04-03 18:43:35 +02004397 if (*varname == NUL)
4398 // Let getbufvar({nr}, "") return the "b:" dictionary.
4399 v = &buf->b_bufvar;
4400 else
4401 v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
4402 varname, FALSE);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004403 if (v != NULL)
4404 {
4405 copy_tv(&v->di_tv, rettv);
4406 done = TRUE;
4407 }
4408 }
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004409 }
4410
4411 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4412 // use the default value
4413 copy_tv(&argvars[2], rettv);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004414}
4415
4416/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004417 * "settabvar()" function
4418 */
4419 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004420f_settabvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004421{
4422 tabpage_T *save_curtab;
4423 tabpage_T *tp;
4424 char_u *varname, *tabvarname;
4425 typval_T *varp;
4426
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004427 if (check_secure())
4428 return;
4429
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004430 if (in_vim9script()
4431 && (check_for_number_arg(argvars, 0) == FAIL
4432 || check_for_string_arg(argvars, 1) == FAIL))
4433 return;
4434
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004435 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4436 varname = tv_get_string_chk(&argvars[1]);
4437 varp = &argvars[2];
4438
4439 if (varname != NULL && varp != NULL && tp != NULL)
4440 {
4441 save_curtab = curtab;
4442 goto_tabpage_tp(tp, FALSE, FALSE);
4443
4444 tabvarname = alloc(STRLEN(varname) + 3);
4445 if (tabvarname != NULL)
4446 {
4447 STRCPY(tabvarname, "t:");
4448 STRCPY(tabvarname + 2, varname);
4449 set_var(tabvarname, varp, TRUE);
4450 vim_free(tabvarname);
4451 }
4452
4453 // Restore current tabpage
4454 if (valid_tabpage(save_curtab))
4455 goto_tabpage_tp(save_curtab, FALSE, FALSE);
4456 }
4457}
4458
4459/*
4460 * "settabwinvar()" function
4461 */
4462 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004463f_settabwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004464{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004465 if (in_vim9script()
4466 && (check_for_number_arg(argvars, 0) == FAIL
4467 || check_for_number_arg(argvars, 1) == FAIL
4468 || check_for_string_arg(argvars, 2) == FAIL))
4469 return;
4470
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004471 setwinvar(argvars, 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004472}
4473
4474/*
4475 * "setwinvar()" function
4476 */
4477 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004478f_setwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004479{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004480 if (in_vim9script()
4481 && (check_for_number_arg(argvars, 0) == FAIL
4482 || check_for_string_arg(argvars, 1) == FAIL))
4483 return;
4484
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004485 setwinvar(argvars, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004486}
4487
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004488/*
4489 * "setbufvar()" function
4490 */
4491 void
4492f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
4493{
4494 buf_T *buf;
4495 char_u *varname, *bufvarname;
4496 typval_T *varp;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004497
4498 if (check_secure())
4499 return;
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004500
4501 if (in_vim9script()
4502 && (check_for_buffer_arg(argvars, 0) == FAIL
4503 || check_for_string_arg(argvars, 1) == FAIL))
4504 return;
4505
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004506 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004507 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004508 varp = &argvars[2];
4509
4510 if (buf != NULL && varname != NULL && varp != NULL)
4511 {
4512 if (*varname == '&')
4513 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004514 aco_save_T aco;
4515
4516 // set curbuf to be our buf, temporarily
4517 aucmd_prepbuf(&aco, buf);
4518
Bram Moolenaar191929b2020-08-19 21:20:49 +02004519 set_option_from_tv(varname + 1, varp);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004520
4521 // reset notion of buffer
4522 aucmd_restbuf(&aco);
4523 }
4524 else
4525 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004526 bufvarname = alloc(STRLEN(varname) + 3);
4527 if (bufvarname != NULL)
4528 {
Bram Moolenaar86015452020-03-29 15:12:15 +02004529 buf_T *save_curbuf = curbuf;
4530
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004531 curbuf = buf;
4532 STRCPY(bufvarname, "b:");
4533 STRCPY(bufvarname + 2, varname);
4534 set_var(bufvarname, varp, TRUE);
4535 vim_free(bufvarname);
4536 curbuf = save_curbuf;
4537 }
4538 }
4539 }
4540}
4541
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004542/*
4543 * Get a callback from "arg". It can be a Funcref or a function name.
4544 * When "arg" is zero return an empty string.
4545 * "cb_name" is not allocated.
4546 * "cb_name" is set to NULL for an invalid argument.
4547 */
4548 callback_T
4549get_callback(typval_T *arg)
4550{
Bram Moolenaar14e579092020-03-07 16:59:25 +01004551 callback_T res;
4552 int r = OK;
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004553
4554 res.cb_free_name = FALSE;
4555 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
4556 {
4557 res.cb_partial = arg->vval.v_partial;
4558 ++res.cb_partial->pt_refcount;
4559 res.cb_name = partial_name(res.cb_partial);
4560 }
4561 else
4562 {
4563 res.cb_partial = NULL;
Bram Moolenaar14e579092020-03-07 16:59:25 +01004564 if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
4565 && isdigit(*arg->vval.v_string))
4566 r = FAIL;
4567 else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004568 {
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00004569 if (arg->v_type == VAR_STRING)
4570 {
4571 char_u *name;
4572
4573 name = get_scriptlocal_funcname(arg->vval.v_string);
4574 if (name != NULL)
4575 {
4576 vim_free(arg->vval.v_string);
4577 arg->vval.v_string = name;
4578 }
4579 }
4580
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004581 res.cb_name = arg->vval.v_string;
4582 func_ref(res.cb_name);
4583 }
4584 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004585 res.cb_name = (char_u *)"";
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004586 else
Bram Moolenaar14e579092020-03-07 16:59:25 +01004587 r = FAIL;
4588
4589 if (r == FAIL)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004590 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00004591 emsg(_(e_invalid_callback_argument));
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004592 res.cb_name = NULL;
4593 }
4594 }
4595 return res;
4596}
4597
4598/*
4599 * Copy a callback into a typval_T.
4600 */
4601 void
4602put_callback(callback_T *cb, typval_T *tv)
4603{
4604 if (cb->cb_partial != NULL)
4605 {
4606 tv->v_type = VAR_PARTIAL;
4607 tv->vval.v_partial = cb->cb_partial;
4608 ++tv->vval.v_partial->pt_refcount;
4609 }
4610 else
4611 {
4612 tv->v_type = VAR_FUNC;
4613 tv->vval.v_string = vim_strsave(cb->cb_name);
4614 func_ref(cb->cb_name);
4615 }
4616}
4617
4618/*
4619 * Make a copy of "src" into "dest", allocating the function name if needed,
4620 * without incrementing the refcount.
4621 */
4622 void
4623set_callback(callback_T *dest, callback_T *src)
4624{
4625 if (src->cb_partial == NULL)
4626 {
4627 // just a function name, make a copy
4628 dest->cb_name = vim_strsave(src->cb_name);
4629 dest->cb_free_name = TRUE;
4630 }
4631 else
4632 {
4633 // cb_name is a pointer into cb_partial
4634 dest->cb_name = src->cb_name;
4635 dest->cb_free_name = FALSE;
4636 }
4637 dest->cb_partial = src->cb_partial;
4638}
4639
4640/*
Bram Moolenaard43906d2020-07-20 21:31:32 +02004641 * Copy callback from "src" to "dest", incrementing the refcounts.
4642 */
4643 void
4644copy_callback(callback_T *dest, callback_T *src)
4645{
4646 dest->cb_partial = src->cb_partial;
4647 if (dest->cb_partial != NULL)
4648 {
4649 dest->cb_name = src->cb_name;
4650 dest->cb_free_name = FALSE;
4651 ++dest->cb_partial->pt_refcount;
4652 }
4653 else
4654 {
4655 dest->cb_name = vim_strsave(src->cb_name);
4656 dest->cb_free_name = TRUE;
4657 func_ref(src->cb_name);
4658 }
4659}
4660
4661/*
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004662 * When a callback refers to an autoload import, change the function name to
4663 * the "path#name" form. Uses the current script context.
4664 * Only works when the name is allocated.
4665 */
4666 void
4667expand_autload_callback(callback_T *cb)
4668{
4669 char_u *p;
4670 imported_T *import;
4671
4672 if (!in_vim9script() || cb->cb_name == NULL || !cb->cb_free_name)
4673 return;
4674 p = vim_strchr(cb->cb_name, '.');
4675 if (p == NULL)
4676 return;
4677 import = find_imported(cb->cb_name, p - cb->cb_name, FALSE, NULL);
4678 if (import != NULL && SCRIPT_ID_VALID(import->imp_sid))
4679 {
4680 scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
4681
4682 if (si->sn_autoload_prefix != NULL)
4683 {
4684 char_u *name = concat_str(si->sn_autoload_prefix, p + 1);
4685
4686 if (name != NULL)
4687 {
4688 vim_free(cb->cb_name);
4689 cb->cb_name = name;
4690 }
4691 }
4692 }
4693}
4694
4695/*
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004696 * Unref/free "callback" returned by get_callback() or set_callback().
4697 */
4698 void
4699free_callback(callback_T *callback)
4700{
4701 if (callback->cb_partial != NULL)
4702 {
4703 partial_unref(callback->cb_partial);
4704 callback->cb_partial = NULL;
4705 }
4706 else if (callback->cb_name != NULL)
4707 func_unref(callback->cb_name);
4708 if (callback->cb_free_name)
4709 {
4710 vim_free(callback->cb_name);
4711 callback->cb_free_name = FALSE;
4712 }
4713 callback->cb_name = NULL;
4714}
4715
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004716#endif // FEAT_EVAL