blob: ffa7e93f7183a5c62c8537804588303e79f146b7 [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;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000372 sctx_T saved_sctx = current_sctx;
373 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200374
375 set_vim_var_string(VV_CC_FROM, enc_from, -1);
376 set_vim_var_string(VV_CC_TO, enc_to, -1);
377 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
378 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000379 ctx = get_option_sctx("charconvert");
380 if (ctx != NULL)
381 current_sctx = *ctx;
382
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200383 if (eval_to_bool(p_ccv, &err, NULL, FALSE))
384 err = TRUE;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000385
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200386 set_vim_var_string(VV_CC_FROM, NULL, -1);
387 set_vim_var_string(VV_CC_TO, NULL, -1);
388 set_vim_var_string(VV_FNAME_IN, NULL, -1);
389 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000390 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200391
392 if (err)
393 return FAIL;
394 return OK;
395}
396
397# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
398 int
399eval_printexpr(char_u *fname, char_u *args)
400{
401 int err = FALSE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000402 sctx_T saved_sctx = current_sctx;
403 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200404
405 set_vim_var_string(VV_FNAME_IN, fname, -1);
406 set_vim_var_string(VV_CMDARG, args, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000407 ctx = get_option_sctx("printexpr");
408 if (ctx != NULL)
409 current_sctx = *ctx;
410
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200411 if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
412 err = TRUE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000413
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200414 set_vim_var_string(VV_FNAME_IN, NULL, -1);
415 set_vim_var_string(VV_CMDARG, NULL, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000416 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200417
418 if (err)
419 {
420 mch_remove(fname);
421 return FAIL;
422 }
423 return OK;
424}
425# endif
426
427# if defined(FEAT_DIFF) || defined(PROTO)
428 void
429eval_diff(
430 char_u *origfile,
431 char_u *newfile,
432 char_u *outfile)
433{
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000434 sctx_T saved_sctx = current_sctx;
435 sctx_T *ctx;
436 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200437
438 set_vim_var_string(VV_FNAME_IN, origfile, -1);
439 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
440 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000441
442 ctx = get_option_sctx("diffexpr");
443 if (ctx != NULL)
444 current_sctx = *ctx;
445
446 // errors are ignored
447 tv = eval_expr(p_dex, NULL);
Bram Moolenaar39b89442022-01-22 18:21:36 +0000448 free_tv(tv);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000449
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200450 set_vim_var_string(VV_FNAME_IN, NULL, -1);
451 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
452 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000453 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200454}
455
456 void
457eval_patch(
458 char_u *origfile,
459 char_u *difffile,
460 char_u *outfile)
461{
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000462 sctx_T saved_sctx = current_sctx;
463 sctx_T *ctx;
464 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200465
466 set_vim_var_string(VV_FNAME_IN, origfile, -1);
467 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
468 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000469
470 ctx = get_option_sctx("patchexpr");
471 if (ctx != NULL)
472 current_sctx = *ctx;
473
474 // errors are ignored
475 tv = eval_expr(p_pex, NULL);
476 free_tv(tv);
477
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200478 set_vim_var_string(VV_FNAME_IN, NULL, -1);
479 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
480 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000481 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200482}
483# endif
484
485#if defined(FEAT_SPELL) || defined(PROTO)
486/*
487 * Evaluate an expression to a list with suggestions.
488 * For the "expr:" part of 'spellsuggest'.
489 * Returns NULL when there is an error.
490 */
491 list_T *
492eval_spell_expr(char_u *badword, char_u *expr)
493{
494 typval_T save_val;
495 typval_T rettv;
496 list_T *list = NULL;
497 char_u *p = skipwhite(expr);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000498 sctx_T saved_sctx = current_sctx;
499 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200500
501 // Set "v:val" to the bad word.
502 prepare_vimvar(VV_VAL, &save_val);
503 set_vim_var_string(VV_VAL, badword, -1);
504 if (p_verbose == 0)
505 ++emsg_off;
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000506 ctx = get_option_sctx("spellsuggest");
507 if (ctx != NULL)
508 current_sctx = *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200509
Bram Moolenaar5409f5d2020-06-24 18:37:35 +0200510 if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK)
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200511 {
512 if (rettv.v_type != VAR_LIST)
513 clear_tv(&rettv);
514 else
515 list = rettv.vval.v_list;
516 }
517
518 if (p_verbose == 0)
519 --emsg_off;
520 clear_tv(get_vim_var_tv(VV_VAL));
521 restore_vimvar(VV_VAL, &save_val);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000522 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200523
524 return list;
525}
526
527/*
528 * "list" is supposed to contain two items: a word and a number. Return the
529 * word in "pp" and the number as the return value.
530 * Return -1 if anything isn't right.
531 * Used to get the good word and score from the eval_spell_expr() result.
532 */
533 int
534get_spellword(list_T *list, char_u **pp)
535{
536 listitem_T *li;
537
538 li = list->lv_first;
539 if (li == NULL)
540 return -1;
541 *pp = tv_get_string(&li->li_tv);
542
543 li = li->li_next;
544 if (li == NULL)
545 return -1;
546 return (int)tv_get_number(&li->li_tv);
547}
548#endif
549
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200550/*
551 * Prepare v: variable "idx" to be used.
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200552 * Save the current typeval in "save_tv" and clear it.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200553 * When not used yet add the variable to the v: hashtable.
554 */
555 void
556prepare_vimvar(int idx, typval_T *save_tv)
557{
558 *save_tv = vimvars[idx].vv_tv;
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200559 vimvars[idx].vv_str = NULL; // don't free it now
Bram Moolenaard787e402021-12-24 21:36:12 +0000560 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200561 hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
562}
563
564/*
565 * Restore v: variable "idx" to typeval "save_tv".
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200566 * Note that the v: variable must have been cleared already.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200567 * When no longer defined, remove the variable from the v: hashtable.
568 */
569 void
570restore_vimvar(int idx, typval_T *save_tv)
571{
572 hashitem_T *hi;
573
574 vimvars[idx].vv_tv = *save_tv;
Bram Moolenaard787e402021-12-24 21:36:12 +0000575 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200576 {
577 hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
578 if (HASHITEM_EMPTY(hi))
579 internal_error("restore_vimvar()");
580 else
581 hash_remove(&vimvarht, hi);
582 }
583}
584
585/*
586 * List Vim variables.
587 */
588 static void
589list_vim_vars(int *first)
590{
591 list_hashtable_vars(&vimvarht, "v:", FALSE, first);
592}
593
594/*
595 * List script-local variables, if there is a script.
596 */
597 static void
598list_script_vars(int *first)
599{
Bram Moolenaare3d46852020-08-29 13:39:17 +0200600 if (SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200601 list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
602 "s:", FALSE, first);
603}
604
605/*
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100606 * Evaluate all the Vim expressions (`=expr`) in string "str" and return the
607 * resulting string. The caller must free the returned string.
608 */
609 static char_u *
610eval_all_expr_in_str(char_u *str)
611{
612 garray_T ga;
613 char_u *s;
614 char_u *p;
615 char_u save_c;
616 char_u *exprval;
617 int status;
618
619 ga_init2(&ga, 1, 80);
620 p = str;
621
622 // Look for `=expr`, evaluate the expression and replace `=expr` with the
623 // result.
624 while (*p != NUL)
625 {
626 s = p;
627 while (*p != NUL && (*p != '`' || p[1] != '='))
628 p++;
629 ga_concat_len(&ga, s, p - s);
630 if (*p == NUL)
631 break; // no backtick expression found
632
633 s = p;
634 p += 2; // skip `=
635
636 status = *p == NUL ? OK : skip_expr(&p, NULL);
637 if (status == FAIL || *p != '`')
638 {
639 // invalid expression or missing ending backtick
640 if (status != FAIL)
641 emsg(_(e_missing_backtick));
642 vim_free(ga.ga_data);
643 return NULL;
644 }
645 s += 2; // skip `=
646 save_c = *p;
647 *p = NUL;
648 exprval = eval_to_string(s, TRUE);
649 *p = save_c;
650 p++;
651 if (exprval == NULL)
652 {
653 // expression evaluation failed
654 vim_free(ga.ga_data);
655 return NULL;
656 }
657 ga_concat(&ga, exprval);
658 vim_free(exprval);
659 }
660 ga_append(&ga, NUL);
661
662 return ga.ga_data;
663}
664
665/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200666 * Get a list of lines from a HERE document. The here document is a list of
667 * lines surrounded by a marker.
668 * cmd << {marker}
669 * {line1}
670 * {line2}
671 * ....
672 * {marker}
673 *
674 * The {marker} is a string. If the optional 'trim' word is supplied before the
675 * marker, then the leading indentation before the lines (matching the
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100676 * indentation in the "cmd" line) is stripped.
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200677 *
678 * When getting lines for an embedded script (e.g. python, lua, perl, ruby,
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100679 * tcl, mzscheme), "script_get" is set to TRUE. In this case, if the marker is
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200680 * missing, then '.' is accepted as a marker.
681 *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100682 * When compiling a heredoc assignment to a variable in a Vim9 def function,
683 * "vim9compile" is set to TRUE. In this case, instead of generating a list of
684 * string values from the heredoc, vim9 instructions are generated. On success
685 * the returned list will be empty.
686 *
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100687 * Returns a List with {lines} or NULL on failure.
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200688 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100689 list_T *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100690heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200691{
Bram Moolenaar42ccb8d2022-04-18 15:45:23 +0100692 char_u *theline = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200693 char_u *marker;
694 list_T *l;
695 char_u *p;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100696 char_u *str;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200697 int marker_indent_len = 0;
698 int text_indent_len = 0;
699 char_u *text_indent = NULL;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200700 char_u dot[] = ".";
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200701 int comment_char = in_vim9script() ? '#' : '"';
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100702 int evalstr = FALSE;
703 int eval_failed = FALSE;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100704 cctx_T *cctx = vim9compile ? eap->cookie : NULL;
705 int count = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200706
707 if (eap->getline == NULL)
708 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000709 emsg(_(e_cannot_use_heredoc_here));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200710 return NULL;
711 }
712
713 // Check for the optional 'trim' word before the marker
714 cmd = skipwhite(cmd);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200715
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100716 while (TRUE)
717 {
718 if (STRNCMP(cmd, "trim", 4) == 0
719 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200720 {
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100721 cmd = skipwhite(cmd + 4);
722
723 // Trim the indentation from all the lines in the here document.
724 // The amount of indentation trimmed is the same as the indentation
725 // of the first line after the :let command line. To find the end
726 // marker the indent of the :let command line is trimmed.
727 p = *eap->cmdlinep;
728 while (VIM_ISWHITE(*p))
729 {
730 p++;
731 marker_indent_len++;
732 }
733 text_indent_len = -1;
734
735 continue;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200736 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100737 if (STRNCMP(cmd, "eval", 4) == 0
738 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
739 {
740 cmd = skipwhite(cmd + 4);
741 evalstr = TRUE;
742 continue;
743 }
744 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200745 }
746
747 // The marker is the next word.
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200748 if (*cmd != NUL && *cmd != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200749 {
750 marker = skipwhite(cmd);
751 p = skiptowhite(marker);
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200752 if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200753 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000754 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200755 return NULL;
756 }
757 *p = NUL;
Bram Moolenaar6ab09532020-05-01 14:10:13 +0200758 if (!script_get && vim_islower(*marker))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200759 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000760 emsg(_(e_marker_cannot_start_with_lower_case_letter));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200761 return NULL;
762 }
763 }
764 else
765 {
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200766 // When getting lines for an embedded script, if the marker is missing,
767 // accept '.' as the marker.
768 if (script_get)
769 marker = dot;
770 else
771 {
Bram Moolenaar1a992222021-12-31 17:25:48 +0000772 emsg(_(e_missing_marker));
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200773 return NULL;
774 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200775 }
776
777 l = list_alloc();
778 if (l == NULL)
779 return NULL;
780
781 for (;;)
782 {
783 int mi = 0;
784 int ti = 0;
785
Bram Moolenaar42ccb8d2022-04-18 15:45:23 +0100786 vim_free(theline);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200787 theline = eap->getline(NUL, eap->cookie, 0, FALSE);
788 if (theline == NULL)
789 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000790 semsg(_(e_missing_end_marker_str), marker);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200791 break;
792 }
793
794 // with "trim": skip the indent matching the :let line to find the
795 // marker
796 if (marker_indent_len > 0
797 && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0)
798 mi = marker_indent_len;
799 if (STRCMP(marker, theline + mi) == 0)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200800 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200801
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100802 // If expression evaluation failed in the heredoc, then skip till the
803 // end marker.
804 if (eval_failed)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100805 continue;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100806
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200807 if (text_indent_len == -1 && *theline != NUL)
808 {
809 // set the text indent from the first line.
810 p = theline;
811 text_indent_len = 0;
812 while (VIM_ISWHITE(*p))
813 {
814 p++;
815 text_indent_len++;
816 }
817 text_indent = vim_strnsave(theline, text_indent_len);
818 }
819 // with "trim": skip the indent matching the first line
820 if (text_indent != NULL)
821 for (ti = 0; ti < text_indent_len; ++ti)
822 if (theline[ti] != text_indent[ti])
823 break;
824
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100825 str = theline + ti;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100826 if (vim9compile)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100827 {
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100828 if (compile_heredoc_string(str, evalstr, cctx) == FAIL)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100829 {
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100830 vim_free(theline);
831 vim_free(text_indent);
832 return FAIL;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100833 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100834 count++;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100835 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100836 else
837 {
838 if (evalstr)
839 {
840 str = eval_all_expr_in_str(str);
841 if (str == NULL)
842 {
843 // expression evaluation failed
844 eval_failed = TRUE;
845 continue;
846 }
847 vim_free(theline);
848 theline = str;
849 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100850
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100851 if (list_append_string(l, str, -1) == FAIL)
852 break;
853 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200854 }
Bram Moolenaar42ccb8d2022-04-18 15:45:23 +0100855 vim_free(theline);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200856 vim_free(text_indent);
857
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100858 if (vim9compile && cctx->ctx_skip != SKIP_YES && !eval_failed)
859 generate_NEWLIST(cctx, count, FALSE);
860
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100861 if (eval_failed)
862 {
863 // expression evaluation in the heredoc failed
864 list_free(l);
865 return NULL;
866 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200867 return l;
868}
869
870/*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200871 * Vim9 variable declaration:
872 * ":var name"
873 * ":var name: type"
874 * ":var name = expr"
875 * ":var name: type = expr"
876 * etc.
877 */
878 void
879ex_var(exarg_T *eap)
880{
Bram Moolenaar330a3882022-03-05 11:05:57 +0000881 char_u *p = eap->cmd;
Bram Moolenaare1d12112022-03-05 11:37:48 +0000882 int has_var;
Bram Moolenaar330a3882022-03-05 11:05:57 +0000883
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200884 if (!in_vim9script())
885 {
886 semsg(_(e_str_cannot_be_used_in_legacy_vim_script), ":var");
887 return;
888 }
Bram Moolenaare1d12112022-03-05 11:37:48 +0000889 has_var = checkforcmd_noparen(&p, "var", 3);
890 if (current_sctx.sc_sid == 0 && has_var)
Bram Moolenaar0e1574c2022-03-03 17:05:35 +0000891 {
892 emsg(_(e_cannot_declare_variable_on_command_line));
893 return;
894 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200895 ex_let(eap);
896}
897
898/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200899 * ":let" list all variable values
900 * ":let var1 var2" list variable values
901 * ":let var = expr" assignment command.
902 * ":let var += expr" assignment command.
903 * ":let var -= expr" assignment command.
904 * ":let var *= expr" assignment command.
905 * ":let var /= expr" assignment command.
906 * ":let var %= expr" assignment command.
907 * ":let var .= expr" assignment command.
908 * ":let var ..= expr" assignment command.
909 * ":let [var1, var2] = expr" unpack list.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100910 * ":let var =<< ..." heredoc
Bram Moolenaard672dde2020-02-26 13:43:51 +0100911 * ":let var: string" Vim9 declaration
Bram Moolenaar2eec3792020-05-25 20:33:55 +0200912 *
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200913 * ":final var = expr" assignment command.
914 * ":final [var1, var2] = expr" unpack list.
915 *
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200916 * ":const" list all variable values
917 * ":const var1 var2" list variable values
918 * ":const var = expr" assignment command.
919 * ":const [var1, var2] = expr" unpack list.
920 */
921 void
Bram Moolenaar2eec3792020-05-25 20:33:55 +0200922ex_let(exarg_T *eap)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200923{
924 char_u *arg = eap->arg;
925 char_u *expr = NULL;
926 typval_T rettv;
927 int i;
928 int var_count = 0;
929 int semicolon = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200930 char_u op[4];
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200931 char_u *argend;
932 int first = TRUE;
933 int concat;
Bram Moolenaar32e35112020-05-14 22:41:15 +0200934 int has_assign;
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100935 int flags = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200936 int vim9script = in_vim9script();
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200937
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200938 if (eap->cmdidx == CMD_final && !vim9script)
939 {
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100940 // In legacy Vim script ":final" is short for ":finally".
941 ex_finally(eap);
942 return;
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200943 }
Bram Moolenaarc58f5452020-10-21 20:58:52 +0200944 if (eap->cmdidx == CMD_let && vim9script)
Bram Moolenaarcfcd0112020-09-27 15:19:27 +0200945 {
946 emsg(_(e_cannot_use_let_in_vim9_script));
947 return;
948 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200949
Bram Moolenaar89b474d2020-12-22 21:19:39 +0100950 if (eap->cmdidx == CMD_const)
951 flags |= ASSIGN_CONST;
952 else if (eap->cmdidx == CMD_final)
953 flags |= ASSIGN_FINAL;
954
955 // Vim9 assignment without ":let", ":const" or ":final"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100956 if (eap->arg == eap->cmd)
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200957 flags |= ASSIGN_NO_DECL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100958
Bram Moolenaar47a519a2020-06-14 23:05:10 +0200959 argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200960 if (argend == NULL)
961 return;
962 if (argend > arg && argend[-1] == '.') // for var.='str'
963 --argend;
964 expr = skipwhite(argend);
965 concat = expr[0] == '.'
Bram Moolenaardd9de502021-08-15 13:49:42 +0200966 && ((expr[1] == '=' && in_old_script(2))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200967 || (expr[1] == '.' && expr[2] == '='));
Bram Moolenaar32e35112020-05-14 22:41:15 +0200968 has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
969 && expr[1] == '=');
Bram Moolenaar822ba242020-05-24 23:00:18 +0200970 if (!has_assign && !concat)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200971 {
972 // ":let" without "=": list variables
973 if (*arg == '[')
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000974 emsg(_(e_invalid_argument));
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200975 else if (expr[0] == '.' && expr[1] == '=')
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000976 emsg(_(e_dot_equal_not_supported_with_script_version_two));
Bram Moolenaarfaac4102020-04-20 17:46:14 +0200977 else if (!ends_excmd2(eap->cmd, arg))
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200978 {
Bram Moolenaar63be3d42020-07-23 13:11:37 +0200979 if (vim9script)
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200980 {
Bram Moolenaarccc25aa2021-03-26 21:27:52 +0100981 if (!ends_excmd2(eap->cmd, skipwhite(argend)))
Bram Moolenaar74409f62022-01-01 15:58:22 +0000982 semsg(_(e_trailing_characters_str), argend);
Bram Moolenaarccc25aa2021-03-26 21:27:52 +0100983 else
984 // Vim9 declaration ":var name: type"
985 arg = vim9_declare_scriptvar(eap, arg);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200986 }
987 else
988 {
989 // ":let var1 var2" - list values
990 arg = list_arg_vars(eap, arg, &first);
991 }
992 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200993 else if (!eap->skip)
994 {
995 // ":let"
996 list_glob_vars(&first);
997 list_buf_vars(&first);
998 list_win_vars(&first);
999 list_tab_vars(&first);
1000 list_script_vars(&first);
1001 list_func_vars(&first);
1002 list_vim_vars(&first);
1003 }
Bram Moolenaar63b91732021-08-05 20:40:03 +02001004 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001005 }
1006 else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
1007 {
1008 list_T *l;
Bram Moolenaar81530e32021-07-28 21:25:49 +02001009 long cur_lnum = SOURCING_LNUM;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001010
1011 // HERE document
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +01001012 l = heredoc_get(eap, expr + 3, FALSE, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001013 if (l != NULL)
1014 {
1015 rettv_list_set(&rettv, l);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001016 if (!eap->skip)
1017 {
Bram Moolenaar81530e32021-07-28 21:25:49 +02001018 // errors are for the assignment, not the end marker
1019 SOURCING_LNUM = cur_lnum;
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001020 op[0] = '=';
1021 op[1] = NUL;
1022 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001023 flags, op);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001024 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001025 clear_tv(&rettv);
1026 }
1027 }
1028 else
1029 {
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02001030 evalarg_T evalarg;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001031 int len = 1;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001032
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02001033 CLEAR_FIELD(rettv);
Bram Moolenaar32e35112020-05-14 22:41:15 +02001034 i = FAIL;
1035 if (has_assign || concat)
1036 {
Bram Moolenaar9a562c12021-01-23 13:39:14 +01001037 int cur_lnum;
1038
Bram Moolenaar32e35112020-05-14 22:41:15 +02001039 op[0] = '=';
1040 op[1] = NUL;
1041 if (*expr != '=')
1042 {
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001043 if (vim9script && (flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar122616d2020-08-21 21:32:50 +02001044 {
1045 // +=, /=, etc. require an existing variable
1046 semsg(_(e_cannot_use_operator_on_new_variable), eap->arg);
1047 i = FAIL;
1048 }
1049 else if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
Bram Moolenaar32e35112020-05-14 22:41:15 +02001050 {
1051 op[0] = *expr; // +=, -=, *=, /=, %= or .=
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001052 ++len;
Bram Moolenaar32e35112020-05-14 22:41:15 +02001053 if (expr[0] == '.' && expr[1] == '.') // ..=
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001054 {
Bram Moolenaar32e35112020-05-14 22:41:15 +02001055 ++expr;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001056 ++len;
1057 }
Bram Moolenaar32e35112020-05-14 22:41:15 +02001058 }
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001059 expr += 2;
Bram Moolenaar32e35112020-05-14 22:41:15 +02001060 }
1061 else
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001062 ++expr;
1063
Bram Moolenaar7f2c3412021-11-29 16:01:49 +00001064 if (vim9script && !eap->skip && (!VIM_ISWHITE(*argend)
Bram Moolenaarc7e44a72020-07-29 21:37:43 +02001065 || !IS_WHITE_OR_NUL(*expr)))
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001066 {
1067 vim_strncpy(op, expr - len, len);
Bram Moolenaare7a73e02021-01-01 19:17:55 +01001068 semsg(_(e_white_space_required_before_and_after_str_at_str),
1069 op, argend);
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001070 i = FAIL;
1071 }
Bram Moolenaar32e35112020-05-14 22:41:15 +02001072
1073 if (eap->skip)
1074 ++emsg_skip;
Bram Moolenaar2eb6fc32021-07-25 14:13:53 +02001075 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
Bram Moolenaarc7e44a72020-07-29 21:37:43 +02001076 expr = skipwhite_and_linebreak(expr, &evalarg);
Bram Moolenaar9a562c12021-01-23 13:39:14 +01001077 cur_lnum = SOURCING_LNUM;
Bram Moolenaarb171fb12020-06-24 20:34:03 +02001078 i = eval0(expr, &rettv, eap, &evalarg);
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02001079 if (eap->skip)
1080 --emsg_skip;
Bram Moolenaarfaf86262020-06-27 23:07:36 +02001081 clear_evalarg(&evalarg, eap);
Bram Moolenaar9a562c12021-01-23 13:39:14 +01001082
1083 // Restore the line number so that any type error is given for the
1084 // declaration, not the expression.
1085 SOURCING_LNUM = cur_lnum;
Bram Moolenaar32e35112020-05-14 22:41:15 +02001086 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001087 if (eap->skip)
1088 {
1089 if (i != FAIL)
1090 clear_tv(&rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001091 }
Bram Moolenaar822ba242020-05-24 23:00:18 +02001092 else if (i != FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001093 {
1094 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001095 flags, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001096 clear_tv(&rettv);
1097 }
1098 }
1099}
1100
1101/*
Bram Moolenaar6c3843c2021-03-04 12:38:21 +01001102 * Assign the typeval "tv" to the variable or variables at "arg_start".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001103 * Handles both "var" with any type and "[var, var; var]" with a list type.
1104 * When "op" is not NULL it points to a string with characters that
1105 * must appear after the variable(s). Use "+", "-" or "." for add, subtract
1106 * or concatenate.
1107 * Returns OK or FAIL;
1108 */
1109 int
1110ex_let_vars(
1111 char_u *arg_start,
1112 typval_T *tv,
1113 int copy, // copy values from "tv", don't move
1114 int semicolon, // from skip_var_list()
1115 int var_count, // from skip_var_list()
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001116 int flags, // ASSIGN_FINAL, ASSIGN_CONST, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001117 char_u *op)
1118{
1119 char_u *arg = arg_start;
1120 list_T *l;
1121 int i;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001122 int var_idx = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001123 listitem_T *item;
1124 typval_T ltv;
1125
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001126 if (tv->v_type == VAR_VOID)
1127 {
1128 emsg(_(e_cannot_use_void_value));
1129 return FAIL;
1130 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001131 if (*arg != '[')
1132 {
1133 // ":let var = expr" or ":for var in list"
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001134 if (ex_let_one(arg, tv, copy, flags, op, op, var_idx) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001135 return FAIL;
1136 return OK;
1137 }
1138
1139 // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
1140 if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
1141 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001142 emsg(_(e_list_required));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001143 return FAIL;
1144 }
1145
1146 i = list_len(l);
1147 if (semicolon == 0 && var_count < i)
1148 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00001149 emsg(_(e_less_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001150 return FAIL;
1151 }
1152 if (var_count - semicolon > i)
1153 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00001154 emsg(_(e_more_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001155 return FAIL;
1156 }
1157
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02001158 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001159 item = l->lv_first;
1160 while (*arg != ']')
1161 {
1162 arg = skipwhite(arg + 1);
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001163 ++var_idx;
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001164 arg = ex_let_one(arg, &item->li_tv, TRUE,
1165 flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001166 item = item->li_next;
1167 if (arg == NULL)
1168 return FAIL;
1169
1170 arg = skipwhite(arg);
1171 if (*arg == ';')
1172 {
1173 // Put the rest of the list (may be empty) in the var after ';'.
1174 // Create a new list for this.
1175 l = list_alloc();
1176 if (l == NULL)
1177 return FAIL;
1178 while (item != NULL)
1179 {
1180 list_append_tv(l, &item->li_tv);
1181 item = item->li_next;
1182 }
1183
1184 ltv.v_type = VAR_LIST;
1185 ltv.v_lock = 0;
1186 ltv.vval.v_list = l;
1187 l->lv_refcount = 1;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001188 ++var_idx;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001189
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001190 arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
1191 flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001192 clear_tv(&ltv);
1193 if (arg == NULL)
1194 return FAIL;
1195 break;
1196 }
1197 else if (*arg != ',' && *arg != ']')
1198 {
1199 internal_error("ex_let_vars()");
1200 return FAIL;
1201 }
1202 }
1203
1204 return OK;
1205}
1206
1207/*
1208 * Skip over assignable variable "var" or list of variables "[var, var]".
1209 * Used for ":let varvar = expr" and ":for varvar in expr".
1210 * For "[var, var]" increment "*var_count" for each variable.
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001211 * for "[var, var; var]" set "semicolon" to 1.
1212 * If "silent" is TRUE do not give an "invalid argument" error message.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001213 * Return NULL for an error.
1214 */
1215 char_u *
1216skip_var_list(
1217 char_u *arg,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001218 int include_type,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001219 int *var_count,
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001220 int *semicolon,
1221 int silent)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001222{
1223 char_u *p, *s;
1224
1225 if (*arg == '[')
1226 {
1227 // "[var, var]": find the matching ']'.
1228 p = arg;
1229 for (;;)
1230 {
1231 p = skipwhite(p + 1); // skip whites after '[', ';' or ','
Bram Moolenaar036d0712021-01-17 20:23:38 +01001232 s = skip_var_one(p, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001233 if (s == p)
1234 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001235 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001236 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001237 return NULL;
1238 }
1239 ++*var_count;
1240
1241 p = skipwhite(s);
1242 if (*p == ']')
1243 break;
1244 else if (*p == ';')
1245 {
1246 if (*semicolon == 1)
1247 {
Bram Moolenaar8b716f52022-02-15 21:17:56 +00001248 if (!silent)
1249 emsg(_(e_double_semicolon_in_list_of_variables));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001250 return NULL;
1251 }
1252 *semicolon = 1;
1253 }
1254 else if (*p != ',')
1255 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001256 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001257 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001258 return NULL;
1259 }
1260 }
1261 return p + 1;
1262 }
1263 else
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001264 return skip_var_one(arg, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001265}
1266
1267/*
1268 * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
1269 * l[idx].
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001270 * In Vim9 script also skip over ": type" if "include_type" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001271 */
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001272 char_u *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001273skip_var_one(char_u *arg, int include_type)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001274{
Bram Moolenaar585587d2021-01-17 20:52:13 +01001275 char_u *end;
1276 int vim9 = in_vim9script();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001277
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001278 if (*arg == '@' && arg[1] != NUL)
1279 return arg + 2;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001280 end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001281 NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
Bram Moolenaar036d0712021-01-17 20:23:38 +01001282
1283 // "a: type" is declaring variable "a" with a type, not "a:".
1284 // Same for "s: type".
Bram Moolenaar585587d2021-01-17 20:52:13 +01001285 if (vim9 && end == arg + 2 && end[-1] == ':')
Bram Moolenaar036d0712021-01-17 20:23:38 +01001286 --end;
1287
Bram Moolenaar585587d2021-01-17 20:52:13 +01001288 if (include_type && vim9)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001289 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001290 if (*end == ':')
Bram Moolenaar4fc224c2020-07-26 17:56:25 +02001291 end = skip_type(skipwhite(end + 1), FALSE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001292 }
1293 return end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001294}
1295
1296/*
1297 * List variables for hashtab "ht" with prefix "prefix".
1298 * If "empty" is TRUE also list NULL strings as empty strings.
1299 */
1300 void
1301list_hashtable_vars(
1302 hashtab_T *ht,
1303 char *prefix,
1304 int empty,
1305 int *first)
1306{
1307 hashitem_T *hi;
1308 dictitem_T *di;
1309 int todo;
1310 char_u buf[IOSIZE];
1311
1312 todo = (int)ht->ht_used;
1313 for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
1314 {
1315 if (!HASHITEM_EMPTY(hi))
1316 {
1317 --todo;
1318 di = HI2DI(hi);
1319
1320 // apply :filter /pat/ to variable name
1321 vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
1322 vim_strcat((char_u *)buf, di->di_key, IOSIZE);
1323 if (message_filtered(buf))
1324 continue;
1325
1326 if (empty || di->di_tv.v_type != VAR_STRING
1327 || di->di_tv.vval.v_string != NULL)
1328 list_one_var(di, prefix, first);
1329 }
1330 }
1331}
1332
1333/*
1334 * List global variables.
1335 */
1336 static void
1337list_glob_vars(int *first)
1338{
1339 list_hashtable_vars(&globvarht, "", TRUE, first);
1340}
1341
1342/*
1343 * List buffer variables.
1344 */
1345 static void
1346list_buf_vars(int *first)
1347{
1348 list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
1349}
1350
1351/*
1352 * List window variables.
1353 */
1354 static void
1355list_win_vars(int *first)
1356{
1357 list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
1358}
1359
1360/*
1361 * List tab page variables.
1362 */
1363 static void
1364list_tab_vars(int *first)
1365{
1366 list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
1367}
1368
1369/*
1370 * List variables in "arg".
1371 */
1372 static char_u *
1373list_arg_vars(exarg_T *eap, char_u *arg, int *first)
1374{
1375 int error = FALSE;
1376 int len;
1377 char_u *name;
1378 char_u *name_start;
1379 char_u *arg_subsc;
1380 char_u *tofree;
1381 typval_T tv;
1382
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001383 while (!ends_excmd2(eap->cmd, arg) && !got_int)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001384 {
1385 if (error || eap->skip)
1386 {
1387 arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1388 if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
1389 {
1390 emsg_severe = TRUE;
Bram Moolenaar4830c212021-08-14 14:59:27 +02001391 if (!did_emsg)
Bram Moolenaar74409f62022-01-01 15:58:22 +00001392 semsg(_(e_trailing_characters_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001393 break;
1394 }
1395 }
1396 else
1397 {
1398 // get_name_len() takes care of expanding curly braces
1399 name_start = name = arg;
1400 len = get_name_len(&arg, &tofree, TRUE, TRUE);
1401 if (len <= 0)
1402 {
1403 // This is mainly to keep test 49 working: when expanding
1404 // curly braces fails overrule the exception error message.
1405 if (len < 0 && !aborting())
1406 {
1407 emsg_severe = TRUE;
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001408 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001409 break;
1410 }
1411 error = TRUE;
1412 }
1413 else
1414 {
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02001415 arg = skipwhite(arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001416 if (tofree != NULL)
1417 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00001418 if (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01001419 EVAL_VAR_VERBOSE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001420 error = TRUE;
1421 else
1422 {
1423 // handle d.key, l[idx], f(expr)
1424 arg_subsc = arg;
Bram Moolenaar32884ad2022-01-07 12:45:29 +00001425 if (handle_subscript(&arg, name_start, &tv,
1426 &EVALARG_EVALUATE, TRUE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001427 error = TRUE;
1428 else
1429 {
1430 if (arg == arg_subsc && len == 2 && name[1] == ':')
1431 {
1432 switch (*name)
1433 {
1434 case 'g': list_glob_vars(first); break;
1435 case 'b': list_buf_vars(first); break;
1436 case 'w': list_win_vars(first); break;
1437 case 't': list_tab_vars(first); break;
1438 case 'v': list_vim_vars(first); break;
1439 case 's': list_script_vars(first); break;
1440 case 'l': list_func_vars(first); break;
1441 default:
Bram Moolenaara6f79292022-01-04 21:30:47 +00001442 semsg(_(e_cant_list_variables_for_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001443 }
1444 }
1445 else
1446 {
1447 char_u numbuf[NUMBUFLEN];
1448 char_u *tf;
1449 int c;
1450 char_u *s;
1451
1452 s = echo_string(&tv, &tf, numbuf, 0);
1453 c = *arg;
1454 *arg = NUL;
1455 list_one_var_a("",
1456 arg == arg_subsc ? name : name_start,
1457 tv.v_type,
1458 s == NULL ? (char_u *)"" : s,
1459 first);
1460 *arg = c;
1461 vim_free(tf);
1462 }
1463 clear_tv(&tv);
1464 }
1465 }
1466 }
1467
1468 vim_free(tofree);
1469 }
1470
1471 arg = skipwhite(arg);
1472 }
1473
1474 return arg;
1475}
1476
1477/*
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001478 * Set an environment variable, part of ex_let_one().
1479 */
1480 static char_u *
1481ex_let_env(
1482 char_u *arg,
1483 typval_T *tv,
1484 int flags,
1485 char_u *endchars,
1486 char_u *op)
1487{
1488 char_u *arg_end = NULL;
1489 char_u *name;
1490 int len;
1491
1492 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1493 && (flags & ASSIGN_FOR_LOOP) == 0)
1494 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001495 emsg(_(e_cannot_lock_environment_variable));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001496 return NULL;
1497 }
1498
1499 // Find the end of the name.
1500 ++arg;
1501 name = arg;
1502 len = get_env_len(&arg);
1503 if (len == 0)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001504 semsg(_(e_invalid_argument_str), name - 1);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001505 else
1506 {
1507 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001508 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001509 else if (endchars != NULL
1510 && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1511 emsg(_(e_unexpected_characters_in_let));
1512 else if (!check_secure())
1513 {
1514 char_u *tofree = NULL;
1515 int c1 = name[len];
1516 char_u *p;
1517
1518 name[len] = NUL;
1519 p = tv_get_string_chk(tv);
1520 if (p != NULL && op != NULL && *op == '.')
1521 {
1522 int mustfree = FALSE;
1523 char_u *s = vim_getenv(name, &mustfree);
1524
1525 if (s != NULL)
1526 {
1527 p = tofree = concat_str(s, p);
1528 if (mustfree)
1529 vim_free(s);
1530 }
1531 }
1532 if (p != NULL)
1533 {
1534 vim_setenv_ext(name, p);
1535 arg_end = arg;
1536 }
1537 name[len] = c1;
1538 vim_free(tofree);
1539 }
1540 }
1541 return arg_end;
1542}
1543
1544/*
1545 * Set an option, part of ex_let_one().
1546 */
1547 static char_u *
1548ex_let_option(
1549 char_u *arg,
1550 typval_T *tv,
1551 int flags,
1552 char_u *endchars,
1553 char_u *op)
1554{
1555 char_u *p;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001556 int scope;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001557 char_u *arg_end = NULL;
1558
1559 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1560 && (flags & ASSIGN_FOR_LOOP) == 0)
1561 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001562 emsg(_(e_cannot_lock_option));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001563 return NULL;
1564 }
1565
1566 // Find the end of the name.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001567 p = find_option_end(&arg, &scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001568 if (p == NULL || (endchars != NULL
1569 && vim_strchr(endchars, *skipwhite(p)) == NULL))
1570 emsg(_(e_unexpected_characters_in_let));
1571 else
1572 {
1573 int c1;
1574 long n = 0;
1575 getoption_T opt_type;
1576 long numval;
1577 char_u *stringval = NULL;
1578 char_u *s = NULL;
1579 int failed = FALSE;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001580 int opt_p_flags;
1581 char_u *tofree = NULL;
Bram Moolenaar92c33eb2021-12-07 11:03:39 +00001582 char_u numbuf[NUMBUFLEN];
1583
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001584 c1 = *p;
1585 *p = NUL;
1586
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001587 opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags,
1588 scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001589 if ((opt_type == gov_bool
1590 || opt_type == gov_number
1591 || opt_type == gov_hidden_bool
1592 || opt_type == gov_hidden_number)
1593 && (tv->v_type != VAR_STRING || !in_vim9script()))
1594 {
1595 if (opt_type == gov_bool || opt_type == gov_hidden_bool)
1596 // bool, possibly hidden
1597 n = (long)tv_get_bool(tv);
1598 else
1599 // number, possibly hidden
1600 n = (long)tv_get_number(tv);
1601 }
1602
Bram Moolenaaref082e12021-12-12 21:02:03 +00001603 if ((opt_p_flags & P_FUNC) && (tv->v_type == VAR_PARTIAL
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001604 || tv->v_type == VAR_FUNC))
1605 {
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001606 // If the option can be set to a function reference or a lambda
1607 // and the passed value is a function reference, then convert it to
1608 // the name (string) of the function reference.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001609 s = tv2string(tv, &tofree, numbuf, 0);
1610 }
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001611 // Avoid setting a string option to the text "v:false" or similar.
1612 // In Vim9 script also don't convert a number to string.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001613 else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001614 && (!in_vim9script() || tv->v_type != VAR_NUMBER))
1615 s = tv_get_string_chk(tv);
1616
1617 if (op != NULL && *op != '=')
1618 {
1619 if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
1620 || (opt_type == gov_string && *op != '.'))
1621 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001622 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001623 failed = TRUE; // don't set the value
1624
1625 }
1626 else
1627 {
1628 // number, in legacy script also bool
1629 if (opt_type == gov_number
1630 || (opt_type == gov_bool && !in_vim9script()))
1631 {
1632 switch (*op)
1633 {
1634 case '+': n = numval + n; break;
1635 case '-': n = numval - n; break;
1636 case '*': n = numval * n; break;
1637 case '/': n = (long)num_divide(numval, n,
1638 &failed); break;
1639 case '%': n = (long)num_modulus(numval, n,
1640 &failed); break;
1641 }
1642 s = NULL;
1643 }
1644 else if (opt_type == gov_string
1645 && stringval != NULL && s != NULL)
1646 {
1647 // string
1648 s = concat_str(stringval, s);
1649 vim_free(stringval);
1650 stringval = s;
1651 }
1652 }
1653 }
1654
1655 if (!failed)
1656 {
1657 if (opt_type != gov_string || s != NULL)
1658 {
Bram Moolenaar8ccbbeb2022-03-02 19:49:38 +00001659 char *err = set_option_value(arg, n, s, scope);
1660
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001661 arg_end = p;
Bram Moolenaar8ccbbeb2022-03-02 19:49:38 +00001662 if (err != NULL)
1663 emsg(_(err));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001664 }
1665 else
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001666 emsg(_(e_string_required));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001667 }
1668 *p = c1;
1669 vim_free(stringval);
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001670 vim_free(tofree);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001671 }
1672 return arg_end;
1673}
1674
1675/*
1676 * Set a register, part of ex_let_one().
1677 */
1678 static char_u *
1679ex_let_register(
1680 char_u *arg,
1681 typval_T *tv,
1682 int flags,
1683 char_u *endchars,
1684 char_u *op)
1685{
1686 char_u *arg_end = NULL;
1687
1688 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1689 && (flags & ASSIGN_FOR_LOOP) == 0)
1690 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001691 emsg(_(e_cannot_lock_register));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001692 return NULL;
1693 }
1694 ++arg;
1695 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001696 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001697 else if (endchars != NULL
1698 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1699 emsg(_(e_unexpected_characters_in_let));
1700 else
1701 {
1702 char_u *ptofree = NULL;
1703 char_u *p;
1704
1705 p = tv_get_string_chk(tv);
1706 if (p != NULL && op != NULL && *op == '.')
1707 {
1708 char_u *s = get_reg_contents(*arg == '@'
1709 ? '"' : *arg, GREG_EXPR_SRC);
1710
1711 if (s != NULL)
1712 {
1713 p = ptofree = concat_str(s, p);
1714 vim_free(s);
1715 }
1716 }
1717 if (p != NULL)
1718 {
1719 write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
1720 arg_end = arg + 1;
1721 }
1722 vim_free(ptofree);
1723 }
1724 return arg_end;
1725}
1726
1727/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001728 * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
1729 * Returns a pointer to the char just after the var name.
1730 * Returns NULL if there is an error.
1731 */
1732 static char_u *
1733ex_let_one(
1734 char_u *arg, // points to variable name
1735 typval_T *tv, // value to assign to variable
1736 int copy, // copy value from "tv"
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001737 int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001738 char_u *endchars, // valid chars after variable name or NULL
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001739 char_u *op, // "+", "-", "." or NULL
1740 int var_idx) // variable index for "let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001741{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001742 char_u *arg_end = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001743
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001744 if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001745 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaarc2ee44c2020-08-02 16:59:00 +02001746 && vim_strchr((char_u *)"$@&", *arg) != NULL)
1747 {
1748 vim9_declare_error(arg);
1749 return NULL;
1750 }
1751
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001752 if (*arg == '$')
1753 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001754 // ":let $VAR = expr": Set environment variable.
1755 return ex_let_env(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001756 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001757 else if (*arg == '&')
1758 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001759 // ":let &option = expr": Set option value.
1760 // ":let &l:option = expr": Set local option value.
1761 // ":let &g:option = expr": Set global option value.
1762 // ":for &ts in range(8)": Set option value for for loop
1763 return ex_let_option(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001764 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001765 else if (*arg == '@')
1766 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001767 // ":let @r = expr": Set register contents.
1768 return ex_let_register(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001769 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001770 else if (eval_isnamec1(*arg) || *arg == '{')
1771 {
1772 lval_T lv;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001773 char_u *p;
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001774 int lval_flags = (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
1775 ? GLV_NO_DECL : 0;
1776 if (op != NULL && *op != '=')
1777 lval_flags |= GLV_ASSIGN_WITH_OP;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001778
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001779 // ":let var = expr": Set internal variable.
1780 // ":let var: type = expr": Set internal variable with type.
1781 // ":let {expr} = expr": Idem, name made with curly braces
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001782 p = get_lval(arg, tv, &lv, FALSE, FALSE, lval_flags, FNE_CHECK_START);
Bram Moolenaar822ba242020-05-24 23:00:18 +02001783 if (p != NULL && lv.ll_name != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001784 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001785 if (endchars != NULL && vim_strchr(endchars,
1786 *skipwhite(lv.ll_name_end)) == NULL)
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001787 {
Bram Moolenaar108010a2021-06-27 22:03:33 +02001788 emsg(_(e_unexpected_characters_in_let));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001789 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001790 else
1791 {
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001792 set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
Bram Moolenaara3589a02021-04-14 13:30:46 +02001793 arg_end = lv.ll_name_end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001794 }
1795 }
1796 clear_lval(&lv);
1797 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001798 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001799 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001800
1801 return arg_end;
1802}
1803
1804/*
1805 * ":unlet[!] var1 ... " command.
1806 */
1807 void
1808ex_unlet(exarg_T *eap)
1809{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001810 ex_unletlock(eap, eap->arg, 0, 0, do_unlet_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001811}
1812
1813/*
1814 * ":lockvar" and ":unlockvar" commands
1815 */
1816 void
1817ex_lockvar(exarg_T *eap)
1818{
1819 char_u *arg = eap->arg;
1820 int deep = 2;
1821
1822 if (eap->forceit)
1823 deep = -1;
1824 else if (vim_isdigit(*arg))
1825 {
1826 deep = getdigits(&arg);
1827 arg = skipwhite(arg);
1828 }
1829
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001830 ex_unletlock(eap, arg, deep, 0, do_lock_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001831}
1832
1833/*
1834 * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001835 * Also used for Vim9 script. "callback" is invoked as:
1836 * callback(&lv, name_end, eap, deep, cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001837 */
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001838 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001839ex_unletlock(
1840 exarg_T *eap,
1841 char_u *argstart,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001842 int deep,
1843 int glv_flags,
1844 int (*callback)(lval_T *, char_u *, exarg_T *, int, void *),
1845 void *cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001846{
1847 char_u *arg = argstart;
1848 char_u *name_end;
1849 int error = FALSE;
1850 lval_T lv;
1851
1852 do
1853 {
1854 if (*arg == '$')
1855 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001856 lv.ll_name = arg;
1857 lv.ll_tv = NULL;
1858 ++arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001859 if (get_env_len(&arg) == 0)
1860 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001861 semsg(_(e_invalid_argument_str), arg - 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001862 return;
1863 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001864 if (!error && !eap->skip
1865 && callback(&lv, arg, eap, deep, cookie) == FAIL)
1866 error = TRUE;
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001867 name_end = arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001868 }
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001869 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001870 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001871 // Parse the name and find the end.
1872 name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error,
Bram Moolenaarc3689572021-01-01 19:40:02 +01001873 glv_flags | GLV_NO_DECL, FNE_CHECK_START);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001874 if (lv.ll_name == NULL)
1875 error = TRUE; // error but continue parsing
1876 if (name_end == NULL || (!VIM_ISWHITE(*name_end)
1877 && !ends_excmd(*name_end)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001878 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001879 if (name_end != NULL)
1880 {
1881 emsg_severe = TRUE;
Bram Moolenaar74409f62022-01-01 15:58:22 +00001882 semsg(_(e_trailing_characters_str), name_end);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001883 }
1884 if (!(eap->skip || error))
1885 clear_lval(&lv);
1886 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001887 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001888
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001889 if (!error && !eap->skip
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001890 && callback(&lv, name_end, eap, deep, cookie) == FAIL)
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001891 error = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001892
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02001893 if (!eap->skip)
1894 clear_lval(&lv);
1895 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001896
1897 arg = skipwhite(name_end);
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001898 } while (!ends_excmd2(name_end, arg));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001899
Bram Moolenaar63b91732021-08-05 20:40:03 +02001900 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001901}
1902
1903 static int
1904do_unlet_var(
1905 lval_T *lp,
1906 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001907 exarg_T *eap,
1908 int deep UNUSED,
1909 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001910{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001911 int forceit = eap->forceit;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001912 int ret = OK;
1913 int cc;
1914
1915 if (lp->ll_tv == NULL)
1916 {
1917 cc = *name_end;
1918 *name_end = NUL;
1919
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001920 // Environment variable, normal name or expanded name.
1921 if (*lp->ll_name == '$')
LemonBoy77142312022-04-15 20:50:46 +01001922 vim_unsetenv_ext(lp->ll_name + 1);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001923 else if (do_unlet(lp->ll_name, forceit) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001924 ret = FAIL;
1925 *name_end = cc;
1926 }
1927 else if ((lp->ll_list != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02001928 && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001929 || (lp->ll_dict != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02001930 && value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001931 return FAIL;
1932 else if (lp->ll_range)
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00001933 list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_n1,
1934 !lp->ll_empty2, lp->ll_n2);
1935 else if (lp->ll_list != NULL)
1936 // unlet a List item.
1937 listitem_remove(lp->ll_list, lp->ll_li);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001938 else
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00001939 // unlet a Dictionary item.
1940 dictitem_remove(lp->ll_dict, lp->ll_di);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001941
1942 return ret;
1943}
1944
1945/*
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001946 * Unlet one item or a range of items from a list.
1947 * Return OK or FAIL.
1948 */
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00001949 void
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001950list_unlet_range(
1951 list_T *l,
1952 listitem_T *li_first,
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001953 long n1_arg,
1954 int has_n2,
1955 long n2)
1956{
1957 listitem_T *li = li_first;
1958 int n1 = n1_arg;
1959
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001960 // Delete a range of List items.
1961 li = li_first;
1962 n1 = n1_arg;
1963 while (li != NULL && (!has_n2 || n2 >= n1))
1964 {
1965 listitem_T *next = li->li_next;
1966
1967 listitem_remove(l, li);
1968 li = next;
1969 ++n1;
1970 }
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01001971}
1972/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001973 * "unlet" a variable. Return OK if it existed, FAIL if not.
1974 * When "forceit" is TRUE don't complain if the variable doesn't exist.
1975 */
1976 int
1977do_unlet(char_u *name, int forceit)
1978{
1979 hashtab_T *ht;
1980 hashitem_T *hi;
1981 char_u *varname;
1982 dict_T *d;
1983 dictitem_T *di;
1984
Bram Moolenaar9aed7292020-12-18 15:38:00 +01001985 // can't :unlet a script variable in Vim9 script
Bram Moolenaareb6880b2020-07-12 17:07:05 +02001986 if (in_vim9script() && check_vim9_unlet(name) == FAIL)
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001987 return FAIL;
1988
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001989 ht = find_var_ht(name, &varname);
Bram Moolenaar9aed7292020-12-18 15:38:00 +01001990
1991 // can't :unlet a script variable in Vim9 script from a function
1992 if (ht == get_script_local_ht()
1993 && SCRIPT_ID_VALID(current_sctx.sc_sid)
1994 && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
1995 == SCRIPT_VERSION_VIM9
1996 && check_vim9_unlet(name) == FAIL)
1997 return FAIL;
1998
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001999 if (ht != NULL && *varname != NUL)
2000 {
2001 d = get_current_funccal_dict(ht);
2002 if (d == NULL)
2003 {
2004 if (ht == &globvarht)
2005 d = &globvardict;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002006 else if (ht == &compat_hashtab)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002007 d = &vimvardict;
2008 else
2009 {
2010 di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
2011 d = di == NULL ? NULL : di->di_tv.vval.v_dict;
2012 }
2013 if (d == NULL)
2014 {
2015 internal_error("do_unlet()");
2016 return FAIL;
2017 }
2018 }
2019 hi = hash_find(ht, varname);
2020 if (HASHITEM_EMPTY(hi))
2021 hi = find_hi_in_scoped_ht(name, &ht);
2022 if (hi != NULL && !HASHITEM_EMPTY(hi))
2023 {
2024 di = HI2DI(hi);
2025 if (var_check_fixed(di->di_flags, name, FALSE)
2026 || var_check_ro(di->di_flags, name, FALSE)
Bram Moolenaara187c432020-09-16 21:08:28 +02002027 || value_check_lock(d->dv_lock, name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002028 return FAIL;
2029
2030 delete_var(ht, hi);
2031 return OK;
2032 }
2033 }
2034 if (forceit)
2035 return OK;
Bram Moolenaare1242042021-12-16 20:56:57 +00002036 semsg(_(e_no_such_variable_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002037 return FAIL;
2038}
2039
2040/*
2041 * Lock or unlock variable indicated by "lp".
2042 * "deep" is the levels to go (-1 for unlimited);
2043 * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
2044 */
2045 static int
2046do_lock_var(
2047 lval_T *lp,
2048 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002049 exarg_T *eap,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002050 int deep,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002051 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002052{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002053 int lock = eap->cmdidx == CMD_lockvar;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002054 int ret = OK;
2055 int cc;
2056 dictitem_T *di;
2057
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002058 if (lp->ll_tv == NULL)
2059 {
2060 cc = *name_end;
2061 *name_end = NUL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002062 if (*lp->ll_name == '$')
2063 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00002064 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002065 ret = FAIL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002066 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002067 else
2068 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002069 // Normal name or expanded name.
2070 di = find_var(lp->ll_name, NULL, TRUE);
2071 if (di == NULL)
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002072 {
2073 if (in_vim9script())
2074 semsg(_(e_cannot_find_variable_to_unlock_str),
2075 lp->ll_name);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002076 ret = FAIL;
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002077 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002078 else
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002079 {
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002080 if ((di->di_flags & DI_FLAGS_FIX)
2081 && di->di_tv.v_type != VAR_DICT
2082 && di->di_tv.v_type != VAR_LIST)
2083 {
2084 // For historic reasons this error is not given for a list
2085 // or dict. E.g., the b: dict could be locked/unlocked.
2086 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
2087 ret = FAIL;
2088 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002089 else
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002090 {
2091 if (in_vim9script())
2092 {
2093 svar_T *sv = find_typval_in_script(&di->di_tv,
2094 0, FALSE);
2095
2096 if (sv != NULL && sv->sv_const != 0)
2097 {
2098 semsg(_(e_cannot_change_readonly_variable_str),
2099 lp->ll_name);
2100 ret = FAIL;
2101 }
2102 }
2103
2104 if (ret == OK)
2105 {
2106 if (lock)
2107 di->di_flags |= DI_FLAGS_LOCK;
2108 else
2109 di->di_flags &= ~DI_FLAGS_LOCK;
2110 if (deep != 0)
2111 item_lock(&di->di_tv, deep, lock, FALSE);
2112 }
2113 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002114 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002115 }
2116 *name_end = cc;
2117 }
Bram Moolenaara187c432020-09-16 21:08:28 +02002118 else if (deep == 0)
2119 {
2120 // nothing to do
2121 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002122 else if (lp->ll_range)
2123 {
2124 listitem_T *li = lp->ll_li;
2125
2126 // (un)lock a range of List items.
2127 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
2128 {
Bram Moolenaar021bda52020-08-17 21:07:22 +02002129 item_lock(&li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002130 li = li->li_next;
2131 ++lp->ll_n1;
2132 }
2133 }
2134 else if (lp->ll_list != NULL)
2135 // (un)lock a List item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002136 item_lock(&lp->ll_li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002137 else
2138 // (un)lock a Dictionary item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002139 item_lock(&lp->ll_di->di_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002140
2141 return ret;
2142}
2143
2144/*
2145 * Lock or unlock an item. "deep" is nr of levels to go.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002146 * When "check_refcount" is TRUE do not lock a list or dict with a reference
2147 * count larger than 1.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002148 */
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002149 void
Bram Moolenaar021bda52020-08-17 21:07:22 +02002150item_lock(typval_T *tv, int deep, int lock, int check_refcount)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002151{
2152 static int recurse = 0;
2153 list_T *l;
2154 listitem_T *li;
2155 dict_T *d;
2156 blob_T *b;
2157 hashitem_T *hi;
2158 int todo;
2159
2160 if (recurse >= DICT_MAXNEST)
2161 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002162 emsg(_(e_variable_nested_too_deep_for_unlock));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002163 return;
2164 }
2165 if (deep == 0)
2166 return;
2167 ++recurse;
2168
2169 // lock/unlock the item itself
2170 if (lock)
2171 tv->v_lock |= VAR_LOCKED;
2172 else
2173 tv->v_lock &= ~VAR_LOCKED;
2174
2175 switch (tv->v_type)
2176 {
2177 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002178 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002179 case VAR_VOID:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002180 case VAR_NUMBER:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002181 case VAR_BOOL:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002182 case VAR_STRING:
2183 case VAR_FUNC:
2184 case VAR_PARTIAL:
2185 case VAR_FLOAT:
2186 case VAR_SPECIAL:
2187 case VAR_JOB:
2188 case VAR_CHANNEL:
Bram Moolenaarf18332f2021-05-07 17:55:55 +02002189 case VAR_INSTR:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002190 break;
2191
2192 case VAR_BLOB:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002193 if ((b = tv->vval.v_blob) != NULL
2194 && !(check_refcount && b->bv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002195 {
2196 if (lock)
2197 b->bv_lock |= VAR_LOCKED;
2198 else
2199 b->bv_lock &= ~VAR_LOCKED;
2200 }
2201 break;
2202 case VAR_LIST:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002203 if ((l = tv->vval.v_list) != NULL
2204 && !(check_refcount && l->lv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002205 {
2206 if (lock)
2207 l->lv_lock |= VAR_LOCKED;
2208 else
2209 l->lv_lock &= ~VAR_LOCKED;
Bram Moolenaar70c43d82022-01-26 21:01:15 +00002210 if (deep < 0 || deep > 1)
2211 {
2212 if (l->lv_first == &range_list_item)
2213 l->lv_lock |= VAR_ITEMS_LOCKED;
2214 else
2215 {
2216 // recursive: lock/unlock the items the List contains
2217 CHECK_LIST_MATERIALIZE(l);
2218 FOR_ALL_LIST_ITEMS(l, li) item_lock(&li->li_tv,
2219 deep - 1, lock, check_refcount);
2220 }
2221 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002222 }
2223 break;
2224 case VAR_DICT:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002225 if ((d = tv->vval.v_dict) != NULL
2226 && !(check_refcount && d->dv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002227 {
2228 if (lock)
2229 d->dv_lock |= VAR_LOCKED;
2230 else
2231 d->dv_lock &= ~VAR_LOCKED;
2232 if (deep < 0 || deep > 1)
2233 {
2234 // recursive: lock/unlock the items the List contains
2235 todo = (int)d->dv_hashtab.ht_used;
2236 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2237 {
2238 if (!HASHITEM_EMPTY(hi))
2239 {
2240 --todo;
Bram Moolenaar021bda52020-08-17 21:07:22 +02002241 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock,
2242 check_refcount);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002243 }
2244 }
2245 }
2246 }
2247 }
2248 --recurse;
2249}
2250
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002251#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
2252/*
2253 * Delete all "menutrans_" variables.
2254 */
2255 void
2256del_menutrans_vars(void)
2257{
2258 hashitem_T *hi;
2259 int todo;
2260
2261 hash_lock(&globvarht);
2262 todo = (int)globvarht.ht_used;
2263 for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
2264 {
2265 if (!HASHITEM_EMPTY(hi))
2266 {
2267 --todo;
2268 if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
2269 delete_var(&globvarht, hi);
2270 }
2271 }
2272 hash_unlock(&globvarht);
2273}
2274#endif
2275
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002276/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002277 * Local string buffer for the next two functions to store a variable name
2278 * with its prefix. Allocated in cat_prefix_varname(), freed later in
2279 * get_user_var_name().
2280 */
2281
2282static char_u *varnamebuf = NULL;
2283static int varnamebuflen = 0;
2284
2285/*
2286 * Function to concatenate a prefix and a variable name.
2287 */
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01002288 char_u *
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002289cat_prefix_varname(int prefix, char_u *name)
2290{
2291 int len;
2292
2293 len = (int)STRLEN(name) + 3;
2294 if (len > varnamebuflen)
2295 {
2296 vim_free(varnamebuf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002297 len += 10; // some additional space
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002298 varnamebuf = alloc(len);
2299 if (varnamebuf == NULL)
2300 {
2301 varnamebuflen = 0;
2302 return NULL;
2303 }
2304 varnamebuflen = len;
2305 }
2306 *varnamebuf = prefix;
2307 varnamebuf[1] = ':';
2308 STRCPY(varnamebuf + 2, name);
2309 return varnamebuf;
2310}
2311
2312/*
2313 * Function given to ExpandGeneric() to obtain the list of user defined
2314 * (global/buffer/window/built-in) variable names.
2315 */
2316 char_u *
2317get_user_var_name(expand_T *xp, int idx)
2318{
2319 static long_u gdone;
2320 static long_u bdone;
2321 static long_u wdone;
2322 static long_u tdone;
2323 static int vidx;
2324 static hashitem_T *hi;
2325 hashtab_T *ht;
2326
2327 if (idx == 0)
2328 {
2329 gdone = bdone = wdone = vidx = 0;
2330 tdone = 0;
2331 }
2332
2333 // Global variables
2334 if (gdone < globvarht.ht_used)
2335 {
2336 if (gdone++ == 0)
2337 hi = globvarht.ht_array;
2338 else
2339 ++hi;
2340 while (HASHITEM_EMPTY(hi))
2341 ++hi;
2342 if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
2343 return cat_prefix_varname('g', hi->hi_key);
2344 return hi->hi_key;
2345 }
2346
2347 // b: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002348 ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002349 if (bdone < ht->ht_used)
2350 {
2351 if (bdone++ == 0)
2352 hi = ht->ht_array;
2353 else
2354 ++hi;
2355 while (HASHITEM_EMPTY(hi))
2356 ++hi;
2357 return cat_prefix_varname('b', hi->hi_key);
2358 }
2359
2360 // w: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002361 ht = &prevwin_curwin()->w_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002362 if (wdone < ht->ht_used)
2363 {
2364 if (wdone++ == 0)
2365 hi = ht->ht_array;
2366 else
2367 ++hi;
2368 while (HASHITEM_EMPTY(hi))
2369 ++hi;
2370 return cat_prefix_varname('w', hi->hi_key);
2371 }
2372
2373 // t: variables
2374 ht = &curtab->tp_vars->dv_hashtab;
2375 if (tdone < ht->ht_used)
2376 {
2377 if (tdone++ == 0)
2378 hi = ht->ht_array;
2379 else
2380 ++hi;
2381 while (HASHITEM_EMPTY(hi))
2382 ++hi;
2383 return cat_prefix_varname('t', hi->hi_key);
2384 }
2385
2386 // v: variables
2387 if (vidx < VV_LEN)
2388 return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
2389
2390 VIM_CLEAR(varnamebuf);
2391 varnamebuflen = 0;
2392 return NULL;
2393}
2394
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002395 char *
2396get_var_special_name(int nr)
2397{
2398 switch (nr)
2399 {
Bram Moolenaara8b8af12021-01-01 15:11:04 +01002400 case VVAL_FALSE: return in_vim9script() ? "false" : "v:false";
2401 case VVAL_TRUE: return in_vim9script() ? "true" : "v:true";
Bram Moolenaar67977822021-01-03 21:53:53 +01002402 case VVAL_NULL: return in_vim9script() ? "null" : "v:null";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002403 case VVAL_NONE: return "v:none";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002404 }
2405 internal_error("get_var_special_name()");
2406 return "42";
2407}
2408
2409/*
2410 * Returns the global variable dictionary
2411 */
2412 dict_T *
2413get_globvar_dict(void)
2414{
2415 return &globvardict;
2416}
2417
2418/*
2419 * Returns the global variable hash table
2420 */
2421 hashtab_T *
2422get_globvar_ht(void)
2423{
2424 return &globvarht;
2425}
2426
2427/*
2428 * Returns the v: variable dictionary
2429 */
2430 dict_T *
2431get_vimvar_dict(void)
2432{
2433 return &vimvardict;
2434}
2435
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002436/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002437 * Returns the index of a v:variable. Negative if not found.
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002438 * Returns DI_ flags in "di_flags".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002439 */
2440 int
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002441find_vim_var(char_u *name, int *di_flags)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002442{
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002443 dictitem_T *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
2444 struct vimvar *vv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002445
2446 if (di == NULL)
2447 return -1;
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002448 *di_flags = di->di_flags;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002449 vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
2450 return (int)(vv - vimvars);
2451}
2452
2453
2454/*
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002455 * Set type of v: variable to "type".
2456 */
2457 void
2458set_vim_var_type(int idx, vartype_T type)
2459{
Bram Moolenaard787e402021-12-24 21:36:12 +00002460 vimvars[idx].vv_tv_type = type;
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002461}
2462
2463/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002464 * Set number v: variable to "val".
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002465 * Note that this does not set the type, use set_vim_var_type() for that.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002466 */
2467 void
2468set_vim_var_nr(int idx, varnumber_T val)
2469{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002470 vimvars[idx].vv_nr = val;
2471}
2472
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002473 char *
2474get_vim_var_name(int idx)
2475{
2476 return vimvars[idx].vv_name;
2477}
2478
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002479/*
2480 * Get typval_T v: variable value.
2481 */
2482 typval_T *
2483get_vim_var_tv(int idx)
2484{
2485 return &vimvars[idx].vv_tv;
2486}
2487
Bram Moolenaard787e402021-12-24 21:36:12 +00002488 type_T *
2489get_vim_var_type(int idx, garray_T *type_list)
2490{
2491 if (vimvars[idx].vv_type != NULL)
2492 return vimvars[idx].vv_type;
2493 return typval2type_vimvar(&vimvars[idx].vv_tv, type_list);
2494}
2495
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002496/*
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002497 * Set v: variable to "tv". Only accepts the same type.
2498 * Takes over the value of "tv".
2499 */
2500 int
2501set_vim_var_tv(int idx, typval_T *tv)
2502{
Bram Moolenaard787e402021-12-24 21:36:12 +00002503 if (vimvars[idx].vv_tv_type != tv->v_type)
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002504 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002505 emsg(_(e_type_mismatch_for_v_variable));
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002506 clear_tv(tv);
2507 return FAIL;
2508 }
Bram Moolenaarcab27672020-04-09 20:10:55 +02002509 // VV_RO is also checked when compiling, but let's check here as well.
2510 if (vimvars[idx].vv_flags & VV_RO)
2511 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02002512 semsg(_(e_cannot_change_readonly_variable_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002513 return FAIL;
2514 }
2515 if (sandbox && (vimvars[idx].vv_flags & VV_RO_SBX))
2516 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00002517 semsg(_(e_cannot_set_variable_in_sandbox_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002518 return FAIL;
2519 }
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002520 clear_tv(&vimvars[idx].vv_di.di_tv);
2521 vimvars[idx].vv_di.di_tv = *tv;
2522 return OK;
2523}
2524
2525/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002526 * Get number v: variable value.
2527 */
2528 varnumber_T
2529get_vim_var_nr(int idx)
2530{
2531 return vimvars[idx].vv_nr;
2532}
2533
2534/*
2535 * Get string v: variable value. Uses a static buffer, can only be used once.
2536 * If the String variable has never been set, return an empty string.
2537 * Never returns NULL;
2538 */
2539 char_u *
2540get_vim_var_str(int idx)
2541{
2542 return tv_get_string(&vimvars[idx].vv_tv);
2543}
2544
2545/*
2546 * Get List v: variable value. Caller must take care of reference count when
2547 * needed.
2548 */
2549 list_T *
2550get_vim_var_list(int idx)
2551{
2552 return vimvars[idx].vv_list;
2553}
2554
2555/*
2556 * Get Dict v: variable value. Caller must take care of reference count when
2557 * needed.
2558 */
2559 dict_T *
2560get_vim_var_dict(int idx)
2561{
2562 return vimvars[idx].vv_dict;
2563}
2564
2565/*
2566 * Set v:char to character "c".
2567 */
2568 void
2569set_vim_var_char(int c)
2570{
2571 char_u buf[MB_MAXBYTES + 1];
2572
2573 if (has_mbyte)
2574 buf[(*mb_char2bytes)(c, buf)] = NUL;
2575 else
2576 {
2577 buf[0] = c;
2578 buf[1] = NUL;
2579 }
2580 set_vim_var_string(VV_CHAR, buf, -1);
2581}
2582
2583/*
2584 * Set v:count to "count" and v:count1 to "count1".
2585 * When "set_prevcount" is TRUE first set v:prevcount from v:count.
2586 */
2587 void
2588set_vcount(
2589 long count,
2590 long count1,
2591 int set_prevcount)
2592{
2593 if (set_prevcount)
2594 vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
2595 vimvars[VV_COUNT].vv_nr = count;
2596 vimvars[VV_COUNT1].vv_nr = count1;
2597}
2598
2599/*
2600 * Save variables that might be changed as a side effect. Used when executing
2601 * a timer callback.
2602 */
2603 void
2604save_vimvars(vimvars_save_T *vvsave)
2605{
2606 vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
2607 vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
2608 vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
2609}
2610
2611/*
2612 * Restore variables saved by save_vimvars().
2613 */
2614 void
2615restore_vimvars(vimvars_save_T *vvsave)
2616{
2617 vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
2618 vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
2619 vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
2620}
2621
2622/*
2623 * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
2624 * value.
2625 */
2626 void
2627set_vim_var_string(
2628 int idx,
2629 char_u *val,
2630 int len) // length of "val" to use or -1 (whole string)
2631{
2632 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002633 vimvars[idx].vv_tv_type = VAR_STRING;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002634 if (val == NULL)
2635 vimvars[idx].vv_str = NULL;
2636 else if (len == -1)
2637 vimvars[idx].vv_str = vim_strsave(val);
2638 else
2639 vimvars[idx].vv_str = vim_strnsave(val, len);
2640}
2641
2642/*
2643 * Set List v: variable to "val".
2644 */
2645 void
2646set_vim_var_list(int idx, list_T *val)
2647{
2648 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002649 vimvars[idx].vv_tv_type = VAR_LIST;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002650 vimvars[idx].vv_list = val;
2651 if (val != NULL)
2652 ++val->lv_refcount;
2653}
2654
2655/*
2656 * Set Dictionary v: variable to "val".
2657 */
2658 void
2659set_vim_var_dict(int idx, dict_T *val)
2660{
2661 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002662 vimvars[idx].vv_tv_type = VAR_DICT;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002663 vimvars[idx].vv_dict = val;
2664 if (val != NULL)
2665 {
2666 ++val->dv_refcount;
2667 dict_set_items_ro(val);
2668 }
2669}
2670
2671/*
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002672 * Set the v:argv list.
2673 */
2674 void
2675set_argv_var(char **argv, int argc)
2676{
2677 list_T *l = list_alloc();
2678 int i;
2679
2680 if (l == NULL)
2681 getout(1);
2682 l->lv_lock = VAR_FIXED;
2683 for (i = 0; i < argc; ++i)
2684 {
2685 if (list_append_string(l, (char_u *)argv[i], -1) == FAIL)
2686 getout(1);
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01002687 l->lv_u.mat.lv_last->li_tv.v_lock = VAR_FIXED;
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002688 }
2689 set_vim_var_list(VV_ARGV, l);
2690}
2691
2692/*
Bram Moolenaar439c0362020-06-06 15:58:03 +02002693 * Reset v:register, taking the 'clipboard' setting into account.
2694 */
2695 void
2696reset_reg_var(void)
2697{
2698 int regname = 0;
2699
2700 // Adjust the register according to 'clipboard', so that when
2701 // "unnamed" is present it becomes '*' or '+' instead of '"'.
2702#ifdef FEAT_CLIPBOARD
2703 adjust_clip_reg(&regname);
2704#endif
2705 set_reg_var(regname);
2706}
2707
2708/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002709 * Set v:register if needed.
2710 */
2711 void
2712set_reg_var(int c)
2713{
2714 char_u regname;
2715
2716 if (c == 0 || c == ' ')
2717 regname = '"';
2718 else
2719 regname = c;
2720 // Avoid free/alloc when the value is already right.
2721 if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
2722 set_vim_var_string(VV_REG, &regname, 1);
2723}
2724
2725/*
2726 * Get or set v:exception. If "oldval" == NULL, return the current value.
2727 * Otherwise, restore the value to "oldval" and return NULL.
2728 * Must always be called in pairs to save and restore v:exception! Does not
2729 * take care of memory allocations.
2730 */
2731 char_u *
2732v_exception(char_u *oldval)
2733{
2734 if (oldval == NULL)
2735 return vimvars[VV_EXCEPTION].vv_str;
2736
2737 vimvars[VV_EXCEPTION].vv_str = oldval;
2738 return NULL;
2739}
2740
2741/*
2742 * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
2743 * Otherwise, restore the value to "oldval" and return NULL.
2744 * Must always be called in pairs to save and restore v:throwpoint! Does not
2745 * take care of memory allocations.
2746 */
2747 char_u *
2748v_throwpoint(char_u *oldval)
2749{
2750 if (oldval == NULL)
2751 return vimvars[VV_THROWPOINT].vv_str;
2752
2753 vimvars[VV_THROWPOINT].vv_str = oldval;
2754 return NULL;
2755}
2756
2757/*
2758 * Set v:cmdarg.
2759 * If "eap" != NULL, use "eap" to generate the value and return the old value.
2760 * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
2761 * Must always be called in pairs!
2762 */
2763 char_u *
2764set_cmdarg(exarg_T *eap, char_u *oldarg)
2765{
2766 char_u *oldval;
2767 char_u *newval;
2768 unsigned len;
2769
2770 oldval = vimvars[VV_CMDARG].vv_str;
2771 if (eap == NULL)
2772 {
2773 vim_free(oldval);
2774 vimvars[VV_CMDARG].vv_str = oldarg;
2775 return NULL;
2776 }
2777
2778 if (eap->force_bin == FORCE_BIN)
2779 len = 6;
2780 else if (eap->force_bin == FORCE_NOBIN)
2781 len = 8;
2782 else
2783 len = 0;
2784
2785 if (eap->read_edit)
2786 len += 7;
2787
2788 if (eap->force_ff != 0)
2789 len += 10; // " ++ff=unix"
2790 if (eap->force_enc != 0)
2791 len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
2792 if (eap->bad_char != 0)
2793 len += 7 + 4; // " ++bad=" + "keep" or "drop"
2794
2795 newval = alloc(len + 1);
2796 if (newval == NULL)
2797 return NULL;
2798
2799 if (eap->force_bin == FORCE_BIN)
2800 sprintf((char *)newval, " ++bin");
2801 else if (eap->force_bin == FORCE_NOBIN)
2802 sprintf((char *)newval, " ++nobin");
2803 else
2804 *newval = NUL;
2805
2806 if (eap->read_edit)
2807 STRCAT(newval, " ++edit");
2808
2809 if (eap->force_ff != 0)
2810 sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
2811 eap->force_ff == 'u' ? "unix"
2812 : eap->force_ff == 'd' ? "dos"
2813 : "mac");
2814 if (eap->force_enc != 0)
2815 sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
2816 eap->cmd + eap->force_enc);
2817 if (eap->bad_char == BAD_KEEP)
2818 STRCPY(newval + STRLEN(newval), " ++bad=keep");
2819 else if (eap->bad_char == BAD_DROP)
2820 STRCPY(newval + STRLEN(newval), " ++bad=drop");
2821 else if (eap->bad_char != 0)
2822 sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
2823 vimvars[VV_CMDARG].vv_str = newval;
2824 return oldval;
2825}
2826
2827/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002828 * Get the value of internal variable "name".
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002829 * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
2830 * imported script ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002831 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
2832 */
2833 int
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02002834eval_variable(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002835 char_u *name,
2836 int len, // length of "name"
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002837 scid_T sid, // script ID for imported item or zero
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002838 typval_T *rettv, // NULL when only checking existence
2839 dictitem_T **dip, // non-NULL when typval's dict item is needed
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002840 int flags) // EVAL_VAR_ flags
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002841{
2842 int ret = OK;
2843 typval_T *tv = NULL;
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002844 int found = FALSE;
Bram Moolenaarf055d452021-07-08 20:57:24 +02002845 hashtab_T *ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002846 int cc;
Bram Moolenaarc967d572021-07-08 21:38:50 +02002847 type_T *type = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002848
2849 // truncate the name, so that we can use strcmp()
2850 cc = name[len];
2851 name[len] = NUL;
2852
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002853 // Check for local variable when debugging.
2854 if ((tv = lookup_debug_var(name)) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002855 {
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002856 // Check for user-defined variables.
Bram Moolenaarc967d572021-07-08 21:38:50 +02002857 dictitem_T *v = find_var(name, &ht, flags & EVAL_VAR_NOAUTOLOAD);
2858
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02002859 if (v != NULL)
2860 {
2861 tv = &v->di_tv;
2862 if (dip != NULL)
2863 *dip = v;
2864 }
Bram Moolenaarc967d572021-07-08 21:38:50 +02002865 else
2866 ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002867 }
2868
Bram Moolenaareb6880b2020-07-12 17:07:05 +02002869 if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002870 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002871 imported_T *import = NULL;
Bram Moolenaar9721fb42020-06-11 23:10:46 +02002872 char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
2873
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002874 if (sid == 0)
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00002875 import = find_imported(p, 0, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002876
2877 // imported variable from another script
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002878 if (import != NULL || sid != 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002879 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002880 if ((flags & EVAL_VAR_IMPORT) == 0)
Bram Moolenaarc620c052020-07-08 15:16:19 +02002881 {
Bram Moolenaar71f21932022-01-07 18:20:55 +00002882 if (SCRIPT_ID_VALID(sid))
Bram Moolenaarc620c052020-07-08 15:16:19 +02002883 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002884 ht = &SCRIPT_VARS(sid);
2885 if (ht != NULL)
2886 {
2887 dictitem_T *v = find_var_in_ht(ht, 0, name,
2888 flags & EVAL_VAR_NOAUTOLOAD);
2889
2890 if (v != NULL)
2891 {
2892 tv = &v->di_tv;
2893 if (dip != NULL)
2894 *dip = v;
2895 }
2896 else
2897 ht = NULL;
2898 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02002899 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002900 else
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002901 {
2902 if (flags & EVAL_VAR_VERBOSE)
Bram Moolenaardd5893b2022-01-20 21:32:54 +00002903 semsg(_(e_expected_dot_after_name_str), name);
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002904 ret = FAIL;
2905 }
Bram Moolenaarf6a44f72020-09-27 13:51:14 +02002906 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02002907 else
2908 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002909 if (rettv != NULL)
2910 {
2911 rettv->v_type = VAR_ANY;
2912 rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
2913 }
2914 found = TRUE;
Bram Moolenaarc620c052020-07-08 15:16:19 +02002915 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002916 }
Bram Moolenaar052ff292021-12-11 13:54:46 +00002917 else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002918 {
Bram Moolenaar848fadd2022-01-30 15:28:30 +00002919 int has_g_prefix = STRNCMP(name, "g:", 2) == 0;
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00002920 ufunc_T *ufunc = find_func(name, FALSE);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002921
Bram Moolenaarb033ee22021-08-15 16:08:36 +02002922 // In Vim9 script we can get a function reference by using the
Bram Moolenaar848fadd2022-01-30 15:28:30 +00002923 // function name. For a global non-autoload function "g:" is
2924 // required.
2925 if (ufunc != NULL && (has_g_prefix
2926 || !func_requires_g_prefix(ufunc)))
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002927 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002928 found = TRUE;
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002929 if (rettv != NULL)
2930 {
2931 rettv->v_type = VAR_FUNC;
Bram Moolenaar848fadd2022-01-30 15:28:30 +00002932 if (has_g_prefix)
Bram Moolenaaref082e12021-12-12 21:02:03 +00002933 // Keep the "g:", otherwise script-local may be
2934 // assumed.
2935 rettv->vval.v_string = vim_strsave(name);
2936 else
2937 rettv->vval.v_string = vim_strsave(ufunc->uf_name);
Bram Moolenaarb033ee22021-08-15 16:08:36 +02002938 if (rettv->vval.v_string != NULL)
2939 func_ref(ufunc->uf_name);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02002940 }
2941 }
2942 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002943 }
2944
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002945 if (!found)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002946 {
Bram Moolenaarc620c052020-07-08 15:16:19 +02002947 if (tv == NULL)
2948 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01002949 if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002950 semsg(_(e_undefined_variable_str), name);
Bram Moolenaarc620c052020-07-08 15:16:19 +02002951 ret = FAIL;
2952 }
2953 else if (rettv != NULL)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002954 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002955 svar_T *sv = NULL;
2956 int was_assigned = FALSE;
2957
Bram Moolenaar11005b02021-07-11 20:59:00 +02002958 if (ht != NULL && ht == get_script_local_ht()
2959 && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
Bram Moolenaarf055d452021-07-08 20:57:24 +02002960 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002961 sv = find_typval_in_script(tv, 0, TRUE);
Bram Moolenaarf055d452021-07-08 20:57:24 +02002962 if (sv != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002963 {
Bram Moolenaarf055d452021-07-08 20:57:24 +02002964 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002965 was_assigned = sv->sv_flags & SVFLAG_ASSIGNED;
2966 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02002967 }
2968
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01002969 // If a list or dict variable wasn't initialized and has meaningful
2970 // type, do it now. Not for global variables, they are not
2971 // declared.
Bram Moolenaar7a222242022-03-01 19:23:24 +00002972 if (ht != &globvarht)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01002973 {
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01002974 if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002975 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01002976 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02002977 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00002978 tv->vval.v_dict = dict_alloc();
2979 if (tv->vval.v_dict != NULL)
2980 {
2981 ++tv->vval.v_dict->dv_refcount;
2982 tv->vval.v_dict->dv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002983 if (sv != NULL)
2984 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00002985 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02002986 }
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01002987 else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002988 && ((type != NULL && !was_assigned)
Bram Moolenaar501f9782022-03-27 16:51:04 +01002989 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02002990 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00002991 tv->vval.v_list = list_alloc();
2992 if (tv->vval.v_list != NULL)
2993 {
2994 ++tv->vval.v_list->lv_refcount;
2995 tv->vval.v_list->lv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01002996 if (sv != NULL)
2997 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00002998 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02002999 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003000 else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003001 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01003002 || !in_vim9script()))
3003 {
3004 tv->vval.v_blob = blob_alloc();
3005 if (tv->vval.v_blob != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003006 {
Bram Moolenaar859cc212022-03-28 15:22:35 +01003007 ++tv->vval.v_blob->bv_refcount;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003008 if (sv != NULL)
3009 sv->sv_flags |= SVFLAG_ASSIGNED;
3010 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003011 }
Bram Moolenaarb7c21af2021-04-18 14:12:31 +02003012 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003013 copy_tv(tv, rettv);
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003014 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003015 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003016
3017 name[len] = cc;
3018
3019 return ret;
3020}
3021
3022/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003023 * Check if variable "name[len]" is a local variable or an argument.
3024 * If so, "*eval_lavars_used" is set to TRUE.
3025 */
3026 void
3027check_vars(char_u *name, int len)
3028{
3029 int cc;
3030 char_u *varname;
3031 hashtab_T *ht;
3032
3033 if (eval_lavars_used == NULL)
3034 return;
3035
3036 // truncate the name, so that we can use strcmp()
3037 cc = name[len];
3038 name[len] = NUL;
3039
3040 ht = find_var_ht(name, &varname);
3041 if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
3042 {
3043 if (find_var(name, NULL, TRUE) != NULL)
3044 *eval_lavars_used = TRUE;
3045 }
3046
3047 name[len] = cc;
3048}
3049
3050/*
3051 * Find variable "name" in the list of variables.
3052 * Return a pointer to it if found, NULL if not found.
3053 * Careful: "a:0" variables don't have a name.
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003054 * When "htp" is not NULL set "htp" to the hashtab_T used.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003055 */
3056 dictitem_T *
3057find_var(char_u *name, hashtab_T **htp, int no_autoload)
3058{
3059 char_u *varname;
3060 hashtab_T *ht;
3061 dictitem_T *ret = NULL;
3062
3063 ht = find_var_ht(name, &varname);
3064 if (htp != NULL)
3065 *htp = ht;
3066 if (ht == NULL)
3067 return NULL;
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003068 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003069 if (ret != NULL)
3070 return ret;
3071
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003072 // Search in parent scope for lambda
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003073 ret = find_var_in_scoped_ht(name, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003074 if (ret != NULL)
3075 return ret;
3076
3077 // in Vim9 script items without a scope can be script-local
3078 if (in_vim9script() && name[0] != NUL && name[1] != ':')
3079 {
3080 ht = get_script_local_ht();
3081 if (ht != NULL)
3082 {
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003083 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003084 if (ret != NULL)
3085 {
3086 if (htp != NULL)
3087 *htp = ht;
3088 return ret;
3089 }
3090 }
3091 }
3092
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003093 // When using "vim9script autoload" script-local items are prefixed but can
3094 // be used with s:name.
3095 if (SCRIPT_ID_VALID(current_sctx.sc_sid)
3096 && name[0] == 's' && name[1] == ':')
3097 {
3098 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
3099
3100 if (si->sn_autoload_prefix != NULL)
3101 {
3102 char_u *auto_name = concat_str(si->sn_autoload_prefix, name + 2);
3103
3104 if (auto_name != NULL)
3105 {
3106 ht = &globvarht;
3107 ret = find_var_in_ht(ht, *name, auto_name, TRUE);
Bram Moolenaar130f65d2022-01-13 20:39:41 +00003108 vim_free(auto_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003109 if (ret != NULL)
3110 {
3111 if (htp != NULL)
3112 *htp = ht;
3113 return ret;
3114 }
3115 }
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003116 }
3117 }
3118
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003119 return NULL;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003120}
3121
3122/*
Bram Moolenaar71f21932022-01-07 18:20:55 +00003123 * Like find_var() but if the name starts with <SNR>99_ then look in the
3124 * referenced script (used for a funcref).
3125 */
3126 dictitem_T *
3127find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload)
3128{
3129 if (STRNCMP(name, "<SNR>", 5) == 0 && isdigit(name[5]))
3130 {
3131 char_u *p = name + 5;
3132 int sid = getdigits(&p);
3133
3134 if (SCRIPT_ID_VALID(sid) && *p == '_')
3135 {
3136 hashtab_T *ht = &SCRIPT_VARS(sid);
3137
3138 if (ht != NULL)
3139 {
3140 dictitem_T *di = find_var_in_ht(ht, 0, p + 1, no_autoload);
3141
3142 if (di != NULL)
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003143 {
3144 if (htp != NULL)
3145 *htp = ht;
Bram Moolenaar71f21932022-01-07 18:20:55 +00003146 return di;
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003147 }
Bram Moolenaar71f21932022-01-07 18:20:55 +00003148 }
3149 }
3150 }
3151
3152 return find_var(name, htp, no_autoload);
3153}
3154
3155/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003156 * Find variable "varname" in hashtab "ht" with name "htname".
Bram Moolenaar52592752020-04-03 18:43:35 +02003157 * When "varname" is empty returns curwin/curtab/etc vars dictionary.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003158 * Returns NULL if not found.
3159 */
3160 dictitem_T *
3161find_var_in_ht(
3162 hashtab_T *ht,
3163 int htname,
3164 char_u *varname,
3165 int no_autoload)
3166{
3167 hashitem_T *hi;
3168
3169 if (*varname == NUL)
3170 {
3171 // Must be something like "s:", otherwise "ht" would be NULL.
3172 switch (htname)
3173 {
3174 case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
3175 case 'g': return &globvars_var;
3176 case 'v': return &vimvars_var;
3177 case 'b': return &curbuf->b_bufvar;
3178 case 'w': return &curwin->w_winvar;
3179 case 't': return &curtab->tp_winvar;
3180 case 'l': return get_funccal_local_var();
3181 case 'a': return get_funccal_args_var();
3182 }
3183 return NULL;
3184 }
3185
3186 hi = hash_find(ht, varname);
3187 if (HASHITEM_EMPTY(hi))
3188 {
3189 // For global variables we may try auto-loading the script. If it
3190 // worked find the variable again. Don't auto-load a script if it was
3191 // loaded already, otherwise it would be loaded every time when
3192 // checking if a function name is a Funcref variable.
3193 if (ht == &globvarht && !no_autoload)
3194 {
3195 // Note: script_autoload() may make "hi" invalid. It must either
3196 // be obtained again or not used.
3197 if (!script_autoload(varname, FALSE) || aborting())
3198 return NULL;
3199 hi = hash_find(ht, varname);
3200 }
3201 if (HASHITEM_EMPTY(hi))
3202 return NULL;
3203 }
3204 return HI2DI(hi);
3205}
3206
3207/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003208 * Get the script-local hashtab. NULL if not in a script context.
3209 */
Bram Moolenaar922acbd2020-10-08 21:30:40 +02003210 hashtab_T *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003211get_script_local_ht(void)
3212{
3213 scid_T sid = current_sctx.sc_sid;
3214
Bram Moolenaare3d46852020-08-29 13:39:17 +02003215 if (SCRIPT_ID_VALID(sid))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003216 return &SCRIPT_VARS(sid);
3217 return NULL;
3218}
3219
3220/*
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003221 * Look for "name[len]" in script-local variables and functions.
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003222 * When "cmd" is TRUE it must look like a command, a function must be followed
3223 * by "(" or "->".
Bram Moolenaar709664c2020-12-12 14:33:41 +01003224 * Return OK when found, FAIL when not found.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003225 */
Bram Moolenaar709664c2020-12-12 14:33:41 +01003226 int
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003227lookup_scriptitem(
Bram Moolenaar709664c2020-12-12 14:33:41 +01003228 char_u *name,
3229 size_t len,
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003230 int cmd,
Bram Moolenaar709664c2020-12-12 14:33:41 +01003231 cctx_T *dummy UNUSED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003232{
3233 hashtab_T *ht = get_script_local_ht();
3234 char_u buffer[30];
3235 char_u *p;
Bram Moolenaar709664c2020-12-12 14:33:41 +01003236 int res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003237 hashitem_T *hi;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003238 int is_global = FALSE;
3239 char_u *fname = name;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003240
3241 if (ht == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003242 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003243 if (len < sizeof(buffer) - 1)
3244 {
Bram Moolenaar7d3664d2020-05-09 13:06:24 +02003245 // avoid an alloc/free for short names
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003246 vim_strncpy(buffer, name, len);
3247 p = buffer;
3248 }
3249 else
3250 {
Bram Moolenaar71ccd032020-06-12 22:59:11 +02003251 p = vim_strnsave(name, len);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003252 if (p == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003253 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003254 }
3255
3256 hi = hash_find(ht, p);
Bram Moolenaar709664c2020-12-12 14:33:41 +01003257 res = HASHITEM_EMPTY(hi) ? FAIL : OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003258
3259 // if not script-local, then perhaps imported
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003260 if (res == FAIL && find_imported(p, 0, FALSE) != NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003261 res = OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003262 if (p != buffer)
3263 vim_free(p);
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003264
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003265 // Find a function, so that a following "->" works.
3266 // When used as a command require "(" or "->" to follow, "Cmd" is a user
3267 // command while "Cmd()" is a function call.
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003268 if (res != OK)
3269 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003270 p = skipwhite(name + len);
3271
3272 if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003273 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003274 // Do not check for an internal function, since it might also be a
3275 // valid command, such as ":split" versus "split()".
3276 // Skip "g:" before a function name.
3277 if (name[0] == 'g' && name[1] == ':')
3278 {
3279 is_global = TRUE;
3280 fname = name + 2;
3281 }
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003282 if (find_func(fname, is_global) != NULL)
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003283 res = OK;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003284 }
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003285 }
3286
Bram Moolenaar709664c2020-12-12 14:33:41 +01003287 return res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003288}
3289
3290/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003291 * Find the hashtab used for a variable name.
3292 * Return NULL if the name is not valid.
3293 * Set "varname" to the start of name without ':'.
3294 */
3295 hashtab_T *
3296find_var_ht(char_u *name, char_u **varname)
3297{
3298 hashitem_T *hi;
3299 hashtab_T *ht;
3300
3301 if (name[0] == NUL)
3302 return NULL;
3303 if (name[1] != ':')
3304 {
3305 // The name must not start with a colon or #.
3306 if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
3307 return NULL;
3308 *varname = name;
3309
3310 // "version" is "v:version" in all scopes if scriptversion < 3.
3311 // Same for a few other variables marked with VV_COMPAT.
Bram Moolenaardd9de502021-08-15 13:49:42 +02003312 if (in_old_script(3))
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003313 {
3314 hi = hash_find(&compat_hashtab, name);
3315 if (!HASHITEM_EMPTY(hi))
3316 return &compat_hashtab;
3317 }
3318
3319 ht = get_funccal_local_ht();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003320 if (ht != NULL)
3321 return ht; // local variable
3322
Bram Moolenaarf0a40692021-06-11 22:05:47 +02003323 // In Vim9 script items at the script level are script-local, except
3324 // for autoload names.
3325 if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003326 {
3327 ht = get_script_local_ht();
3328 if (ht != NULL)
3329 return ht;
3330 }
3331
3332 return &globvarht; // global variable
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003333 }
3334 *varname = name + 2;
3335 if (*name == 'g') // global variable
3336 return &globvarht;
3337 // There must be no ':' or '#' in the rest of the name, unless g: is used
3338 if (vim_strchr(name + 2, ':') != NULL
3339 || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
3340 return NULL;
3341 if (*name == 'b') // buffer variable
3342 return &curbuf->b_vars->dv_hashtab;
3343 if (*name == 'w') // window variable
3344 return &curwin->w_vars->dv_hashtab;
3345 if (*name == 't') // tab page variable
3346 return &curtab->tp_vars->dv_hashtab;
3347 if (*name == 'v') // v: variable
3348 return &vimvarht;
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003349 if (get_current_funccal() != NULL
Bram Moolenaar0cb5bcf2020-06-20 18:19:09 +02003350 && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003351 {
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003352 // a: and l: are only used in functions defined with ":function"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003353 if (*name == 'a') // a: function argument
3354 return get_funccal_args_ht();
3355 if (*name == 'l') // l: local function variable
3356 return get_funccal_local_ht();
3357 }
3358 if (*name == 's') // script variable
3359 {
3360 ht = get_script_local_ht();
3361 if (ht != NULL)
3362 return ht;
3363 }
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003364 return NULL;
3365}
3366
3367/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003368 * Get the string value of a (global/local) variable.
3369 * Note: see tv_get_string() for how long the pointer remains valid.
3370 * Returns NULL when it doesn't exist.
3371 */
3372 char_u *
3373get_var_value(char_u *name)
3374{
3375 dictitem_T *v;
3376
3377 v = find_var(name, NULL, FALSE);
3378 if (v == NULL)
3379 return NULL;
3380 return tv_get_string(&v->di_tv);
3381}
3382
3383/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003384 * Allocate a new hashtab for a sourced script. It will be used while
3385 * sourcing this script and when executing functions defined in the script.
3386 */
3387 void
3388new_script_vars(scid_T id)
3389{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003390 scriptvar_T *sv;
3391
Bram Moolenaar7ebcba62020-01-12 17:42:55 +01003392 sv = ALLOC_CLEAR_ONE(scriptvar_T);
3393 if (sv == NULL)
3394 return;
3395 init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
Bram Moolenaar21b9e972020-01-26 19:26:46 +01003396 SCRIPT_ITEM(id)->sn_vars = sv;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003397}
3398
3399/*
3400 * Initialize dictionary "dict" as a scope and set variable "dict_var" to
3401 * point to it.
3402 */
3403 void
3404init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
3405{
3406 hash_init(&dict->dv_hashtab);
3407 dict->dv_lock = 0;
3408 dict->dv_scope = scope;
3409 dict->dv_refcount = DO_NOT_FREE_CNT;
3410 dict->dv_copyID = 0;
3411 dict_var->di_tv.vval.v_dict = dict;
3412 dict_var->di_tv.v_type = VAR_DICT;
3413 dict_var->di_tv.v_lock = VAR_FIXED;
3414 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
3415 dict_var->di_key[0] = NUL;
3416}
3417
3418/*
3419 * Unreference a dictionary initialized by init_var_dict().
3420 */
3421 void
3422unref_var_dict(dict_T *dict)
3423{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003424 // Now the dict needs to be freed if no one else is using it, go back to
3425 // normal reference counting.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003426 dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
3427 dict_unref(dict);
3428}
3429
3430/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003431 * Clean up a list of internal variables.
3432 * Frees all allocated variables and the value they contain.
3433 * Clears hashtab "ht", does not free it.
3434 */
3435 void
3436vars_clear(hashtab_T *ht)
3437{
3438 vars_clear_ext(ht, TRUE);
3439}
3440
3441/*
3442 * Like vars_clear(), but only free the value if "free_val" is TRUE.
3443 */
3444 void
3445vars_clear_ext(hashtab_T *ht, int free_val)
3446{
3447 int todo;
3448 hashitem_T *hi;
3449 dictitem_T *v;
3450
3451 hash_lock(ht);
3452 todo = (int)ht->ht_used;
3453 for (hi = ht->ht_array; todo > 0; ++hi)
3454 {
3455 if (!HASHITEM_EMPTY(hi))
3456 {
3457 --todo;
3458
3459 // Free the variable. Don't remove it from the hashtab,
3460 // ht_array might change then. hash_clear() takes care of it
3461 // later.
3462 v = HI2DI(hi);
3463 if (free_val)
3464 clear_tv(&v->di_tv);
3465 if (v->di_flags & DI_FLAGS_ALLOC)
3466 vim_free(v);
3467 }
3468 }
3469 hash_clear(ht);
Bram Moolenaar8d739de2020-10-14 19:39:19 +02003470 hash_init(ht);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003471}
3472
3473/*
3474 * Delete a variable from hashtab "ht" at item "hi".
3475 * Clear the variable value and free the dictitem.
3476 */
Bram Moolenaarfcdc5d82020-10-10 19:07:09 +02003477 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003478delete_var(hashtab_T *ht, hashitem_T *hi)
3479{
3480 dictitem_T *di = HI2DI(hi);
3481
3482 hash_remove(ht, hi);
3483 clear_tv(&di->di_tv);
3484 vim_free(di);
3485}
3486
3487/*
3488 * List the value of one internal variable.
3489 */
3490 static void
3491list_one_var(dictitem_T *v, char *prefix, int *first)
3492{
3493 char_u *tofree;
3494 char_u *s;
3495 char_u numbuf[NUMBUFLEN];
3496
3497 s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
3498 list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
3499 s == NULL ? (char_u *)"" : s, first);
3500 vim_free(tofree);
3501}
3502
3503 static void
3504list_one_var_a(
3505 char *prefix,
3506 char_u *name,
3507 int type,
3508 char_u *string,
3509 int *first) // when TRUE clear rest of screen and set to FALSE
3510{
3511 // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
3512 msg_start();
3513 msg_puts(prefix);
3514 if (name != NULL) // "a:" vars don't have a name stored
3515 msg_puts((char *)name);
3516 msg_putchar(' ');
3517 msg_advance(22);
3518 if (type == VAR_NUMBER)
3519 msg_putchar('#');
3520 else if (type == VAR_FUNC || type == VAR_PARTIAL)
3521 msg_putchar('*');
3522 else if (type == VAR_LIST)
3523 {
3524 msg_putchar('[');
3525 if (*string == '[')
3526 ++string;
3527 }
3528 else if (type == VAR_DICT)
3529 {
3530 msg_putchar('{');
3531 if (*string == '{')
3532 ++string;
3533 }
3534 else
3535 msg_putchar(' ');
3536
3537 msg_outtrans(string);
3538
3539 if (type == VAR_FUNC || type == VAR_PARTIAL)
3540 msg_puts("()");
3541 if (*first)
3542 {
3543 msg_clr_eos();
3544 *first = FALSE;
3545 }
3546}
3547
3548/*
3549 * Set variable "name" to value in "tv".
3550 * If the variable already exists, the value is updated.
3551 * Otherwise the variable is created.
3552 */
3553 void
3554set_var(
3555 char_u *name,
3556 typval_T *tv,
3557 int copy) // make copy of value in "tv"
3558{
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003559 set_var_const(name, 0, NULL, tv, copy, ASSIGN_DECL, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003560}
3561
3562/*
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003563 * Set variable "name" to value in "tv_arg".
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003564 * When "sid" is non-zero "name" is in the script with this ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003565 * If the variable already exists and "is_const" is FALSE the value is updated.
3566 * Otherwise the variable is created.
3567 */
3568 void
3569set_var_const(
3570 char_u *name,
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003571 scid_T sid,
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003572 type_T *type_arg,
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003573 typval_T *tv_arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003574 int copy, // make copy of value in "tv"
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003575 int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaarf785aa12021-02-11 21:19:34 +01003576 int var_idx) // index for ":let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003577{
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003578 typval_T *tv = tv_arg;
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003579 type_T *type = type_arg;
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003580 typval_T bool_tv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003581 dictitem_T *di;
Bram Moolenaar993faa32022-02-21 15:59:11 +00003582 typval_T *dest_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003583 char_u *varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003584 char_u *name_tofree = NULL;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003585 hashtab_T *ht = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003586 int is_script_local;
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003587 int vim9script = in_vim9script();
Bram Moolenaare535db82021-03-31 21:07:24 +02003588 int var_in_vim9script;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003589 int var_in_autoload = FALSE;
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003590 int flags = flags_arg;
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003591 int free_tv_arg = !copy; // free tv_arg if not used
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003592
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003593 if (sid != 0)
3594 {
3595 if (SCRIPT_ID_VALID(sid))
3596 ht = &SCRIPT_VARS(sid);
3597 varname = name;
3598 }
3599 else
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003600 {
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003601 scriptitem_T *si;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003602
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003603 if (in_vim9script() && is_export
3604 && SCRIPT_ID_VALID(current_sctx.sc_sid)
3605 && (si = SCRIPT_ITEM(current_sctx.sc_sid))
Bram Moolenaar0e1574c2022-03-03 17:05:35 +00003606 ->sn_autoload_prefix != NULL)
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003607 {
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003608 // In a vim9 autoload script an exported variable is put in the
3609 // global namespace with the autoload prefix.
3610 var_in_autoload = TRUE;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003611 varname = concat_str(si->sn_autoload_prefix, name);
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003612 if (varname == NULL)
3613 goto failed;
3614 name_tofree = varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003615 ht = &globvarht;
3616 }
3617 else
3618 ht = find_var_ht(name, &varname);
3619 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003620 if (ht == NULL || *varname == NUL)
3621 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003622 semsg(_(e_illegal_variable_name_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003623 goto failed;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003624 }
Bram Moolenaar54969f42022-02-07 13:56:44 +00003625 is_script_local = ht == get_script_local_ht() || sid != 0
3626 || var_in_autoload;
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003627
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003628 if (vim9script
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003629 && !is_script_local
Bram Moolenaar3862ea32021-01-01 21:05:55 +01003630 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01003631 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003632 && name[1] == ':')
Bram Moolenaar67979662020-06-20 22:50:47 +02003633 {
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003634 vim9_declare_error(name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003635 goto failed;
Bram Moolenaar67979662020-06-20 22:50:47 +02003636 }
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003637 if ((flags & ASSIGN_FOR_LOOP) && name[1] == ':'
3638 && vim_strchr((char_u *)"gwbt", name[0]) != NULL)
3639 // Do not make g:var, w:var, b:var or t:var final.
3640 flags &= ~ASSIGN_FINAL;
3641
Bram Moolenaare535db82021-03-31 21:07:24 +02003642 var_in_vim9script = is_script_local && current_script_is_vim9();
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003643 if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
3644 {
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02003645 // For "[a, _] = list" the underscore is ignored.
3646 if ((flags & ASSIGN_UNPACK) == 0)
3647 emsg(_(e_cannot_use_underscore_here));
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003648 goto failed;
3649 }
Bram Moolenaar67979662020-06-20 22:50:47 +02003650
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003651 di = find_var_in_ht(ht, 0, varname, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003652
Bram Moolenaar24e93162021-07-18 20:40:33 +02003653 if (di == NULL && var_in_vim9script)
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003654 {
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003655 imported_T *import = find_imported(varname, 0, FALSE);
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003656
Bram Moolenaar24e93162021-07-18 20:40:33 +02003657 if (import != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003658 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003659 // imported name space cannot be used
Bram Moolenaar24e93162021-07-18 20:40:33 +02003660 if ((flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003661 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003662 semsg(_(e_redefining_imported_item_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003663 goto failed;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003664 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003665 semsg(_(e_cannot_use_str_itself_it_is_imported), name);
3666 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003667 }
Bram Moolenaar75e27d72022-02-13 13:56:29 +00003668 if (!in_vim9script())
3669 {
3670 semsg(_(e_cannot_create_vim9_script_variable_in_function_str),
3671 name);
3672 goto failed;
3673 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003674 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003675
Bram Moolenaar993faa32022-02-21 15:59:11 +00003676 // Search in parent scope which is possible to reference from lambda
3677 if (di == NULL)
3678 di = find_var_in_scoped_ht(name, TRUE);
3679
3680 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
3681 && var_wrong_func_name(name, di == NULL))
3682 goto failed;
3683
3684 if (need_convert_to_bool(type, tv))
Bram Moolenaar24e93162021-07-18 20:40:33 +02003685 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00003686 // Destination is a bool and the value is not, but it can be
3687 // converted.
3688 CLEAR_FIELD(bool_tv);
3689 bool_tv.v_type = VAR_BOOL;
3690 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
3691 tv = &bool_tv;
3692 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003693
Bram Moolenaar993faa32022-02-21 15:59:11 +00003694 if (di != NULL)
3695 {
3696 // Item already exists. Allowed to replace when reloading.
3697 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003698 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00003699 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
3700 && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003701 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00003702 emsg(_(e_cannot_modify_existing_variable));
3703 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003704 }
3705
Bram Moolenaar993faa32022-02-21 15:59:11 +00003706 if (is_script_local && vim9script
3707 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
Bram Moolenaar12be7342021-03-31 21:47:33 +02003708 {
3709 semsg(_(e_redefining_script_item_str), name);
3710 goto failed;
3711 }
3712
Bram Moolenaar993faa32022-02-21 15:59:11 +00003713 if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003714 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00003715 where_T where = WHERE_INIT;
Bram Moolenaar7a411a32022-04-04 14:58:06 +01003716 svar_T *sv = find_typval_in_script(&di->di_tv, sid, TRUE);
Bram Moolenaar993faa32022-02-21 15:59:11 +00003717
3718 if (sv != NULL)
3719 {
3720 // check the type and adjust to bool if needed
3721 where.wt_index = var_idx;
3722 where.wt_variable = TRUE;
3723 if (check_script_var_type(sv, tv, name, where) == FAIL)
3724 goto failed;
3725 if (type == NULL)
3726 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003727 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar993faa32022-02-21 15:59:11 +00003728 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003729 }
3730
Bram Moolenaar993faa32022-02-21 15:59:11 +00003731 if ((flags & ASSIGN_FOR_LOOP) == 0
3732 && var_check_permission(di, name) == FAIL)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003733 goto failed;
Bram Moolenaar993faa32022-02-21 15:59:11 +00003734 }
3735 else
3736 {
3737 // can only redefine once
3738 di->di_flags &= ~DI_FLAGS_RELOAD;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003739
Bram Moolenaar993faa32022-02-21 15:59:11 +00003740 // A Vim9 script-local variable is also present in sn_all_vars
3741 // and sn_var_vals. It may set "type" from "tv".
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003742 if (var_in_vim9script || var_in_autoload)
Bram Moolenaar993faa32022-02-21 15:59:11 +00003743 update_vim9_script_var(FALSE, di,
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003744 var_in_autoload ? name : di->di_key, flags,
Bram Moolenaar993faa32022-02-21 15:59:11 +00003745 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar07a65d22020-12-26 20:09:15 +01003746 }
3747
Bram Moolenaar993faa32022-02-21 15:59:11 +00003748 // existing variable, need to clear the value
3749
3750 // Handle setting internal di: variables separately where needed to
3751 // prevent changing the type.
3752 if (ht == &vimvarht)
3753 {
3754 if (di->di_tv.v_type == VAR_STRING)
3755 {
3756 VIM_CLEAR(di->di_tv.vval.v_string);
3757 if (copy || tv->v_type != VAR_STRING)
3758 {
3759 char_u *val = tv_get_string(tv);
3760
3761 // Careful: when assigning to v:errmsg and
3762 // tv_get_string() causes an error message the variable
3763 // will already be set.
3764 if (di->di_tv.vval.v_string == NULL)
3765 di->di_tv.vval.v_string = vim_strsave(val);
3766 }
3767 else
3768 {
3769 // Take over the string to avoid an extra alloc/free.
3770 di->di_tv.vval.v_string = tv->vval.v_string;
3771 tv->vval.v_string = NULL;
3772 }
3773 goto failed;
3774 }
3775 else if (di->di_tv.v_type == VAR_NUMBER)
3776 {
3777 di->di_tv.vval.v_number = tv_get_number(tv);
3778 if (STRCMP(varname, "searchforward") == 0)
3779 set_search_direction(di->di_tv.vval.v_number
3780 ? '/' : '?');
3781#ifdef FEAT_SEARCH_EXTRA
3782 else if (STRCMP(varname, "hlsearch") == 0)
3783 {
3784 no_hlsearch = !di->di_tv.vval.v_number;
3785 redraw_all_later(SOME_VALID);
3786 }
3787#endif
3788 goto failed;
3789 }
3790 else if (di->di_tv.v_type != tv->v_type)
3791 {
3792 semsg(_(e_setting_str_to_value_with_wrong_type), name);
3793 goto failed;
3794 }
3795 }
3796
3797 clear_tv(&di->di_tv);
3798 }
3799 else
3800 {
3801 // Item not found, check if a function already exists.
3802 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
3803 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
3804 {
3805 semsg(_(e_redefining_script_item_str), name);
3806 goto failed;
3807 }
3808
3809 // add a new variable
3810 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
3811 {
3812 semsg(_(e_unknown_variable_str), name);
3813 goto failed;
3814 }
3815
3816 // Can't add "v:" or "a:" variable.
3817 if (ht == &vimvarht || ht == get_funccal_args_ht())
3818 {
3819 semsg(_(e_illegal_variable_name_str), name);
3820 goto failed;
3821 }
3822
3823 // Make sure the variable name is valid. In Vim9 script an
3824 // autoload variable must be prefixed with "g:" unless in an
3825 // autoload script.
3826 if (!valid_varname(varname, -1, !vim9script
3827 || STRNCMP(name, "g:", 2) == 0 || var_in_autoload))
3828 goto failed;
3829
3830 di = alloc(sizeof(dictitem_T) + STRLEN(varname));
3831 if (di == NULL)
3832 goto failed;
3833 STRCPY(di->di_key, varname);
3834 if (hash_add(ht, DI2HIKEY(di)) == FAIL)
3835 {
3836 vim_free(di);
3837 goto failed;
3838 }
3839 di->di_flags = DI_FLAGS_ALLOC;
3840 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
3841 di->di_flags |= DI_FLAGS_LOCK;
3842
3843 // A Vim9 script-local variable is also added to sn_all_vars and
3844 // sn_var_vals. It may set "type" from "tv".
3845 if (var_in_vim9script || var_in_autoload)
3846 update_vim9_script_var(TRUE, di,
3847 var_in_autoload ? name : di->di_key, flags,
3848 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003849 }
3850
Bram Moolenaar993faa32022-02-21 15:59:11 +00003851 dest_tv = &di->di_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003852 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
Bram Moolenaar24e93162021-07-18 20:40:33 +02003853 copy_tv(tv, dest_tv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003854 else
3855 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003856 *dest_tv = *tv;
3857 dest_tv->v_lock = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003858 init_tv(tv);
3859 }
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003860 free_tv_arg = FALSE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003861
Bram Moolenaaraa210a32021-01-02 15:41:03 +01003862 if (vim9script && type != NULL)
Bram Moolenaar381692b2022-02-02 20:01:27 +00003863 set_tv_type(dest_tv, type);
Bram Moolenaaraa210a32021-01-02 15:41:03 +01003864
Bram Moolenaar1dcf55d2020-12-22 22:07:30 +01003865 // ":const var = value" locks the value
3866 // ":final var = value" locks "var"
Bram Moolenaar30fd8202020-09-26 15:09:30 +02003867 if (flags & ASSIGN_CONST)
Bram Moolenaar021bda52020-08-17 21:07:22 +02003868 // Like :lockvar! name: lock the value and what it contains, but only
3869 // if the reference count is up to one. That locks only literal
3870 // values.
Bram Moolenaar24e93162021-07-18 20:40:33 +02003871 item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
Bram Moolenaar24e93162021-07-18 20:40:33 +02003872
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003873failed:
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003874 vim_free(name_tofree);
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003875 if (free_tv_arg)
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003876 clear_tv(tv_arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003877}
3878
3879/*
Bram Moolenaar3bdc90b2020-12-22 20:35:40 +01003880 * Check in this order for backwards compatibility:
3881 * - Whether the variable is read-only
3882 * - Whether the variable value is locked
3883 * - Whether the variable is locked
3884 */
3885 int
3886var_check_permission(dictitem_T *di, char_u *name)
3887{
3888 if (var_check_ro(di->di_flags, name, FALSE)
3889 || value_check_lock(di->di_tv.v_lock, name, FALSE)
3890 || var_check_lock(di->di_flags, name, FALSE))
3891 return FAIL;
3892 return OK;
3893}
3894
3895/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003896 * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
3897 * Also give an error message.
3898 */
3899 int
3900var_check_ro(int flags, char_u *name, int use_gettext)
3901{
3902 if (flags & DI_FLAGS_RO)
3903 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003904 if (name == NULL)
3905 emsg(_(e_cannot_change_readonly_variable));
3906 else
3907 semsg(_(e_cannot_change_readonly_variable_str),
Bram Moolenaard8e44472021-07-21 22:20:33 +02003908 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003909 return TRUE;
3910 }
3911 if ((flags & DI_FLAGS_RO_SBX) && sandbox)
3912 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003913 if (name == NULL)
3914 emsg(_(e_cannot_set_variable_in_sandbox));
3915 else
3916 semsg(_(e_cannot_set_variable_in_sandbox_str),
3917 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003918 return TRUE;
3919 }
3920 return FALSE;
3921}
3922
3923/*
Bram Moolenaara187c432020-09-16 21:08:28 +02003924 * Return TRUE if di_flags "flags" indicates variable "name" is locked.
3925 * Also give an error message.
3926 */
3927 int
3928var_check_lock(int flags, char_u *name, int use_gettext)
3929{
3930 if (flags & DI_FLAGS_LOCK)
3931 {
3932 semsg(_(e_variable_is_locked_str),
3933 use_gettext ? (char_u *)_(name) : name);
3934 return TRUE;
3935 }
3936 return FALSE;
3937}
3938
3939/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003940 * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
3941 * Also give an error message.
3942 */
3943 int
3944var_check_fixed(int flags, char_u *name, int use_gettext)
3945{
3946 if (flags & DI_FLAGS_FIX)
3947 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003948 if (name == NULL)
3949 emsg(_(e_cannot_delete_variable));
3950 else
3951 semsg(_(e_cannot_delete_variable_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003952 use_gettext ? (char_u *)_(name) : name);
3953 return TRUE;
3954 }
3955 return FALSE;
3956}
3957
3958/*
3959 * Check if a funcref is assigned to a valid variable name.
3960 * Return TRUE and give an error if not.
3961 */
3962 int
Bram Moolenaar98b4f142020-08-08 15:46:01 +02003963var_wrong_func_name(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003964 char_u *name, // points to start of variable name
3965 int new_var) // TRUE when creating the variable
3966{
Bram Moolenaar32154662021-03-28 21:14:06 +02003967 // Allow for w: b: s: and t:. In Vim9 script s: is not allowed, because
3968 // the name can be used without the s: prefix.
3969 if (!((vim_strchr((char_u *)"wbt", name[0]) != NULL
3970 || (!in_vim9script() && name[0] == 's')) && name[1] == ':')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003971 && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
3972 ? name[2] : name[0]))
3973 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00003974 semsg(_(e_funcref_variable_name_must_start_with_capital_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003975 return TRUE;
3976 }
3977 // Don't allow hiding a function. When "v" is not NULL we might be
3978 // assigning another function to the same var, the type is checked
3979 // below.
3980 if (new_var && function_exists(name, FALSE))
3981 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00003982 semsg(_(e_variable_name_conflicts_with_existing_function_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003983 name);
3984 return TRUE;
3985 }
3986 return FALSE;
3987}
3988
3989/*
Bram Moolenaara187c432020-09-16 21:08:28 +02003990 * Return TRUE if "flags" indicates variable "name" has a locked (immutable)
3991 * value. Also give an error message, using "name" or _("name") when
3992 * "use_gettext" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003993 */
3994 int
Bram Moolenaara187c432020-09-16 21:08:28 +02003995value_check_lock(int lock, char_u *name, int use_gettext)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003996{
3997 if (lock & VAR_LOCKED)
3998 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00003999 if (name == NULL)
4000 emsg(_(e_value_is_locked));
4001 else
4002 semsg(_(e_value_is_locked_str),
4003 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004004 return TRUE;
4005 }
4006 if (lock & VAR_FIXED)
4007 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004008 if (name == NULL)
4009 emsg(_(e_cannot_change_value));
4010 else
4011 semsg(_(e_cannot_change_value_of_str),
4012 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004013 return TRUE;
4014 }
4015 return FALSE;
4016}
4017
4018/*
Bram Moolenaar03290b82020-12-19 16:30:44 +01004019 * Check if a variable name is valid. When "autoload" is true "#" is allowed.
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004020 * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004021 * Return FALSE and give an error if not.
4022 */
4023 int
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004024valid_varname(char_u *varname, int len, int autoload)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004025{
4026 char_u *p;
4027
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004028 for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004029 if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
Bram Moolenaar03290b82020-12-19 16:30:44 +01004030 && !(autoload && *p == AUTOLOAD_CHAR))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004031 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004032 semsg(_(e_illegal_variable_name_str), varname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004033 return FALSE;
4034 }
4035 return TRUE;
4036}
4037
4038/*
4039 * getwinvar() and gettabwinvar()
4040 */
4041 static void
4042getwinvar(
4043 typval_T *argvars,
4044 typval_T *rettv,
4045 int off) // 1 for gettabwinvar()
4046{
4047 win_T *win;
4048 char_u *varname;
4049 dictitem_T *v;
4050 tabpage_T *tp = NULL;
4051 int done = FALSE;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004052 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004053 int need_switch_win;
4054
4055 if (off == 1)
4056 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4057 else
4058 tp = curtab;
4059 win = find_win_by_nr(&argvars[off], tp);
4060 varname = tv_get_string_chk(&argvars[off + 1]);
4061 ++emsg_off;
4062
4063 rettv->v_type = VAR_STRING;
4064 rettv->vval.v_string = NULL;
4065
4066 if (win != NULL && varname != NULL)
4067 {
4068 // Set curwin to be our win, temporarily. Also set the tabpage,
4069 // otherwise the window is not valid. Only do this when needed,
4070 // autocommands get blocked.
4071 need_switch_win = !(tp == curtab && win == curwin);
4072 if (!need_switch_win
Bram Moolenaar18f47402022-01-06 13:24:51 +00004073 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004074 {
4075 if (*varname == '&')
4076 {
4077 if (varname[1] == NUL)
4078 {
4079 // get all window-local options in a dict
4080 dict_T *opts = get_winbuf_options(FALSE);
4081
4082 if (opts != NULL)
4083 {
4084 rettv_dict_set(rettv, opts);
4085 done = TRUE;
4086 }
4087 }
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02004088 else if (eval_option(&varname, rettv, 1) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004089 // window-local-option
4090 done = TRUE;
4091 }
4092 else
4093 {
4094 // Look up the variable.
4095 // Let getwinvar({nr}, "") return the "w:" dictionary.
4096 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
4097 varname, FALSE);
4098 if (v != NULL)
4099 {
4100 copy_tv(&v->di_tv, rettv);
4101 done = TRUE;
4102 }
4103 }
4104 }
4105
4106 if (need_switch_win)
4107 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00004108 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004109 }
4110
4111 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
4112 // use the default return value
4113 copy_tv(&argvars[off + 2], rettv);
4114
4115 --emsg_off;
4116}
4117
4118/*
Bram Moolenaar191929b2020-08-19 21:20:49 +02004119 * Set option "varname" to the value of "varp" for the current buffer/window.
4120 */
4121 static void
4122set_option_from_tv(char_u *varname, typval_T *varp)
4123{
4124 long numval = 0;
4125 char_u *strval;
4126 char_u nbuf[NUMBUFLEN];
4127 int error = FALSE;
4128
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004129 if (varp->v_type == VAR_BOOL)
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004130 {
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004131 numval = (long)varp->vval.v_number;
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004132 strval = (char_u *)"0"; // avoid using "false"
4133 }
4134 else
4135 {
4136 if (!in_vim9script() || varp->v_type != VAR_STRING)
4137 numval = (long)tv_get_number_chk(varp, &error);
4138 strval = tv_get_string_buf_chk(varp, nbuf);
4139 }
Bram Moolenaar191929b2020-08-19 21:20:49 +02004140 if (!error && strval != NULL)
Bram Moolenaar31e5c602022-04-15 13:53:33 +01004141 set_option_value_give_err(varname, numval, strval, OPT_LOCAL);
Bram Moolenaar191929b2020-08-19 21:20:49 +02004142}
4143
4144/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004145 * "setwinvar()" and "settabwinvar()" functions
4146 */
4147 static void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004148setwinvar(typval_T *argvars, int off)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004149{
4150 win_T *win;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004151 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004152 int need_switch_win;
4153 char_u *varname, *winvarname;
4154 typval_T *varp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004155 tabpage_T *tp = NULL;
4156
4157 if (check_secure())
4158 return;
4159
4160 if (off == 1)
4161 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4162 else
4163 tp = curtab;
4164 win = find_win_by_nr(&argvars[off], tp);
4165 varname = tv_get_string_chk(&argvars[off + 1]);
4166 varp = &argvars[off + 2];
4167
4168 if (win != NULL && varname != NULL && varp != NULL)
4169 {
4170 need_switch_win = !(tp == curtab && win == curwin);
4171 if (!need_switch_win
Bram Moolenaar18f47402022-01-06 13:24:51 +00004172 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004173 {
4174 if (*varname == '&')
Bram Moolenaar191929b2020-08-19 21:20:49 +02004175 set_option_from_tv(varname + 1, varp);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004176 else
4177 {
4178 winvarname = alloc(STRLEN(varname) + 3);
4179 if (winvarname != NULL)
4180 {
4181 STRCPY(winvarname, "w:");
4182 STRCPY(winvarname + 2, varname);
4183 set_var(winvarname, varp, TRUE);
4184 vim_free(winvarname);
4185 }
4186 }
4187 }
4188 if (need_switch_win)
Bram Moolenaar18f47402022-01-06 13:24:51 +00004189 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004190 }
4191}
4192
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004193/*
4194 * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
4195 * v:option_type, and v:option_command.
4196 */
4197 void
4198reset_v_option_vars(void)
4199{
4200 set_vim_var_string(VV_OPTION_NEW, NULL, -1);
4201 set_vim_var_string(VV_OPTION_OLD, NULL, -1);
4202 set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
4203 set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
4204 set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
4205 set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
4206}
4207
4208/*
4209 * Add an assert error to v:errors.
4210 */
4211 void
4212assert_error(garray_T *gap)
4213{
4214 struct vimvar *vp = &vimvars[VV_ERRORS];
4215
Bram Moolenaard787e402021-12-24 21:36:12 +00004216 if (vp->vv_tv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004217 // Make sure v:errors is a list.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004218 set_vim_var_list(VV_ERRORS, list_alloc());
4219 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
4220}
4221
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004222 int
4223var_exists(char_u *var)
4224{
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004225 char_u *arg = var;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004226 char_u *name;
4227 char_u *tofree;
4228 typval_T tv;
4229 int len = 0;
4230 int n = FALSE;
4231
4232 // get_name_len() takes care of expanding curly braces
4233 name = var;
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004234 len = get_name_len(&arg, &tofree, TRUE, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004235 if (len > 0)
4236 {
4237 if (tofree != NULL)
4238 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004239 n = (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01004240 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004241 if (n)
4242 {
4243 // handle d.key, l[idx], f(expr)
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004244 arg = skipwhite(arg);
Bram Moolenaar32884ad2022-01-07 12:45:29 +00004245 n = (handle_subscript(&arg, name, &tv, &EVALARG_EVALUATE,
4246 FALSE) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004247 if (n)
4248 clear_tv(&tv);
4249 }
4250 }
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004251 if (*arg != NUL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004252 n = FALSE;
4253
4254 vim_free(tofree);
4255 return n;
4256}
4257
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004258static lval_T *redir_lval = NULL;
4259#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
4260static garray_T redir_ga; // only valid when redir_lval is not NULL
4261static char_u *redir_endp = NULL;
4262static char_u *redir_varname = NULL;
4263
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004264 int
4265alloc_redir_lval(void)
4266{
4267 redir_lval = ALLOC_CLEAR_ONE(lval_T);
4268 if (redir_lval == NULL)
4269 return FAIL;
4270 return OK;
4271}
4272
4273 void
4274clear_redir_lval(void)
4275{
4276 VIM_CLEAR(redir_lval);
4277}
4278
4279 void
4280init_redir_ga(void)
4281{
Bram Moolenaar04935fb2022-01-08 16:19:22 +00004282 ga_init2(&redir_ga, sizeof(char), 500);
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004283}
4284
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004285/*
4286 * Start recording command output to a variable
4287 * When "append" is TRUE append to an existing variable.
4288 * Returns OK if successfully completed the setup. FAIL otherwise.
4289 */
4290 int
4291var_redir_start(char_u *name, int append)
4292{
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004293 int called_emsg_before;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004294 typval_T tv;
4295
4296 // Catch a bad name early.
4297 if (!eval_isnamec1(*name))
4298 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004299 emsg(_(e_invalid_argument));
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004300 return FAIL;
4301 }
4302
4303 // Make a copy of the name, it is used in redir_lval until redir ends.
4304 redir_varname = vim_strsave(name);
4305 if (redir_varname == NULL)
4306 return FAIL;
4307
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004308 if (alloc_redir_lval() == FAIL)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004309 {
4310 var_redir_stop();
4311 return FAIL;
4312 }
4313
4314 // The output is stored in growarray "redir_ga" until redirection ends.
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004315 init_redir_ga();
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004316
4317 // Parse the variable name (can be a dict or list entry).
4318 redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
4319 FNE_CHECK_START);
4320 if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
4321 {
4322 clear_lval(redir_lval);
4323 if (redir_endp != NULL && *redir_endp != NUL)
4324 // Trailing characters are present after the variable name
Bram Moolenaar74409f62022-01-01 15:58:22 +00004325 semsg(_(e_trailing_characters_str), redir_endp);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004326 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004327 semsg(_(e_invalid_argument_str), name);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004328 redir_endp = NULL; // don't store a value, only cleanup
4329 var_redir_stop();
4330 return FAIL;
4331 }
4332
4333 // check if we can write to the variable: set it to or append an empty
4334 // string
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004335 called_emsg_before = called_emsg;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004336 tv.v_type = VAR_STRING;
4337 tv.vval.v_string = (char_u *)"";
4338 if (append)
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004339 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004340 ASSIGN_NO_DECL, (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004341 else
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004342 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004343 ASSIGN_NO_DECL, (char_u *)"=", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004344 clear_lval(redir_lval);
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004345 if (called_emsg > called_emsg_before)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004346 {
4347 redir_endp = NULL; // don't store a value, only cleanup
4348 var_redir_stop();
4349 return FAIL;
4350 }
4351
4352 return OK;
4353}
4354
4355/*
4356 * Append "value[value_len]" to the variable set by var_redir_start().
4357 * The actual appending is postponed until redirection ends, because the value
4358 * appended may in fact be the string we write to, changing it may cause freed
4359 * memory to be used:
4360 * :redir => foo
4361 * :let foo
4362 * :redir END
4363 */
4364 void
4365var_redir_str(char_u *value, int value_len)
4366{
4367 int len;
4368
4369 if (redir_lval == NULL)
4370 return;
4371
4372 if (value_len == -1)
4373 len = (int)STRLEN(value); // Append the entire string
4374 else
4375 len = value_len; // Append only "value_len" characters
4376
4377 if (ga_grow(&redir_ga, len) == OK)
4378 {
4379 mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
4380 redir_ga.ga_len += len;
4381 }
4382 else
4383 var_redir_stop();
4384}
4385
4386/*
4387 * Stop redirecting command output to a variable.
4388 * Frees the allocated memory.
4389 */
4390 void
4391var_redir_stop(void)
4392{
4393 typval_T tv;
4394
4395 if (EVALCMD_BUSY)
4396 {
4397 redir_lval = NULL;
4398 return;
4399 }
4400
4401 if (redir_lval != NULL)
4402 {
4403 // If there was no error: assign the text to the variable.
4404 if (redir_endp != NULL)
4405 {
4406 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4407 tv.v_type = VAR_STRING;
4408 tv.vval.v_string = redir_ga.ga_data;
4409 // Call get_lval() again, if it's inside a Dict or List it may
4410 // have changed.
4411 redir_endp = get_lval(redir_varname, NULL, redir_lval,
4412 FALSE, FALSE, 0, FNE_CHECK_START);
4413 if (redir_endp != NULL && redir_lval->ll_name != NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004414 set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004415 (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004416 clear_lval(redir_lval);
4417 }
4418
4419 // free the collected output
4420 VIM_CLEAR(redir_ga.ga_data);
4421
4422 VIM_CLEAR(redir_lval);
4423 }
4424 VIM_CLEAR(redir_varname);
4425}
4426
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004427/*
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004428 * Get the collected redirected text and clear redir_ga.
4429 */
4430 char_u *
4431get_clear_redir_ga(void)
4432{
4433 char_u *res;
4434
4435 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4436 res = redir_ga.ga_data;
4437 redir_ga.ga_data = NULL;
4438 return res;
4439}
4440
4441/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004442 * "gettabvar()" function
4443 */
4444 void
4445f_gettabvar(typval_T *argvars, typval_T *rettv)
4446{
Bram Moolenaar18f47402022-01-06 13:24:51 +00004447 switchwin_T switchwin;
4448 tabpage_T *tp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004449 dictitem_T *v;
4450 char_u *varname;
4451 int done = FALSE;
4452
4453 rettv->v_type = VAR_STRING;
4454 rettv->vval.v_string = NULL;
4455
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004456 if (in_vim9script()
4457 && (check_for_number_arg(argvars, 0) == FAIL
4458 || check_for_string_arg(argvars, 1) == FAIL))
4459 return;
4460
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004461 varname = tv_get_string_chk(&argvars[1]);
4462 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4463 if (tp != NULL && varname != NULL)
4464 {
4465 // Set tp to be our tabpage, temporarily. Also set the window to the
4466 // first window in the tabpage, otherwise the window is not valid.
Bram Moolenaar18f47402022-01-06 13:24:51 +00004467 if (switch_win(&switchwin,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004468 tp == curtab || tp->tp_firstwin == NULL ? firstwin
4469 : tp->tp_firstwin, tp, TRUE) == OK)
4470 {
4471 // look up the variable
4472 // Let gettabvar({nr}, "") return the "t:" dictionary.
4473 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
4474 if (v != NULL)
4475 {
4476 copy_tv(&v->di_tv, rettv);
4477 done = TRUE;
4478 }
4479 }
4480
4481 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00004482 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004483 }
4484
4485 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4486 copy_tv(&argvars[2], rettv);
4487}
4488
4489/*
4490 * "gettabwinvar()" function
4491 */
4492 void
4493f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4494{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004495 if (in_vim9script()
4496 && (check_for_number_arg(argvars, 0) == FAIL
4497 || check_for_number_arg(argvars, 1) == FAIL
4498 || check_for_string_arg(argvars, 2) == FAIL))
4499 return;
4500
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004501 getwinvar(argvars, rettv, 1);
4502}
4503
4504/*
4505 * "getwinvar()" function
4506 */
4507 void
4508f_getwinvar(typval_T *argvars, typval_T *rettv)
4509{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004510 if (in_vim9script()
4511 && (check_for_number_arg(argvars, 0) == FAIL
4512 || check_for_string_arg(argvars, 1) == FAIL))
4513 return;
4514
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004515 getwinvar(argvars, rettv, 0);
4516}
4517
4518/*
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004519 * "getbufvar()" function
4520 */
4521 void
4522f_getbufvar(typval_T *argvars, typval_T *rettv)
4523{
4524 buf_T *buf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004525 char_u *varname;
4526 dictitem_T *v;
4527 int done = FALSE;
4528
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004529 if (in_vim9script()
4530 && (check_for_buffer_arg(argvars, 0) == FAIL
4531 || check_for_string_arg(argvars, 1) == FAIL))
4532 return;
4533
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004534 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004535 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004536
4537 rettv->v_type = VAR_STRING;
4538 rettv->vval.v_string = NULL;
4539
4540 if (buf != NULL && varname != NULL)
4541 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004542 if (*varname == '&')
4543 {
Bram Moolenaar86015452020-03-29 15:12:15 +02004544 buf_T *save_curbuf = curbuf;
4545
4546 // set curbuf to be our buf, temporarily
4547 curbuf = buf;
4548
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004549 if (varname[1] == NUL)
4550 {
4551 // get all buffer-local options in a dict
4552 dict_T *opts = get_winbuf_options(TRUE);
4553
4554 if (opts != NULL)
4555 {
4556 rettv_dict_set(rettv, opts);
4557 done = TRUE;
4558 }
4559 }
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02004560 else if (eval_option(&varname, rettv, TRUE) == OK)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004561 // buffer-local-option
4562 done = TRUE;
Bram Moolenaar86015452020-03-29 15:12:15 +02004563
4564 // restore previous notion of curbuf
4565 curbuf = save_curbuf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004566 }
4567 else
4568 {
4569 // Look up the variable.
Bram Moolenaar52592752020-04-03 18:43:35 +02004570 if (*varname == NUL)
4571 // Let getbufvar({nr}, "") return the "b:" dictionary.
4572 v = &buf->b_bufvar;
4573 else
4574 v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
4575 varname, FALSE);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004576 if (v != NULL)
4577 {
4578 copy_tv(&v->di_tv, rettv);
4579 done = TRUE;
4580 }
4581 }
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004582 }
4583
4584 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4585 // use the default value
4586 copy_tv(&argvars[2], rettv);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004587}
4588
4589/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004590 * "settabvar()" function
4591 */
4592 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004593f_settabvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004594{
4595 tabpage_T *save_curtab;
4596 tabpage_T *tp;
4597 char_u *varname, *tabvarname;
4598 typval_T *varp;
4599
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004600 if (check_secure())
4601 return;
4602
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004603 if (in_vim9script()
4604 && (check_for_number_arg(argvars, 0) == FAIL
4605 || check_for_string_arg(argvars, 1) == FAIL))
4606 return;
4607
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004608 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4609 varname = tv_get_string_chk(&argvars[1]);
4610 varp = &argvars[2];
4611
4612 if (varname != NULL && varp != NULL && tp != NULL)
4613 {
4614 save_curtab = curtab;
4615 goto_tabpage_tp(tp, FALSE, FALSE);
4616
4617 tabvarname = alloc(STRLEN(varname) + 3);
4618 if (tabvarname != NULL)
4619 {
4620 STRCPY(tabvarname, "t:");
4621 STRCPY(tabvarname + 2, varname);
4622 set_var(tabvarname, varp, TRUE);
4623 vim_free(tabvarname);
4624 }
4625
4626 // Restore current tabpage
4627 if (valid_tabpage(save_curtab))
4628 goto_tabpage_tp(save_curtab, FALSE, FALSE);
4629 }
4630}
4631
4632/*
4633 * "settabwinvar()" function
4634 */
4635 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004636f_settabwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004637{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004638 if (in_vim9script()
4639 && (check_for_number_arg(argvars, 0) == FAIL
4640 || check_for_number_arg(argvars, 1) == FAIL
4641 || check_for_string_arg(argvars, 2) == FAIL))
4642 return;
4643
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004644 setwinvar(argvars, 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004645}
4646
4647/*
4648 * "setwinvar()" function
4649 */
4650 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004651f_setwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004652{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004653 if (in_vim9script()
4654 && (check_for_number_arg(argvars, 0) == FAIL
4655 || check_for_string_arg(argvars, 1) == FAIL))
4656 return;
4657
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004658 setwinvar(argvars, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004659}
4660
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004661/*
4662 * "setbufvar()" function
4663 */
4664 void
4665f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
4666{
4667 buf_T *buf;
4668 char_u *varname, *bufvarname;
4669 typval_T *varp;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004670
4671 if (check_secure())
4672 return;
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004673
4674 if (in_vim9script()
4675 && (check_for_buffer_arg(argvars, 0) == FAIL
4676 || check_for_string_arg(argvars, 1) == FAIL))
4677 return;
4678
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004679 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004680 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004681 varp = &argvars[2];
4682
4683 if (buf != NULL && varname != NULL && varp != NULL)
4684 {
4685 if (*varname == '&')
4686 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004687 aco_save_T aco;
4688
4689 // set curbuf to be our buf, temporarily
4690 aucmd_prepbuf(&aco, buf);
4691
Bram Moolenaar191929b2020-08-19 21:20:49 +02004692 set_option_from_tv(varname + 1, varp);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004693
4694 // reset notion of buffer
4695 aucmd_restbuf(&aco);
4696 }
4697 else
4698 {
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004699 bufvarname = alloc(STRLEN(varname) + 3);
4700 if (bufvarname != NULL)
4701 {
Bram Moolenaar86015452020-03-29 15:12:15 +02004702 buf_T *save_curbuf = curbuf;
4703
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004704 curbuf = buf;
4705 STRCPY(bufvarname, "b:");
4706 STRCPY(bufvarname + 2, varname);
4707 set_var(bufvarname, varp, TRUE);
4708 vim_free(bufvarname);
4709 curbuf = save_curbuf;
4710 }
4711 }
4712 }
4713}
4714
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004715/*
4716 * Get a callback from "arg". It can be a Funcref or a function name.
4717 * When "arg" is zero return an empty string.
4718 * "cb_name" is not allocated.
4719 * "cb_name" is set to NULL for an invalid argument.
4720 */
4721 callback_T
4722get_callback(typval_T *arg)
4723{
Bram Moolenaar14e579092020-03-07 16:59:25 +01004724 callback_T res;
4725 int r = OK;
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004726
4727 res.cb_free_name = FALSE;
4728 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
4729 {
4730 res.cb_partial = arg->vval.v_partial;
4731 ++res.cb_partial->pt_refcount;
4732 res.cb_name = partial_name(res.cb_partial);
4733 }
4734 else
4735 {
4736 res.cb_partial = NULL;
Bram Moolenaar14e579092020-03-07 16:59:25 +01004737 if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
4738 && isdigit(*arg->vval.v_string))
4739 r = FAIL;
4740 else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004741 {
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00004742 if (arg->v_type == VAR_STRING)
4743 {
4744 char_u *name;
4745
4746 name = get_scriptlocal_funcname(arg->vval.v_string);
4747 if (name != NULL)
4748 {
4749 vim_free(arg->vval.v_string);
4750 arg->vval.v_string = name;
4751 }
4752 }
4753
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004754 res.cb_name = arg->vval.v_string;
4755 func_ref(res.cb_name);
4756 }
4757 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004758 res.cb_name = (char_u *)"";
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004759 else
Bram Moolenaar14e579092020-03-07 16:59:25 +01004760 r = FAIL;
4761
4762 if (r == FAIL)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004763 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00004764 emsg(_(e_invalid_callback_argument));
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004765 res.cb_name = NULL;
4766 }
4767 }
4768 return res;
4769}
4770
4771/*
4772 * Copy a callback into a typval_T.
4773 */
4774 void
4775put_callback(callback_T *cb, typval_T *tv)
4776{
4777 if (cb->cb_partial != NULL)
4778 {
4779 tv->v_type = VAR_PARTIAL;
4780 tv->vval.v_partial = cb->cb_partial;
4781 ++tv->vval.v_partial->pt_refcount;
4782 }
4783 else
4784 {
4785 tv->v_type = VAR_FUNC;
4786 tv->vval.v_string = vim_strsave(cb->cb_name);
4787 func_ref(cb->cb_name);
4788 }
4789}
4790
4791/*
4792 * Make a copy of "src" into "dest", allocating the function name if needed,
4793 * without incrementing the refcount.
4794 */
4795 void
4796set_callback(callback_T *dest, callback_T *src)
4797{
4798 if (src->cb_partial == NULL)
4799 {
4800 // just a function name, make a copy
4801 dest->cb_name = vim_strsave(src->cb_name);
4802 dest->cb_free_name = TRUE;
4803 }
4804 else
4805 {
4806 // cb_name is a pointer into cb_partial
4807 dest->cb_name = src->cb_name;
4808 dest->cb_free_name = FALSE;
4809 }
4810 dest->cb_partial = src->cb_partial;
4811}
4812
4813/*
Bram Moolenaard43906d2020-07-20 21:31:32 +02004814 * Copy callback from "src" to "dest", incrementing the refcounts.
4815 */
4816 void
4817copy_callback(callback_T *dest, callback_T *src)
4818{
4819 dest->cb_partial = src->cb_partial;
4820 if (dest->cb_partial != NULL)
4821 {
4822 dest->cb_name = src->cb_name;
4823 dest->cb_free_name = FALSE;
4824 ++dest->cb_partial->pt_refcount;
4825 }
4826 else
4827 {
4828 dest->cb_name = vim_strsave(src->cb_name);
4829 dest->cb_free_name = TRUE;
4830 func_ref(src->cb_name);
4831 }
4832}
4833
4834/*
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004835 * When a callback refers to an autoload import, change the function name to
4836 * the "path#name" form. Uses the current script context.
4837 * Only works when the name is allocated.
4838 */
4839 void
4840expand_autload_callback(callback_T *cb)
4841{
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004842 char_u *name;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004843 char_u *p;
4844 imported_T *import;
4845
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004846 if (!in_vim9script() || cb->cb_name == NULL
4847 || (!cb->cb_free_name
4848 && (cb->cb_partial == NULL || cb->cb_partial->pt_name == NULL)))
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004849 return;
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004850 if (cb->cb_partial != NULL)
4851 name = cb->cb_partial->pt_name;
4852 else
4853 name = cb->cb_name;
4854 p = vim_strchr(name, '.');
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004855 if (p == NULL)
4856 return;
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00004857 import = find_imported(name, p - name, FALSE);
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004858 if (import != NULL && SCRIPT_ID_VALID(import->imp_sid))
4859 {
4860 scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
4861
4862 if (si->sn_autoload_prefix != NULL)
4863 {
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004864 char_u *newname = concat_str(si->sn_autoload_prefix, p + 1);
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004865
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004866 if (newname != NULL)
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004867 {
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00004868 if (cb->cb_partial != NULL)
4869 {
4870 if (cb->cb_name == cb->cb_partial->pt_name)
4871 cb->cb_name = newname;
4872 vim_free(cb->cb_partial->pt_name);
4873 cb->cb_partial->pt_name = newname;
4874 }
4875 else
4876 {
4877 vim_free(cb->cb_name);
4878 cb->cb_name = newname;
4879 }
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004880 }
4881 }
4882 }
4883}
4884
4885/*
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02004886 * Unref/free "callback" returned by get_callback() or set_callback().
4887 */
4888 void
4889free_callback(callback_T *callback)
4890{
4891 if (callback->cb_partial != NULL)
4892 {
4893 partial_unref(callback->cb_partial);
4894 callback->cb_partial = NULL;
4895 }
4896 else if (callback->cb_name != NULL)
4897 func_unref(callback->cb_name);
4898 if (callback->cb_free_name)
4899 {
4900 vim_free(callback->cb_name);
4901 callback->cb_free_name = FALSE;
4902 }
4903 callback->cb_name = NULL;
4904}
4905
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004906#endif // FEAT_EVAL