blob: 62728ed8ab4a80e8340eb03d4c10fb6eb54b16e7 [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},
Shougo Matsushita61021aa2022-07-27 14:40:00 +0100114 {VV_NAME("completed_item", VAR_DICT), &t_dict_string, 0},
Bram Moolenaard787e402021-12-24 21:36:12 +0000115 {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},
Bram Moolenaarc0c2c262023-01-12 21:08:53 +0000142 {VV_NAME("t_class", VAR_NUMBER), NULL, VV_RO},
143 {VV_NAME("t_object", VAR_NUMBER), NULL, VV_RO},
Bram Moolenaard787e402021-12-24 21:36:12 +0000144 {VV_NAME("termrfgresp", VAR_STRING), NULL, VV_RO},
145 {VV_NAME("termrbgresp", VAR_STRING), NULL, VV_RO},
146 {VV_NAME("termu7resp", VAR_STRING), NULL, VV_RO},
147 {VV_NAME("termstyleresp", VAR_STRING), NULL, VV_RO},
148 {VV_NAME("termblinkresp", VAR_STRING), NULL, VV_RO},
149 {VV_NAME("event", VAR_DICT), NULL, VV_RO},
150 {VV_NAME("versionlong", VAR_NUMBER), NULL, VV_RO},
151 {VV_NAME("echospace", VAR_NUMBER), NULL, VV_RO},
152 {VV_NAME("argv", VAR_LIST), &t_list_string, VV_RO},
153 {VV_NAME("collate", VAR_STRING), NULL, VV_RO},
154 {VV_NAME("exiting", VAR_SPECIAL), NULL, VV_RO},
155 {VV_NAME("colornames", VAR_DICT), &t_dict_string, VV_RO},
156 {VV_NAME("sizeofint", VAR_NUMBER), NULL, VV_RO},
157 {VV_NAME("sizeoflong", VAR_NUMBER), NULL, VV_RO},
158 {VV_NAME("sizeofpointer", VAR_NUMBER), NULL, VV_RO},
naohiro ono56200ee2022-01-01 14:59:44 +0000159 {VV_NAME("maxcol", VAR_NUMBER), NULL, VV_RO},
Yee Cheng Chinc13b3d12023-08-20 21:18:38 +0200160 {VV_NAME("python3_version", VAR_NUMBER), NULL, VV_RO},
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +0200161 {VV_NAME("t_typealias", VAR_NUMBER), NULL, VV_RO},
Yegappan Lakshmanan3164cf82024-03-28 10:36:42 +0100162 {VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO},
163 {VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200164};
165
166// shorthand
Bram Moolenaard787e402021-12-24 21:36:12 +0000167#define vv_tv_type vv_di.di_tv.v_type
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200168#define vv_nr vv_di.di_tv.vval.v_number
169#define vv_float vv_di.di_tv.vval.v_float
170#define vv_str vv_di.di_tv.vval.v_string
171#define vv_list vv_di.di_tv.vval.v_list
172#define vv_dict vv_di.di_tv.vval.v_dict
173#define vv_blob vv_di.di_tv.vval.v_blob
174#define vv_tv vv_di.di_tv
175
176static dictitem_T vimvars_var; // variable used for v:
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200177static dict_T vimvardict; // Dictionary with v: variables
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200178#define vimvarht vimvardict.dv_hashtab
179
180// for VIM_VERSION_ defines
181#include "version.h"
182
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200183static void list_glob_vars(int *first);
184static void list_buf_vars(int *first);
185static void list_win_vars(int *first);
186static void list_tab_vars(int *first);
187static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100188static 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 +0200189static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
190static 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 +0200191static void list_one_var(dictitem_T *v, char *prefix, int *first);
192static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
193
194/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200195 * Initialize global and vim special variables
196 */
197 void
198evalvars_init(void)
199{
200 int i;
201 struct vimvar *p;
202
203 init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
204 init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
205 vimvardict.dv_lock = VAR_FIXED;
206 hash_init(&compat_hashtab);
207
208 for (i = 0; i < VV_LEN; ++i)
209 {
210 p = &vimvars[i];
211 if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
212 {
Bram Moolenaar097c5372023-05-24 21:02:24 +0100213 iemsg("Name too long, increase size of dictitem16_T");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200214 getout(1);
215 }
216 STRCPY(p->vv_di.di_key, p->vv_name);
217 if (p->vv_flags & VV_RO)
218 p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
219 else if (p->vv_flags & VV_RO_SBX)
220 p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
221 else
222 p->vv_di.di_flags = DI_FLAGS_FIX;
223
224 // add to v: scope dict, unless the value is not always available
Bram Moolenaard787e402021-12-24 21:36:12 +0000225 if (p->vv_tv_type != VAR_UNKNOWN)
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000226 hash_add(&vimvarht, p->vv_di.di_key, "initialization");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200227 if (p->vv_flags & VV_COMPAT)
228 // add to compat scope dict
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000229 hash_add(&compat_hashtab, p->vv_di.di_key, "initialization");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200230 }
Bram Moolenaar016faaa2020-10-03 12:57:27 +0200231 set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
232 set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200233
234 set_vim_var_nr(VV_SEARCHFORWARD, 1L);
235 set_vim_var_nr(VV_HLSEARCH, 1L);
Bram Moolenaarf0068c52020-11-30 17:42:10 +0100236 set_vim_var_nr(VV_EXITING, VVAL_NULL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200237 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
238 set_vim_var_list(VV_ERRORS, list_alloc());
239 set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
240
241 set_vim_var_nr(VV_FALSE, VVAL_FALSE);
242 set_vim_var_nr(VV_TRUE, VVAL_TRUE);
243 set_vim_var_nr(VV_NONE, VVAL_NONE);
244 set_vim_var_nr(VV_NULL, VVAL_NULL);
Bram Moolenaar57d5a012021-01-21 21:42:31 +0100245 set_vim_var_nr(VV_NUMBERMAX, VARNUM_MAX);
246 set_vim_var_nr(VV_NUMBERMIN, VARNUM_MIN);
Bram Moolenaarf9706e92020-02-22 14:27:04 +0100247 set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
Bram Moolenaar69b30722021-11-02 21:39:49 +0000248 set_vim_var_nr(VV_SIZEOFINT, sizeof(int));
249 set_vim_var_nr(VV_SIZEOFLONG, sizeof(long));
250 set_vim_var_nr(VV_SIZEOFPOINTER, sizeof(char *));
naohiro ono56200ee2022-01-01 14:59:44 +0000251 set_vim_var_nr(VV_MAXCOL, MAXCOL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200252
253 set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
254 set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
255 set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
256 set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
257 set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
258 set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
259 set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
260 set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
261 set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
262 set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
263 set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
Bram Moolenaarc0c2c262023-01-12 21:08:53 +0000264 set_vim_var_nr(VV_TYPE_CLASS, VAR_TYPE_CLASS);
265 set_vim_var_nr(VV_TYPE_OBJECT, VAR_TYPE_OBJECT);
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +0200266 set_vim_var_nr(VV_TYPE_TYPEALIAS, VAR_TYPE_TYPEALIAS);
Yegappan Lakshmanan3164cf82024-03-28 10:36:42 +0100267 set_vim_var_nr(VV_TYPE_ENUM, VAR_TYPE_ENUM);
268 set_vim_var_nr(VV_TYPE_ENUMVALUE, VAR_TYPE_ENUMVALUE);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200269
270 set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
271
Drew Vogele30d1022021-10-24 20:35:07 +0100272 set_vim_var_dict(VV_COLORNAMES, dict_alloc());
273
Yee Cheng Chinc13b3d12023-08-20 21:18:38 +0200274#ifdef FEAT_PYTHON3
275 set_vim_var_nr(VV_PYTHON3_VERSION, python3_version());
276#endif
277
Bram Moolenaar439c0362020-06-06 15:58:03 +0200278 // Default for v:register is not 0 but '"'. This is adjusted once the
279 // clipboard has been setup by calling reset_reg_var().
280 set_reg_var(0);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200281}
282
283#if defined(EXITFREE) || defined(PROTO)
284/*
285 * Free all vim variables information on exit
286 */
287 void
288evalvars_clear(void)
289{
290 int i;
291 struct vimvar *p;
292
293 for (i = 0; i < VV_LEN; ++i)
294 {
295 p = &vimvars[i];
296 if (p->vv_di.di_tv.v_type == VAR_STRING)
297 VIM_CLEAR(p->vv_str);
298 else if (p->vv_di.di_tv.v_type == VAR_LIST)
299 {
300 list_unref(p->vv_list);
301 p->vv_list = NULL;
302 }
303 }
304 hash_clear(&vimvarht);
305 hash_init(&vimvarht); // garbage_collect() will access it
306 hash_clear(&compat_hashtab);
307
308 // global variables
309 vars_clear(&globvarht);
310
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100311 // Script-local variables. Clear all the variables here.
312 // The scriptvar_T is cleared later in free_scriptnames(), because a
313 // variable in one script might hold a reference to the whole scope of
314 // another script.
315 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200316 vars_clear(&SCRIPT_VARS(i));
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200317}
318#endif
319
320 int
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200321garbage_collect_globvars(int copyID)
322{
323 return set_ref_in_ht(&globvarht, copyID, NULL);
324}
325
326 int
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200327garbage_collect_vimvars(int copyID)
328{
329 return set_ref_in_ht(&vimvarht, copyID, NULL);
330}
331
332 int
333garbage_collect_scriptvars(int copyID)
334{
Bram Moolenaared234f22020-10-15 20:42:20 +0200335 int i;
336 int idx;
337 int abort = FALSE;
338 scriptitem_T *si;
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200339
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100340 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaared234f22020-10-15 20:42:20 +0200341 {
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200342 abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
343
Bram Moolenaared234f22020-10-15 20:42:20 +0200344 si = SCRIPT_ITEM(i);
345 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
346 {
347 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
348
Bram Moolenaard00a7fb2021-03-08 20:47:14 +0100349 if (sv->sv_name != NULL)
350 abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL);
Bram Moolenaared234f22020-10-15 20:42:20 +0200351 }
352 }
353
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200354 return abort;
355}
356
357/*
358 * Set an internal variable to a string value. Creates the variable if it does
359 * not already exist.
360 */
361 void
362set_internal_string_var(char_u *name, char_u *value)
363{
364 char_u *val;
365 typval_T *tvp;
366
367 val = vim_strsave(value);
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000368 if (val == NULL)
369 return;
370
371 tvp = alloc_string_tv(val);
372 if (tvp == NULL)
373 return;
374
375 set_var(name, tvp, FALSE);
376 free_tv(tvp);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200377}
378
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200379 int
380eval_charconvert(
381 char_u *enc_from,
382 char_u *enc_to,
383 char_u *fname_from,
384 char_u *fname_to)
385{
386 int err = FALSE;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000387 sctx_T saved_sctx = current_sctx;
388 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200389
390 set_vim_var_string(VV_CC_FROM, enc_from, -1);
391 set_vim_var_string(VV_CC_TO, enc_to, -1);
392 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
393 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000394 ctx = get_option_sctx("charconvert");
395 if (ctx != NULL)
396 current_sctx = *ctx;
397
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100398 if (eval_to_bool(p_ccv, &err, NULL, FALSE, TRUE))
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200399 err = TRUE;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000400
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200401 set_vim_var_string(VV_CC_FROM, NULL, -1);
402 set_vim_var_string(VV_CC_TO, NULL, -1);
403 set_vim_var_string(VV_FNAME_IN, NULL, -1);
404 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000405 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200406
407 if (err)
408 return FAIL;
409 return OK;
410}
411
412# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
413 int
414eval_printexpr(char_u *fname, char_u *args)
415{
416 int err = FALSE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000417 sctx_T saved_sctx = current_sctx;
418 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200419
420 set_vim_var_string(VV_FNAME_IN, fname, -1);
421 set_vim_var_string(VV_CMDARG, args, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000422 ctx = get_option_sctx("printexpr");
423 if (ctx != NULL)
424 current_sctx = *ctx;
425
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100426 if (eval_to_bool(p_pexpr, &err, NULL, FALSE, TRUE))
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200427 err = TRUE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000428
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200429 set_vim_var_string(VV_FNAME_IN, NULL, -1);
430 set_vim_var_string(VV_CMDARG, NULL, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000431 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200432
433 if (err)
434 {
435 mch_remove(fname);
436 return FAIL;
437 }
438 return OK;
439}
440# endif
441
442# if defined(FEAT_DIFF) || defined(PROTO)
443 void
444eval_diff(
445 char_u *origfile,
446 char_u *newfile,
447 char_u *outfile)
448{
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000449 sctx_T saved_sctx = current_sctx;
450 sctx_T *ctx;
451 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200452
453 set_vim_var_string(VV_FNAME_IN, origfile, -1);
454 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
455 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000456
457 ctx = get_option_sctx("diffexpr");
458 if (ctx != NULL)
459 current_sctx = *ctx;
460
461 // errors are ignored
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100462 tv = eval_expr_ext(p_dex, NULL, TRUE);
Bram Moolenaar39b89442022-01-22 18:21:36 +0000463 free_tv(tv);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000464
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200465 set_vim_var_string(VV_FNAME_IN, NULL, -1);
466 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
467 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000468 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200469}
470
471 void
472eval_patch(
473 char_u *origfile,
474 char_u *difffile,
475 char_u *outfile)
476{
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000477 sctx_T saved_sctx = current_sctx;
478 sctx_T *ctx;
479 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200480
481 set_vim_var_string(VV_FNAME_IN, origfile, -1);
482 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
483 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000484
485 ctx = get_option_sctx("patchexpr");
486 if (ctx != NULL)
487 current_sctx = *ctx;
488
489 // errors are ignored
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100490 tv = eval_expr_ext(p_pex, NULL, TRUE);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000491 free_tv(tv);
492
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200493 set_vim_var_string(VV_FNAME_IN, NULL, -1);
494 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
495 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000496 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200497}
498# endif
499
500#if defined(FEAT_SPELL) || defined(PROTO)
501/*
502 * Evaluate an expression to a list with suggestions.
503 * For the "expr:" part of 'spellsuggest'.
504 * Returns NULL when there is an error.
505 */
506 list_T *
507eval_spell_expr(char_u *badword, char_u *expr)
508{
509 typval_T save_val;
510 typval_T rettv;
511 list_T *list = NULL;
512 char_u *p = skipwhite(expr);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000513 sctx_T saved_sctx = current_sctx;
514 sctx_T *ctx;
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100515 int r;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200516
517 // Set "v:val" to the bad word.
518 prepare_vimvar(VV_VAL, &save_val);
519 set_vim_var_string(VV_VAL, badword, -1);
520 if (p_verbose == 0)
521 ++emsg_off;
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000522 ctx = get_option_sctx("spellsuggest");
523 if (ctx != NULL)
524 current_sctx = *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200525
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100526 r = may_call_simple_func(p, &rettv);
527 if (r == NOTDONE)
528 r = eval1(&p, &rettv, &EVALARG_EVALUATE);
529 if (r == OK)
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200530 {
531 if (rettv.v_type != VAR_LIST)
532 clear_tv(&rettv);
533 else
534 list = rettv.vval.v_list;
535 }
536
537 if (p_verbose == 0)
538 --emsg_off;
539 clear_tv(get_vim_var_tv(VV_VAL));
540 restore_vimvar(VV_VAL, &save_val);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000541 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200542
543 return list;
544}
545
546/*
547 * "list" is supposed to contain two items: a word and a number. Return the
548 * word in "pp" and the number as the return value.
549 * Return -1 if anything isn't right.
550 * Used to get the good word and score from the eval_spell_expr() result.
551 */
552 int
553get_spellword(list_T *list, char_u **pp)
554{
555 listitem_T *li;
556
557 li = list->lv_first;
558 if (li == NULL)
559 return -1;
560 *pp = tv_get_string(&li->li_tv);
561
562 li = li->li_next;
563 if (li == NULL)
564 return -1;
565 return (int)tv_get_number(&li->li_tv);
566}
567#endif
568
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200569/*
570 * Prepare v: variable "idx" to be used.
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200571 * Save the current typeval in "save_tv" and clear it.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200572 * When not used yet add the variable to the v: hashtable.
573 */
574 void
575prepare_vimvar(int idx, typval_T *save_tv)
576{
577 *save_tv = vimvars[idx].vv_tv;
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200578 vimvars[idx].vv_str = NULL; // don't free it now
Bram Moolenaard787e402021-12-24 21:36:12 +0000579 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000580 hash_add(&vimvarht, vimvars[idx].vv_di.di_key, "prepare vimvar");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200581}
582
583/*
584 * Restore v: variable "idx" to typeval "save_tv".
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200585 * Note that the v: variable must have been cleared already.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200586 * When no longer defined, remove the variable from the v: hashtable.
587 */
588 void
589restore_vimvar(int idx, typval_T *save_tv)
590{
591 hashitem_T *hi;
592
593 vimvars[idx].vv_tv = *save_tv;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000594 if (vimvars[idx].vv_tv_type != VAR_UNKNOWN)
595 return;
596
597 hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
598 if (HASHITEM_EMPTY(hi))
599 internal_error("restore_vimvar()");
600 else
601 hash_remove(&vimvarht, hi, "restore vimvar");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200602}
603
604/*
605 * List Vim variables.
606 */
607 static void
608list_vim_vars(int *first)
609{
610 list_hashtable_vars(&vimvarht, "v:", FALSE, first);
611}
612
613/*
614 * List script-local variables, if there is a script.
615 */
616 static void
617list_script_vars(int *first)
618{
Bram Moolenaare3d46852020-08-29 13:39:17 +0200619 if (SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200620 list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
621 "s:", FALSE, first);
622}
623
624/*
Bram Moolenaar9510d222022-09-11 15:14:05 +0100625 * Return TRUE if "name" starts with "g:", "w:", "t:" or "b:".
626 * But only when an identifier character follows.
627 */
628 int
629is_scoped_variable(char_u *name)
630{
631 return vim_strchr((char_u *)"gwbt", name[0]) != NULL
632 && name[1] == ':'
633 && eval_isnamec(name[2]);
634}
635
636/*
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100637 * Evaluate one Vim expression {expr} in string "p" and append the
638 * resulting string to "gap". "p" points to the opening "{".
Bram Moolenaar70c41242022-05-10 18:11:43 +0100639 * When "evaluate" is FALSE only skip over the expression.
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100640 * Return a pointer to the character after "}", NULL for an error.
641 */
642 char_u *
Bram Moolenaar70c41242022-05-10 18:11:43 +0100643eval_one_expr_in_str(char_u *p, garray_T *gap, int evaluate)
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100644{
645 char_u *block_start = skipwhite(p + 1); // skip the opening {
646 char_u *block_end = block_start;
647 char_u *expr_val;
648
649 if (*block_start == NUL)
650 {
651 semsg(_(e_missing_close_curly_str), p);
652 return NULL;
653 }
654 if (skip_expr(&block_end, NULL) == FAIL)
655 return NULL;
656 block_end = skipwhite(block_end);
657 if (*block_end != '}')
658 {
659 semsg(_(e_missing_close_curly_str), p);
660 return NULL;
661 }
Bram Moolenaar70c41242022-05-10 18:11:43 +0100662 if (evaluate)
663 {
664 *block_end = NUL;
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100665 expr_val = eval_to_string(block_start, TRUE, FALSE);
Bram Moolenaar70c41242022-05-10 18:11:43 +0100666 *block_end = '}';
667 if (expr_val == NULL)
668 return NULL;
669 ga_concat(gap, expr_val);
670 vim_free(expr_val);
671 }
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100672
673 return block_end + 1;
674}
675
676/*
677 * Evaluate all the Vim expressions {expr} in "str" and return the resulting
678 * string in allocated memory. "{{" is reduced to "{" and "}}" to "}".
679 * Used for a heredoc assignment.
680 * Returns NULL for an error.
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100681 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +0100682 static char_u *
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100683eval_all_expr_in_str(char_u *str)
684{
685 garray_T ga;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100686 char_u *p;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100687
688 ga_init2(&ga, 1, 80);
689 p = str;
690
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100691 while (*p != NUL)
692 {
LemonBoy2eaef102022-05-06 13:14:50 +0100693 char_u *lit_start;
LemonBoy2eaef102022-05-06 13:14:50 +0100694 int escaped_brace = FALSE;
695
696 // Look for a block start.
697 lit_start = p;
698 while (*p != '{' && *p != '}' && *p != NUL)
699 ++p;
700
701 if (*p != NUL && *p == p[1])
702 {
703 // Escaped brace, unescape and continue.
704 // Include the brace in the literal string.
705 ++p;
706 escaped_brace = TRUE;
707 }
708 else if (*p == '}')
709 {
710 semsg(_(e_stray_closing_curly_str), str);
711 ga_clear(&ga);
712 return NULL;
713 }
714
715 // Append the literal part.
716 ga_concat_len(&ga, lit_start, (size_t)(p - lit_start));
717
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100718 if (*p == NUL)
LemonBoy2eaef102022-05-06 13:14:50 +0100719 break;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100720
LemonBoy2eaef102022-05-06 13:14:50 +0100721 if (escaped_brace)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100722 {
LemonBoy2eaef102022-05-06 13:14:50 +0100723 // Skip the second brace.
724 ++p;
725 continue;
726 }
727
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100728 // Evaluate the expression and append the result.
Bram Moolenaar70c41242022-05-10 18:11:43 +0100729 p = eval_one_expr_in_str(p, &ga, TRUE);
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100730 if (p == NULL)
LemonBoy2eaef102022-05-06 13:14:50 +0100731 {
732 ga_clear(&ga);
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100733 return NULL;
734 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100735 }
736 ga_append(&ga, NUL);
737
738 return ga.ga_data;
739}
740
741/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200742 * Get a list of lines from a HERE document. The here document is a list of
743 * lines surrounded by a marker.
744 * cmd << {marker}
745 * {line1}
746 * {line2}
747 * ....
748 * {marker}
749 *
750 * The {marker} is a string. If the optional 'trim' word is supplied before the
751 * marker, then the leading indentation before the lines (matching the
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100752 * indentation in the "cmd" line) is stripped.
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200753 *
754 * When getting lines for an embedded script (e.g. python, lua, perl, ruby,
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100755 * tcl, mzscheme), "script_get" is set to TRUE. In this case, if the marker is
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200756 * missing, then '.' is accepted as a marker.
757 *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100758 * When compiling a heredoc assignment to a variable in a Vim9 def function,
759 * "vim9compile" is set to TRUE. In this case, instead of generating a list of
760 * string values from the heredoc, vim9 instructions are generated. On success
761 * the returned list will be empty.
762 *
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100763 * Returns a List with {lines} or NULL on failure.
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200764 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100765 list_T *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100766heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200767{
Bram Moolenaar42ccb8d2022-04-18 15:45:23 +0100768 char_u *theline = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200769 char_u *marker;
770 list_T *l;
771 char_u *p;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100772 char_u *str;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200773 int marker_indent_len = 0;
774 int text_indent_len = 0;
775 char_u *text_indent = NULL;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200776 char_u dot[] = ".";
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200777 int comment_char = in_vim9script() ? '#' : '"';
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100778 int evalstr = FALSE;
779 int eval_failed = FALSE;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100780 cctx_T *cctx = vim9compile ? eap->cookie : NULL;
781 int count = 0;
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200782 int heredoc_in_string = FALSE;
783 char_u *line_arg = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200784
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200785 if (eap->ea_getline == NULL && vim_strchr(cmd, '\n') == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200786 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000787 emsg(_(e_cannot_use_heredoc_here));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200788 return NULL;
789 }
790
791 // Check for the optional 'trim' word before the marker
792 cmd = skipwhite(cmd);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200793
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100794 while (TRUE)
795 {
796 if (STRNCMP(cmd, "trim", 4) == 0
797 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200798 {
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100799 cmd = skipwhite(cmd + 4);
800
801 // Trim the indentation from all the lines in the here document.
802 // The amount of indentation trimmed is the same as the indentation
803 // of the first line after the :let command line. To find the end
804 // marker the indent of the :let command line is trimmed.
805 p = *eap->cmdlinep;
806 while (VIM_ISWHITE(*p))
807 {
808 p++;
809 marker_indent_len++;
810 }
811 text_indent_len = -1;
812
813 continue;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200814 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100815 if (STRNCMP(cmd, "eval", 4) == 0
816 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
817 {
818 cmd = skipwhite(cmd + 4);
819 evalstr = TRUE;
820 continue;
821 }
822 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200823 }
824
825 // The marker is the next word.
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200826 if (*cmd != NUL && *cmd != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200827 {
828 marker = skipwhite(cmd);
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200829 p = skiptowhite_or_nl(marker);
830 if (*p == NL)
831 {
832 // heredoc in a string
833 line_arg = p + 1;
834 heredoc_in_string = TRUE;
835 }
836 else if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200837 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000838 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200839 return NULL;
840 }
841 *p = NUL;
Bram Moolenaar6ab09532020-05-01 14:10:13 +0200842 if (!script_get && vim_islower(*marker))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200843 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000844 emsg(_(e_marker_cannot_start_with_lower_case_letter));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200845 return NULL;
846 }
847 }
848 else
849 {
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200850 // When getting lines for an embedded script, if the marker is missing,
851 // accept '.' as the marker.
852 if (script_get)
853 marker = dot;
854 else
855 {
Bram Moolenaar1a992222021-12-31 17:25:48 +0000856 emsg(_(e_missing_marker));
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200857 return NULL;
858 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200859 }
860
861 l = list_alloc();
862 if (l == NULL)
863 return NULL;
864
865 for (;;)
866 {
867 int mi = 0;
868 int ti = 0;
869
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200870 if (heredoc_in_string)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200871 {
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200872 char_u *next_line;
873
874 // heredoc in a string separated by newlines. Get the next line
875 // from the string.
876
877 if (*line_arg == NUL)
878 {
879 semsg(_(e_missing_end_marker_str), marker);
880 break;
881 }
882
883 theline = line_arg;
884 next_line = vim_strchr(theline, '\n');
885 if (next_line == NULL)
886 line_arg += STRLEN(line_arg);
887 else
888 {
889 *next_line = NUL;
890 line_arg = next_line + 1;
891 }
892 }
893 else
894 {
895 vim_free(theline);
896 theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
897 if (theline == NULL)
898 {
899 semsg(_(e_missing_end_marker_str), marker);
900 break;
901 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200902 }
903
904 // with "trim": skip the indent matching the :let line to find the
905 // marker
906 if (marker_indent_len > 0
907 && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0)
908 mi = marker_indent_len;
909 if (STRCMP(marker, theline + mi) == 0)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200910 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200911
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100912 // If expression evaluation failed in the heredoc, then skip till the
913 // end marker.
914 if (eval_failed)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100915 continue;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100916
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200917 if (text_indent_len == -1 && *theline != NUL)
918 {
919 // set the text indent from the first line.
920 p = theline;
921 text_indent_len = 0;
922 while (VIM_ISWHITE(*p))
923 {
924 p++;
925 text_indent_len++;
926 }
927 text_indent = vim_strnsave(theline, text_indent_len);
928 }
929 // with "trim": skip the indent matching the first line
930 if (text_indent != NULL)
931 for (ti = 0; ti < text_indent_len; ++ti)
932 if (theline[ti] != text_indent[ti])
933 break;
934
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100935 str = theline + ti;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100936 if (vim9compile)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100937 {
LemonBoy2eaef102022-05-06 13:14:50 +0100938 if (compile_all_expr_in_str(str, evalstr, cctx) == FAIL)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100939 {
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100940 vim_free(theline);
941 vim_free(text_indent);
942 return FAIL;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100943 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100944 count++;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100945 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100946 else
947 {
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200948 int free_str = FALSE;
949
Bram Moolenaar05c7f5d2022-04-28 16:51:41 +0100950 if (evalstr && !eap->skip)
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100951 {
952 str = eval_all_expr_in_str(str);
953 if (str == NULL)
954 {
955 // expression evaluation failed
956 eval_failed = TRUE;
957 continue;
958 }
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200959 free_str = TRUE;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100960 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100961
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100962 if (list_append_string(l, str, -1) == FAIL)
963 break;
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200964 if (free_str)
965 vim_free(str);
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100966 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200967 }
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200968 if (heredoc_in_string)
969 // Next command follows the heredoc in the string.
970 eap->nextcmd = line_arg;
971 else
972 vim_free(theline);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200973 vim_free(text_indent);
974
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100975 if (vim9compile && cctx->ctx_skip != SKIP_YES && !eval_failed)
976 generate_NEWLIST(cctx, count, FALSE);
977
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100978 if (eval_failed)
979 {
980 // expression evaluation in the heredoc failed
981 list_free(l);
982 return NULL;
983 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200984 return l;
985}
986
987/*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200988 * Vim9 variable declaration:
989 * ":var name"
990 * ":var name: type"
991 * ":var name = expr"
992 * ":var name: type = expr"
993 * etc.
994 */
995 void
996ex_var(exarg_T *eap)
997{
Bram Moolenaar330a3882022-03-05 11:05:57 +0000998 char_u *p = eap->cmd;
Bram Moolenaare1d12112022-03-05 11:37:48 +0000999 int has_var;
Bram Moolenaar330a3882022-03-05 11:05:57 +00001000
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001001 if (!in_vim9script())
1002 {
1003 semsg(_(e_str_cannot_be_used_in_legacy_vim_script), ":var");
1004 return;
1005 }
Bram Moolenaare1d12112022-03-05 11:37:48 +00001006 has_var = checkforcmd_noparen(&p, "var", 3);
1007 if (current_sctx.sc_sid == 0 && has_var)
Bram Moolenaar0e1574c2022-03-03 17:05:35 +00001008 {
1009 emsg(_(e_cannot_declare_variable_on_command_line));
1010 return;
1011 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001012 ex_let(eap);
1013}
1014
1015/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001016 * ":let" list all variable values
1017 * ":let var1 var2" list variable values
1018 * ":let var = expr" assignment command.
1019 * ":let var += expr" assignment command.
1020 * ":let var -= expr" assignment command.
1021 * ":let var *= expr" assignment command.
1022 * ":let var /= expr" assignment command.
1023 * ":let var %= expr" assignment command.
1024 * ":let var .= expr" assignment command.
1025 * ":let var ..= expr" assignment command.
1026 * ":let [var1, var2] = expr" unpack list.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001027 * ":let var =<< ..." heredoc
Bram Moolenaard672dde2020-02-26 13:43:51 +01001028 * ":let var: string" Vim9 declaration
Bram Moolenaar2eec3792020-05-25 20:33:55 +02001029 *
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001030 * ":final var = expr" assignment command.
1031 * ":final [var1, var2] = expr" unpack list.
1032 *
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001033 * ":const" list all variable values
1034 * ":const var1 var2" list variable values
1035 * ":const var = expr" assignment command.
1036 * ":const [var1, var2] = expr" unpack list.
1037 */
1038 void
Bram Moolenaar2eec3792020-05-25 20:33:55 +02001039ex_let(exarg_T *eap)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001040{
1041 char_u *arg = eap->arg;
1042 char_u *expr = NULL;
1043 typval_T rettv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001044 int var_count = 0;
1045 int semicolon = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001046 char_u op[4];
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001047 char_u *argend;
1048 int first = TRUE;
1049 int concat;
Bram Moolenaar32e35112020-05-14 22:41:15 +02001050 int has_assign;
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001051 int flags = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001052 int vim9script = in_vim9script();
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001053
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001054 if (eap->cmdidx == CMD_final && !vim9script)
1055 {
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001056 // In legacy Vim script ":final" is short for ":finally".
1057 ex_finally(eap);
1058 return;
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001059 }
Bram Moolenaarc58f5452020-10-21 20:58:52 +02001060 if (eap->cmdidx == CMD_let && vim9script)
Bram Moolenaarcfcd0112020-09-27 15:19:27 +02001061 {
1062 emsg(_(e_cannot_use_let_in_vim9_script));
1063 return;
1064 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001065
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001066 if (eap->cmdidx == CMD_const)
1067 flags |= ASSIGN_CONST;
1068 else if (eap->cmdidx == CMD_final)
1069 flags |= ASSIGN_FINAL;
1070
1071 // Vim9 assignment without ":let", ":const" or ":final"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001072 if (eap->arg == eap->cmd)
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001073 flags |= ASSIGN_NO_DECL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001074
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001075 argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001076 if (argend == NULL)
1077 return;
1078 if (argend > arg && argend[-1] == '.') // for var.='str'
1079 --argend;
1080 expr = skipwhite(argend);
1081 concat = expr[0] == '.'
Bram Moolenaardd9de502021-08-15 13:49:42 +02001082 && ((expr[1] == '=' && in_old_script(2))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001083 || (expr[1] == '.' && expr[2] == '='));
Bram Moolenaar32e35112020-05-14 22:41:15 +02001084 has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
1085 && expr[1] == '=');
Bram Moolenaar822ba242020-05-24 23:00:18 +02001086 if (!has_assign && !concat)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001087 {
1088 // ":let" without "=": list variables
1089 if (*arg == '[')
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001090 emsg(_(e_invalid_argument));
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001091 else if (expr[0] == '.' && expr[1] == '=')
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001092 emsg(_(e_dot_equal_not_supported_with_script_version_two));
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001093 else if (!ends_excmd2(eap->cmd, arg))
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001094 {
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001095 if (vim9script)
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001096 {
Bram Moolenaarccc25aa2021-03-26 21:27:52 +01001097 if (!ends_excmd2(eap->cmd, skipwhite(argend)))
Bram Moolenaar74409f62022-01-01 15:58:22 +00001098 semsg(_(e_trailing_characters_str), argend);
Bram Moolenaarccc25aa2021-03-26 21:27:52 +01001099 else
1100 // Vim9 declaration ":var name: type"
1101 arg = vim9_declare_scriptvar(eap, arg);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001102 }
1103 else
1104 {
1105 // ":let var1 var2" - list values
1106 arg = list_arg_vars(eap, arg, &first);
1107 }
1108 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001109 else if (!eap->skip)
1110 {
1111 // ":let"
1112 list_glob_vars(&first);
1113 list_buf_vars(&first);
1114 list_win_vars(&first);
1115 list_tab_vars(&first);
1116 list_script_vars(&first);
1117 list_func_vars(&first);
1118 list_vim_vars(&first);
1119 }
Bram Moolenaar63b91732021-08-05 20:40:03 +02001120 set_nextcmd(eap, arg);
zeertzjq474891b2023-04-12 21:36:03 +01001121 return;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001122 }
zeertzjq474891b2023-04-12 21:36:03 +01001123
1124 if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001125 {
Bram Moolenaard9876422022-10-12 12:58:54 +01001126 list_T *l = NULL;
Bram Moolenaar81530e32021-07-28 21:25:49 +02001127 long cur_lnum = SOURCING_LNUM;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001128
Bram Moolenaard9876422022-10-12 12:58:54 +01001129 // :let text =<< [trim] [eval] END
1130 // :var text =<< [trim] [eval] END
1131 if (vim9script && !eap->skip && (!VIM_ISWHITE(expr[-1])
1132 || !IS_WHITE_OR_NUL(expr[3])))
1133 semsg(_(e_white_space_required_before_and_after_str_at_str),
1134 "=<<", expr);
1135 else
1136 l = heredoc_get(eap, expr + 3, FALSE, FALSE);
1137
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001138 if (l != NULL)
1139 {
1140 rettv_list_set(&rettv, l);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001141 if (!eap->skip)
1142 {
Bram Moolenaar81530e32021-07-28 21:25:49 +02001143 // errors are for the assignment, not the end marker
1144 SOURCING_LNUM = cur_lnum;
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001145 op[0] = '=';
1146 op[1] = NUL;
1147 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001148 flags, op);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001149 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001150 clear_tv(&rettv);
1151 }
zeertzjq474891b2023-04-12 21:36:03 +01001152 return;
1153 }
1154
1155 evalarg_T evalarg;
1156 int len = 1;
1157
1158 CLEAR_FIELD(rettv);
1159
1160 int cur_lnum;
1161
1162 op[0] = '=';
1163 op[1] = NUL;
1164 if (*expr != '=')
1165 {
1166 if (vim9script && (flags & ASSIGN_NO_DECL) == 0)
1167 {
1168 // +=, /=, etc. require an existing variable
1169 semsg(_(e_cannot_use_operator_on_new_variable_str), eap->arg);
1170 }
1171 else if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
1172 {
1173 op[0] = *expr; // +=, -=, *=, /=, %= or .=
1174 ++len;
1175 if (expr[0] == '.' && expr[1] == '.') // ..=
1176 {
1177 ++expr;
1178 ++len;
1179 }
1180 }
1181 expr += 2;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001182 }
1183 else
zeertzjq474891b2023-04-12 21:36:03 +01001184 ++expr;
1185
1186 if (vim9script && !eap->skip && (!VIM_ISWHITE(*argend)
1187 || !IS_WHITE_OR_NUL(*expr)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001188 {
zeertzjq474891b2023-04-12 21:36:03 +01001189 vim_strncpy(op, expr - len, len);
1190 semsg(_(e_white_space_required_before_and_after_str_at_str),
1191 op, argend);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001192 }
zeertzjq474891b2023-04-12 21:36:03 +01001193
1194 if (eap->skip)
1195 ++emsg_skip;
1196 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
1197 expr = skipwhite_and_linebreak(expr, &evalarg);
1198 cur_lnum = SOURCING_LNUM;
1199 int eval_res = eval0(expr, &rettv, eap, &evalarg);
1200 if (eap->skip)
1201 --emsg_skip;
1202 clear_evalarg(&evalarg, eap);
1203
1204 // Restore the line number so that any type error is given for the
1205 // declaration, not the expression.
1206 SOURCING_LNUM = cur_lnum;
1207
1208 if (!eap->skip && eval_res != FAIL)
1209 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
1210 flags, op);
1211 if (eval_res != FAIL)
1212 clear_tv(&rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001213}
1214
1215/*
Bram Moolenaar6c3843c2021-03-04 12:38:21 +01001216 * Assign the typeval "tv" to the variable or variables at "arg_start".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001217 * Handles both "var" with any type and "[var, var; var]" with a list type.
1218 * When "op" is not NULL it points to a string with characters that
1219 * must appear after the variable(s). Use "+", "-" or "." for add, subtract
1220 * or concatenate.
1221 * Returns OK or FAIL;
1222 */
1223 int
1224ex_let_vars(
1225 char_u *arg_start,
1226 typval_T *tv,
1227 int copy, // copy values from "tv", don't move
1228 int semicolon, // from skip_var_list()
1229 int var_count, // from skip_var_list()
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001230 int flags, // ASSIGN_FINAL, ASSIGN_CONST, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001231 char_u *op)
1232{
1233 char_u *arg = arg_start;
1234 list_T *l;
1235 int i;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001236 int var_idx = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001237 listitem_T *item;
1238 typval_T ltv;
1239
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001240 if (tv->v_type == VAR_VOID)
1241 {
1242 emsg(_(e_cannot_use_void_value));
1243 return FAIL;
1244 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001245 if (*arg != '[')
1246 {
1247 // ":let var = expr" or ":for var in list"
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001248 if (ex_let_one(arg, tv, copy, flags, op, op, var_idx) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001249 return FAIL;
1250 return OK;
1251 }
1252
1253 // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
1254 if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
1255 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001256 emsg(_(e_list_required));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001257 return FAIL;
1258 }
1259
1260 i = list_len(l);
1261 if (semicolon == 0 && var_count < i)
1262 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00001263 emsg(_(e_less_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001264 return FAIL;
1265 }
1266 if (var_count - semicolon > i)
1267 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00001268 emsg(_(e_more_targets_than_list_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001269 return FAIL;
1270 }
1271
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02001272 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001273 item = l->lv_first;
1274 while (*arg != ']')
1275 {
1276 arg = skipwhite(arg + 1);
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001277 ++var_idx;
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001278 arg = ex_let_one(arg, &item->li_tv, TRUE,
1279 flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001280 item = item->li_next;
1281 if (arg == NULL)
1282 return FAIL;
1283
1284 arg = skipwhite(arg);
1285 if (*arg == ';')
1286 {
1287 // Put the rest of the list (may be empty) in the var after ';'.
1288 // Create a new list for this.
1289 l = list_alloc();
1290 if (l == NULL)
1291 return FAIL;
1292 while (item != NULL)
1293 {
1294 list_append_tv(l, &item->li_tv);
1295 item = item->li_next;
1296 }
1297
1298 ltv.v_type = VAR_LIST;
1299 ltv.v_lock = 0;
1300 ltv.vval.v_list = l;
1301 l->lv_refcount = 1;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001302 ++var_idx;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001303
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001304 arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
1305 flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001306 clear_tv(&ltv);
1307 if (arg == NULL)
1308 return FAIL;
1309 break;
1310 }
1311 else if (*arg != ',' && *arg != ']')
1312 {
1313 internal_error("ex_let_vars()");
1314 return FAIL;
1315 }
1316 }
1317
1318 return OK;
1319}
1320
1321/*
1322 * Skip over assignable variable "var" or list of variables "[var, var]".
1323 * Used for ":let varvar = expr" and ":for varvar in expr".
1324 * For "[var, var]" increment "*var_count" for each variable.
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001325 * for "[var, var; var]" set "semicolon" to 1.
1326 * If "silent" is TRUE do not give an "invalid argument" error message.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001327 * Return NULL for an error.
1328 */
1329 char_u *
1330skip_var_list(
1331 char_u *arg,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001332 int include_type,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001333 int *var_count,
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001334 int *semicolon,
1335 int silent)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001336{
1337 char_u *p, *s;
1338
1339 if (*arg == '[')
1340 {
1341 // "[var, var]": find the matching ']'.
1342 p = arg;
1343 for (;;)
1344 {
1345 p = skipwhite(p + 1); // skip whites after '[', ';' or ','
Bram Moolenaar036d0712021-01-17 20:23:38 +01001346 s = skip_var_one(p, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001347 if (s == p)
1348 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001349 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001350 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001351 return NULL;
1352 }
1353 ++*var_count;
1354
1355 p = skipwhite(s);
1356 if (*p == ']')
1357 break;
1358 else if (*p == ';')
1359 {
1360 if (*semicolon == 1)
1361 {
Bram Moolenaar8b716f52022-02-15 21:17:56 +00001362 if (!silent)
1363 emsg(_(e_double_semicolon_in_list_of_variables));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001364 return NULL;
1365 }
1366 *semicolon = 1;
1367 }
1368 else if (*p != ',')
1369 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001370 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001371 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001372 return NULL;
1373 }
1374 }
1375 return p + 1;
1376 }
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01001377
Bram Moolenaare8e369a2022-09-21 18:59:14 +01001378 return skip_var_one(arg, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001379}
1380
1381/*
1382 * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
1383 * l[idx].
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001384 * In Vim9 script also skip over ": type" if "include_type" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001385 */
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001386 char_u *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001387skip_var_one(char_u *arg, int include_type)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001388{
Bram Moolenaar585587d2021-01-17 20:52:13 +01001389 char_u *end;
1390 int vim9 = in_vim9script();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001391
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001392 if (*arg == '@' && arg[1] != NUL)
1393 return arg + 2;
Bram Moolenaar1573e732022-11-16 20:33:21 +00001394
1395 // termcap option name may have non-alpha characters
1396 if (STRNCMP(arg, "&t_", 3) == 0 && arg[3] != NUL && arg[4] != NUL)
1397 return arg + 5;
1398
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001399 end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001400 NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
Bram Moolenaar036d0712021-01-17 20:23:38 +01001401
1402 // "a: type" is declaring variable "a" with a type, not "a:".
1403 // Same for "s: type".
Bram Moolenaar585587d2021-01-17 20:52:13 +01001404 if (vim9 && end == arg + 2 && end[-1] == ':')
Bram Moolenaar036d0712021-01-17 20:23:38 +01001405 --end;
1406
Bram Moolenaar585587d2021-01-17 20:52:13 +01001407 if (include_type && vim9)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001408 {
Bram Moolenaarce93d162023-01-30 21:12:34 +00001409 if (*skipwhite(end) == ':')
1410 end = skip_type(skipwhite(skipwhite(end) + 1), FALSE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001411 }
1412 return end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001413}
1414
1415/*
1416 * List variables for hashtab "ht" with prefix "prefix".
1417 * If "empty" is TRUE also list NULL strings as empty strings.
1418 */
1419 void
1420list_hashtable_vars(
1421 hashtab_T *ht,
1422 char *prefix,
1423 int empty,
1424 int *first)
1425{
1426 hashitem_T *hi;
1427 dictitem_T *di;
1428 int todo;
1429 char_u buf[IOSIZE];
1430
Bram Moolenaaref2c3252022-11-25 16:31:51 +00001431 int save_ht_flags = ht->ht_flags;
1432 ht->ht_flags |= HTFLAGS_FROZEN;
1433
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001434 todo = (int)ht->ht_used;
1435 for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
1436 {
1437 if (!HASHITEM_EMPTY(hi))
1438 {
1439 --todo;
1440 di = HI2DI(hi);
1441
1442 // apply :filter /pat/ to variable name
1443 vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
1444 vim_strcat((char_u *)buf, di->di_key, IOSIZE);
1445 if (message_filtered(buf))
1446 continue;
1447
1448 if (empty || di->di_tv.v_type != VAR_STRING
1449 || di->di_tv.vval.v_string != NULL)
1450 list_one_var(di, prefix, first);
1451 }
1452 }
Bram Moolenaaref2c3252022-11-25 16:31:51 +00001453
1454 ht->ht_flags = save_ht_flags;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001455}
1456
1457/*
1458 * List global variables.
1459 */
1460 static void
1461list_glob_vars(int *first)
1462{
1463 list_hashtable_vars(&globvarht, "", TRUE, first);
1464}
1465
1466/*
1467 * List buffer variables.
1468 */
1469 static void
1470list_buf_vars(int *first)
1471{
1472 list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
1473}
1474
1475/*
1476 * List window variables.
1477 */
1478 static void
1479list_win_vars(int *first)
1480{
1481 list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
1482}
1483
1484/*
1485 * List tab page variables.
1486 */
1487 static void
1488list_tab_vars(int *first)
1489{
1490 list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
1491}
1492
1493/*
1494 * List variables in "arg".
1495 */
1496 static char_u *
1497list_arg_vars(exarg_T *eap, char_u *arg, int *first)
1498{
1499 int error = FALSE;
1500 int len;
1501 char_u *name;
1502 char_u *name_start;
1503 char_u *arg_subsc;
1504 char_u *tofree;
1505 typval_T tv;
1506
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001507 while (!ends_excmd2(eap->cmd, arg) && !got_int)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001508 {
1509 if (error || eap->skip)
1510 {
1511 arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1512 if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
1513 {
1514 emsg_severe = TRUE;
Bram Moolenaar4830c212021-08-14 14:59:27 +02001515 if (!did_emsg)
Bram Moolenaar74409f62022-01-01 15:58:22 +00001516 semsg(_(e_trailing_characters_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001517 break;
1518 }
1519 }
1520 else
1521 {
1522 // get_name_len() takes care of expanding curly braces
1523 name_start = name = arg;
1524 len = get_name_len(&arg, &tofree, TRUE, TRUE);
1525 if (len <= 0)
1526 {
1527 // This is mainly to keep test 49 working: when expanding
1528 // curly braces fails overrule the exception error message.
1529 if (len < 0 && !aborting())
1530 {
1531 emsg_severe = TRUE;
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001532 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001533 break;
1534 }
1535 error = TRUE;
1536 }
1537 else
1538 {
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02001539 arg = skipwhite(arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001540 if (tofree != NULL)
1541 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00001542 if (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01001543 EVAL_VAR_VERBOSE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001544 error = TRUE;
1545 else
1546 {
1547 // handle d.key, l[idx], f(expr)
1548 arg_subsc = arg;
Bram Moolenaar32884ad2022-01-07 12:45:29 +00001549 if (handle_subscript(&arg, name_start, &tv,
1550 &EVALARG_EVALUATE, TRUE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001551 error = TRUE;
1552 else
1553 {
1554 if (arg == arg_subsc && len == 2 && name[1] == ':')
1555 {
1556 switch (*name)
1557 {
1558 case 'g': list_glob_vars(first); break;
1559 case 'b': list_buf_vars(first); break;
1560 case 'w': list_win_vars(first); break;
1561 case 't': list_tab_vars(first); break;
1562 case 'v': list_vim_vars(first); break;
1563 case 's': list_script_vars(first); break;
1564 case 'l': list_func_vars(first); break;
1565 default:
Bram Moolenaara6f79292022-01-04 21:30:47 +00001566 semsg(_(e_cant_list_variables_for_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001567 }
1568 }
1569 else
1570 {
1571 char_u numbuf[NUMBUFLEN];
1572 char_u *tf;
1573 int c;
1574 char_u *s;
1575
1576 s = echo_string(&tv, &tf, numbuf, 0);
1577 c = *arg;
1578 *arg = NUL;
1579 list_one_var_a("",
1580 arg == arg_subsc ? name : name_start,
1581 tv.v_type,
1582 s == NULL ? (char_u *)"" : s,
1583 first);
1584 *arg = c;
1585 vim_free(tf);
1586 }
1587 clear_tv(&tv);
1588 }
1589 }
1590 }
1591
1592 vim_free(tofree);
1593 }
1594
1595 arg = skipwhite(arg);
1596 }
1597
1598 return arg;
1599}
1600
1601/*
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001602 * Set an environment variable, part of ex_let_one().
1603 */
1604 static char_u *
1605ex_let_env(
1606 char_u *arg,
1607 typval_T *tv,
1608 int flags,
1609 char_u *endchars,
1610 char_u *op)
1611{
1612 char_u *arg_end = NULL;
1613 char_u *name;
1614 int len;
1615
1616 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1617 && (flags & ASSIGN_FOR_LOOP) == 0)
1618 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001619 emsg(_(e_cannot_lock_environment_variable));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001620 return NULL;
1621 }
1622
1623 // Find the end of the name.
1624 ++arg;
1625 name = arg;
1626 len = get_env_len(&arg);
1627 if (len == 0)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001628 semsg(_(e_invalid_argument_str), name - 1);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001629 else
1630 {
1631 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001632 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001633 else if (endchars != NULL
1634 && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1635 emsg(_(e_unexpected_characters_in_let));
1636 else if (!check_secure())
1637 {
1638 char_u *tofree = NULL;
1639 int c1 = name[len];
1640 char_u *p;
1641
1642 name[len] = NUL;
1643 p = tv_get_string_chk(tv);
1644 if (p != NULL && op != NULL && *op == '.')
1645 {
1646 int mustfree = FALSE;
1647 char_u *s = vim_getenv(name, &mustfree);
1648
1649 if (s != NULL)
1650 {
1651 p = tofree = concat_str(s, p);
1652 if (mustfree)
1653 vim_free(s);
1654 }
1655 }
1656 if (p != NULL)
1657 {
1658 vim_setenv_ext(name, p);
1659 arg_end = arg;
1660 }
1661 name[len] = c1;
1662 vim_free(tofree);
1663 }
1664 }
1665 return arg_end;
1666}
1667
1668/*
1669 * Set an option, part of ex_let_one().
1670 */
1671 static char_u *
1672ex_let_option(
1673 char_u *arg,
1674 typval_T *tv,
1675 int flags,
1676 char_u *endchars,
1677 char_u *op)
1678{
1679 char_u *p;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001680 int scope;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001681 char_u *arg_end = NULL;
1682
1683 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1684 && (flags & ASSIGN_FOR_LOOP) == 0)
1685 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001686 emsg(_(e_cannot_lock_option));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001687 return NULL;
1688 }
1689
1690 // Find the end of the name.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001691 p = find_option_end(&arg, &scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001692 if (p == NULL || (endchars != NULL
1693 && vim_strchr(endchars, *skipwhite(p)) == NULL))
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001694 {
zeertzjq4c7cb372023-06-14 16:39:54 +01001695 emsg(_(e_unexpected_characters_in_let));
1696 return NULL;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001697 }
zeertzjq4c7cb372023-06-14 16:39:54 +01001698
1699 int c1;
1700 long n = 0;
1701 getoption_T opt_type;
1702 long numval;
1703 char_u *stringval = NULL;
1704 char_u *s = NULL;
1705 int failed = FALSE;
1706 int opt_p_flags;
1707 char_u *tofree = NULL;
1708 char_u numbuf[NUMBUFLEN];
1709
1710 c1 = *p;
1711 *p = NUL;
1712
1713 opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, scope);
1714 if (opt_type == gov_unknown && arg[0] != 't' && arg[1] != '_')
1715 {
1716 semsg(_(e_unknown_option_str_2), arg);
1717 goto theend;
1718 }
1719 if (op != NULL && *op != '='
1720 && (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
1721 || (opt_type == gov_string && *op != '.')))
1722 {
1723 semsg(_(e_wrong_variable_type_for_str_equal), op);
1724 goto theend;
1725 }
1726
1727 if ((opt_type == gov_bool
1728 || opt_type == gov_number
1729 || opt_type == gov_hidden_bool
1730 || opt_type == gov_hidden_number)
1731 && (tv->v_type != VAR_STRING || !in_vim9script()))
1732 {
1733 if (opt_type == gov_bool || opt_type == gov_hidden_bool)
1734 // bool, possibly hidden
1735 n = (long)tv_get_bool_chk(tv, &failed);
1736 else
1737 // number, possibly hidden
1738 n = (long)tv_get_number_chk(tv, &failed);
1739 if (failed)
1740 goto theend;
1741 }
1742
1743 if ((opt_p_flags & P_FUNC) && (tv->v_type == VAR_PARTIAL
1744 || tv->v_type == VAR_FUNC))
1745 {
1746 // If the option can be set to a function reference or a lambda
1747 // and the passed value is a function reference, then convert it to
1748 // the name (string) of the function reference.
1749 s = tv2string(tv, &tofree, numbuf, 0);
1750 if (s == NULL)
1751 goto theend;
1752 }
1753 // Avoid setting a string option to the text "v:false" or similar.
1754 // In Vim9 script also don't convert a number to string.
1755 else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
1756 && (!in_vim9script() || tv->v_type != VAR_NUMBER))
1757 {
1758 s = tv_get_string_chk(tv);
1759 if (s == NULL)
1760 goto theend;
1761 }
1762 else if (opt_type == gov_string || opt_type == gov_hidden_string)
1763 {
1764 emsg(_(e_string_required));
1765 goto theend;
1766 }
1767
1768 if (op != NULL && *op != '=')
1769 {
1770 // number, in legacy script also bool
1771 if (opt_type == gov_number
1772 || (opt_type == gov_bool && !in_vim9script()))
1773 {
1774 switch (*op)
1775 {
1776 case '+': n = numval + n; break;
1777 case '-': n = numval - n; break;
1778 case '*': n = numval * n; break;
1779 case '/': n = (long)num_divide(numval, n, &failed); break;
1780 case '%': n = (long)num_modulus(numval, n, &failed); break;
1781 }
1782 s = NULL;
1783 if (failed)
1784 goto theend;
1785 }
1786 else if (opt_type == gov_string && stringval != NULL && s != NULL)
1787 {
1788 // string
1789 s = concat_str(stringval, s);
1790 vim_free(stringval);
1791 stringval = s;
1792 }
1793 }
1794
1795 char *err = set_option_value(arg, n, s, scope);
1796 arg_end = p;
1797 if (err != NULL)
1798 emsg(_(err));
1799
1800theend:
1801 *p = c1;
1802 vim_free(stringval);
1803 vim_free(tofree);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001804 return arg_end;
1805}
1806
1807/*
1808 * Set a register, part of ex_let_one().
1809 */
1810 static char_u *
1811ex_let_register(
1812 char_u *arg,
1813 typval_T *tv,
1814 int flags,
1815 char_u *endchars,
1816 char_u *op)
1817{
1818 char_u *arg_end = NULL;
1819
1820 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1821 && (flags & ASSIGN_FOR_LOOP) == 0)
1822 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001823 emsg(_(e_cannot_lock_register));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001824 return NULL;
1825 }
1826 ++arg;
1827 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001828 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001829 else if (endchars != NULL
1830 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1831 emsg(_(e_unexpected_characters_in_let));
1832 else
1833 {
1834 char_u *ptofree = NULL;
1835 char_u *p;
1836
1837 p = tv_get_string_chk(tv);
1838 if (p != NULL && op != NULL && *op == '.')
1839 {
1840 char_u *s = get_reg_contents(*arg == '@'
1841 ? '"' : *arg, GREG_EXPR_SRC);
1842
1843 if (s != NULL)
1844 {
1845 p = ptofree = concat_str(s, p);
1846 vim_free(s);
1847 }
1848 }
1849 if (p != NULL)
1850 {
1851 write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
1852 arg_end = arg + 1;
1853 }
1854 vim_free(ptofree);
1855 }
1856 return arg_end;
1857}
1858
1859/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001860 * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
1861 * Returns a pointer to the char just after the var name.
1862 * Returns NULL if there is an error.
1863 */
1864 static char_u *
1865ex_let_one(
1866 char_u *arg, // points to variable name
1867 typval_T *tv, // value to assign to variable
1868 int copy, // copy value from "tv"
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001869 int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001870 char_u *endchars, // valid chars after variable name or NULL
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001871 char_u *op, // "+", "-", "." or NULL
1872 int var_idx) // variable index for "let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001873{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001874 char_u *arg_end = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001875
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001876 if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001877 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaarc2ee44c2020-08-02 16:59:00 +02001878 && vim_strchr((char_u *)"$@&", *arg) != NULL)
1879 {
1880 vim9_declare_error(arg);
1881 return NULL;
1882 }
1883
Ernie Rael9ed53752023-12-11 17:40:46 +01001884 if (check_typval_is_value(tv) == FAIL)
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02001885 return NULL;
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02001886
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001887 if (*arg == '$')
1888 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001889 // ":let $VAR = expr": Set environment variable.
1890 return ex_let_env(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001891 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001892 else if (*arg == '&')
1893 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001894 // ":let &option = expr": Set option value.
1895 // ":let &l:option = expr": Set local option value.
1896 // ":let &g:option = expr": Set global option value.
1897 // ":for &ts in range(8)": Set option value for for loop
1898 return ex_let_option(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001899 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001900 else if (*arg == '@')
1901 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001902 // ":let @r = expr": Set register contents.
1903 return ex_let_register(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001904 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001905 else if (eval_isnamec1(*arg) || *arg == '{')
1906 {
1907 lval_T lv;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001908 char_u *p;
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001909 int lval_flags = (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
1910 ? GLV_NO_DECL : 0;
Yegappan Lakshmananb5a07192023-10-05 20:14:43 +02001911 lval_flags |= (flags & ASSIGN_FOR_LOOP) ? GLV_FOR_LOOP : 0;
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001912 if (op != NULL && *op != '=')
1913 lval_flags |= GLV_ASSIGN_WITH_OP;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001914
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001915 // ":let var = expr": Set internal variable.
1916 // ":let var: type = expr": Set internal variable with type.
1917 // ":let {expr} = expr": Idem, name made with curly braces
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001918 p = get_lval(arg, tv, &lv, FALSE, FALSE, lval_flags, FNE_CHECK_START);
Bram Moolenaar822ba242020-05-24 23:00:18 +02001919 if (p != NULL && lv.ll_name != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001920 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001921 if (endchars != NULL && vim_strchr(endchars,
1922 *skipwhite(lv.ll_name_end)) == NULL)
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001923 {
Bram Moolenaar108010a2021-06-27 22:03:33 +02001924 emsg(_(e_unexpected_characters_in_let));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001925 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001926 else
1927 {
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001928 set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
Bram Moolenaara3589a02021-04-14 13:30:46 +02001929 arg_end = lv.ll_name_end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001930 }
1931 }
1932 clear_lval(&lv);
1933 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001934 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001935 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001936
1937 return arg_end;
1938}
1939
1940/*
1941 * ":unlet[!] var1 ... " command.
1942 */
1943 void
1944ex_unlet(exarg_T *eap)
1945{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001946 ex_unletlock(eap, eap->arg, 0, 0, do_unlet_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001947}
1948
1949/*
1950 * ":lockvar" and ":unlockvar" commands
1951 */
1952 void
1953ex_lockvar(exarg_T *eap)
1954{
1955 char_u *arg = eap->arg;
1956 int deep = 2;
1957
1958 if (eap->forceit)
1959 deep = -1;
1960 else if (vim_isdigit(*arg))
1961 {
1962 deep = getdigits(&arg);
1963 arg = skipwhite(arg);
1964 }
1965
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001966 ex_unletlock(eap, arg, deep, 0, do_lock_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001967}
1968
1969/*
1970 * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001971 * Also used for Vim9 script. "callback" is invoked as:
1972 * callback(&lv, name_end, eap, deep, cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001973 */
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001974 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001975ex_unletlock(
1976 exarg_T *eap,
1977 char_u *argstart,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02001978 int deep,
1979 int glv_flags,
1980 int (*callback)(lval_T *, char_u *, exarg_T *, int, void *),
1981 void *cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001982{
1983 char_u *arg = argstart;
1984 char_u *name_end;
1985 int error = FALSE;
1986 lval_T lv;
1987
1988 do
1989 {
1990 if (*arg == '$')
1991 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02001992 lv.ll_name = arg;
1993 lv.ll_tv = NULL;
1994 ++arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001995 if (get_env_len(&arg) == 0)
1996 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001997 semsg(_(e_invalid_argument_str), arg - 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001998 return;
1999 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002000 if (!error && !eap->skip
2001 && callback(&lv, arg, eap, deep, cookie) == FAIL)
2002 error = TRUE;
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002003 name_end = arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002004 }
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002005 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002006 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002007 // Parse the name and find the end.
2008 name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error,
Bram Moolenaarc3689572021-01-01 19:40:02 +01002009 glv_flags | GLV_NO_DECL, FNE_CHECK_START);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002010 if (lv.ll_name == NULL)
2011 error = TRUE; // error but continue parsing
2012 if (name_end == NULL || (!VIM_ISWHITE(*name_end)
2013 && !ends_excmd(*name_end)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002014 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002015 if (name_end != NULL)
2016 {
2017 emsg_severe = TRUE;
Bram Moolenaar74409f62022-01-01 15:58:22 +00002018 semsg(_(e_trailing_characters_str), name_end);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002019 }
2020 if (!(eap->skip || error))
2021 clear_lval(&lv);
2022 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002023 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002024
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002025 if (!error && !eap->skip
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002026 && callback(&lv, name_end, eap, deep, cookie) == FAIL)
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002027 error = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002028
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002029 if (!eap->skip)
2030 clear_lval(&lv);
2031 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002032
2033 arg = skipwhite(name_end);
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002034 } while (!ends_excmd2(name_end, arg));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002035
Bram Moolenaar63b91732021-08-05 20:40:03 +02002036 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002037}
2038
2039 static int
2040do_unlet_var(
2041 lval_T *lp,
2042 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002043 exarg_T *eap,
2044 int deep UNUSED,
2045 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002046{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002047 int forceit = eap->forceit;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002048 int ret = OK;
2049 int cc;
2050
2051 if (lp->ll_tv == NULL)
2052 {
2053 cc = *name_end;
2054 *name_end = NUL;
2055
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002056 // Environment variable, normal name or expanded name.
2057 if (*lp->ll_name == '$')
LemonBoy77142312022-04-15 20:50:46 +01002058 vim_unsetenv_ext(lp->ll_name + 1);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002059 else if (do_unlet(lp->ll_name, forceit) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002060 ret = FAIL;
2061 *name_end = cc;
2062 }
2063 else if ((lp->ll_list != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02002064 && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002065 || (lp->ll_dict != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02002066 && value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002067 return FAIL;
2068 else if (lp->ll_range)
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002069 list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_n1,
2070 !lp->ll_empty2, lp->ll_n2);
2071 else if (lp->ll_list != NULL)
2072 // unlet a List item.
2073 listitem_remove(lp->ll_list, lp->ll_li);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002074 else
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002075 // unlet a Dictionary item.
Bram Moolenaaref2c3252022-11-25 16:31:51 +00002076 dictitem_remove(lp->ll_dict, lp->ll_di, "unlet");
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002077
2078 return ret;
2079}
2080
2081/*
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002082 * Unlet one item or a range of items from a list.
2083 * Return OK or FAIL.
2084 */
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002085 void
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002086list_unlet_range(
2087 list_T *l,
2088 listitem_T *li_first,
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002089 long n1_arg,
2090 int has_n2,
2091 long n2)
2092{
2093 listitem_T *li = li_first;
2094 int n1 = n1_arg;
2095
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002096 // Delete a range of List items.
2097 li = li_first;
2098 n1 = n1_arg;
2099 while (li != NULL && (!has_n2 || n2 >= n1))
2100 {
2101 listitem_T *next = li->li_next;
2102
2103 listitem_remove(l, li);
2104 li = next;
2105 ++n1;
2106 }
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002107}
2108/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002109 * "unlet" a variable. Return OK if it existed, FAIL if not.
2110 * When "forceit" is TRUE don't complain if the variable doesn't exist.
2111 */
2112 int
2113do_unlet(char_u *name, int forceit)
2114{
2115 hashtab_T *ht;
2116 hashitem_T *hi;
mityu8be36ee2022-05-25 17:29:46 +01002117 char_u *varname = NULL; // init to shut up gcc
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002118 dict_T *d;
2119 dictitem_T *di;
2120
Bram Moolenaar9aed7292020-12-18 15:38:00 +01002121 // can't :unlet a script variable in Vim9 script
Bram Moolenaareb6880b2020-07-12 17:07:05 +02002122 if (in_vim9script() && check_vim9_unlet(name) == FAIL)
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002123 return FAIL;
2124
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002125 ht = find_var_ht(name, &varname);
Bram Moolenaar9aed7292020-12-18 15:38:00 +01002126
2127 // can't :unlet a script variable in Vim9 script from a function
2128 if (ht == get_script_local_ht()
2129 && SCRIPT_ID_VALID(current_sctx.sc_sid)
2130 && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
2131 == SCRIPT_VERSION_VIM9
2132 && check_vim9_unlet(name) == FAIL)
2133 return FAIL;
2134
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002135 if (ht != NULL && *varname != NUL)
2136 {
2137 d = get_current_funccal_dict(ht);
2138 if (d == NULL)
2139 {
2140 if (ht == &globvarht)
2141 d = &globvardict;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002142 else if (ht == &compat_hashtab)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002143 d = &vimvardict;
2144 else
2145 {
2146 di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
2147 d = di == NULL ? NULL : di->di_tv.vval.v_dict;
2148 }
2149 if (d == NULL)
2150 {
2151 internal_error("do_unlet()");
2152 return FAIL;
2153 }
2154 }
2155 hi = hash_find(ht, varname);
2156 if (HASHITEM_EMPTY(hi))
2157 hi = find_hi_in_scoped_ht(name, &ht);
2158 if (hi != NULL && !HASHITEM_EMPTY(hi))
2159 {
2160 di = HI2DI(hi);
2161 if (var_check_fixed(di->di_flags, name, FALSE)
2162 || var_check_ro(di->di_flags, name, FALSE)
Bram Moolenaaref2c3252022-11-25 16:31:51 +00002163 || value_check_lock(d->dv_lock, name, FALSE)
2164 || check_hashtab_frozen(ht, "unlet"))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002165 return FAIL;
2166
2167 delete_var(ht, hi);
2168 return OK;
2169 }
2170 }
2171 if (forceit)
2172 return OK;
Bram Moolenaare1242042021-12-16 20:56:57 +00002173 semsg(_(e_no_such_variable_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002174 return FAIL;
2175}
2176
Ernie Raelee865f32023-09-29 19:53:55 +02002177 static void
2178report_lockvar_member(char *msg, lval_T *lp)
2179{
2180 int did_alloc = FALSE;
2181 char_u *vname = (char_u *)"";
2182 char_u *class_name = lp->ll_class != NULL
2183 ? lp->ll_class->class_name : (char_u *)"";
2184 if (lp->ll_name != NULL)
2185 {
2186 if (lp->ll_name_end == NULL)
2187 vname = lp->ll_name;
2188 else
2189 {
2190 vname = vim_strnsave(lp->ll_name, lp->ll_name_end - lp->ll_name);
2191 if (vname == NULL)
2192 return;
2193 did_alloc = TRUE;
2194 }
2195 }
2196 semsg(_(msg), vname, class_name);
2197 if (did_alloc)
2198 vim_free(vname);
2199}
2200
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002201/*
2202 * Lock or unlock variable indicated by "lp".
2203 * "deep" is the levels to go (-1 for unlimited);
2204 * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
2205 */
2206 static int
2207do_lock_var(
2208 lval_T *lp,
2209 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002210 exarg_T *eap,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002211 int deep,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002212 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002213{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002214 int lock = eap->cmdidx == CMD_lockvar;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002215 int ret = OK;
2216 int cc;
2217 dictitem_T *di;
2218
Ernie Raelee865f32023-09-29 19:53:55 +02002219#ifdef LOG_LOCKVAR
2220 ch_log(NULL, "LKVAR: do_lock_var(): name %s, is_root %d", lp->ll_name, lp->ll_is_root);
2221#endif
2222
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002223 if (lp->ll_tv == NULL)
2224 {
2225 cc = *name_end;
2226 *name_end = NUL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002227 if (*lp->ll_name == '$')
2228 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00002229 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002230 ret = FAIL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002231 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002232 else
2233 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002234 // Normal name or expanded name.
2235 di = find_var(lp->ll_name, NULL, TRUE);
2236 if (di == NULL)
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002237 {
2238 if (in_vim9script())
2239 semsg(_(e_cannot_find_variable_to_unlock_str),
2240 lp->ll_name);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002241 ret = FAIL;
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002242 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002243 else
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002244 {
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002245 if ((di->di_flags & DI_FLAGS_FIX)
2246 && di->di_tv.v_type != VAR_DICT
2247 && di->di_tv.v_type != VAR_LIST)
2248 {
2249 // For historic reasons this error is not given for a list
2250 // or dict. E.g., the b: dict could be locked/unlocked.
2251 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
2252 ret = FAIL;
2253 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002254 else
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002255 {
2256 if (in_vim9script())
2257 {
2258 svar_T *sv = find_typval_in_script(&di->di_tv,
2259 0, FALSE);
2260
2261 if (sv != NULL && sv->sv_const != 0)
2262 {
2263 semsg(_(e_cannot_change_readonly_variable_str),
2264 lp->ll_name);
2265 ret = FAIL;
2266 }
2267 }
2268
2269 if (ret == OK)
2270 {
2271 if (lock)
2272 di->di_flags |= DI_FLAGS_LOCK;
2273 else
2274 di->di_flags &= ~DI_FLAGS_LOCK;
2275 if (deep != 0)
2276 item_lock(&di->di_tv, deep, lock, FALSE);
2277 }
2278 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002279 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002280 }
2281 *name_end = cc;
2282 }
Ernie Raelee865f32023-09-29 19:53:55 +02002283 else if (deep == 0 && lp->ll_object == NULL && lp->ll_class == NULL)
Bram Moolenaara187c432020-09-16 21:08:28 +02002284 {
2285 // nothing to do
2286 }
Ernie Raelee865f32023-09-29 19:53:55 +02002287 else if (lp->ll_is_root)
2288 // (un)lock the item.
2289 item_lock(lp->ll_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002290 else if (lp->ll_range)
2291 {
2292 listitem_T *li = lp->ll_li;
2293
2294 // (un)lock a range of List items.
2295 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
2296 {
Bram Moolenaar021bda52020-08-17 21:07:22 +02002297 item_lock(&li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002298 li = li->li_next;
2299 ++lp->ll_n1;
2300 }
2301 }
2302 else if (lp->ll_list != NULL)
2303 // (un)lock a List item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002304 item_lock(&lp->ll_li->li_tv, deep, lock, FALSE);
Ernie Raelee865f32023-09-29 19:53:55 +02002305 else if (lp->ll_object != NULL) // This check must be before ll_class.
2306 {
2307 // (un)lock an object variable.
2308 report_lockvar_member(e_cannot_lock_object_variable_str, lp);
2309 ret = FAIL;
2310 }
2311 else if (lp->ll_class != NULL)
2312 {
2313 // (un)lock a class variable.
2314 report_lockvar_member(e_cannot_lock_class_variable_str, lp);
2315 ret = FAIL;
2316 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002317 else
Ernie Raelee865f32023-09-29 19:53:55 +02002318 {
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002319 // (un)lock a Dictionary item.
Ernie Raelee865f32023-09-29 19:53:55 +02002320 if (lp->ll_di == NULL)
2321 {
2322 emsg(_(e_dictionary_required));
2323 ret = FAIL;
2324 }
2325 else
2326 item_lock(&lp->ll_di->di_tv, deep, lock, FALSE);
2327 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002328
2329 return ret;
2330}
2331
2332/*
2333 * Lock or unlock an item. "deep" is nr of levels to go.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002334 * When "check_refcount" is TRUE do not lock a list or dict with a reference
2335 * count larger than 1.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002336 */
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002337 void
Bram Moolenaar021bda52020-08-17 21:07:22 +02002338item_lock(typval_T *tv, int deep, int lock, int check_refcount)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002339{
2340 static int recurse = 0;
2341 list_T *l;
2342 listitem_T *li;
2343 dict_T *d;
2344 blob_T *b;
2345 hashitem_T *hi;
2346 int todo;
2347
Ernie Raelee865f32023-09-29 19:53:55 +02002348#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +02002349 ch_log(NULL, "LKVAR: item_lock(): type %s", vartype_name(tv->v_type));
Ernie Raelee865f32023-09-29 19:53:55 +02002350#endif
2351
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002352 if (recurse >= DICT_MAXNEST)
2353 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002354 emsg(_(e_variable_nested_too_deep_for_unlock));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002355 return;
2356 }
2357 if (deep == 0)
2358 return;
2359 ++recurse;
2360
2361 // lock/unlock the item itself
2362 if (lock)
2363 tv->v_lock |= VAR_LOCKED;
2364 else
2365 tv->v_lock &= ~VAR_LOCKED;
2366
2367 switch (tv->v_type)
2368 {
2369 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002370 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002371 case VAR_VOID:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002372 case VAR_NUMBER:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002373 case VAR_BOOL:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002374 case VAR_STRING:
2375 case VAR_FUNC:
2376 case VAR_PARTIAL:
2377 case VAR_FLOAT:
2378 case VAR_SPECIAL:
2379 case VAR_JOB:
2380 case VAR_CHANNEL:
Bram Moolenaarf18332f2021-05-07 17:55:55 +02002381 case VAR_INSTR:
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002382 case VAR_CLASS:
2383 case VAR_OBJECT:
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02002384 case VAR_TYPEALIAS:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002385 break;
2386
2387 case VAR_BLOB:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002388 if ((b = tv->vval.v_blob) != NULL
2389 && !(check_refcount && b->bv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002390 {
2391 if (lock)
2392 b->bv_lock |= VAR_LOCKED;
2393 else
2394 b->bv_lock &= ~VAR_LOCKED;
2395 }
2396 break;
2397 case VAR_LIST:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002398 if ((l = tv->vval.v_list) != NULL
2399 && !(check_refcount && l->lv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002400 {
2401 if (lock)
2402 l->lv_lock |= VAR_LOCKED;
2403 else
2404 l->lv_lock &= ~VAR_LOCKED;
Bram Moolenaar70c43d82022-01-26 21:01:15 +00002405 if (deep < 0 || deep > 1)
2406 {
2407 if (l->lv_first == &range_list_item)
2408 l->lv_lock |= VAR_ITEMS_LOCKED;
2409 else
2410 {
2411 // recursive: lock/unlock the items the List contains
2412 CHECK_LIST_MATERIALIZE(l);
2413 FOR_ALL_LIST_ITEMS(l, li) item_lock(&li->li_tv,
2414 deep - 1, lock, check_refcount);
2415 }
2416 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002417 }
2418 break;
2419 case VAR_DICT:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002420 if ((d = tv->vval.v_dict) != NULL
2421 && !(check_refcount && d->dv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002422 {
2423 if (lock)
2424 d->dv_lock |= VAR_LOCKED;
2425 else
2426 d->dv_lock &= ~VAR_LOCKED;
2427 if (deep < 0 || deep > 1)
2428 {
2429 // recursive: lock/unlock the items the List contains
2430 todo = (int)d->dv_hashtab.ht_used;
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +00002431 FOR_ALL_HASHTAB_ITEMS(&d->dv_hashtab, hi, todo)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002432 {
2433 if (!HASHITEM_EMPTY(hi))
2434 {
2435 --todo;
Bram Moolenaar021bda52020-08-17 21:07:22 +02002436 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock,
2437 check_refcount);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002438 }
2439 }
2440 }
2441 }
2442 }
2443 --recurse;
2444}
2445
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002446#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
2447/*
2448 * Delete all "menutrans_" variables.
2449 */
2450 void
2451del_menutrans_vars(void)
2452{
2453 hashitem_T *hi;
2454 int todo;
2455
2456 hash_lock(&globvarht);
2457 todo = (int)globvarht.ht_used;
2458 for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
2459 {
2460 if (!HASHITEM_EMPTY(hi))
2461 {
2462 --todo;
2463 if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
2464 delete_var(&globvarht, hi);
2465 }
2466 }
2467 hash_unlock(&globvarht);
2468}
2469#endif
2470
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002471/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002472 * Local string buffer for the next two functions to store a variable name
2473 * with its prefix. Allocated in cat_prefix_varname(), freed later in
2474 * get_user_var_name().
2475 */
2476
2477static char_u *varnamebuf = NULL;
2478static int varnamebuflen = 0;
2479
2480/*
2481 * Function to concatenate a prefix and a variable name.
2482 */
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01002483 char_u *
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002484cat_prefix_varname(int prefix, char_u *name)
2485{
2486 int len;
2487
2488 len = (int)STRLEN(name) + 3;
2489 if (len > varnamebuflen)
2490 {
2491 vim_free(varnamebuf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002492 len += 10; // some additional space
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002493 varnamebuf = alloc(len);
2494 if (varnamebuf == NULL)
2495 {
2496 varnamebuflen = 0;
2497 return NULL;
2498 }
2499 varnamebuflen = len;
2500 }
2501 *varnamebuf = prefix;
2502 varnamebuf[1] = ':';
2503 STRCPY(varnamebuf + 2, name);
2504 return varnamebuf;
2505}
2506
2507/*
2508 * Function given to ExpandGeneric() to obtain the list of user defined
2509 * (global/buffer/window/built-in) variable names.
2510 */
2511 char_u *
2512get_user_var_name(expand_T *xp, int idx)
2513{
2514 static long_u gdone;
2515 static long_u bdone;
2516 static long_u wdone;
2517 static long_u tdone;
2518 static int vidx;
2519 static hashitem_T *hi;
2520 hashtab_T *ht;
2521
2522 if (idx == 0)
2523 {
2524 gdone = bdone = wdone = vidx = 0;
2525 tdone = 0;
2526 }
2527
2528 // Global variables
2529 if (gdone < globvarht.ht_used)
2530 {
2531 if (gdone++ == 0)
2532 hi = globvarht.ht_array;
2533 else
2534 ++hi;
2535 while (HASHITEM_EMPTY(hi))
2536 ++hi;
2537 if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
2538 return cat_prefix_varname('g', hi->hi_key);
2539 return hi->hi_key;
2540 }
2541
2542 // b: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002543 ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002544 if (bdone < ht->ht_used)
2545 {
2546 if (bdone++ == 0)
2547 hi = ht->ht_array;
2548 else
2549 ++hi;
2550 while (HASHITEM_EMPTY(hi))
2551 ++hi;
2552 return cat_prefix_varname('b', hi->hi_key);
2553 }
2554
2555 // w: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002556 ht = &prevwin_curwin()->w_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002557 if (wdone < ht->ht_used)
2558 {
2559 if (wdone++ == 0)
2560 hi = ht->ht_array;
2561 else
2562 ++hi;
2563 while (HASHITEM_EMPTY(hi))
2564 ++hi;
2565 return cat_prefix_varname('w', hi->hi_key);
2566 }
2567
2568 // t: variables
2569 ht = &curtab->tp_vars->dv_hashtab;
2570 if (tdone < ht->ht_used)
2571 {
2572 if (tdone++ == 0)
2573 hi = ht->ht_array;
2574 else
2575 ++hi;
2576 while (HASHITEM_EMPTY(hi))
2577 ++hi;
2578 return cat_prefix_varname('t', hi->hi_key);
2579 }
2580
2581 // v: variables
2582 if (vidx < VV_LEN)
2583 return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
2584
2585 VIM_CLEAR(varnamebuf);
2586 varnamebuflen = 0;
2587 return NULL;
2588}
2589
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002590 char *
2591get_var_special_name(int nr)
2592{
2593 switch (nr)
2594 {
Bram Moolenaara8b8af12021-01-01 15:11:04 +01002595 case VVAL_FALSE: return in_vim9script() ? "false" : "v:false";
2596 case VVAL_TRUE: return in_vim9script() ? "true" : "v:true";
Bram Moolenaar67977822021-01-03 21:53:53 +01002597 case VVAL_NULL: return in_vim9script() ? "null" : "v:null";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002598 case VVAL_NONE: return "v:none";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002599 }
2600 internal_error("get_var_special_name()");
2601 return "42";
2602}
2603
2604/*
2605 * Returns the global variable dictionary
2606 */
2607 dict_T *
2608get_globvar_dict(void)
2609{
2610 return &globvardict;
2611}
2612
2613/*
2614 * Returns the global variable hash table
2615 */
2616 hashtab_T *
2617get_globvar_ht(void)
2618{
2619 return &globvarht;
2620}
2621
2622/*
2623 * Returns the v: variable dictionary
2624 */
2625 dict_T *
2626get_vimvar_dict(void)
2627{
2628 return &vimvardict;
2629}
2630
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002631/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002632 * Returns the index of a v:variable. Negative if not found.
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002633 * Returns DI_ flags in "di_flags".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002634 */
2635 int
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002636find_vim_var(char_u *name, int *di_flags)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002637{
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002638 dictitem_T *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
2639 struct vimvar *vv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002640
2641 if (di == NULL)
2642 return -1;
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002643 *di_flags = di->di_flags;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002644 vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
2645 return (int)(vv - vimvars);
2646}
2647
2648
2649/*
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002650 * Set type of v: variable to "type".
2651 */
2652 void
2653set_vim_var_type(int idx, vartype_T type)
2654{
Bram Moolenaard787e402021-12-24 21:36:12 +00002655 vimvars[idx].vv_tv_type = type;
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002656}
2657
2658/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002659 * Set number v: variable to "val".
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002660 * Note that this does not set the type, use set_vim_var_type() for that.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002661 */
2662 void
2663set_vim_var_nr(int idx, varnumber_T val)
2664{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002665 vimvars[idx].vv_nr = val;
2666}
2667
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002668 char *
2669get_vim_var_name(int idx)
2670{
2671 return vimvars[idx].vv_name;
2672}
2673
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002674/*
2675 * Get typval_T v: variable value.
2676 */
2677 typval_T *
2678get_vim_var_tv(int idx)
2679{
2680 return &vimvars[idx].vv_tv;
2681}
2682
Bram Moolenaard787e402021-12-24 21:36:12 +00002683 type_T *
2684get_vim_var_type(int idx, garray_T *type_list)
2685{
2686 if (vimvars[idx].vv_type != NULL)
2687 return vimvars[idx].vv_type;
2688 return typval2type_vimvar(&vimvars[idx].vv_tv, type_list);
2689}
2690
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002691/*
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002692 * Set v: variable to "tv". Only accepts the same type.
2693 * Takes over the value of "tv".
2694 */
2695 int
2696set_vim_var_tv(int idx, typval_T *tv)
2697{
Bram Moolenaard787e402021-12-24 21:36:12 +00002698 if (vimvars[idx].vv_tv_type != tv->v_type)
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002699 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002700 emsg(_(e_type_mismatch_for_v_variable));
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002701 clear_tv(tv);
2702 return FAIL;
2703 }
Bram Moolenaarcab27672020-04-09 20:10:55 +02002704 // VV_RO is also checked when compiling, but let's check here as well.
2705 if (vimvars[idx].vv_flags & VV_RO)
2706 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02002707 semsg(_(e_cannot_change_readonly_variable_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002708 return FAIL;
2709 }
2710 if (sandbox && (vimvars[idx].vv_flags & VV_RO_SBX))
2711 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00002712 semsg(_(e_cannot_set_variable_in_sandbox_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002713 return FAIL;
2714 }
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002715 clear_tv(&vimvars[idx].vv_di.di_tv);
2716 vimvars[idx].vv_di.di_tv = *tv;
2717 return OK;
2718}
2719
2720/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002721 * Get number v: variable value.
2722 */
2723 varnumber_T
2724get_vim_var_nr(int idx)
2725{
2726 return vimvars[idx].vv_nr;
2727}
2728
2729/*
2730 * Get string v: variable value. Uses a static buffer, can only be used once.
2731 * If the String variable has never been set, return an empty string.
2732 * Never returns NULL;
2733 */
2734 char_u *
2735get_vim_var_str(int idx)
2736{
2737 return tv_get_string(&vimvars[idx].vv_tv);
2738}
2739
2740/*
2741 * Get List v: variable value. Caller must take care of reference count when
2742 * needed.
2743 */
2744 list_T *
2745get_vim_var_list(int idx)
2746{
2747 return vimvars[idx].vv_list;
2748}
2749
2750/*
2751 * Get Dict v: variable value. Caller must take care of reference count when
2752 * needed.
2753 */
2754 dict_T *
2755get_vim_var_dict(int idx)
2756{
2757 return vimvars[idx].vv_dict;
2758}
2759
2760/*
2761 * Set v:char to character "c".
2762 */
2763 void
2764set_vim_var_char(int c)
2765{
2766 char_u buf[MB_MAXBYTES + 1];
2767
2768 if (has_mbyte)
2769 buf[(*mb_char2bytes)(c, buf)] = NUL;
2770 else
2771 {
2772 buf[0] = c;
2773 buf[1] = NUL;
2774 }
2775 set_vim_var_string(VV_CHAR, buf, -1);
2776}
2777
2778/*
2779 * Set v:count to "count" and v:count1 to "count1".
2780 * When "set_prevcount" is TRUE first set v:prevcount from v:count.
2781 */
2782 void
2783set_vcount(
2784 long count,
2785 long count1,
2786 int set_prevcount)
2787{
2788 if (set_prevcount)
2789 vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
2790 vimvars[VV_COUNT].vv_nr = count;
2791 vimvars[VV_COUNT1].vv_nr = count1;
2792}
2793
2794/*
2795 * Save variables that might be changed as a side effect. Used when executing
2796 * a timer callback.
2797 */
2798 void
2799save_vimvars(vimvars_save_T *vvsave)
2800{
2801 vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
2802 vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
2803 vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
2804}
2805
2806/*
2807 * Restore variables saved by save_vimvars().
2808 */
2809 void
2810restore_vimvars(vimvars_save_T *vvsave)
2811{
2812 vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
2813 vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
2814 vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
2815}
2816
2817/*
2818 * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
2819 * value.
2820 */
2821 void
2822set_vim_var_string(
2823 int idx,
2824 char_u *val,
2825 int len) // length of "val" to use or -1 (whole string)
2826{
2827 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002828 vimvars[idx].vv_tv_type = VAR_STRING;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002829 if (val == NULL)
2830 vimvars[idx].vv_str = NULL;
2831 else if (len == -1)
2832 vimvars[idx].vv_str = vim_strsave(val);
2833 else
2834 vimvars[idx].vv_str = vim_strnsave(val, len);
2835}
2836
2837/*
2838 * Set List v: variable to "val".
2839 */
2840 void
2841set_vim_var_list(int idx, list_T *val)
2842{
2843 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002844 vimvars[idx].vv_tv_type = VAR_LIST;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002845 vimvars[idx].vv_list = val;
2846 if (val != NULL)
2847 ++val->lv_refcount;
2848}
2849
2850/*
2851 * Set Dictionary v: variable to "val".
2852 */
2853 void
2854set_vim_var_dict(int idx, dict_T *val)
2855{
2856 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002857 vimvars[idx].vv_tv_type = VAR_DICT;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002858 vimvars[idx].vv_dict = val;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00002859 if (val == NULL)
2860 return;
2861
2862 ++val->dv_refcount;
2863 dict_set_items_ro(val);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002864}
2865
2866/*
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002867 * Set the v:argv list.
2868 */
2869 void
2870set_argv_var(char **argv, int argc)
2871{
2872 list_T *l = list_alloc();
2873 int i;
2874
2875 if (l == NULL)
2876 getout(1);
2877 l->lv_lock = VAR_FIXED;
2878 for (i = 0; i < argc; ++i)
2879 {
2880 if (list_append_string(l, (char_u *)argv[i], -1) == FAIL)
2881 getout(1);
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01002882 l->lv_u.mat.lv_last->li_tv.v_lock = VAR_FIXED;
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002883 }
2884 set_vim_var_list(VV_ARGV, l);
2885}
2886
2887/*
Bram Moolenaar439c0362020-06-06 15:58:03 +02002888 * Reset v:register, taking the 'clipboard' setting into account.
2889 */
2890 void
2891reset_reg_var(void)
2892{
2893 int regname = 0;
2894
2895 // Adjust the register according to 'clipboard', so that when
2896 // "unnamed" is present it becomes '*' or '+' instead of '"'.
2897#ifdef FEAT_CLIPBOARD
2898 adjust_clip_reg(&regname);
2899#endif
2900 set_reg_var(regname);
2901}
2902
2903/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002904 * Set v:register if needed.
2905 */
2906 void
2907set_reg_var(int c)
2908{
2909 char_u regname;
2910
2911 if (c == 0 || c == ' ')
2912 regname = '"';
2913 else
2914 regname = c;
2915 // Avoid free/alloc when the value is already right.
2916 if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
2917 set_vim_var_string(VV_REG, &regname, 1);
2918}
2919
2920/*
2921 * Get or set v:exception. If "oldval" == NULL, return the current value.
2922 * Otherwise, restore the value to "oldval" and return NULL.
2923 * Must always be called in pairs to save and restore v:exception! Does not
2924 * take care of memory allocations.
2925 */
2926 char_u *
2927v_exception(char_u *oldval)
2928{
2929 if (oldval == NULL)
2930 return vimvars[VV_EXCEPTION].vv_str;
2931
2932 vimvars[VV_EXCEPTION].vv_str = oldval;
2933 return NULL;
2934}
2935
2936/*
2937 * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
2938 * Otherwise, restore the value to "oldval" and return NULL.
2939 * Must always be called in pairs to save and restore v:throwpoint! Does not
2940 * take care of memory allocations.
2941 */
2942 char_u *
2943v_throwpoint(char_u *oldval)
2944{
2945 if (oldval == NULL)
2946 return vimvars[VV_THROWPOINT].vv_str;
2947
2948 vimvars[VV_THROWPOINT].vv_str = oldval;
2949 return NULL;
2950}
2951
2952/*
2953 * Set v:cmdarg.
2954 * If "eap" != NULL, use "eap" to generate the value and return the old value.
2955 * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
2956 * Must always be called in pairs!
2957 */
2958 char_u *
2959set_cmdarg(exarg_T *eap, char_u *oldarg)
2960{
2961 char_u *oldval;
2962 char_u *newval;
2963 unsigned len;
2964
2965 oldval = vimvars[VV_CMDARG].vv_str;
2966 if (eap == NULL)
2967 {
2968 vim_free(oldval);
2969 vimvars[VV_CMDARG].vv_str = oldarg;
2970 return NULL;
2971 }
2972
2973 if (eap->force_bin == FORCE_BIN)
2974 len = 6;
2975 else if (eap->force_bin == FORCE_NOBIN)
2976 len = 8;
2977 else
2978 len = 0;
2979
2980 if (eap->read_edit)
2981 len += 7;
2982
2983 if (eap->force_ff != 0)
2984 len += 10; // " ++ff=unix"
2985 if (eap->force_enc != 0)
2986 len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
2987 if (eap->bad_char != 0)
2988 len += 7 + 4; // " ++bad=" + "keep" or "drop"
2989
2990 newval = alloc(len + 1);
2991 if (newval == NULL)
2992 return NULL;
2993
2994 if (eap->force_bin == FORCE_BIN)
2995 sprintf((char *)newval, " ++bin");
2996 else if (eap->force_bin == FORCE_NOBIN)
2997 sprintf((char *)newval, " ++nobin");
2998 else
2999 *newval = NUL;
3000
3001 if (eap->read_edit)
3002 STRCAT(newval, " ++edit");
3003
3004 if (eap->force_ff != 0)
3005 sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
3006 eap->force_ff == 'u' ? "unix"
3007 : eap->force_ff == 'd' ? "dos"
3008 : "mac");
3009 if (eap->force_enc != 0)
3010 sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
3011 eap->cmd + eap->force_enc);
3012 if (eap->bad_char == BAD_KEEP)
3013 STRCPY(newval + STRLEN(newval), " ++bad=keep");
3014 else if (eap->bad_char == BAD_DROP)
3015 STRCPY(newval + STRLEN(newval), " ++bad=drop");
3016 else if (eap->bad_char != 0)
3017 sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
3018 vimvars[VV_CMDARG].vv_str = newval;
3019 return oldval;
3020}
3021
3022/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003023 * Get the value of internal variable "name".
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003024 * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
3025 * imported script ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003026 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
3027 */
3028 int
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02003029eval_variable(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003030 char_u *name,
Bram Moolenaar94674f22023-01-06 18:42:20 +00003031 int len, // length of "name" or zero
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003032 scid_T sid, // script ID for imported item or zero
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003033 typval_T *rettv, // NULL when only checking existence
3034 dictitem_T **dip, // non-NULL when typval's dict item is needed
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003035 int flags) // EVAL_VAR_ flags
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003036{
3037 int ret = OK;
3038 typval_T *tv = NULL;
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003039 int found = FALSE;
Bram Moolenaarf055d452021-07-08 20:57:24 +02003040 hashtab_T *ht = NULL;
Bram Moolenaar94674f22023-01-06 18:42:20 +00003041 int cc = 0;
Bram Moolenaarc967d572021-07-08 21:38:50 +02003042 type_T *type = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003043
Bram Moolenaar94674f22023-01-06 18:42:20 +00003044 if (len > 0)
3045 {
3046 // truncate the name, so that we can use strcmp()
3047 cc = name[len];
3048 name[len] = NUL;
3049 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003050
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003051 // Check for local variable when debugging.
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003052 if ((sid == 0) && (tv = lookup_debug_var(name)) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003053 {
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003054 // Check for user-defined variables.
Bram Moolenaarc967d572021-07-08 21:38:50 +02003055 dictitem_T *v = find_var(name, &ht, flags & EVAL_VAR_NOAUTOLOAD);
3056
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003057 if (v != NULL)
3058 {
3059 tv = &v->di_tv;
3060 if (dip != NULL)
3061 *dip = v;
3062 }
Bram Moolenaarc967d572021-07-08 21:38:50 +02003063 else
3064 ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003065 }
3066
Bram Moolenaareb6880b2020-07-12 17:07:05 +02003067 if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003068 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003069 imported_T *import = NULL;
Bram Moolenaar9721fb42020-06-11 23:10:46 +02003070 char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
3071
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003072 if (sid == 0)
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003073 import = find_imported(p, 0, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003074
3075 // imported variable from another script
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003076 if (import != NULL || sid != 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003077 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003078 if ((flags & EVAL_VAR_IMPORT) == 0)
Bram Moolenaarc620c052020-07-08 15:16:19 +02003079 {
Bram Moolenaar71f21932022-01-07 18:20:55 +00003080 if (SCRIPT_ID_VALID(sid))
Bram Moolenaarc620c052020-07-08 15:16:19 +02003081 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003082 ht = &SCRIPT_VARS(sid);
3083 if (ht != NULL)
3084 {
3085 dictitem_T *v = find_var_in_ht(ht, 0, name,
3086 flags & EVAL_VAR_NOAUTOLOAD);
3087
3088 if (v != NULL)
3089 {
3090 tv = &v->di_tv;
3091 if (dip != NULL)
3092 *dip = v;
3093 }
3094 else
3095 ht = NULL;
3096 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003097 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003098 else
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003099 {
3100 if (flags & EVAL_VAR_VERBOSE)
Bram Moolenaardd5893b2022-01-20 21:32:54 +00003101 semsg(_(e_expected_dot_after_name_str), name);
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003102 ret = FAIL;
3103 }
Bram Moolenaarf6a44f72020-09-27 13:51:14 +02003104 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003105 else
3106 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003107 if (rettv != NULL)
3108 {
Bram Moolenaar753885b2022-08-24 16:30:36 +01003109 // special value that is used in handle_subscript()
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003110 rettv->v_type = VAR_ANY;
3111 rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
3112 }
3113 found = TRUE;
Bram Moolenaarc620c052020-07-08 15:16:19 +02003114 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003115 }
Bram Moolenaar052ff292021-12-11 13:54:46 +00003116 else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003117 {
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003118 int has_g_prefix = STRNCMP(name, "g:", 2) == 0;
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003119 ufunc_T *ufunc = find_func(name, FALSE);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003120
Bram Moolenaarb033ee22021-08-15 16:08:36 +02003121 // In Vim9 script we can get a function reference by using the
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003122 // function name. For a global non-autoload function "g:" is
3123 // required.
3124 if (ufunc != NULL && (has_g_prefix
3125 || !func_requires_g_prefix(ufunc)))
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003126 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003127 found = TRUE;
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003128 if (rettv != NULL)
3129 {
3130 rettv->v_type = VAR_FUNC;
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003131 if (has_g_prefix)
Bram Moolenaaref082e12021-12-12 21:02:03 +00003132 // Keep the "g:", otherwise script-local may be
3133 // assumed.
3134 rettv->vval.v_string = vim_strsave(name);
3135 else
3136 rettv->vval.v_string = vim_strsave(ufunc->uf_name);
Bram Moolenaarb033ee22021-08-15 16:08:36 +02003137 if (rettv->vval.v_string != NULL)
3138 func_ref(ufunc->uf_name);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003139 }
3140 }
3141 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003142 }
3143
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003144 if (!found)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003145 {
Bram Moolenaarc620c052020-07-08 15:16:19 +02003146 if (tv == NULL)
3147 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003148 if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
Bram Moolenaar451c2e32020-08-15 16:33:28 +02003149 semsg(_(e_undefined_variable_str), name);
Bram Moolenaarc620c052020-07-08 15:16:19 +02003150 ret = FAIL;
3151 }
3152 else if (rettv != NULL)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003153 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003154 svar_T *sv = NULL;
3155 int was_assigned = FALSE;
3156
Bram Moolenaar11005b02021-07-11 20:59:00 +02003157 if (ht != NULL && ht == get_script_local_ht()
3158 && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
Bram Moolenaarf055d452021-07-08 20:57:24 +02003159 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003160 sv = find_typval_in_script(tv, 0, TRUE);
Bram Moolenaarf055d452021-07-08 20:57:24 +02003161 if (sv != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003162 {
Bram Moolenaarf055d452021-07-08 20:57:24 +02003163 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003164 was_assigned = sv->sv_flags & SVFLAG_ASSIGNED;
3165 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003166 }
3167
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003168 if ((tv->v_type == VAR_TYPEALIAS || tv->v_type == VAR_CLASS)
3169 && sid != 0)
3170 {
3171 // type alias or class imported from another script. Check
3172 // whether it is exported from the other script.
3173 sv = find_typval_in_script(tv, sid, TRUE);
3174 if (sv == NULL)
3175 {
3176 ret = FAIL;
3177 goto done;
3178 }
3179 if ((sv->sv_flags & SVFLAG_EXPORTED) == 0)
3180 {
3181 semsg(_(e_item_not_exported_in_script_str), name);
3182 ret = FAIL;
3183 goto done;
3184 }
3185 }
3186
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01003187 // If a list or dict variable wasn't initialized and has meaningful
3188 // type, do it now. Not for global variables, they are not
3189 // declared.
Bram Moolenaar7a222242022-03-01 19:23:24 +00003190 if (ht != &globvarht)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003191 {
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01003192 if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003193 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01003194 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02003195 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00003196 tv->vval.v_dict = dict_alloc();
3197 if (tv->vval.v_dict != NULL)
3198 {
3199 ++tv->vval.v_dict->dv_refcount;
3200 tv->vval.v_dict->dv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003201 if (sv != NULL)
3202 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00003203 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003204 }
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01003205 else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003206 && ((type != NULL && !was_assigned)
Bram Moolenaar501f9782022-03-27 16:51:04 +01003207 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02003208 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00003209 tv->vval.v_list = list_alloc();
3210 if (tv->vval.v_list != NULL)
3211 {
3212 ++tv->vval.v_list->lv_refcount;
3213 tv->vval.v_list->lv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003214 if (sv != NULL)
3215 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00003216 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003217 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003218 else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003219 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01003220 || !in_vim9script()))
3221 {
3222 tv->vval.v_blob = blob_alloc();
3223 if (tv->vval.v_blob != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003224 {
Bram Moolenaar859cc212022-03-28 15:22:35 +01003225 ++tv->vval.v_blob->bv_refcount;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003226 if (sv != NULL)
3227 sv->sv_flags |= SVFLAG_ASSIGNED;
3228 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003229 }
Bram Moolenaarb7c21af2021-04-18 14:12:31 +02003230 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003231 copy_tv(tv, rettv);
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003232 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003233 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003234
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003235done:
Bram Moolenaar94674f22023-01-06 18:42:20 +00003236 if (len > 0)
3237 name[len] = cc;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003238
3239 return ret;
3240}
3241
3242/*
Bram Moolenaara86655a2023-01-12 17:06:27 +00003243 * Get the value of internal variable "name", also handling "import.name".
3244 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
3245 */
3246 int
3247eval_variable_import(
3248 char_u *name,
3249 typval_T *rettv)
3250{
3251 char_u *s = name;
3252 while (ASCII_ISALNUM(*s) || *s == '_')
3253 ++s;
3254 int len = (int)(s - name);
3255
3256 if (eval_variable(name, len, 0, rettv, NULL, EVAL_VAR_IMPORT) == FAIL)
3257 return FAIL;
3258 if (rettv->v_type == VAR_ANY && *s == '.')
3259 {
Bram Moolenaar40594002023-01-12 20:04:51 +00003260 char_u *ns = s + 1;
3261 s = ns;
3262 while (ASCII_ISALNUM(*s) || *s == '_')
3263 ++s;
Bram Moolenaara86655a2023-01-12 17:06:27 +00003264 int sid = rettv->vval.v_number;
Bram Moolenaar40594002023-01-12 20:04:51 +00003265 return eval_variable(ns, (int)(s - ns), sid, rettv, NULL, 0);
Bram Moolenaara86655a2023-01-12 17:06:27 +00003266 }
3267 return OK;
3268}
3269
3270
3271/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003272 * Check if variable "name[len]" is a local variable or an argument.
3273 * If so, "*eval_lavars_used" is set to TRUE.
3274 */
3275 void
3276check_vars(char_u *name, int len)
3277{
3278 int cc;
3279 char_u *varname;
3280 hashtab_T *ht;
3281
3282 if (eval_lavars_used == NULL)
3283 return;
3284
3285 // truncate the name, so that we can use strcmp()
3286 cc = name[len];
3287 name[len] = NUL;
3288
3289 ht = find_var_ht(name, &varname);
3290 if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
3291 {
3292 if (find_var(name, NULL, TRUE) != NULL)
3293 *eval_lavars_used = TRUE;
3294 }
3295
3296 name[len] = cc;
3297}
3298
3299/*
3300 * Find variable "name" in the list of variables.
3301 * Return a pointer to it if found, NULL if not found.
3302 * Careful: "a:0" variables don't have a name.
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003303 * When "htp" is not NULL set "htp" to the hashtab_T used.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003304 */
3305 dictitem_T *
3306find_var(char_u *name, hashtab_T **htp, int no_autoload)
3307{
3308 char_u *varname;
3309 hashtab_T *ht;
3310 dictitem_T *ret = NULL;
3311
3312 ht = find_var_ht(name, &varname);
3313 if (htp != NULL)
3314 *htp = ht;
3315 if (ht == NULL)
3316 return NULL;
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003317 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003318 if (ret != NULL)
3319 return ret;
3320
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003321 // Search in parent scope for lambda
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003322 ret = find_var_in_scoped_ht(name, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003323 if (ret != NULL)
3324 return ret;
3325
3326 // in Vim9 script items without a scope can be script-local
3327 if (in_vim9script() && name[0] != NUL && name[1] != ':')
3328 {
3329 ht = get_script_local_ht();
3330 if (ht != NULL)
3331 {
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003332 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003333 if (ret != NULL)
3334 {
3335 if (htp != NULL)
3336 *htp = ht;
3337 return ret;
3338 }
3339 }
3340 }
3341
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003342 // When using "vim9script autoload" script-local items are prefixed but can
3343 // be used with s:name.
3344 if (SCRIPT_ID_VALID(current_sctx.sc_sid)
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003345 && (in_vim9script() || (name[0] == 's' && name[1] == ':')))
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003346 {
3347 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
3348
3349 if (si->sn_autoload_prefix != NULL)
3350 {
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003351 char_u *base_name = (name[0] == 's' && name[1] == ':')
3352 ? name + 2 : name;
3353 char_u *auto_name = concat_str(si->sn_autoload_prefix, base_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003354
3355 if (auto_name != NULL)
3356 {
3357 ht = &globvarht;
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003358 ret = find_var_in_ht(ht, 'g', auto_name, TRUE);
Bram Moolenaar130f65d2022-01-13 20:39:41 +00003359 vim_free(auto_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003360 if (ret != NULL)
3361 {
3362 if (htp != NULL)
3363 *htp = ht;
3364 return ret;
3365 }
3366 }
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003367 }
3368 }
3369
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003370 return NULL;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003371}
3372
3373/*
Bram Moolenaar71f21932022-01-07 18:20:55 +00003374 * Like find_var() but if the name starts with <SNR>99_ then look in the
3375 * referenced script (used for a funcref).
3376 */
3377 dictitem_T *
3378find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload)
3379{
Keith Thompson184f71c2024-01-04 21:19:04 +01003380 if (STRNCMP(name, "<SNR>", 5) == 0 && SAFE_isdigit(name[5]))
Bram Moolenaar71f21932022-01-07 18:20:55 +00003381 {
3382 char_u *p = name + 5;
3383 int sid = getdigits(&p);
3384
3385 if (SCRIPT_ID_VALID(sid) && *p == '_')
3386 {
3387 hashtab_T *ht = &SCRIPT_VARS(sid);
3388
3389 if (ht != NULL)
3390 {
3391 dictitem_T *di = find_var_in_ht(ht, 0, p + 1, no_autoload);
3392
3393 if (di != NULL)
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003394 {
3395 if (htp != NULL)
3396 *htp = ht;
Bram Moolenaar71f21932022-01-07 18:20:55 +00003397 return di;
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003398 }
Bram Moolenaar71f21932022-01-07 18:20:55 +00003399 }
3400 }
3401 }
3402
3403 return find_var(name, htp, no_autoload);
3404}
3405
3406/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003407 * Find variable "varname" in hashtab "ht" with name "htname".
Bram Moolenaar52592752020-04-03 18:43:35 +02003408 * When "varname" is empty returns curwin/curtab/etc vars dictionary.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003409 * Returns NULL if not found.
3410 */
3411 dictitem_T *
3412find_var_in_ht(
3413 hashtab_T *ht,
3414 int htname,
3415 char_u *varname,
3416 int no_autoload)
3417{
3418 hashitem_T *hi;
3419
3420 if (*varname == NUL)
3421 {
3422 // Must be something like "s:", otherwise "ht" would be NULL.
3423 switch (htname)
3424 {
3425 case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
3426 case 'g': return &globvars_var;
3427 case 'v': return &vimvars_var;
3428 case 'b': return &curbuf->b_bufvar;
3429 case 'w': return &curwin->w_winvar;
3430 case 't': return &curtab->tp_winvar;
3431 case 'l': return get_funccal_local_var();
3432 case 'a': return get_funccal_args_var();
3433 }
3434 return NULL;
3435 }
3436
3437 hi = hash_find(ht, varname);
3438 if (HASHITEM_EMPTY(hi))
3439 {
3440 // For global variables we may try auto-loading the script. If it
3441 // worked find the variable again. Don't auto-load a script if it was
3442 // loaded already, otherwise it would be loaded every time when
3443 // checking if a function name is a Funcref variable.
3444 if (ht == &globvarht && !no_autoload)
3445 {
3446 // Note: script_autoload() may make "hi" invalid. It must either
3447 // be obtained again or not used.
3448 if (!script_autoload(varname, FALSE) || aborting())
3449 return NULL;
3450 hi = hash_find(ht, varname);
3451 }
3452 if (HASHITEM_EMPTY(hi))
3453 return NULL;
3454 }
3455 return HI2DI(hi);
3456}
3457
3458/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003459 * Get the script-local hashtab. NULL if not in a script context.
3460 */
Bram Moolenaar922acbd2020-10-08 21:30:40 +02003461 hashtab_T *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003462get_script_local_ht(void)
3463{
3464 scid_T sid = current_sctx.sc_sid;
3465
Bram Moolenaare3d46852020-08-29 13:39:17 +02003466 if (SCRIPT_ID_VALID(sid))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003467 return &SCRIPT_VARS(sid);
3468 return NULL;
3469}
3470
3471/*
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003472 * Look for "name[len]" in script-local variables and functions.
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003473 * When "cmd" is TRUE it must look like a command, a function must be followed
3474 * by "(" or "->".
Bram Moolenaar709664c2020-12-12 14:33:41 +01003475 * Return OK when found, FAIL when not found.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003476 */
Bram Moolenaar709664c2020-12-12 14:33:41 +01003477 int
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003478lookup_scriptitem(
Bram Moolenaar709664c2020-12-12 14:33:41 +01003479 char_u *name,
3480 size_t len,
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003481 int cmd,
Bram Moolenaar709664c2020-12-12 14:33:41 +01003482 cctx_T *dummy UNUSED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003483{
3484 hashtab_T *ht = get_script_local_ht();
3485 char_u buffer[30];
3486 char_u *p;
Bram Moolenaar709664c2020-12-12 14:33:41 +01003487 int res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003488 hashitem_T *hi;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003489 int is_global = FALSE;
3490 char_u *fname = name;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003491
3492 if (ht == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003493 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003494 if (len < sizeof(buffer) - 1)
3495 {
Bram Moolenaar7d3664d2020-05-09 13:06:24 +02003496 // avoid an alloc/free for short names
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003497 vim_strncpy(buffer, name, len);
3498 p = buffer;
3499 }
3500 else
3501 {
Bram Moolenaar71ccd032020-06-12 22:59:11 +02003502 p = vim_strnsave(name, len);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003503 if (p == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003504 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003505 }
3506
3507 hi = hash_find(ht, p);
Bram Moolenaar709664c2020-12-12 14:33:41 +01003508 res = HASHITEM_EMPTY(hi) ? FAIL : OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003509
3510 // if not script-local, then perhaps imported
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003511 if (res == FAIL && find_imported(p, 0, FALSE) != NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003512 res = OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003513 if (p != buffer)
3514 vim_free(p);
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003515
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003516 // Find a function, so that a following "->" works.
3517 // When used as a command require "(" or "->" to follow, "Cmd" is a user
3518 // command while "Cmd()" is a function call.
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003519 if (res != OK)
3520 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003521 p = skipwhite(name + len);
3522
3523 if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003524 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003525 // Do not check for an internal function, since it might also be a
3526 // valid command, such as ":split" versus "split()".
3527 // Skip "g:" before a function name.
3528 if (name[0] == 'g' && name[1] == ':')
3529 {
3530 is_global = TRUE;
3531 fname = name + 2;
3532 }
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003533 if (find_func(fname, is_global) != NULL)
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003534 res = OK;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003535 }
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003536 }
3537
Bram Moolenaar709664c2020-12-12 14:33:41 +01003538 return res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003539}
3540
3541/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003542 * Find the hashtab used for a variable name.
3543 * Return NULL if the name is not valid.
3544 * Set "varname" to the start of name without ':'.
3545 */
3546 hashtab_T *
3547find_var_ht(char_u *name, char_u **varname)
3548{
3549 hashitem_T *hi;
3550 hashtab_T *ht;
3551
3552 if (name[0] == NUL)
3553 return NULL;
3554 if (name[1] != ':')
3555 {
3556 // The name must not start with a colon or #.
3557 if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
3558 return NULL;
3559 *varname = name;
3560
3561 // "version" is "v:version" in all scopes if scriptversion < 3.
3562 // Same for a few other variables marked with VV_COMPAT.
Bram Moolenaardd9de502021-08-15 13:49:42 +02003563 if (in_old_script(3))
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003564 {
3565 hi = hash_find(&compat_hashtab, name);
3566 if (!HASHITEM_EMPTY(hi))
3567 return &compat_hashtab;
3568 }
3569
3570 ht = get_funccal_local_ht();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003571 if (ht != NULL)
3572 return ht; // local variable
3573
Bram Moolenaarf0a40692021-06-11 22:05:47 +02003574 // In Vim9 script items at the script level are script-local, except
3575 // for autoload names.
3576 if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003577 {
3578 ht = get_script_local_ht();
3579 if (ht != NULL)
3580 return ht;
3581 }
3582
3583 return &globvarht; // global variable
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003584 }
3585 *varname = name + 2;
3586 if (*name == 'g') // global variable
3587 return &globvarht;
3588 // There must be no ':' or '#' in the rest of the name, unless g: is used
3589 if (vim_strchr(name + 2, ':') != NULL
3590 || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
3591 return NULL;
3592 if (*name == 'b') // buffer variable
3593 return &curbuf->b_vars->dv_hashtab;
3594 if (*name == 'w') // window variable
3595 return &curwin->w_vars->dv_hashtab;
3596 if (*name == 't') // tab page variable
3597 return &curtab->tp_vars->dv_hashtab;
3598 if (*name == 'v') // v: variable
3599 return &vimvarht;
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003600 if (get_current_funccal() != NULL
Bram Moolenaarca16c602022-09-06 18:57:08 +01003601 && get_current_funccal()->fc_func->uf_def_status
3602 == UF_NOT_COMPILED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003603 {
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003604 // a: and l: are only used in functions defined with ":function"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003605 if (*name == 'a') // a: function argument
3606 return get_funccal_args_ht();
3607 if (*name == 'l') // l: local function variable
3608 return get_funccal_local_ht();
3609 }
3610 if (*name == 's') // script variable
3611 {
3612 ht = get_script_local_ht();
3613 if (ht != NULL)
3614 return ht;
3615 }
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003616 return NULL;
3617}
3618
3619/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003620 * Get the string value of a (global/local) variable.
3621 * Note: see tv_get_string() for how long the pointer remains valid.
3622 * Returns NULL when it doesn't exist.
3623 */
3624 char_u *
3625get_var_value(char_u *name)
3626{
3627 dictitem_T *v;
3628
3629 v = find_var(name, NULL, FALSE);
3630 if (v == NULL)
3631 return NULL;
3632 return tv_get_string(&v->di_tv);
3633}
3634
3635/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003636 * Allocate a new hashtab for a sourced script. It will be used while
3637 * sourcing this script and when executing functions defined in the script.
3638 */
3639 void
3640new_script_vars(scid_T id)
3641{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003642 scriptvar_T *sv;
3643
Bram Moolenaar7ebcba62020-01-12 17:42:55 +01003644 sv = ALLOC_CLEAR_ONE(scriptvar_T);
3645 if (sv == NULL)
3646 return;
3647 init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
Bram Moolenaar21b9e972020-01-26 19:26:46 +01003648 SCRIPT_ITEM(id)->sn_vars = sv;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003649}
3650
3651/*
3652 * Initialize dictionary "dict" as a scope and set variable "dict_var" to
3653 * point to it.
3654 */
3655 void
3656init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
3657{
3658 hash_init(&dict->dv_hashtab);
3659 dict->dv_lock = 0;
3660 dict->dv_scope = scope;
3661 dict->dv_refcount = DO_NOT_FREE_CNT;
3662 dict->dv_copyID = 0;
3663 dict_var->di_tv.vval.v_dict = dict;
3664 dict_var->di_tv.v_type = VAR_DICT;
3665 dict_var->di_tv.v_lock = VAR_FIXED;
3666 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
3667 dict_var->di_key[0] = NUL;
3668}
3669
3670/*
3671 * Unreference a dictionary initialized by init_var_dict().
3672 */
3673 void
3674unref_var_dict(dict_T *dict)
3675{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003676 // Now the dict needs to be freed if no one else is using it, go back to
3677 // normal reference counting.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003678 dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
3679 dict_unref(dict);
3680}
3681
3682/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003683 * Clean up a list of internal variables.
3684 * Frees all allocated variables and the value they contain.
3685 * Clears hashtab "ht", does not free it.
3686 */
3687 void
3688vars_clear(hashtab_T *ht)
3689{
3690 vars_clear_ext(ht, TRUE);
3691}
3692
3693/*
3694 * Like vars_clear(), but only free the value if "free_val" is TRUE.
3695 */
3696 void
3697vars_clear_ext(hashtab_T *ht, int free_val)
3698{
3699 int todo;
3700 hashitem_T *hi;
3701 dictitem_T *v;
3702
3703 hash_lock(ht);
3704 todo = (int)ht->ht_used;
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +00003705 FOR_ALL_HASHTAB_ITEMS(ht, hi, todo)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003706 {
3707 if (!HASHITEM_EMPTY(hi))
3708 {
3709 --todo;
3710
3711 // Free the variable. Don't remove it from the hashtab,
3712 // ht_array might change then. hash_clear() takes care of it
3713 // later.
3714 v = HI2DI(hi);
3715 if (free_val)
3716 clear_tv(&v->di_tv);
3717 if (v->di_flags & DI_FLAGS_ALLOC)
3718 vim_free(v);
3719 }
3720 }
3721 hash_clear(ht);
Bram Moolenaar8d739de2020-10-14 19:39:19 +02003722 hash_init(ht);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003723}
3724
3725/*
3726 * Delete a variable from hashtab "ht" at item "hi".
3727 * Clear the variable value and free the dictitem.
3728 */
Bram Moolenaarfcdc5d82020-10-10 19:07:09 +02003729 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003730delete_var(hashtab_T *ht, hashitem_T *hi)
3731{
3732 dictitem_T *di = HI2DI(hi);
3733
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00003734 if (hash_remove(ht, hi, "delete variable") != OK)
3735 return;
3736
3737 clear_tv(&di->di_tv);
3738 vim_free(di);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003739}
3740
3741/*
3742 * List the value of one internal variable.
3743 */
3744 static void
3745list_one_var(dictitem_T *v, char *prefix, int *first)
3746{
3747 char_u *tofree;
3748 char_u *s;
3749 char_u numbuf[NUMBUFLEN];
3750
3751 s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
3752 list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
3753 s == NULL ? (char_u *)"" : s, first);
3754 vim_free(tofree);
3755}
3756
3757 static void
3758list_one_var_a(
3759 char *prefix,
3760 char_u *name,
3761 int type,
3762 char_u *string,
3763 int *first) // when TRUE clear rest of screen and set to FALSE
3764{
3765 // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
3766 msg_start();
3767 msg_puts(prefix);
3768 if (name != NULL) // "a:" vars don't have a name stored
3769 msg_puts((char *)name);
3770 msg_putchar(' ');
3771 msg_advance(22);
3772 if (type == VAR_NUMBER)
3773 msg_putchar('#');
3774 else if (type == VAR_FUNC || type == VAR_PARTIAL)
3775 msg_putchar('*');
3776 else if (type == VAR_LIST)
3777 {
3778 msg_putchar('[');
3779 if (*string == '[')
3780 ++string;
3781 }
3782 else if (type == VAR_DICT)
3783 {
3784 msg_putchar('{');
3785 if (*string == '{')
3786 ++string;
3787 }
3788 else
3789 msg_putchar(' ');
3790
3791 msg_outtrans(string);
3792
3793 if (type == VAR_FUNC || type == VAR_PARTIAL)
3794 msg_puts("()");
3795 if (*first)
3796 {
3797 msg_clr_eos();
3798 *first = FALSE;
3799 }
3800}
3801
3802/*
zeertzjqedcba962023-09-24 23:13:51 +02003803 * Addition handling for setting a v: variable.
3804 * Return TRUE if the variable should be set normally,
3805 * FALSE if nothing else needs to be done.
3806 */
3807 int
3808before_set_vvar(
3809 char_u *varname,
3810 dictitem_T *di,
3811 typval_T *tv,
3812 int copy,
3813 int *type_error)
3814{
3815 if (di->di_tv.v_type == VAR_STRING)
3816 {
3817 VIM_CLEAR(di->di_tv.vval.v_string);
3818 if (copy || tv->v_type != VAR_STRING)
3819 {
3820 char_u *val = tv_get_string(tv);
3821
3822 // Careful: when assigning to v:errmsg and
3823 // tv_get_string() causes an error message the variable
3824 // will already be set.
3825 if (di->di_tv.vval.v_string == NULL)
3826 di->di_tv.vval.v_string = vim_strsave(val);
3827 }
3828 else
3829 {
3830 // Take over the string to avoid an extra alloc/free.
3831 di->di_tv.vval.v_string = tv->vval.v_string;
3832 tv->vval.v_string = NULL;
3833 }
3834 return FALSE;
3835 }
3836 else if (di->di_tv.v_type == VAR_NUMBER)
3837 {
3838 di->di_tv.vval.v_number = tv_get_number(tv);
3839 if (STRCMP(varname, "searchforward") == 0)
3840 set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
3841#ifdef FEAT_SEARCH_EXTRA
3842 else if (STRCMP(varname, "hlsearch") == 0)
3843 {
3844 no_hlsearch = !di->di_tv.vval.v_number;
3845 redraw_all_later(UPD_SOME_VALID);
3846 }
3847#endif
3848 return FALSE;
3849 }
3850 else if (di->di_tv.v_type != tv->v_type)
3851 {
3852 *type_error = TRUE;
3853 return FALSE;
3854 }
3855 return TRUE;
3856}
3857
3858/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003859 * Set variable "name" to value in "tv".
3860 * If the variable already exists, the value is updated.
3861 * Otherwise the variable is created.
3862 */
3863 void
3864set_var(
3865 char_u *name,
3866 typval_T *tv,
3867 int copy) // make copy of value in "tv"
3868{
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003869 set_var_const(name, 0, NULL, tv, copy, ASSIGN_DECL, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003870}
3871
3872/*
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003873 * Set variable "name" to value in "tv_arg".
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003874 * When "sid" is non-zero "name" is in the script with this ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003875 * If the variable already exists and "is_const" is FALSE the value is updated.
3876 * Otherwise the variable is created.
3877 */
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01003878 int
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003879set_var_const(
3880 char_u *name,
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003881 scid_T sid,
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003882 type_T *type_arg,
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003883 typval_T *tv_arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003884 int copy, // make copy of value in "tv"
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003885 int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaarf785aa12021-02-11 21:19:34 +01003886 int var_idx) // index for ":let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003887{
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003888 typval_T *tv = tv_arg;
Bram Moolenaar7824fc82021-11-26 17:36:51 +00003889 type_T *type = type_arg;
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003890 typval_T bool_tv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003891 dictitem_T *di;
Bram Moolenaar993faa32022-02-21 15:59:11 +00003892 typval_T *dest_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003893 char_u *varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003894 char_u *name_tofree = NULL;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003895 hashtab_T *ht = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003896 int is_script_local;
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003897 int vim9script = in_vim9script();
Bram Moolenaare535db82021-03-31 21:07:24 +02003898 int var_in_vim9script;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003899 int var_in_autoload = FALSE;
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003900 int flags = flags_arg;
Bram Moolenaardd297bc2021-12-10 10:37:38 +00003901 int free_tv_arg = !copy; // free tv_arg if not used
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01003902 int rc = FAIL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003903
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003904 if (sid != 0)
3905 {
3906 if (SCRIPT_ID_VALID(sid))
3907 ht = &SCRIPT_VARS(sid);
3908 varname = name;
3909 }
3910 else
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003911 {
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003912 scriptitem_T *si;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003913
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003914 if (in_vim9script() && is_export
3915 && SCRIPT_ID_VALID(current_sctx.sc_sid)
3916 && (si = SCRIPT_ITEM(current_sctx.sc_sid))
Bram Moolenaar0e1574c2022-03-03 17:05:35 +00003917 ->sn_autoload_prefix != NULL)
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003918 {
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003919 // In a vim9 autoload script an exported variable is put in the
3920 // global namespace with the autoload prefix.
3921 var_in_autoload = TRUE;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00003922 varname = concat_str(si->sn_autoload_prefix, name);
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003923 if (varname == NULL)
3924 goto failed;
3925 name_tofree = varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00003926 ht = &globvarht;
3927 }
3928 else
3929 ht = find_var_ht(name, &varname);
3930 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003931 if (ht == NULL || *varname == NUL)
3932 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003933 semsg(_(e_illegal_variable_name_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003934 goto failed;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003935 }
Bram Moolenaar54969f42022-02-07 13:56:44 +00003936 is_script_local = ht == get_script_local_ht() || sid != 0
3937 || var_in_autoload;
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003938
Bram Moolenaardbeecb22020-09-14 18:15:09 +02003939 if (vim9script
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003940 && !is_script_local
Bram Moolenaar3862ea32021-01-01 21:05:55 +01003941 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01003942 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003943 && name[1] == ':')
Bram Moolenaar67979662020-06-20 22:50:47 +02003944 {
Bram Moolenaare55b1c02020-06-21 15:52:59 +02003945 vim9_declare_error(name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003946 goto failed;
Bram Moolenaar67979662020-06-20 22:50:47 +02003947 }
Bram Moolenaar9510d222022-09-11 15:14:05 +01003948 if ((flags & ASSIGN_FOR_LOOP) && is_scoped_variable(name))
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02003949 // Do not make g:var, w:var, b:var or t:var final.
3950 flags &= ~ASSIGN_FINAL;
3951
Bram Moolenaare535db82021-03-31 21:07:24 +02003952 var_in_vim9script = is_script_local && current_script_is_vim9();
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003953 if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
3954 {
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02003955 // For "[a, _] = list" the underscore is ignored.
3956 if ((flags & ASSIGN_UNPACK) == 0)
3957 emsg(_(e_cannot_use_underscore_here));
Bram Moolenaar962c43b2021-04-10 17:18:09 +02003958 goto failed;
3959 }
Bram Moolenaar67979662020-06-20 22:50:47 +02003960
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003961 di = find_var_in_ht(ht, 0, varname, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003962
Bram Moolenaar24e93162021-07-18 20:40:33 +02003963 if (di == NULL && var_in_vim9script)
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003964 {
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003965 imported_T *import = find_imported(varname, 0, FALSE);
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02003966
Bram Moolenaar24e93162021-07-18 20:40:33 +02003967 if (import != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003968 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003969 // imported name space cannot be used
Bram Moolenaar24e93162021-07-18 20:40:33 +02003970 if ((flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003971 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02003972 semsg(_(e_redefining_imported_item_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02003973 goto failed;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003974 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003975 semsg(_(e_cannot_use_str_itself_it_is_imported), name);
3976 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02003977 }
Bram Moolenaar75e27d72022-02-13 13:56:29 +00003978 if (!in_vim9script())
3979 {
3980 semsg(_(e_cannot_create_vim9_script_variable_in_function_str),
3981 name);
3982 goto failed;
3983 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02003984 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003985
Bram Moolenaar993faa32022-02-21 15:59:11 +00003986 // Search in parent scope which is possible to reference from lambda
3987 if (di == NULL)
3988 di = find_var_in_scoped_ht(name, TRUE);
3989
3990 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
3991 && var_wrong_func_name(name, di == NULL))
3992 goto failed;
3993
3994 if (need_convert_to_bool(type, tv))
Bram Moolenaar24e93162021-07-18 20:40:33 +02003995 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00003996 // Destination is a bool and the value is not, but it can be
3997 // converted.
3998 CLEAR_FIELD(bool_tv);
3999 bool_tv.v_type = VAR_BOOL;
4000 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
4001 tv = &bool_tv;
4002 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02004003
Bram Moolenaar993faa32022-02-21 15:59:11 +00004004 if (di != NULL)
4005 {
4006 // Item already exists. Allowed to replace when reloading.
4007 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004008 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004009 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
4010 && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004011 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004012 emsg(_(e_cannot_modify_existing_variable));
4013 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02004014 }
4015
Bram Moolenaar993faa32022-02-21 15:59:11 +00004016 if (is_script_local && vim9script
4017 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
Bram Moolenaar12be7342021-03-31 21:47:33 +02004018 {
4019 semsg(_(e_redefining_script_item_str), name);
4020 goto failed;
4021 }
4022
Ernie Raele75fde62023-12-21 17:18:54 +01004023 if (check_typval_is_value(&di->di_tv) == FAIL)
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02004024 goto failed;
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02004025
Yegappan Lakshmanan1af35632024-02-06 11:03:36 +01004026 // List and Blob types can be modified in-place using the "+="
4027 // compound operator. For other types, this is not allowed.
4028 int type_inplace_modifiable =
4029 (di->di_tv.v_type == VAR_LIST || di->di_tv.v_type == VAR_BLOB);
4030
4031 if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0
4032 && ((flags & ASSIGN_COMPOUND_OP) == 0
4033 || !type_inplace_modifiable))
Bram Moolenaar24e93162021-07-18 20:40:33 +02004034 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004035 where_T where = WHERE_INIT;
Bram Moolenaar7a411a32022-04-04 14:58:06 +01004036 svar_T *sv = find_typval_in_script(&di->di_tv, sid, TRUE);
Bram Moolenaar993faa32022-02-21 15:59:11 +00004037
4038 if (sv != NULL)
4039 {
4040 // check the type and adjust to bool if needed
LemonBoyc5d27442023-08-19 13:02:35 +02004041 if (var_idx > 0)
4042 {
4043 where.wt_index = var_idx;
4044 where.wt_kind = WT_VARIABLE;
4045 }
Bram Moolenaar993faa32022-02-21 15:59:11 +00004046 if (check_script_var_type(sv, tv, name, where) == FAIL)
4047 goto failed;
4048 if (type == NULL)
4049 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01004050 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004051 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02004052 }
4053
Yegappan Lakshmanan1af35632024-02-06 11:03:36 +01004054 // Modifying a final variable with a List value using the "+="
4055 // operator is allowed. For other types, it is not allowed.
4056 if (((flags & ASSIGN_FOR_LOOP) == 0
4057 && ((flags & ASSIGN_COMPOUND_OP) == 0
4058 || !type_inplace_modifiable))
Bram Moolenaar16d2c022023-06-05 19:46:18 +01004059 ? var_check_permission(di, name) == FAIL
4060 : var_check_ro(di->di_flags, name, FALSE))
Bram Moolenaar24e93162021-07-18 20:40:33 +02004061 goto failed;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004062 }
4063 else
4064 {
4065 // can only redefine once
4066 di->di_flags &= ~DI_FLAGS_RELOAD;
Bram Moolenaar24e93162021-07-18 20:40:33 +02004067
Bram Moolenaar993faa32022-02-21 15:59:11 +00004068 // A Vim9 script-local variable is also present in sn_all_vars
4069 // and sn_var_vals. It may set "type" from "tv".
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004070 if (var_in_vim9script || var_in_autoload)
Bram Moolenaar993faa32022-02-21 15:59:11 +00004071 update_vim9_script_var(FALSE, di,
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004072 var_in_autoload ? name : di->di_key, flags,
Bram Moolenaar993faa32022-02-21 15:59:11 +00004073 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar07a65d22020-12-26 20:09:15 +01004074 }
4075
Bram Moolenaar993faa32022-02-21 15:59:11 +00004076 // existing variable, need to clear the value
4077
zeertzjqedcba962023-09-24 23:13:51 +02004078 // Handle setting internal v: variables separately where needed to
Bram Moolenaar993faa32022-02-21 15:59:11 +00004079 // prevent changing the type.
zeertzjqedcba962023-09-24 23:13:51 +02004080 int type_error = FALSE;
4081 if (ht == &vimvarht
4082 && !before_set_vvar(varname, di, tv, copy, &type_error))
Bram Moolenaar993faa32022-02-21 15:59:11 +00004083 {
zeertzjqedcba962023-09-24 23:13:51 +02004084 if (type_error)
4085 semsg(_(e_setting_v_str_to_value_with_wrong_type), varname);
4086 goto failed;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004087 }
4088
4089 clear_tv(&di->di_tv);
Bram Moolenaar766ae5b2022-09-14 00:30:51 +01004090
4091 if ((flags & ASSIGN_UPDATE_BLOCK_ID)
4092 && SCRIPT_ID_VALID(current_sctx.sc_sid))
4093 {
4094 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
4095
4096 update_script_var_block_id(name, si->sn_current_block_id);
4097 }
Bram Moolenaar993faa32022-02-21 15:59:11 +00004098 }
4099 else
4100 {
4101 // Item not found, check if a function already exists.
4102 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
4103 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
4104 {
4105 semsg(_(e_redefining_script_item_str), name);
4106 goto failed;
4107 }
4108
4109 // add a new variable
4110 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
4111 {
4112 semsg(_(e_unknown_variable_str), name);
4113 goto failed;
4114 }
4115
Bram Moolenaaref2c3252022-11-25 16:31:51 +00004116 if (check_hashtab_frozen(ht, "add variable"))
4117 goto failed;
4118
Bram Moolenaar993faa32022-02-21 15:59:11 +00004119 // Can't add "v:" or "a:" variable.
4120 if (ht == &vimvarht || ht == get_funccal_args_ht())
4121 {
4122 semsg(_(e_illegal_variable_name_str), name);
4123 goto failed;
4124 }
4125
4126 // Make sure the variable name is valid. In Vim9 script an
4127 // autoload variable must be prefixed with "g:" unless in an
4128 // autoload script.
4129 if (!valid_varname(varname, -1, !vim9script
4130 || STRNCMP(name, "g:", 2) == 0 || var_in_autoload))
4131 goto failed;
4132
zeertzjq1b438a82023-02-01 13:11:15 +00004133 di = alloc(offsetof(dictitem_T, di_key) + STRLEN(varname) + 1);
Bram Moolenaar993faa32022-02-21 15:59:11 +00004134 if (di == NULL)
4135 goto failed;
4136 STRCPY(di->di_key, varname);
Bram Moolenaaref2c3252022-11-25 16:31:51 +00004137 if (hash_add(ht, DI2HIKEY(di), "add variable") == FAIL)
Bram Moolenaar993faa32022-02-21 15:59:11 +00004138 {
4139 vim_free(di);
4140 goto failed;
4141 }
4142 di->di_flags = DI_FLAGS_ALLOC;
4143 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
4144 di->di_flags |= DI_FLAGS_LOCK;
4145
4146 // A Vim9 script-local variable is also added to sn_all_vars and
4147 // sn_var_vals. It may set "type" from "tv".
4148 if (var_in_vim9script || var_in_autoload)
4149 update_vim9_script_var(TRUE, di,
4150 var_in_autoload ? name : di->di_key, flags,
4151 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004152 }
4153
Bram Moolenaar993faa32022-02-21 15:59:11 +00004154 dest_tv = &di->di_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004155 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004156 copy_tv(tv, dest_tv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004157 else
4158 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02004159 *dest_tv = *tv;
4160 dest_tv->v_lock = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004161 init_tv(tv);
4162 }
Bram Moolenaardd297bc2021-12-10 10:37:38 +00004163 free_tv_arg = FALSE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004164
Bram Moolenaaraa210a32021-01-02 15:41:03 +01004165 if (vim9script && type != NULL)
Bram Moolenaar381692b2022-02-02 20:01:27 +00004166 set_tv_type(dest_tv, type);
Bram Moolenaaraa210a32021-01-02 15:41:03 +01004167
Bram Moolenaar1dcf55d2020-12-22 22:07:30 +01004168 // ":const var = value" locks the value
4169 // ":final var = value" locks "var"
Bram Moolenaar30fd8202020-09-26 15:09:30 +02004170 if (flags & ASSIGN_CONST)
Bram Moolenaar021bda52020-08-17 21:07:22 +02004171 // Like :lockvar! name: lock the value and what it contains, but only
4172 // if the reference count is up to one. That locks only literal
4173 // values.
Bram Moolenaar24e93162021-07-18 20:40:33 +02004174 item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
Bram Moolenaar24e93162021-07-18 20:40:33 +02004175
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01004176 rc = OK;
4177
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004178failed:
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004179 vim_free(name_tofree);
Bram Moolenaardd297bc2021-12-10 10:37:38 +00004180 if (free_tv_arg)
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004181 clear_tv(tv_arg);
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01004182
4183 return rc;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004184}
4185
4186/*
Bram Moolenaar3bdc90b2020-12-22 20:35:40 +01004187 * Check in this order for backwards compatibility:
4188 * - Whether the variable is read-only
4189 * - Whether the variable value is locked
4190 * - Whether the variable is locked
4191 */
4192 int
4193var_check_permission(dictitem_T *di, char_u *name)
4194{
4195 if (var_check_ro(di->di_flags, name, FALSE)
4196 || value_check_lock(di->di_tv.v_lock, name, FALSE)
4197 || var_check_lock(di->di_flags, name, FALSE))
4198 return FAIL;
4199 return OK;
4200}
4201
4202/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004203 * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
4204 * Also give an error message.
4205 */
4206 int
4207var_check_ro(int flags, char_u *name, int use_gettext)
4208{
4209 if (flags & DI_FLAGS_RO)
4210 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004211 if (name == NULL)
4212 emsg(_(e_cannot_change_readonly_variable));
4213 else
4214 semsg(_(e_cannot_change_readonly_variable_str),
Bram Moolenaard8e44472021-07-21 22:20:33 +02004215 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004216 return TRUE;
4217 }
4218 if ((flags & DI_FLAGS_RO_SBX) && sandbox)
4219 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004220 if (name == NULL)
4221 emsg(_(e_cannot_set_variable_in_sandbox));
4222 else
4223 semsg(_(e_cannot_set_variable_in_sandbox_str),
4224 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004225 return TRUE;
4226 }
4227 return FALSE;
4228}
4229
4230/*
Bram Moolenaara187c432020-09-16 21:08:28 +02004231 * Return TRUE if di_flags "flags" indicates variable "name" is locked.
4232 * Also give an error message.
4233 */
4234 int
4235var_check_lock(int flags, char_u *name, int use_gettext)
4236{
4237 if (flags & DI_FLAGS_LOCK)
4238 {
4239 semsg(_(e_variable_is_locked_str),
4240 use_gettext ? (char_u *)_(name) : name);
4241 return TRUE;
4242 }
4243 return FALSE;
4244}
4245
4246/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004247 * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
4248 * Also give an error message.
4249 */
4250 int
4251var_check_fixed(int flags, char_u *name, int use_gettext)
4252{
4253 if (flags & DI_FLAGS_FIX)
4254 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004255 if (name == NULL)
4256 emsg(_(e_cannot_delete_variable));
4257 else
4258 semsg(_(e_cannot_delete_variable_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004259 use_gettext ? (char_u *)_(name) : name);
4260 return TRUE;
4261 }
4262 return FALSE;
4263}
4264
4265/*
4266 * Check if a funcref is assigned to a valid variable name.
4267 * Return TRUE and give an error if not.
4268 */
4269 int
Bram Moolenaar98b4f142020-08-08 15:46:01 +02004270var_wrong_func_name(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004271 char_u *name, // points to start of variable name
4272 int new_var) // TRUE when creating the variable
4273{
Bram Moolenaar32154662021-03-28 21:14:06 +02004274 // Allow for w: b: s: and t:. In Vim9 script s: is not allowed, because
4275 // the name can be used without the s: prefix.
thinca6c667bd2022-09-02 11:25:37 +01004276 // Allow autoload variable.
Bram Moolenaar32154662021-03-28 21:14:06 +02004277 if (!((vim_strchr((char_u *)"wbt", name[0]) != NULL
4278 || (!in_vim9script() && name[0] == 's')) && name[1] == ':')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004279 && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
thinca6c667bd2022-09-02 11:25:37 +01004280 ? name[2] : name[0])
4281 && vim_strchr(name, '#') == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004282 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00004283 semsg(_(e_funcref_variable_name_must_start_with_capital_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004284 return TRUE;
4285 }
4286 // Don't allow hiding a function. When "v" is not NULL we might be
4287 // assigning another function to the same var, the type is checked
4288 // below.
4289 if (new_var && function_exists(name, FALSE))
4290 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00004291 semsg(_(e_variable_name_conflicts_with_existing_function_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004292 name);
4293 return TRUE;
4294 }
4295 return FALSE;
4296}
4297
4298/*
Bram Moolenaara187c432020-09-16 21:08:28 +02004299 * Return TRUE if "flags" indicates variable "name" has a locked (immutable)
4300 * value. Also give an error message, using "name" or _("name") when
4301 * "use_gettext" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004302 */
4303 int
Bram Moolenaara187c432020-09-16 21:08:28 +02004304value_check_lock(int lock, char_u *name, int use_gettext)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004305{
4306 if (lock & VAR_LOCKED)
4307 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004308 if (name == NULL)
4309 emsg(_(e_value_is_locked));
4310 else
4311 semsg(_(e_value_is_locked_str),
4312 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004313 return TRUE;
4314 }
4315 if (lock & VAR_FIXED)
4316 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004317 if (name == NULL)
4318 emsg(_(e_cannot_change_value));
4319 else
4320 semsg(_(e_cannot_change_value_of_str),
4321 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004322 return TRUE;
4323 }
4324 return FALSE;
4325}
4326
4327/*
Bram Moolenaar03290b82020-12-19 16:30:44 +01004328 * Check if a variable name is valid. When "autoload" is true "#" is allowed.
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004329 * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004330 * Return FALSE and give an error if not.
4331 */
4332 int
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004333valid_varname(char_u *varname, int len, int autoload)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004334{
4335 char_u *p;
4336
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004337 for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004338 if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
Bram Moolenaar03290b82020-12-19 16:30:44 +01004339 && !(autoload && *p == AUTOLOAD_CHAR))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004340 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004341 semsg(_(e_illegal_variable_name_str), varname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004342 return FALSE;
4343 }
4344 return TRUE;
4345}
4346
4347/*
LemonBoy47d4e312022-05-04 18:12:55 +01004348 * Implements the logic to retrieve local variable and option values.
4349 * Used by "getwinvar()" "gettabvar()" "gettabwinvar()" "getbufvar()".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004350 */
4351 static void
LemonBoy47d4e312022-05-04 18:12:55 +01004352get_var_from(
4353 char_u *varname,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004354 typval_T *rettv,
LemonBoy47d4e312022-05-04 18:12:55 +01004355 typval_T *deftv, // Default value if not found.
4356 int htname, // 't'ab, 'w'indow or 'b'uffer local.
4357 tabpage_T *tp, // can be NULL
4358 win_T *win,
4359 buf_T *buf) // Ignored if htname is not 'b'.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004360{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004361 dictitem_T *v;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004362 int done = FALSE;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004363 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004364 int need_switch_win;
zeertzjqcd6ad642022-07-25 12:28:09 +01004365 int do_change_curbuf = buf != NULL && htname == 'b';
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004366
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004367 ++emsg_off;
4368
4369 rettv->v_type = VAR_STRING;
4370 rettv->vval.v_string = NULL;
4371
LemonBoy47d4e312022-05-04 18:12:55 +01004372 if (varname != NULL && tp != NULL && win != NULL
4373 && (htname != 'b' || buf != NULL))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004374 {
4375 // Set curwin to be our win, temporarily. Also set the tabpage,
4376 // otherwise the window is not valid. Only do this when needed,
4377 // autocommands get blocked.
LemonBoy47d4e312022-05-04 18:12:55 +01004378 // If we have a buffer reference avoid the switching, we're saving and
4379 // restoring curbuf directly.
zeertzjqcd6ad642022-07-25 12:28:09 +01004380 need_switch_win = !(tp == curtab && win == curwin) && !do_change_curbuf;
LemonBoy47d4e312022-05-04 18:12:55 +01004381 if (!need_switch_win || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004382 {
LemonBoy47d4e312022-05-04 18:12:55 +01004383 // Handle options. There are no tab-local options.
4384 if (*varname == '&' && htname != 't')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004385 {
LemonBoy47d4e312022-05-04 18:12:55 +01004386 buf_T *save_curbuf = curbuf;
4387
4388 // Change curbuf so the option is read from the correct buffer.
zeertzjqcd6ad642022-07-25 12:28:09 +01004389 if (do_change_curbuf)
LemonBoy47d4e312022-05-04 18:12:55 +01004390 curbuf = buf;
4391
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004392 if (varname[1] == NUL)
4393 {
zeertzjqcd6ad642022-07-25 12:28:09 +01004394 // get all window-local or buffer-local options in a dict
LemonBoy47d4e312022-05-04 18:12:55 +01004395 dict_T *opts = get_winbuf_options(htname == 'b');
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004396
4397 if (opts != NULL)
4398 {
4399 rettv_dict_set(rettv, opts);
4400 done = TRUE;
4401 }
4402 }
LemonBoy47d4e312022-05-04 18:12:55 +01004403 else if (eval_option(&varname, rettv, TRUE) == OK)
4404 // Local option
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004405 done = TRUE;
LemonBoy47d4e312022-05-04 18:12:55 +01004406
4407 curbuf = save_curbuf;
4408 }
4409 else if (*varname == NUL)
4410 {
4411 // Empty string: return a dict with all the local variables.
4412 if (htname == 'b')
4413 v = &buf->b_bufvar;
4414 else if (htname == 'w')
4415 v = &win->w_winvar;
4416 else
4417 v = &tp->tp_winvar;
4418 copy_tv(&v->di_tv, rettv);
4419 done = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004420 }
4421 else
4422 {
LemonBoy47d4e312022-05-04 18:12:55 +01004423 hashtab_T *ht;
4424
4425 if (htname == 'b')
4426 ht = &buf->b_vars->dv_hashtab;
4427 else if (htname == 'w')
4428 ht = &win->w_vars->dv_hashtab;
4429 else
4430 ht = &tp->tp_vars->dv_hashtab;
4431
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004432 // Look up the variable.
LemonBoy47d4e312022-05-04 18:12:55 +01004433 v = find_var_in_ht(ht, htname, varname, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004434 if (v != NULL)
4435 {
4436 copy_tv(&v->di_tv, rettv);
4437 done = TRUE;
4438 }
4439 }
4440 }
4441
4442 if (need_switch_win)
4443 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00004444 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004445 }
4446
LemonBoy47d4e312022-05-04 18:12:55 +01004447 if (!done && deftv->v_type != VAR_UNKNOWN)
4448 // use the default value
4449 copy_tv(deftv, rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004450
4451 --emsg_off;
4452}
4453
4454/*
LemonBoy47d4e312022-05-04 18:12:55 +01004455 * getwinvar() and gettabwinvar()
4456 */
4457 static void
4458getwinvar(
4459 typval_T *argvars,
4460 typval_T *rettv,
4461 int off) // 1 for gettabwinvar()
4462{
4463 char_u *varname;
4464 tabpage_T *tp;
4465 win_T *win;
4466
4467 if (off == 1)
4468 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4469 else
4470 tp = curtab;
4471 win = find_win_by_nr(&argvars[off], tp);
4472 varname = tv_get_string_chk(&argvars[off + 1]);
4473
4474 get_var_from(varname, rettv, &argvars[off + 2], 'w', tp, win, NULL);
4475}
4476
4477/*
Bram Moolenaar191929b2020-08-19 21:20:49 +02004478 * Set option "varname" to the value of "varp" for the current buffer/window.
4479 */
4480 static void
4481set_option_from_tv(char_u *varname, typval_T *varp)
4482{
4483 long numval = 0;
4484 char_u *strval;
4485 char_u nbuf[NUMBUFLEN];
4486 int error = FALSE;
4487
zeertzjq4c7cb372023-06-14 16:39:54 +01004488 int opt_idx = findoption(varname);
4489 if (opt_idx < 0)
4490 {
4491 semsg(_(e_unknown_option_str_2), varname);
4492 return;
4493 }
4494 int opt_p_flags = get_option_flags(opt_idx);
4495
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004496 if (varp->v_type == VAR_BOOL)
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004497 {
zeertzjq4c7cb372023-06-14 16:39:54 +01004498 if (opt_p_flags & P_STRING)
Bram Moolenaar28f84e12022-07-27 12:30:13 +01004499 {
4500 emsg(_(e_string_required));
4501 return;
4502 }
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004503 numval = (long)varp->vval.v_number;
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004504 strval = (char_u *)"0"; // avoid using "false"
4505 }
4506 else
4507 {
zeertzjq4c7cb372023-06-14 16:39:54 +01004508 if ((opt_p_flags & (P_NUM|P_BOOL))
4509 && (!in_vim9script() || varp->v_type != VAR_STRING))
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004510 numval = (long)tv_get_number_chk(varp, &error);
zeertzjq4c7cb372023-06-14 16:39:54 +01004511 if (!error)
4512 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004513 }
Bram Moolenaar191929b2020-08-19 21:20:49 +02004514 if (!error && strval != NULL)
Bram Moolenaar31e5c602022-04-15 13:53:33 +01004515 set_option_value_give_err(varname, numval, strval, OPT_LOCAL);
Bram Moolenaar191929b2020-08-19 21:20:49 +02004516}
4517
4518/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004519 * "setwinvar()" and "settabwinvar()" functions
4520 */
4521 static void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004522setwinvar(typval_T *argvars, int off)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004523{
4524 win_T *win;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004525 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004526 int need_switch_win;
4527 char_u *varname, *winvarname;
4528 typval_T *varp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004529 tabpage_T *tp = NULL;
4530
4531 if (check_secure())
4532 return;
4533
4534 if (off == 1)
4535 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4536 else
4537 tp = curtab;
4538 win = find_win_by_nr(&argvars[off], tp);
4539 varname = tv_get_string_chk(&argvars[off + 1]);
4540 varp = &argvars[off + 2];
4541
zeertzjqea720ae2023-01-03 10:54:09 +00004542 if (win == NULL || varname == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004543 return;
4544
4545 need_switch_win = !(tp == curtab && win == curwin);
4546 if (!need_switch_win
4547 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004548 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004549 if (*varname == '&')
4550 set_option_from_tv(varname + 1, varp);
4551 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004552 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004553 winvarname = alloc(STRLEN(varname) + 3);
4554 if (winvarname != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004555 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004556 STRCPY(winvarname, "w:");
4557 STRCPY(winvarname + 2, varname);
4558 set_var(winvarname, varp, TRUE);
4559 vim_free(winvarname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004560 }
4561 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004562 }
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004563 if (need_switch_win)
4564 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004565}
4566
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004567/*
4568 * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
4569 * v:option_type, and v:option_command.
4570 */
4571 void
4572reset_v_option_vars(void)
4573{
4574 set_vim_var_string(VV_OPTION_NEW, NULL, -1);
4575 set_vim_var_string(VV_OPTION_OLD, NULL, -1);
4576 set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
4577 set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
4578 set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
4579 set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
4580}
4581
4582/*
4583 * Add an assert error to v:errors.
4584 */
4585 void
4586assert_error(garray_T *gap)
4587{
4588 struct vimvar *vp = &vimvars[VV_ERRORS];
4589
Bram Moolenaard787e402021-12-24 21:36:12 +00004590 if (vp->vv_tv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004591 // Make sure v:errors is a list.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004592 set_vim_var_list(VV_ERRORS, list_alloc());
4593 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
4594}
4595
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004596 int
4597var_exists(char_u *var)
4598{
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004599 char_u *arg = var;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004600 char_u *name;
4601 char_u *tofree;
4602 typval_T tv;
4603 int len = 0;
4604 int n = FALSE;
4605
4606 // get_name_len() takes care of expanding curly braces
4607 name = var;
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004608 len = get_name_len(&arg, &tofree, TRUE, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004609 if (len > 0)
4610 {
4611 if (tofree != NULL)
4612 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004613 n = (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01004614 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004615 if (n)
4616 {
4617 // handle d.key, l[idx], f(expr)
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004618 arg = skipwhite(arg);
Bram Moolenaar32884ad2022-01-07 12:45:29 +00004619 n = (handle_subscript(&arg, name, &tv, &EVALARG_EVALUATE,
4620 FALSE) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004621 if (n)
4622 clear_tv(&tv);
4623 }
4624 }
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004625 if (*arg != NUL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004626 n = FALSE;
4627
4628 vim_free(tofree);
4629 return n;
4630}
4631
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004632static lval_T *redir_lval = NULL;
4633#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
4634static garray_T redir_ga; // only valid when redir_lval is not NULL
4635static char_u *redir_endp = NULL;
4636static char_u *redir_varname = NULL;
4637
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004638 int
4639alloc_redir_lval(void)
4640{
4641 redir_lval = ALLOC_CLEAR_ONE(lval_T);
4642 if (redir_lval == NULL)
4643 return FAIL;
4644 return OK;
4645}
4646
4647 void
4648clear_redir_lval(void)
4649{
4650 VIM_CLEAR(redir_lval);
4651}
4652
4653 void
4654init_redir_ga(void)
4655{
Bram Moolenaar04935fb2022-01-08 16:19:22 +00004656 ga_init2(&redir_ga, sizeof(char), 500);
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004657}
4658
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004659/*
4660 * Start recording command output to a variable
4661 * When "append" is TRUE append to an existing variable.
4662 * Returns OK if successfully completed the setup. FAIL otherwise.
4663 */
4664 int
4665var_redir_start(char_u *name, int append)
4666{
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004667 int called_emsg_before;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004668 typval_T tv;
4669
4670 // Catch a bad name early.
4671 if (!eval_isnamec1(*name))
4672 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004673 emsg(_(e_invalid_argument));
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004674 return FAIL;
4675 }
4676
4677 // Make a copy of the name, it is used in redir_lval until redir ends.
4678 redir_varname = vim_strsave(name);
4679 if (redir_varname == NULL)
4680 return FAIL;
4681
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004682 if (alloc_redir_lval() == FAIL)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004683 {
4684 var_redir_stop();
4685 return FAIL;
4686 }
4687
4688 // The output is stored in growarray "redir_ga" until redirection ends.
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004689 init_redir_ga();
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004690
4691 // Parse the variable name (can be a dict or list entry).
4692 redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
4693 FNE_CHECK_START);
4694 if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
4695 {
4696 clear_lval(redir_lval);
4697 if (redir_endp != NULL && *redir_endp != NUL)
4698 // Trailing characters are present after the variable name
Bram Moolenaar74409f62022-01-01 15:58:22 +00004699 semsg(_(e_trailing_characters_str), redir_endp);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004700 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004701 semsg(_(e_invalid_argument_str), name);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004702 redir_endp = NULL; // don't store a value, only cleanup
4703 var_redir_stop();
4704 return FAIL;
4705 }
4706
4707 // check if we can write to the variable: set it to or append an empty
4708 // string
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004709 called_emsg_before = called_emsg;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004710 tv.v_type = VAR_STRING;
4711 tv.vval.v_string = (char_u *)"";
4712 if (append)
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004713 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004714 ASSIGN_NO_DECL, (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004715 else
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004716 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004717 ASSIGN_NO_DECL, (char_u *)"=", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004718 clear_lval(redir_lval);
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004719 if (called_emsg > called_emsg_before)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004720 {
4721 redir_endp = NULL; // don't store a value, only cleanup
4722 var_redir_stop();
4723 return FAIL;
4724 }
4725
4726 return OK;
4727}
4728
4729/*
4730 * Append "value[value_len]" to the variable set by var_redir_start().
4731 * The actual appending is postponed until redirection ends, because the value
4732 * appended may in fact be the string we write to, changing it may cause freed
4733 * memory to be used:
4734 * :redir => foo
4735 * :let foo
4736 * :redir END
4737 */
4738 void
4739var_redir_str(char_u *value, int value_len)
4740{
4741 int len;
4742
4743 if (redir_lval == NULL)
4744 return;
4745
4746 if (value_len == -1)
4747 len = (int)STRLEN(value); // Append the entire string
4748 else
4749 len = value_len; // Append only "value_len" characters
4750
4751 if (ga_grow(&redir_ga, len) == OK)
4752 {
4753 mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
4754 redir_ga.ga_len += len;
4755 }
4756 else
4757 var_redir_stop();
4758}
4759
4760/*
4761 * Stop redirecting command output to a variable.
4762 * Frees the allocated memory.
4763 */
4764 void
4765var_redir_stop(void)
4766{
4767 typval_T tv;
4768
4769 if (EVALCMD_BUSY)
4770 {
4771 redir_lval = NULL;
4772 return;
4773 }
4774
4775 if (redir_lval != NULL)
4776 {
4777 // If there was no error: assign the text to the variable.
4778 if (redir_endp != NULL)
4779 {
4780 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4781 tv.v_type = VAR_STRING;
4782 tv.vval.v_string = redir_ga.ga_data;
4783 // Call get_lval() again, if it's inside a Dict or List it may
4784 // have changed.
4785 redir_endp = get_lval(redir_varname, NULL, redir_lval,
4786 FALSE, FALSE, 0, FNE_CHECK_START);
4787 if (redir_endp != NULL && redir_lval->ll_name != NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004788 set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004789 (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004790 clear_lval(redir_lval);
4791 }
4792
4793 // free the collected output
4794 VIM_CLEAR(redir_ga.ga_data);
4795
4796 VIM_CLEAR(redir_lval);
4797 }
4798 VIM_CLEAR(redir_varname);
4799}
4800
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004801/*
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004802 * Get the collected redirected text and clear redir_ga.
4803 */
4804 char_u *
4805get_clear_redir_ga(void)
4806{
4807 char_u *res;
4808
4809 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4810 res = redir_ga.ga_data;
4811 redir_ga.ga_data = NULL;
4812 return res;
4813}
4814
4815/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004816 * "gettabvar()" function
4817 */
4818 void
4819f_gettabvar(typval_T *argvars, typval_T *rettv)
4820{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004821 char_u *varname;
LemonBoy47d4e312022-05-04 18:12:55 +01004822 tabpage_T *tp;
4823 win_T *win = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004824
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004825 if (in_vim9script()
4826 && (check_for_number_arg(argvars, 0) == FAIL
4827 || check_for_string_arg(argvars, 1) == FAIL))
4828 return;
4829
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004830 varname = tv_get_string_chk(&argvars[1]);
4831 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
LemonBoy47d4e312022-05-04 18:12:55 +01004832 if (tp != NULL)
4833 win = tp == curtab || tp->tp_firstwin == NULL ? firstwin
4834 : tp->tp_firstwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004835
LemonBoy47d4e312022-05-04 18:12:55 +01004836 get_var_from(varname, rettv, &argvars[2], 't', tp, win, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004837}
4838
4839/*
4840 * "gettabwinvar()" function
4841 */
4842 void
4843f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4844{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004845 if (in_vim9script()
4846 && (check_for_number_arg(argvars, 0) == FAIL
4847 || check_for_number_arg(argvars, 1) == FAIL
4848 || check_for_string_arg(argvars, 2) == FAIL))
4849 return;
4850
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004851 getwinvar(argvars, rettv, 1);
4852}
4853
4854/*
4855 * "getwinvar()" function
4856 */
4857 void
4858f_getwinvar(typval_T *argvars, typval_T *rettv)
4859{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004860 if (in_vim9script()
4861 && (check_for_number_arg(argvars, 0) == FAIL
4862 || check_for_string_arg(argvars, 1) == FAIL))
4863 return;
4864
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004865 getwinvar(argvars, rettv, 0);
4866}
4867
4868/*
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004869 * "getbufvar()" function
4870 */
4871 void
4872f_getbufvar(typval_T *argvars, typval_T *rettv)
4873{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004874 char_u *varname;
LemonBoy47d4e312022-05-04 18:12:55 +01004875 buf_T *buf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004876
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004877 if (in_vim9script()
4878 && (check_for_buffer_arg(argvars, 0) == FAIL
4879 || check_for_string_arg(argvars, 1) == FAIL))
4880 return;
4881
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004882 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004883 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004884
LemonBoy47d4e312022-05-04 18:12:55 +01004885 get_var_from(varname, rettv, &argvars[2], 'b', curtab, curwin, buf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004886}
4887
4888/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004889 * "settabvar()" function
4890 */
4891 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004892f_settabvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004893{
4894 tabpage_T *save_curtab;
4895 tabpage_T *tp;
zeertzjqb47fbb42024-02-12 22:50:26 +01004896 tabpage_T *save_lu_tp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004897 char_u *varname, *tabvarname;
4898 typval_T *varp;
4899
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004900 if (check_secure())
4901 return;
4902
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004903 if (in_vim9script()
4904 && (check_for_number_arg(argvars, 0) == FAIL
4905 || check_for_string_arg(argvars, 1) == FAIL))
4906 return;
4907
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004908 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4909 varname = tv_get_string_chk(&argvars[1]);
4910 varp = &argvars[2];
4911
zeertzjqea720ae2023-01-03 10:54:09 +00004912 if (varname == NULL || tp == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004913 return;
4914
4915 save_curtab = curtab;
zeertzjqb47fbb42024-02-12 22:50:26 +01004916 save_lu_tp = lastused_tabpage;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004917 goto_tabpage_tp(tp, FALSE, FALSE);
4918
4919 tabvarname = alloc(STRLEN(varname) + 3);
4920 if (tabvarname != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004921 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004922 STRCPY(tabvarname, "t:");
4923 STRCPY(tabvarname + 2, varname);
4924 set_var(tabvarname, varp, TRUE);
4925 vim_free(tabvarname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004926 }
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004927
zeertzjqb47fbb42024-02-12 22:50:26 +01004928 // Restore current tabpage and last accessed tabpage.
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004929 if (valid_tabpage(save_curtab))
zeertzjqb47fbb42024-02-12 22:50:26 +01004930 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004931 goto_tabpage_tp(save_curtab, FALSE, FALSE);
zeertzjqb47fbb42024-02-12 22:50:26 +01004932 if (valid_tabpage(save_lu_tp))
4933 lastused_tabpage = save_lu_tp;
4934 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004935}
4936
4937/*
4938 * "settabwinvar()" function
4939 */
4940 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004941f_settabwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004942{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004943 if (in_vim9script()
4944 && (check_for_number_arg(argvars, 0) == FAIL
4945 || check_for_number_arg(argvars, 1) == FAIL
4946 || check_for_string_arg(argvars, 2) == FAIL))
4947 return;
4948
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004949 setwinvar(argvars, 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004950}
4951
4952/*
4953 * "setwinvar()" function
4954 */
4955 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004956f_setwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004957{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004958 if (in_vim9script()
4959 && (check_for_number_arg(argvars, 0) == FAIL
4960 || check_for_string_arg(argvars, 1) == FAIL))
4961 return;
4962
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004963 setwinvar(argvars, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004964}
4965
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004966/*
4967 * "setbufvar()" function
4968 */
4969 void
4970f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
4971{
4972 buf_T *buf;
4973 char_u *varname, *bufvarname;
4974 typval_T *varp;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004975
4976 if (check_secure())
4977 return;
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02004978
4979 if (in_vim9script()
4980 && (check_for_buffer_arg(argvars, 0) == FAIL
4981 || check_for_string_arg(argvars, 1) == FAIL))
4982 return;
4983
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004984 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02004985 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004986 varp = &argvars[2];
4987
zeertzjqea720ae2023-01-03 10:54:09 +00004988 if (buf == NULL || varname == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004989 return;
4990
4991 if (*varname == '&')
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004992 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004993 aco_save_T aco;
Christian Brabandtac4cffc2024-01-16 17:22:38 +01004994 // safe the current window position, it could
4995 // change because of 'scrollbind' window-local
4996 // options
4997 linenr_T old_topline = curwin->w_topline;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004998
4999 // Set curbuf to be our buf, temporarily.
5000 aucmd_prepbuf(&aco, buf);
5001 if (curbuf == buf)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005002 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005003 // Only when it worked to set "curbuf".
5004 set_option_from_tv(varname + 1, varp);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005005
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005006 // reset notion of buffer
5007 aucmd_restbuf(&aco);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005008 }
Christian Brabandtac4cffc2024-01-16 17:22:38 +01005009 curwin->w_topline = old_topline;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005010 }
5011 else
5012 {
5013 bufvarname = alloc(STRLEN(varname) + 3);
5014 if (bufvarname != NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005015 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005016 buf_T *save_curbuf = curbuf;
Bram Moolenaar86015452020-03-29 15:12:15 +02005017
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005018 curbuf = buf;
5019 STRCPY(bufvarname, "b:");
5020 STRCPY(bufvarname + 2, varname);
5021 set_var(bufvarname, varp, TRUE);
5022 vim_free(bufvarname);
5023 curbuf = save_curbuf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005024 }
5025 }
5026}
5027
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005028/*
5029 * Get a callback from "arg". It can be a Funcref or a function name.
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005030 * When "arg" is zero "res.cb_name" is set to an empty string.
5031 * If "res.cb_name" is allocated then "res.cb_free_name" is set to TRUE.
5032 * "res.cb_name" is set to NULL for an invalid argument.
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005033 */
5034 callback_T
5035get_callback(typval_T *arg)
5036{
Bram Moolenaar14e579092020-03-07 16:59:25 +01005037 callback_T res;
5038 int r = OK;
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005039
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005040 CLEAR_FIELD(res);
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005041 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
5042 {
5043 res.cb_partial = arg->vval.v_partial;
5044 ++res.cb_partial->pt_refcount;
5045 res.cb_name = partial_name(res.cb_partial);
5046 }
5047 else
5048 {
Bram Moolenaar14e579092020-03-07 16:59:25 +01005049 if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
Keith Thompson184f71c2024-01-04 21:19:04 +01005050 && SAFE_isdigit(*arg->vval.v_string))
Bram Moolenaar14e579092020-03-07 16:59:25 +01005051 r = FAIL;
5052 else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005053 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005054 res.cb_name = arg->vval.v_string;
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005055 if (arg->v_type == VAR_STRING)
5056 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005057 char_u *name = get_scriptlocal_funcname(arg->vval.v_string);
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005058 if (name != NULL)
5059 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005060 res.cb_name = name;
5061 res.cb_free_name = TRUE;
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005062 }
5063 }
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005064 func_ref(res.cb_name);
5065 }
5066 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005067 res.cb_name = (char_u *)"";
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005068 else
Bram Moolenaar14e579092020-03-07 16:59:25 +01005069 r = FAIL;
5070
5071 if (r == FAIL)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005072 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00005073 emsg(_(e_invalid_callback_argument));
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005074 res.cb_name = NULL;
5075 }
5076 }
5077 return res;
5078}
5079
5080/*
5081 * Copy a callback into a typval_T.
5082 */
5083 void
5084put_callback(callback_T *cb, typval_T *tv)
5085{
5086 if (cb->cb_partial != NULL)
5087 {
5088 tv->v_type = VAR_PARTIAL;
5089 tv->vval.v_partial = cb->cb_partial;
5090 ++tv->vval.v_partial->pt_refcount;
5091 }
5092 else
5093 {
5094 tv->v_type = VAR_FUNC;
5095 tv->vval.v_string = vim_strsave(cb->cb_name);
5096 func_ref(cb->cb_name);
5097 }
5098}
5099
5100/*
5101 * Make a copy of "src" into "dest", allocating the function name if needed,
5102 * without incrementing the refcount.
5103 */
5104 void
5105set_callback(callback_T *dest, callback_T *src)
5106{
5107 if (src->cb_partial == NULL)
5108 {
5109 // just a function name, make a copy
5110 dest->cb_name = vim_strsave(src->cb_name);
5111 dest->cb_free_name = TRUE;
5112 }
5113 else
5114 {
5115 // cb_name is a pointer into cb_partial
5116 dest->cb_name = src->cb_name;
5117 dest->cb_free_name = FALSE;
5118 }
5119 dest->cb_partial = src->cb_partial;
5120}
5121
5122/*
Bram Moolenaard43906d2020-07-20 21:31:32 +02005123 * Copy callback from "src" to "dest", incrementing the refcounts.
5124 */
5125 void
5126copy_callback(callback_T *dest, callback_T *src)
5127{
5128 dest->cb_partial = src->cb_partial;
5129 if (dest->cb_partial != NULL)
5130 {
5131 dest->cb_name = src->cb_name;
5132 dest->cb_free_name = FALSE;
5133 ++dest->cb_partial->pt_refcount;
5134 }
5135 else
5136 {
5137 dest->cb_name = vim_strsave(src->cb_name);
5138 dest->cb_free_name = TRUE;
5139 func_ref(src->cb_name);
5140 }
5141}
5142
5143/*
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005144 * When a callback refers to an autoload import, change the function name to
5145 * the "path#name" form. Uses the current script context.
5146 * Only works when the name is allocated.
5147 */
5148 void
5149expand_autload_callback(callback_T *cb)
5150{
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005151 char_u *name;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005152 char_u *p;
5153 imported_T *import;
5154
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005155 if (!in_vim9script() || cb->cb_name == NULL
5156 || (!cb->cb_free_name
5157 && (cb->cb_partial == NULL || cb->cb_partial->pt_name == NULL)))
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005158 return;
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005159 if (cb->cb_partial != NULL)
5160 name = cb->cb_partial->pt_name;
5161 else
5162 name = cb->cb_name;
5163 p = vim_strchr(name, '.');
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005164 if (p == NULL)
5165 return;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005166
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00005167 import = find_imported(name, p - name, FALSE);
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005168 if (import == NULL || !SCRIPT_ID_VALID(import->imp_sid))
5169 return;
5170
5171 scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
5172 if (si->sn_autoload_prefix == NULL)
5173 return;
5174
5175 char_u *newname = concat_str(si->sn_autoload_prefix, p + 1);
5176 if (newname == NULL)
5177 return;
5178
5179 if (cb->cb_partial != NULL)
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005180 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005181 if (cb->cb_name == cb->cb_partial->pt_name)
5182 cb->cb_name = newname;
5183 vim_free(cb->cb_partial->pt_name);
5184 cb->cb_partial->pt_name = newname;
5185 }
5186 else
5187 {
5188 vim_free(cb->cb_name);
5189 cb->cb_name = newname;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005190 }
5191}
5192
5193/*
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005194 * Unref/free "callback" returned by get_callback() or set_callback().
5195 */
5196 void
5197free_callback(callback_T *callback)
5198{
5199 if (callback->cb_partial != NULL)
5200 {
5201 partial_unref(callback->cb_partial);
5202 callback->cb_partial = NULL;
5203 }
5204 else if (callback->cb_name != NULL)
5205 func_unref(callback->cb_name);
5206 if (callback->cb_free_name)
5207 {
5208 vim_free(callback->cb_name);
5209 callback->cb_free_name = FALSE;
5210 }
5211 callback->cb_name = NULL;
5212}
5213
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005214#endif // FEAT_EVAL