blob: d94d3e860857b7758fa5be1fe0e1081a88a67c50 [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},
ichizok663d18d2025-01-02 18:06:00 +0100163 {VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
zeertzjq6655bef2025-01-06 18:32:13 +0100164 {VV_NAME("stacktrace", VAR_LIST), &t_list_dict_any, VV_RO},
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100165 {VV_NAME("t_tuple", VAR_NUMBER), NULL, VV_RO},
Foxe Chenb90c2392025-06-27 21:10:35 +0200166 {VV_NAME("wayland_display", VAR_STRING), NULL, VV_RO},
167 {VV_NAME("clipmethod", VAR_STRING), NULL, VV_RO},
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200168};
169
170// shorthand
Bram Moolenaard787e402021-12-24 21:36:12 +0000171#define vv_tv_type vv_di.di_tv.v_type
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200172#define vv_nr vv_di.di_tv.vval.v_number
173#define vv_float vv_di.di_tv.vval.v_float
174#define vv_str vv_di.di_tv.vval.v_string
175#define vv_list vv_di.di_tv.vval.v_list
176#define vv_dict vv_di.di_tv.vval.v_dict
177#define vv_blob vv_di.di_tv.vval.v_blob
178#define vv_tv vv_di.di_tv
179
180static dictitem_T vimvars_var; // variable used for v:
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200181static dict_T vimvardict; // Dictionary with v: variables
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200182#define vimvarht vimvardict.dv_hashtab
183
184// for VIM_VERSION_ defines
185#include "version.h"
186
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200187static void list_glob_vars(int *first);
188static void list_buf_vars(int *first);
189static void list_win_vars(int *first);
190static void list_tab_vars(int *first);
191static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100192static 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 +0200193static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie);
194static 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 +0200195static void list_one_var(dictitem_T *v, char *prefix, int *first);
196static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
197
198/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200199 * Initialize global and vim special variables
200 */
201 void
202evalvars_init(void)
203{
204 int i;
205 struct vimvar *p;
206
207 init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
208 init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
209 vimvardict.dv_lock = VAR_FIXED;
210 hash_init(&compat_hashtab);
211
212 for (i = 0; i < VV_LEN; ++i)
213 {
214 p = &vimvars[i];
215 if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
216 {
Bram Moolenaar097c5372023-05-24 21:02:24 +0100217 iemsg("Name too long, increase size of dictitem16_T");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200218 getout(1);
219 }
220 STRCPY(p->vv_di.di_key, p->vv_name);
221 if (p->vv_flags & VV_RO)
222 p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
223 else if (p->vv_flags & VV_RO_SBX)
224 p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
225 else
226 p->vv_di.di_flags = DI_FLAGS_FIX;
227
228 // add to v: scope dict, unless the value is not always available
Bram Moolenaard787e402021-12-24 21:36:12 +0000229 if (p->vv_tv_type != VAR_UNKNOWN)
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000230 hash_add(&vimvarht, p->vv_di.di_key, "initialization");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200231 if (p->vv_flags & VV_COMPAT)
232 // add to compat scope dict
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000233 hash_add(&compat_hashtab, p->vv_di.di_key, "initialization");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200234 }
Bram Moolenaar016faaa2020-10-03 12:57:27 +0200235 set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
236 set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200237
238 set_vim_var_nr(VV_SEARCHFORWARD, 1L);
239 set_vim_var_nr(VV_HLSEARCH, 1L);
Bram Moolenaarf0068c52020-11-30 17:42:10 +0100240 set_vim_var_nr(VV_EXITING, VVAL_NULL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200241 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
242 set_vim_var_list(VV_ERRORS, list_alloc());
243 set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
244
245 set_vim_var_nr(VV_FALSE, VVAL_FALSE);
246 set_vim_var_nr(VV_TRUE, VVAL_TRUE);
247 set_vim_var_nr(VV_NONE, VVAL_NONE);
248 set_vim_var_nr(VV_NULL, VVAL_NULL);
Bram Moolenaar57d5a012021-01-21 21:42:31 +0100249 set_vim_var_nr(VV_NUMBERMAX, VARNUM_MAX);
250 set_vim_var_nr(VV_NUMBERMIN, VARNUM_MIN);
Bram Moolenaarf9706e92020-02-22 14:27:04 +0100251 set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
Bram Moolenaar69b30722021-11-02 21:39:49 +0000252 set_vim_var_nr(VV_SIZEOFINT, sizeof(int));
253 set_vim_var_nr(VV_SIZEOFLONG, sizeof(long));
254 set_vim_var_nr(VV_SIZEOFPOINTER, sizeof(char *));
naohiro ono56200ee2022-01-01 14:59:44 +0000255 set_vim_var_nr(VV_MAXCOL, MAXCOL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200256
257 set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
258 set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
259 set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
260 set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
261 set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
262 set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
263 set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
264 set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
265 set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
266 set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
267 set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
Bram Moolenaarc0c2c262023-01-12 21:08:53 +0000268 set_vim_var_nr(VV_TYPE_CLASS, VAR_TYPE_CLASS);
269 set_vim_var_nr(VV_TYPE_OBJECT, VAR_TYPE_OBJECT);
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +0200270 set_vim_var_nr(VV_TYPE_TYPEALIAS, VAR_TYPE_TYPEALIAS);
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100271 set_vim_var_nr(VV_TYPE_ENUM, VAR_TYPE_ENUM);
Yegappan Lakshmanan3164cf82024-03-28 10:36:42 +0100272 set_vim_var_nr(VV_TYPE_ENUMVALUE, VAR_TYPE_ENUMVALUE);
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100273 set_vim_var_nr(VV_TYPE_TUPLE, VAR_TYPE_TUPLE);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200274
275 set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
276
Drew Vogele30d1022021-10-24 20:35:07 +0100277 set_vim_var_dict(VV_COLORNAMES, dict_alloc());
278
Yee Cheng Chinc13b3d12023-08-20 21:18:38 +0200279#ifdef FEAT_PYTHON3
280 set_vim_var_nr(VV_PYTHON3_VERSION, python3_version());
281#endif
282
Bram Moolenaar439c0362020-06-06 15:58:03 +0200283 // Default for v:register is not 0 but '"'. This is adjusted once the
284 // clipboard has been setup by calling reset_reg_var().
285 set_reg_var(0);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200286}
287
288#if defined(EXITFREE) || defined(PROTO)
289/*
290 * Free all vim variables information on exit
291 */
292 void
293evalvars_clear(void)
294{
295 int i;
296 struct vimvar *p;
297
298 for (i = 0; i < VV_LEN; ++i)
299 {
300 p = &vimvars[i];
301 if (p->vv_di.di_tv.v_type == VAR_STRING)
302 VIM_CLEAR(p->vv_str);
303 else if (p->vv_di.di_tv.v_type == VAR_LIST)
304 {
305 list_unref(p->vv_list);
306 p->vv_list = NULL;
307 }
308 }
309 hash_clear(&vimvarht);
310 hash_init(&vimvarht); // garbage_collect() will access it
311 hash_clear(&compat_hashtab);
312
313 // global variables
314 vars_clear(&globvarht);
315
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100316 // Script-local variables. Clear all the variables here.
317 // The scriptvar_T is cleared later in free_scriptnames(), because a
318 // variable in one script might hold a reference to the whole scope of
319 // another script.
320 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200321 vars_clear(&SCRIPT_VARS(i));
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200322}
323#endif
324
325 int
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200326garbage_collect_globvars(int copyID)
327{
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100328 return set_ref_in_ht(&globvarht, copyID, NULL, NULL);
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200329}
330
331 int
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200332garbage_collect_vimvars(int copyID)
333{
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100334 return set_ref_in_ht(&vimvarht, copyID, NULL, NULL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200335}
336
337 int
338garbage_collect_scriptvars(int copyID)
339{
Bram Moolenaared234f22020-10-15 20:42:20 +0200340 int i;
341 int idx;
342 int abort = FALSE;
343 scriptitem_T *si;
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200344
Bram Moolenaar7ebcba62020-01-12 17:42:55 +0100345 for (i = 1; i <= script_items.ga_len; ++i)
Bram Moolenaared234f22020-10-15 20:42:20 +0200346 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100347 abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL, NULL);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200348
Bram Moolenaared234f22020-10-15 20:42:20 +0200349 si = SCRIPT_ITEM(i);
350 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
351 {
352 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
353
Bram Moolenaard00a7fb2021-03-08 20:47:14 +0100354 if (sv->sv_name != NULL)
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100355 abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL, NULL);
Bram Moolenaared234f22020-10-15 20:42:20 +0200356 }
357 }
358
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200359 return abort;
360}
361
362/*
363 * Set an internal variable to a string value. Creates the variable if it does
364 * not already exist.
365 */
366 void
367set_internal_string_var(char_u *name, char_u *value)
368{
369 char_u *val;
370 typval_T *tvp;
371
372 val = vim_strsave(value);
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000373 if (val == NULL)
374 return;
375
376 tvp = alloc_string_tv(val);
377 if (tvp == NULL)
378 return;
379
380 set_var(name, tvp, FALSE);
381 free_tv(tvp);
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200382}
383
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200384 int
385eval_charconvert(
386 char_u *enc_from,
387 char_u *enc_to,
388 char_u *fname_from,
389 char_u *fname_to)
390{
391 int err = FALSE;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000392 sctx_T saved_sctx = current_sctx;
393 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200394
395 set_vim_var_string(VV_CC_FROM, enc_from, -1);
396 set_vim_var_string(VV_CC_TO, enc_to, -1);
397 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
398 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000399 ctx = get_option_sctx("charconvert");
400 if (ctx != NULL)
401 current_sctx = *ctx;
402
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100403 if (eval_to_bool(p_ccv, &err, NULL, FALSE, TRUE))
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200404 err = TRUE;
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000405
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200406 set_vim_var_string(VV_CC_FROM, NULL, -1);
407 set_vim_var_string(VV_CC_TO, NULL, -1);
408 set_vim_var_string(VV_FNAME_IN, NULL, -1);
409 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaarf4e88f22022-01-23 14:17:28 +0000410 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200411
412 if (err)
413 return FAIL;
414 return OK;
415}
416
417# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
418 int
419eval_printexpr(char_u *fname, char_u *args)
420{
421 int err = FALSE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000422 sctx_T saved_sctx = current_sctx;
423 sctx_T *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200424
425 set_vim_var_string(VV_FNAME_IN, fname, -1);
426 set_vim_var_string(VV_CMDARG, args, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000427 ctx = get_option_sctx("printexpr");
428 if (ctx != NULL)
429 current_sctx = *ctx;
430
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100431 if (eval_to_bool(p_pexpr, &err, NULL, FALSE, TRUE))
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200432 err = TRUE;
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000433
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200434 set_vim_var_string(VV_FNAME_IN, NULL, -1);
435 set_vim_var_string(VV_CMDARG, NULL, -1);
Bram Moolenaar7ef4a2f2022-01-23 13:44:35 +0000436 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200437
438 if (err)
439 {
440 mch_remove(fname);
441 return FAIL;
442 }
443 return OK;
444}
445# endif
446
447# if defined(FEAT_DIFF) || defined(PROTO)
448 void
449eval_diff(
450 char_u *origfile,
451 char_u *newfile,
452 char_u *outfile)
453{
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000454 sctx_T saved_sctx = current_sctx;
455 sctx_T *ctx;
456 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200457
458 set_vim_var_string(VV_FNAME_IN, origfile, -1);
459 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
460 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000461
462 ctx = get_option_sctx("diffexpr");
463 if (ctx != NULL)
464 current_sctx = *ctx;
465
466 // errors are ignored
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100467 tv = eval_expr_ext(p_dex, NULL, TRUE);
Bram Moolenaar39b89442022-01-22 18:21:36 +0000468 free_tv(tv);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000469
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200470 set_vim_var_string(VV_FNAME_IN, NULL, -1);
471 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
472 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar7b29f6a2022-01-22 17:58:13 +0000473 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200474}
475
476 void
477eval_patch(
478 char_u *origfile,
479 char_u *difffile,
480 char_u *outfile)
481{
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000482 sctx_T saved_sctx = current_sctx;
483 sctx_T *ctx;
484 typval_T *tv;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200485
486 set_vim_var_string(VV_FNAME_IN, origfile, -1);
487 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
488 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000489
490 ctx = get_option_sctx("patchexpr");
491 if (ctx != NULL)
492 current_sctx = *ctx;
493
494 // errors are ignored
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100495 tv = eval_expr_ext(p_pex, NULL, TRUE);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000496 free_tv(tv);
497
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200498 set_vim_var_string(VV_FNAME_IN, NULL, -1);
499 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
500 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
Bram Moolenaar36c2add2022-01-22 20:55:30 +0000501 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200502}
503# endif
504
505#if defined(FEAT_SPELL) || defined(PROTO)
506/*
507 * Evaluate an expression to a list with suggestions.
508 * For the "expr:" part of 'spellsuggest'.
509 * Returns NULL when there is an error.
510 */
511 list_T *
512eval_spell_expr(char_u *badword, char_u *expr)
513{
514 typval_T save_val;
515 typval_T rettv;
516 list_T *list = NULL;
517 char_u *p = skipwhite(expr);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000518 sctx_T saved_sctx = current_sctx;
519 sctx_T *ctx;
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100520 int r;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200521
522 // Set "v:val" to the bad word.
523 prepare_vimvar(VV_VAL, &save_val);
524 set_vim_var_string(VV_VAL, badword, -1);
525 if (p_verbose == 0)
526 ++emsg_off;
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000527 ctx = get_option_sctx("spellsuggest");
528 if (ctx != NULL)
529 current_sctx = *ctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200530
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100531 r = may_call_simple_func(p, &rettv);
532 if (r == NOTDONE)
533 r = eval1(&p, &rettv, &EVALARG_EVALUATE);
534 if (r == OK)
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200535 {
536 if (rettv.v_type != VAR_LIST)
537 clear_tv(&rettv);
538 else
539 list = rettv.vval.v_list;
540 }
541
542 if (p_verbose == 0)
543 --emsg_off;
544 clear_tv(get_vim_var_tv(VV_VAL));
545 restore_vimvar(VV_VAL, &save_val);
Bram Moolenaar2a7aa832022-01-23 17:59:06 +0000546 current_sctx = saved_sctx;
Bram Moolenaarda6c0332019-09-01 16:01:30 +0200547
548 return list;
549}
550
551/*
552 * "list" is supposed to contain two items: a word and a number. Return the
553 * word in "pp" and the number as the return value.
554 * Return -1 if anything isn't right.
555 * Used to get the good word and score from the eval_spell_expr() result.
556 */
557 int
558get_spellword(list_T *list, char_u **pp)
559{
560 listitem_T *li;
561
562 li = list->lv_first;
563 if (li == NULL)
564 return -1;
565 *pp = tv_get_string(&li->li_tv);
566
567 li = li->li_next;
568 if (li == NULL)
569 return -1;
570 return (int)tv_get_number(&li->li_tv);
571}
572#endif
573
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200574/*
575 * Prepare v: variable "idx" to be used.
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200576 * Save the current typeval in "save_tv" and clear it.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200577 * When not used yet add the variable to the v: hashtable.
578 */
579 void
580prepare_vimvar(int idx, typval_T *save_tv)
581{
582 *save_tv = vimvars[idx].vv_tv;
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200583 vimvars[idx].vv_str = NULL; // don't free it now
Bram Moolenaard787e402021-12-24 21:36:12 +0000584 if (vimvars[idx].vv_tv_type == VAR_UNKNOWN)
Bram Moolenaaref2c3252022-11-25 16:31:51 +0000585 hash_add(&vimvarht, vimvars[idx].vv_di.di_key, "prepare vimvar");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200586}
587
588/*
589 * Restore v: variable "idx" to typeval "save_tv".
Bram Moolenaar27da7de2019-09-03 17:13:37 +0200590 * Note that the v: variable must have been cleared already.
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200591 * When no longer defined, remove the variable from the v: hashtable.
592 */
593 void
594restore_vimvar(int idx, typval_T *save_tv)
595{
596 hashitem_T *hi;
597
598 vimvars[idx].vv_tv = *save_tv;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000599 if (vimvars[idx].vv_tv_type != VAR_UNKNOWN)
600 return;
601
602 hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
603 if (HASHITEM_EMPTY(hi))
604 internal_error("restore_vimvar()");
605 else
606 hash_remove(&vimvarht, hi, "restore vimvar");
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200607}
608
609/*
610 * List Vim variables.
611 */
612 static void
613list_vim_vars(int *first)
614{
615 list_hashtable_vars(&vimvarht, "v:", FALSE, first);
616}
617
618/*
619 * List script-local variables, if there is a script.
620 */
621 static void
622list_script_vars(int *first)
623{
Bram Moolenaare3d46852020-08-29 13:39:17 +0200624 if (SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaare5cdf152019-08-29 22:09:46 +0200625 list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
626 "s:", FALSE, first);
627}
628
629/*
Bram Moolenaar9510d222022-09-11 15:14:05 +0100630 * Return TRUE if "name" starts with "g:", "w:", "t:" or "b:".
631 * But only when an identifier character follows.
632 */
633 int
634is_scoped_variable(char_u *name)
635{
636 return vim_strchr((char_u *)"gwbt", name[0]) != NULL
637 && name[1] == ':'
638 && eval_isnamec(name[2]);
639}
640
641/*
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100642 * Evaluate one Vim expression {expr} in string "p" and append the
643 * resulting string to "gap". "p" points to the opening "{".
Bram Moolenaar70c41242022-05-10 18:11:43 +0100644 * When "evaluate" is FALSE only skip over the expression.
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100645 * Return a pointer to the character after "}", NULL for an error.
646 */
647 char_u *
Bram Moolenaar70c41242022-05-10 18:11:43 +0100648eval_one_expr_in_str(char_u *p, garray_T *gap, int evaluate)
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100649{
650 char_u *block_start = skipwhite(p + 1); // skip the opening {
651 char_u *block_end = block_start;
652 char_u *expr_val;
653
654 if (*block_start == NUL)
655 {
656 semsg(_(e_missing_close_curly_str), p);
657 return NULL;
658 }
659 if (skip_expr(&block_end, NULL) == FAIL)
660 return NULL;
661 block_end = skipwhite(block_end);
662 if (*block_end != '}')
663 {
664 semsg(_(e_missing_close_curly_str), p);
665 return NULL;
666 }
Bram Moolenaar70c41242022-05-10 18:11:43 +0100667 if (evaluate)
668 {
669 *block_end = NUL;
Yegappan Lakshmananbce51d92024-04-15 19:19:52 +0200670 expr_val = eval_to_string(block_start, FALSE, FALSE);
Bram Moolenaar70c41242022-05-10 18:11:43 +0100671 *block_end = '}';
672 if (expr_val == NULL)
673 return NULL;
674 ga_concat(gap, expr_val);
675 vim_free(expr_val);
676 }
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100677
678 return block_end + 1;
679}
680
681/*
682 * Evaluate all the Vim expressions {expr} in "str" and return the resulting
683 * string in allocated memory. "{{" is reduced to "{" and "}}" to "}".
684 * Used for a heredoc assignment.
685 * Returns NULL for an error.
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100686 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +0100687 static char_u *
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100688eval_all_expr_in_str(char_u *str)
689{
690 garray_T ga;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100691 char_u *p;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100692
693 ga_init2(&ga, 1, 80);
694 p = str;
695
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100696 while (*p != NUL)
697 {
LemonBoy2eaef102022-05-06 13:14:50 +0100698 char_u *lit_start;
LemonBoy2eaef102022-05-06 13:14:50 +0100699 int escaped_brace = FALSE;
700
701 // Look for a block start.
702 lit_start = p;
703 while (*p != '{' && *p != '}' && *p != NUL)
704 ++p;
705
706 if (*p != NUL && *p == p[1])
707 {
708 // Escaped brace, unescape and continue.
709 // Include the brace in the literal string.
710 ++p;
711 escaped_brace = TRUE;
712 }
713 else if (*p == '}')
714 {
715 semsg(_(e_stray_closing_curly_str), str);
716 ga_clear(&ga);
717 return NULL;
718 }
719
720 // Append the literal part.
721 ga_concat_len(&ga, lit_start, (size_t)(p - lit_start));
722
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100723 if (*p == NUL)
LemonBoy2eaef102022-05-06 13:14:50 +0100724 break;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100725
LemonBoy2eaef102022-05-06 13:14:50 +0100726 if (escaped_brace)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100727 {
LemonBoy2eaef102022-05-06 13:14:50 +0100728 // Skip the second brace.
729 ++p;
730 continue;
731 }
732
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100733 // Evaluate the expression and append the result.
Bram Moolenaar70c41242022-05-10 18:11:43 +0100734 p = eval_one_expr_in_str(p, &ga, TRUE);
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100735 if (p == NULL)
LemonBoy2eaef102022-05-06 13:14:50 +0100736 {
737 ga_clear(&ga);
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100738 return NULL;
739 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100740 }
741 ga_append(&ga, NUL);
742
743 return ga.ga_data;
744}
745
746/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200747 * Get a list of lines from a HERE document. The here document is a list of
748 * lines surrounded by a marker.
749 * cmd << {marker}
750 * {line1}
751 * {line2}
752 * ....
753 * {marker}
754 *
755 * The {marker} is a string. If the optional 'trim' word is supplied before the
756 * marker, then the leading indentation before the lines (matching the
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100757 * indentation in the "cmd" line) is stripped.
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200758 *
759 * When getting lines for an embedded script (e.g. python, lua, perl, ruby,
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100760 * tcl, mzscheme), "script_get" is set to TRUE. In this case, if the marker is
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200761 * missing, then '.' is accepted as a marker.
762 *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100763 * When compiling a heredoc assignment to a variable in a Vim9 def function,
764 * "vim9compile" is set to TRUE. In this case, instead of generating a list of
765 * string values from the heredoc, vim9 instructions are generated. On success
766 * the returned list will be empty.
767 *
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100768 * Returns a List with {lines} or NULL on failure.
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200769 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100770 list_T *
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100771heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200772{
Bram Moolenaar42ccb8d2022-04-18 15:45:23 +0100773 char_u *theline = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200774 char_u *marker;
775 list_T *l;
776 char_u *p;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100777 char_u *str;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200778 int marker_indent_len = 0;
779 int text_indent_len = 0;
780 char_u *text_indent = NULL;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200781 char_u dot[] = ".";
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200782 int comment_char = in_vim9script() ? '#' : '"';
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100783 int evalstr = FALSE;
784 int eval_failed = FALSE;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100785 cctx_T *cctx = vim9compile ? eap->cookie : NULL;
786 int count = 0;
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200787 int heredoc_in_string = FALSE;
788 char_u *line_arg = NULL;
zeertzjq1f5175d2024-04-13 17:52:26 +0200789 char_u *nl_ptr = vim_strchr(cmd, '\n');
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200790
zeertzjq1f5175d2024-04-13 17:52:26 +0200791 if (nl_ptr != NULL)
792 {
793 heredoc_in_string = TRUE;
794 line_arg = nl_ptr + 1;
795 *nl_ptr = NUL;
796 }
797 else if (eap->ea_getline == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200798 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000799 emsg(_(e_cannot_use_heredoc_here));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200800 return NULL;
801 }
802
803 // Check for the optional 'trim' word before the marker
804 cmd = skipwhite(cmd);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200805
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100806 while (TRUE)
807 {
808 if (STRNCMP(cmd, "trim", 4) == 0
809 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200810 {
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100811 cmd = skipwhite(cmd + 4);
812
813 // Trim the indentation from all the lines in the here document.
814 // The amount of indentation trimmed is the same as the indentation
815 // of the first line after the :let command line. To find the end
816 // marker the indent of the :let command line is trimmed.
817 p = *eap->cmdlinep;
818 while (VIM_ISWHITE(*p))
819 {
820 p++;
821 marker_indent_len++;
822 }
823 text_indent_len = -1;
824
825 continue;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200826 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100827 if (STRNCMP(cmd, "eval", 4) == 0
828 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4])))
829 {
830 cmd = skipwhite(cmd + 4);
831 evalstr = TRUE;
832 continue;
833 }
834 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200835 }
836
837 // The marker is the next word.
Bram Moolenaarc0e29012020-09-27 14:22:48 +0200838 if (*cmd != NUL && *cmd != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200839 {
840 marker = skipwhite(cmd);
zeertzjq1f5175d2024-04-13 17:52:26 +0200841 p = skiptowhite(marker);
842 if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200843 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000844 semsg(_(e_trailing_characters_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200845 return NULL;
846 }
847 *p = NUL;
Bram Moolenaar6ab09532020-05-01 14:10:13 +0200848 if (!script_get && vim_islower(*marker))
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200849 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000850 emsg(_(e_marker_cannot_start_with_lower_case_letter));
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200851 return NULL;
852 }
853 }
854 else
855 {
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200856 // When getting lines for an embedded script, if the marker is missing,
857 // accept '.' as the marker.
858 if (script_get)
859 marker = dot;
860 else
861 {
Bram Moolenaar1a992222021-12-31 17:25:48 +0000862 emsg(_(e_missing_marker));
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +0200863 return NULL;
864 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200865 }
866
867 l = list_alloc();
868 if (l == NULL)
869 return NULL;
870
871 for (;;)
872 {
873 int mi = 0;
874 int ti = 0;
875
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200876 if (heredoc_in_string)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200877 {
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200878 char_u *next_line;
879
880 // heredoc in a string separated by newlines. Get the next line
881 // from the string.
882
883 if (*line_arg == NUL)
884 {
885 semsg(_(e_missing_end_marker_str), marker);
886 break;
887 }
888
889 theline = line_arg;
890 next_line = vim_strchr(theline, '\n');
891 if (next_line == NULL)
892 line_arg += STRLEN(line_arg);
893 else
894 {
895 *next_line = NUL;
896 line_arg = next_line + 1;
897 }
898 }
899 else
900 {
901 vim_free(theline);
902 theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
903 if (theline == NULL)
904 {
905 semsg(_(e_missing_end_marker_str), marker);
906 break;
907 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200908 }
909
910 // with "trim": skip the indent matching the :let line to find the
911 // marker
912 if (marker_indent_len > 0
913 && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0)
914 mi = marker_indent_len;
915 if (STRCMP(marker, theline + mi) == 0)
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200916 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200917
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100918 // If expression evaluation failed in the heredoc, then skip till the
919 // end marker.
920 if (eval_failed)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100921 continue;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100922
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200923 if (text_indent_len == -1 && *theline != NUL)
924 {
925 // set the text indent from the first line.
926 p = theline;
927 text_indent_len = 0;
928 while (VIM_ISWHITE(*p))
929 {
930 p++;
931 text_indent_len++;
932 }
933 text_indent = vim_strnsave(theline, text_indent_len);
934 }
935 // with "trim": skip the indent matching the first line
936 if (text_indent != NULL)
937 for (ti = 0; ti < text_indent_len; ++ti)
938 if (theline[ti] != text_indent[ti])
939 break;
940
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100941 str = theline + ti;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100942 if (vim9compile)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100943 {
LemonBoy2eaef102022-05-06 13:14:50 +0100944 if (compile_all_expr_in_str(str, evalstr, cctx) == FAIL)
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100945 {
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100946 vim_free(theline);
947 vim_free(text_indent);
948 return FAIL;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100949 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100950 count++;
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100951 }
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100952 else
953 {
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200954 int free_str = FALSE;
955
Bram Moolenaar05c7f5d2022-04-28 16:51:41 +0100956 if (evalstr && !eap->skip)
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100957 {
958 str = eval_all_expr_in_str(str);
959 if (str == NULL)
960 {
961 // expression evaluation failed
962 eval_failed = TRUE;
963 continue;
964 }
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200965 free_str = TRUE;
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100966 }
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100967
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100968 if (list_append_string(l, str, -1) == FAIL)
969 break;
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200970 if (free_str)
971 vim_free(str);
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100972 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200973 }
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200974 if (heredoc_in_string)
975 // Next command follows the heredoc in the string.
976 eap->nextcmd = line_arg;
977 else
978 vim_free(theline);
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200979 vim_free(text_indent);
980
Yegappan Lakshmanan1fc6ea92022-04-21 23:30:15 +0100981 if (vim9compile && cctx->ctx_skip != SKIP_YES && !eval_failed)
982 generate_NEWLIST(cctx, count, FALSE);
983
Yegappan Lakshmananefbfa862022-04-17 12:47:40 +0100984 if (eval_failed)
985 {
986 // expression evaluation in the heredoc failed
987 list_free(l);
988 return NULL;
989 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +0200990 return l;
991}
992
993/*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200994 * Vim9 variable declaration:
995 * ":var name"
996 * ":var name: type"
997 * ":var name = expr"
998 * ":var name: type = expr"
999 * etc.
1000 */
1001 void
1002ex_var(exarg_T *eap)
1003{
Bram Moolenaar330a3882022-03-05 11:05:57 +00001004 char_u *p = eap->cmd;
Bram Moolenaare1d12112022-03-05 11:37:48 +00001005 int has_var;
Bram Moolenaar330a3882022-03-05 11:05:57 +00001006
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001007 if (!in_vim9script())
1008 {
1009 semsg(_(e_str_cannot_be_used_in_legacy_vim_script), ":var");
1010 return;
1011 }
Bram Moolenaare1d12112022-03-05 11:37:48 +00001012 has_var = checkforcmd_noparen(&p, "var", 3);
1013 if (current_sctx.sc_sid == 0 && has_var)
Bram Moolenaar0e1574c2022-03-03 17:05:35 +00001014 {
1015 emsg(_(e_cannot_declare_variable_on_command_line));
1016 return;
1017 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001018 ex_let(eap);
1019}
1020
1021/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001022 * ":let" list all variable values
1023 * ":let var1 var2" list variable values
1024 * ":let var = expr" assignment command.
1025 * ":let var += expr" assignment command.
1026 * ":let var -= expr" assignment command.
1027 * ":let var *= expr" assignment command.
1028 * ":let var /= expr" assignment command.
1029 * ":let var %= expr" assignment command.
1030 * ":let var .= expr" assignment command.
1031 * ":let var ..= expr" assignment command.
1032 * ":let [var1, var2] = expr" unpack list.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001033 * ":let var =<< ..." heredoc
Bram Moolenaard672dde2020-02-26 13:43:51 +01001034 * ":let var: string" Vim9 declaration
Bram Moolenaar2eec3792020-05-25 20:33:55 +02001035 *
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001036 * ":final var = expr" assignment command.
1037 * ":final [var1, var2] = expr" unpack list.
1038 *
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001039 * ":const" list all variable values
1040 * ":const var1 var2" list variable values
1041 * ":const var = expr" assignment command.
1042 * ":const [var1, var2] = expr" unpack list.
1043 */
1044 void
Bram Moolenaar2eec3792020-05-25 20:33:55 +02001045ex_let(exarg_T *eap)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001046{
1047 char_u *arg = eap->arg;
1048 char_u *expr = NULL;
1049 typval_T rettv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001050 int var_count = 0;
1051 int semicolon = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001052 char_u op[4];
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001053 char_u *argend;
1054 int first = TRUE;
1055 int concat;
Bram Moolenaar32e35112020-05-14 22:41:15 +02001056 int has_assign;
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001057 int flags = 0;
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001058 int vim9script = in_vim9script();
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001059
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001060 if (eap->cmdidx == CMD_final && !vim9script)
1061 {
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001062 // In legacy Vim script ":final" is short for ":finally".
1063 ex_finally(eap);
1064 return;
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001065 }
Bram Moolenaarc58f5452020-10-21 20:58:52 +02001066 if (eap->cmdidx == CMD_let && vim9script)
Bram Moolenaarcfcd0112020-09-27 15:19:27 +02001067 {
1068 emsg(_(e_cannot_use_let_in_vim9_script));
1069 return;
1070 }
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001071
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001072 if (eap->cmdidx == CMD_const)
1073 flags |= ASSIGN_CONST;
1074 else if (eap->cmdidx == CMD_final)
1075 flags |= ASSIGN_FINAL;
1076
1077 // Vim9 assignment without ":let", ":const" or ":final"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001078 if (eap->arg == eap->cmd)
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001079 flags |= ASSIGN_NO_DECL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001080
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001081 argend = skip_var_list(arg, TRUE, &var_count, &semicolon, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001082 if (argend == NULL)
1083 return;
1084 if (argend > arg && argend[-1] == '.') // for var.='str'
1085 --argend;
1086 expr = skipwhite(argend);
1087 concat = expr[0] == '.'
Bram Moolenaardd9de502021-08-15 13:49:42 +02001088 && ((expr[1] == '=' && in_old_script(2))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001089 || (expr[1] == '.' && expr[2] == '='));
Bram Moolenaar32e35112020-05-14 22:41:15 +02001090 has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
1091 && expr[1] == '=');
Bram Moolenaar822ba242020-05-24 23:00:18 +02001092 if (!has_assign && !concat)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001093 {
1094 // ":let" without "=": list variables
1095 if (*arg == '[')
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001096 emsg(_(e_invalid_argument));
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001097 else if (expr[0] == '.' && expr[1] == '=')
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001098 emsg(_(e_dot_equal_not_supported_with_script_version_two));
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001099 else if (!ends_excmd2(eap->cmd, arg))
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001100 {
Bram Moolenaar63be3d42020-07-23 13:11:37 +02001101 if (vim9script)
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001102 {
Bram Moolenaarccc25aa2021-03-26 21:27:52 +01001103 if (!ends_excmd2(eap->cmd, skipwhite(argend)))
Bram Moolenaar74409f62022-01-01 15:58:22 +00001104 semsg(_(e_trailing_characters_str), argend);
Bram Moolenaarccc25aa2021-03-26 21:27:52 +01001105 else
1106 // Vim9 declaration ":var name: type"
1107 arg = vim9_declare_scriptvar(eap, arg);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +02001108 }
1109 else
1110 {
1111 // ":let var1 var2" - list values
1112 arg = list_arg_vars(eap, arg, &first);
1113 }
1114 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001115 else if (!eap->skip)
1116 {
1117 // ":let"
1118 list_glob_vars(&first);
1119 list_buf_vars(&first);
1120 list_win_vars(&first);
1121 list_tab_vars(&first);
1122 list_script_vars(&first);
1123 list_func_vars(&first);
1124 list_vim_vars(&first);
1125 }
Bram Moolenaar63b91732021-08-05 20:40:03 +02001126 set_nextcmd(eap, arg);
zeertzjq474891b2023-04-12 21:36:03 +01001127 return;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001128 }
zeertzjq474891b2023-04-12 21:36:03 +01001129
1130 if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001131 {
Bram Moolenaard9876422022-10-12 12:58:54 +01001132 list_T *l = NULL;
Bram Moolenaar81530e32021-07-28 21:25:49 +02001133 long cur_lnum = SOURCING_LNUM;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001134
Bram Moolenaard9876422022-10-12 12:58:54 +01001135 // :let text =<< [trim] [eval] END
1136 // :var text =<< [trim] [eval] END
1137 if (vim9script && !eap->skip && (!VIM_ISWHITE(expr[-1])
1138 || !IS_WHITE_OR_NUL(expr[3])))
1139 semsg(_(e_white_space_required_before_and_after_str_at_str),
1140 "=<<", expr);
1141 else
1142 l = heredoc_get(eap, expr + 3, FALSE, FALSE);
1143
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001144 if (l != NULL)
1145 {
1146 rettv_list_set(&rettv, l);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001147 if (!eap->skip)
1148 {
Bram Moolenaar81530e32021-07-28 21:25:49 +02001149 // errors are for the assignment, not the end marker
1150 SOURCING_LNUM = cur_lnum;
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001151 op[0] = '=';
1152 op[1] = NUL;
1153 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001154 flags, op);
Bram Moolenaarb1ba9ab2019-10-16 23:34:42 +02001155 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001156 clear_tv(&rettv);
1157 }
zeertzjq474891b2023-04-12 21:36:03 +01001158 return;
1159 }
1160
1161 evalarg_T evalarg;
1162 int len = 1;
1163
1164 CLEAR_FIELD(rettv);
1165
1166 int cur_lnum;
1167
1168 op[0] = '=';
1169 op[1] = NUL;
1170 if (*expr != '=')
1171 {
1172 if (vim9script && (flags & ASSIGN_NO_DECL) == 0)
1173 {
1174 // +=, /=, etc. require an existing variable
1175 semsg(_(e_cannot_use_operator_on_new_variable_str), eap->arg);
1176 }
1177 else if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
1178 {
1179 op[0] = *expr; // +=, -=, *=, /=, %= or .=
1180 ++len;
1181 if (expr[0] == '.' && expr[1] == '.') // ..=
1182 {
1183 ++expr;
1184 ++len;
1185 }
1186 }
1187 expr += 2;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001188 }
1189 else
zeertzjq474891b2023-04-12 21:36:03 +01001190 ++expr;
1191
1192 if (vim9script && !eap->skip && (!VIM_ISWHITE(*argend)
1193 || !IS_WHITE_OR_NUL(*expr)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001194 {
zeertzjq474891b2023-04-12 21:36:03 +01001195 vim_strncpy(op, expr - len, len);
1196 semsg(_(e_white_space_required_before_and_after_str_at_str),
1197 op, argend);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001198 }
zeertzjq474891b2023-04-12 21:36:03 +01001199
1200 if (eap->skip)
1201 ++emsg_skip;
1202 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
1203 expr = skipwhite_and_linebreak(expr, &evalarg);
1204 cur_lnum = SOURCING_LNUM;
1205 int eval_res = eval0(expr, &rettv, eap, &evalarg);
1206 if (eap->skip)
1207 --emsg_skip;
1208 clear_evalarg(&evalarg, eap);
1209
1210 // Restore the line number so that any type error is given for the
1211 // declaration, not the expression.
1212 SOURCING_LNUM = cur_lnum;
1213
1214 if (!eap->skip && eval_res != FAIL)
1215 (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
1216 flags, op);
1217 if (eval_res != FAIL)
1218 clear_tv(&rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001219}
1220
1221/*
Bram Moolenaar6c3843c2021-03-04 12:38:21 +01001222 * Assign the typeval "tv" to the variable or variables at "arg_start".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001223 * Handles both "var" with any type and "[var, var; var]" with a list type.
1224 * When "op" is not NULL it points to a string with characters that
1225 * must appear after the variable(s). Use "+", "-" or "." for add, subtract
1226 * or concatenate.
1227 * Returns OK or FAIL;
1228 */
1229 int
1230ex_let_vars(
1231 char_u *arg_start,
1232 typval_T *tv,
1233 int copy, // copy values from "tv", don't move
1234 int semicolon, // from skip_var_list()
1235 int var_count, // from skip_var_list()
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001236 int flags, // ASSIGN_FINAL, ASSIGN_CONST, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001237 char_u *op)
1238{
1239 char_u *arg = arg_start;
1240 list_T *l;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001241 tuple_T *tuple = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001242 int i;
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001243 int var_idx = 0;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001244 listitem_T *item = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001245 typval_T ltv;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001246 int is_list = tv->v_type == VAR_LIST;
1247 int idx;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001248
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001249 if (tv->v_type == VAR_VOID)
1250 {
1251 emsg(_(e_cannot_use_void_value));
1252 return FAIL;
1253 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001254 if (*arg != '[')
1255 {
1256 // ":let var = expr" or ":for var in list"
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001257 if (ex_let_one(arg, tv, copy, flags, op, op, var_idx) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001258 return FAIL;
1259 return OK;
1260 }
1261
1262 // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001263 // or
1264 // ":let [v1, v2] = tuple" or ":for [v1, v2] in tupletuple"
1265 if (tv->v_type != VAR_LIST && tv->v_type != VAR_TUPLE)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001266 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001267 emsg(_(e_list_or_tuple_required));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001268 return FAIL;
1269 }
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001270 if (is_list)
1271 {
1272 l = tv->vval.v_list;
1273 if (l == NULL)
1274 {
1275 emsg(_(e_list_required));
1276 return FAIL;
1277 }
1278 i = list_len(l);
1279 }
1280 else
1281 {
1282 tuple = tv->vval.v_tuple;
1283 if (tuple == NULL)
1284 {
1285 emsg(_(e_tuple_required));
1286 return FAIL;
1287 }
1288 i = tuple_len(tuple);
1289 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001290
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001291 if (semicolon == 0 && var_count < i)
1292 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001293 emsg(_(is_list ? e_less_targets_than_list_items
1294 : e_less_targets_than_tuple_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001295 return FAIL;
1296 }
1297 if (var_count - semicolon > i)
1298 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001299 emsg(_(is_list ? e_more_targets_than_list_items
1300 : e_more_targets_than_tuple_items));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001301 return FAIL;
1302 }
1303
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001304 if (is_list)
1305 {
1306 CHECK_LIST_MATERIALIZE(l);
1307 item = l->lv_first;
1308 }
1309 else
1310 idx = 0;
1311
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001312 while (*arg != ']')
1313 {
1314 arg = skipwhite(arg + 1);
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001315 ++var_idx;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001316 arg = ex_let_one(arg, is_list ? &item->li_tv : TUPLE_ITEM(tuple, idx),
1317 TRUE, flags | ASSIGN_UNPACK, (char_u *)",;]", op,
1318 var_idx);
1319 if (is_list)
1320 item = item->li_next;
1321 else
1322 idx++;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001323 if (arg == NULL)
1324 return FAIL;
1325
1326 arg = skipwhite(arg);
1327 if (*arg == ';')
1328 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001329 // Put the rest of the list or tuple (may be empty) in the var
1330 // after ';'. Create a new list or tuple for this.
1331 if (is_list)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001332 {
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001333 // Put the rest of the list (may be empty) in the var
1334 // after ';'. Create a new list for this.
1335 l = list_alloc();
1336 if (l == NULL)
1337 return FAIL;
1338
1339 // list
1340 while (item != NULL)
1341 {
1342 list_append_tv(l, &item->li_tv);
1343 item = item->li_next;
1344 }
1345
1346 ltv.v_type = VAR_LIST;
1347 ltv.v_lock = 0;
1348 ltv.vval.v_list = l;
1349 l->lv_refcount = 1;
1350 }
1351 else
1352 {
1353 tuple_T *new_tuple = tuple_alloc();
1354 if (new_tuple == NULL)
1355 return FAIL;
1356
1357 // Put the rest of the tuple (may be empty) in the var
1358 // after ';'. Create a new tuple for this.
1359 while (idx < TUPLE_LEN(tuple))
1360 {
1361 typval_T new_tv;
1362
1363 copy_tv(TUPLE_ITEM(tuple, idx), &new_tv);
1364 if (tuple_append_tv(new_tuple, &new_tv) == FAIL)
1365 return FAIL;
1366 idx++;
1367 }
1368
1369 ltv.v_type = VAR_TUPLE;
1370 ltv.v_lock = 0;
1371 ltv.vval.v_tuple = new_tuple;
1372 new_tuple->tv_refcount = 1;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001373 }
1374
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001375 ++var_idx;
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02001376 arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001377 flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001378 clear_tv(&ltv);
1379 if (arg == NULL)
1380 return FAIL;
1381 break;
1382 }
1383 else if (*arg != ',' && *arg != ']')
1384 {
1385 internal_error("ex_let_vars()");
1386 return FAIL;
1387 }
1388 }
1389
1390 return OK;
1391}
1392
1393/*
1394 * Skip over assignable variable "var" or list of variables "[var, var]".
1395 * Used for ":let varvar = expr" and ":for varvar in expr".
1396 * For "[var, var]" increment "*var_count" for each variable.
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001397 * for "[var, var; var]" set "semicolon" to 1.
1398 * If "silent" is TRUE do not give an "invalid argument" error message.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001399 * Return NULL for an error.
1400 */
1401 char_u *
1402skip_var_list(
1403 char_u *arg,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001404 int include_type,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001405 int *var_count,
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001406 int *semicolon,
1407 int silent)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001408{
1409 char_u *p, *s;
1410
1411 if (*arg == '[')
1412 {
1413 // "[var, var]": find the matching ']'.
1414 p = arg;
1415 for (;;)
1416 {
1417 p = skipwhite(p + 1); // skip whites after '[', ';' or ','
Bram Moolenaar036d0712021-01-17 20:23:38 +01001418 s = skip_var_one(p, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001419 if (s == p)
1420 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001421 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001422 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001423 return NULL;
1424 }
1425 ++*var_count;
1426
1427 p = skipwhite(s);
1428 if (*p == ']')
1429 break;
1430 else if (*p == ';')
1431 {
1432 if (*semicolon == 1)
1433 {
Bram Moolenaar8b716f52022-02-15 21:17:56 +00001434 if (!silent)
1435 emsg(_(e_double_semicolon_in_list_of_variables));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001436 return NULL;
1437 }
1438 *semicolon = 1;
1439 }
1440 else if (*p != ',')
1441 {
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001442 if (!silent)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001443 semsg(_(e_invalid_argument_str), p);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001444 return NULL;
1445 }
1446 }
1447 return p + 1;
1448 }
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01001449
Bram Moolenaare8e369a2022-09-21 18:59:14 +01001450 return skip_var_one(arg, include_type);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001451}
1452
1453/*
1454 * Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
1455 * l[idx].
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001456 * In Vim9 script also skip over ": type" if "include_type" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001457 */
Bram Moolenaar47a519a2020-06-14 23:05:10 +02001458 char_u *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001459skip_var_one(char_u *arg, int include_type)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001460{
Bram Moolenaar585587d2021-01-17 20:52:13 +01001461 char_u *end;
1462 int vim9 = in_vim9script();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001463
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001464 if (*arg == '@' && arg[1] != NUL)
1465 return arg + 2;
Bram Moolenaar1573e732022-11-16 20:33:21 +00001466
1467 // termcap option name may have non-alpha characters
1468 if (STRNCMP(arg, "&t_", 3) == 0 && arg[3] != NUL && arg[4] != NUL)
1469 return arg + 5;
1470
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001471 end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001472 NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
Bram Moolenaar036d0712021-01-17 20:23:38 +01001473
1474 // "a: type" is declaring variable "a" with a type, not "a:".
1475 // Same for "s: type".
Bram Moolenaar585587d2021-01-17 20:52:13 +01001476 if (vim9 && end == arg + 2 && end[-1] == ':')
Bram Moolenaar036d0712021-01-17 20:23:38 +01001477 --end;
1478
Bram Moolenaar585587d2021-01-17 20:52:13 +01001479 if (include_type && vim9)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001480 {
Bram Moolenaarce93d162023-01-30 21:12:34 +00001481 if (*skipwhite(end) == ':')
1482 end = skip_type(skipwhite(skipwhite(end) + 1), FALSE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001483 }
1484 return end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001485}
1486
1487/*
1488 * List variables for hashtab "ht" with prefix "prefix".
1489 * If "empty" is TRUE also list NULL strings as empty strings.
1490 */
1491 void
1492list_hashtable_vars(
1493 hashtab_T *ht,
1494 char *prefix,
1495 int empty,
1496 int *first)
1497{
1498 hashitem_T *hi;
1499 dictitem_T *di;
1500 int todo;
1501 char_u buf[IOSIZE];
1502
Bram Moolenaaref2c3252022-11-25 16:31:51 +00001503 int save_ht_flags = ht->ht_flags;
1504 ht->ht_flags |= HTFLAGS_FROZEN;
1505
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001506 todo = (int)ht->ht_used;
1507 for (hi = ht->ht_array; todo > 0 && !got_int; ++hi)
1508 {
1509 if (!HASHITEM_EMPTY(hi))
1510 {
1511 --todo;
1512 di = HI2DI(hi);
1513
1514 // apply :filter /pat/ to variable name
1515 vim_strncpy((char_u *)buf, (char_u *)prefix, IOSIZE - 1);
1516 vim_strcat((char_u *)buf, di->di_key, IOSIZE);
1517 if (message_filtered(buf))
1518 continue;
1519
1520 if (empty || di->di_tv.v_type != VAR_STRING
1521 || di->di_tv.vval.v_string != NULL)
1522 list_one_var(di, prefix, first);
1523 }
1524 }
Bram Moolenaaref2c3252022-11-25 16:31:51 +00001525
1526 ht->ht_flags = save_ht_flags;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001527}
1528
1529/*
1530 * List global variables.
1531 */
1532 static void
1533list_glob_vars(int *first)
1534{
1535 list_hashtable_vars(&globvarht, "", TRUE, first);
1536}
1537
1538/*
1539 * List buffer variables.
1540 */
1541 static void
1542list_buf_vars(int *first)
1543{
1544 list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", TRUE, first);
1545}
1546
1547/*
1548 * List window variables.
1549 */
1550 static void
1551list_win_vars(int *first)
1552{
1553 list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", TRUE, first);
1554}
1555
1556/*
1557 * List tab page variables.
1558 */
1559 static void
1560list_tab_vars(int *first)
1561{
1562 list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", TRUE, first);
1563}
1564
1565/*
1566 * List variables in "arg".
1567 */
1568 static char_u *
1569list_arg_vars(exarg_T *eap, char_u *arg, int *first)
1570{
1571 int error = FALSE;
1572 int len;
1573 char_u *name;
1574 char_u *name_start;
1575 char_u *arg_subsc;
1576 char_u *tofree;
1577 typval_T tv;
1578
Bram Moolenaarfaac4102020-04-20 17:46:14 +02001579 while (!ends_excmd2(eap->cmd, arg) && !got_int)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001580 {
1581 if (error || eap->skip)
1582 {
1583 arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
1584 if (!VIM_ISWHITE(*arg) && !ends_excmd(*arg))
1585 {
1586 emsg_severe = TRUE;
Bram Moolenaar4830c212021-08-14 14:59:27 +02001587 if (!did_emsg)
Bram Moolenaar74409f62022-01-01 15:58:22 +00001588 semsg(_(e_trailing_characters_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001589 break;
1590 }
1591 }
1592 else
1593 {
1594 // get_name_len() takes care of expanding curly braces
1595 name_start = name = arg;
1596 len = get_name_len(&arg, &tofree, TRUE, TRUE);
1597 if (len <= 0)
1598 {
1599 // This is mainly to keep test 49 working: when expanding
1600 // curly braces fails overrule the exception error message.
1601 if (len < 0 && !aborting())
1602 {
1603 emsg_severe = TRUE;
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001604 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001605 break;
1606 }
1607 error = TRUE;
1608 }
1609 else
1610 {
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02001611 arg = skipwhite(arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001612 if (tofree != NULL)
1613 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00001614 if (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01001615 EVAL_VAR_VERBOSE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001616 error = TRUE;
1617 else
1618 {
1619 // handle d.key, l[idx], f(expr)
1620 arg_subsc = arg;
Bram Moolenaar32884ad2022-01-07 12:45:29 +00001621 if (handle_subscript(&arg, name_start, &tv,
1622 &EVALARG_EVALUATE, TRUE) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001623 error = TRUE;
1624 else
1625 {
1626 if (arg == arg_subsc && len == 2 && name[1] == ':')
1627 {
1628 switch (*name)
1629 {
1630 case 'g': list_glob_vars(first); break;
1631 case 'b': list_buf_vars(first); break;
1632 case 'w': list_win_vars(first); break;
1633 case 't': list_tab_vars(first); break;
1634 case 'v': list_vim_vars(first); break;
1635 case 's': list_script_vars(first); break;
1636 case 'l': list_func_vars(first); break;
1637 default:
Bram Moolenaara6f79292022-01-04 21:30:47 +00001638 semsg(_(e_cant_list_variables_for_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001639 }
1640 }
1641 else
1642 {
1643 char_u numbuf[NUMBUFLEN];
1644 char_u *tf;
1645 int c;
1646 char_u *s;
1647
1648 s = echo_string(&tv, &tf, numbuf, 0);
1649 c = *arg;
1650 *arg = NUL;
1651 list_one_var_a("",
1652 arg == arg_subsc ? name : name_start,
1653 tv.v_type,
1654 s == NULL ? (char_u *)"" : s,
1655 first);
1656 *arg = c;
1657 vim_free(tf);
1658 }
1659 clear_tv(&tv);
1660 }
1661 }
1662 }
1663
1664 vim_free(tofree);
1665 }
1666
1667 arg = skipwhite(arg);
1668 }
1669
1670 return arg;
1671}
1672
1673/*
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001674 * Set an environment variable, part of ex_let_one().
1675 */
1676 static char_u *
1677ex_let_env(
1678 char_u *arg,
1679 typval_T *tv,
1680 int flags,
1681 char_u *endchars,
1682 char_u *op)
1683{
1684 char_u *arg_end = NULL;
1685 char_u *name;
1686 int len;
1687
1688 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1689 && (flags & ASSIGN_FOR_LOOP) == 0)
1690 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001691 emsg(_(e_cannot_lock_environment_variable));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001692 return NULL;
1693 }
1694
1695 // Find the end of the name.
1696 ++arg;
1697 name = arg;
1698 len = get_env_len(&arg);
1699 if (len == 0)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001700 semsg(_(e_invalid_argument_str), name - 1);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001701 else
1702 {
1703 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001704 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001705 else if (endchars != NULL
1706 && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1707 emsg(_(e_unexpected_characters_in_let));
1708 else if (!check_secure())
1709 {
1710 char_u *tofree = NULL;
1711 int c1 = name[len];
1712 char_u *p;
1713
1714 name[len] = NUL;
1715 p = tv_get_string_chk(tv);
1716 if (p != NULL && op != NULL && *op == '.')
1717 {
1718 int mustfree = FALSE;
1719 char_u *s = vim_getenv(name, &mustfree);
1720
1721 if (s != NULL)
1722 {
1723 p = tofree = concat_str(s, p);
1724 if (mustfree)
1725 vim_free(s);
1726 }
1727 }
1728 if (p != NULL)
1729 {
1730 vim_setenv_ext(name, p);
1731 arg_end = arg;
1732 }
1733 name[len] = c1;
1734 vim_free(tofree);
1735 }
1736 }
1737 return arg_end;
1738}
1739
1740/*
1741 * Set an option, part of ex_let_one().
1742 */
1743 static char_u *
1744ex_let_option(
1745 char_u *arg,
1746 typval_T *tv,
1747 int flags,
1748 char_u *endchars,
1749 char_u *op)
1750{
1751 char_u *p;
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001752 int scope;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001753 char_u *arg_end = NULL;
1754
1755 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1756 && (flags & ASSIGN_FOR_LOOP) == 0)
1757 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001758 emsg(_(e_cannot_lock_option));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001759 return NULL;
1760 }
1761
1762 // Find the end of the name.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00001763 p = find_option_end(&arg, &scope);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001764 if (p == NULL || (endchars != NULL
1765 && vim_strchr(endchars, *skipwhite(p)) == NULL))
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001766 {
zeertzjq4c7cb372023-06-14 16:39:54 +01001767 emsg(_(e_unexpected_characters_in_let));
1768 return NULL;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001769 }
zeertzjq4c7cb372023-06-14 16:39:54 +01001770
1771 int c1;
1772 long n = 0;
1773 getoption_T opt_type;
1774 long numval;
1775 char_u *stringval = NULL;
1776 char_u *s = NULL;
1777 int failed = FALSE;
1778 int opt_p_flags;
1779 char_u *tofree = NULL;
1780 char_u numbuf[NUMBUFLEN];
1781
1782 c1 = *p;
1783 *p = NUL;
1784
1785 opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, scope);
1786 if (opt_type == gov_unknown && arg[0] != 't' && arg[1] != '_')
1787 {
1788 semsg(_(e_unknown_option_str_2), arg);
1789 goto theend;
1790 }
1791 if (op != NULL && *op != '='
1792 && (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
1793 || (opt_type == gov_string && *op != '.')))
1794 {
1795 semsg(_(e_wrong_variable_type_for_str_equal), op);
1796 goto theend;
1797 }
1798
1799 if ((opt_type == gov_bool
1800 || opt_type == gov_number
1801 || opt_type == gov_hidden_bool
1802 || opt_type == gov_hidden_number)
1803 && (tv->v_type != VAR_STRING || !in_vim9script()))
1804 {
1805 if (opt_type == gov_bool || opt_type == gov_hidden_bool)
1806 // bool, possibly hidden
1807 n = (long)tv_get_bool_chk(tv, &failed);
1808 else
1809 // number, possibly hidden
1810 n = (long)tv_get_number_chk(tv, &failed);
1811 if (failed)
1812 goto theend;
1813 }
1814
1815 if ((opt_p_flags & P_FUNC) && (tv->v_type == VAR_PARTIAL
1816 || tv->v_type == VAR_FUNC))
1817 {
1818 // If the option can be set to a function reference or a lambda
1819 // and the passed value is a function reference, then convert it to
1820 // the name (string) of the function reference.
1821 s = tv2string(tv, &tofree, numbuf, 0);
1822 if (s == NULL)
1823 goto theend;
1824 }
1825 // Avoid setting a string option to the text "v:false" or similar.
1826 // In Vim9 script also don't convert a number to string.
1827 else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
1828 && (!in_vim9script() || tv->v_type != VAR_NUMBER))
1829 {
1830 s = tv_get_string_chk(tv);
1831 if (s == NULL)
1832 goto theend;
1833 }
1834 else if (opt_type == gov_string || opt_type == gov_hidden_string)
1835 {
1836 emsg(_(e_string_required));
1837 goto theend;
1838 }
1839
1840 if (op != NULL && *op != '=')
1841 {
1842 // number, in legacy script also bool
1843 if (opt_type == gov_number
1844 || (opt_type == gov_bool && !in_vim9script()))
1845 {
1846 switch (*op)
1847 {
1848 case '+': n = numval + n; break;
1849 case '-': n = numval - n; break;
1850 case '*': n = numval * n; break;
1851 case '/': n = (long)num_divide(numval, n, &failed); break;
1852 case '%': n = (long)num_modulus(numval, n, &failed); break;
1853 }
1854 s = NULL;
1855 if (failed)
1856 goto theend;
1857 }
1858 else if (opt_type == gov_string && stringval != NULL && s != NULL)
1859 {
1860 // string
1861 s = concat_str(stringval, s);
1862 vim_free(stringval);
1863 stringval = s;
1864 }
1865 }
1866
1867 char *err = set_option_value(arg, n, s, scope);
1868 arg_end = p;
1869 if (err != NULL)
1870 emsg(_(err));
1871
1872theend:
1873 *p = c1;
1874 vim_free(stringval);
1875 vim_free(tofree);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001876 return arg_end;
1877}
1878
1879/*
1880 * Set a register, part of ex_let_one().
1881 */
1882 static char_u *
1883ex_let_register(
1884 char_u *arg,
1885 typval_T *tv,
1886 int flags,
1887 char_u *endchars,
1888 char_u *op)
1889{
1890 char_u *arg_end = NULL;
1891
1892 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
1893 && (flags & ASSIGN_FOR_LOOP) == 0)
1894 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00001895 emsg(_(e_cannot_lock_register));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001896 return NULL;
1897 }
1898 ++arg;
1899 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00001900 semsg(_(e_wrong_variable_type_for_str_equal), op);
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001901 else if (endchars != NULL
1902 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1903 emsg(_(e_unexpected_characters_in_let));
1904 else
1905 {
1906 char_u *ptofree = NULL;
1907 char_u *p;
1908
1909 p = tv_get_string_chk(tv);
1910 if (p != NULL && op != NULL && *op == '.')
1911 {
1912 char_u *s = get_reg_contents(*arg == '@'
1913 ? '"' : *arg, GREG_EXPR_SRC);
1914
1915 if (s != NULL)
1916 {
1917 p = ptofree = concat_str(s, p);
1918 vim_free(s);
1919 }
1920 }
1921 if (p != NULL)
1922 {
1923 write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
1924 arg_end = arg + 1;
1925 }
1926 vim_free(ptofree);
1927 }
1928 return arg_end;
1929}
1930
1931/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001932 * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
1933 * Returns a pointer to the char just after the var name.
1934 * Returns NULL if there is an error.
1935 */
1936 static char_u *
1937ex_let_one(
1938 char_u *arg, // points to variable name
1939 typval_T *tv, // value to assign to variable
1940 int copy, // copy value from "tv"
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001941 int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001942 char_u *endchars, // valid chars after variable name or NULL
Bram Moolenaarf785aa12021-02-11 21:19:34 +01001943 char_u *op, // "+", "-", "." or NULL
1944 int var_idx) // variable index for "let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001945{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001946 char_u *arg_end = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001947
Bram Moolenaar3862ea32021-01-01 21:05:55 +01001948 if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01001949 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaarc2ee44c2020-08-02 16:59:00 +02001950 && vim_strchr((char_u *)"$@&", *arg) != NULL)
1951 {
1952 vim9_declare_error(arg);
1953 return NULL;
1954 }
1955
Ernie Rael9ed53752023-12-11 17:40:46 +01001956 if (check_typval_is_value(tv) == FAIL)
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02001957 return NULL;
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02001958
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001959 if (*arg == '$')
1960 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001961 // ":let $VAR = expr": Set environment variable.
1962 return ex_let_env(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001963 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001964 else if (*arg == '&')
1965 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001966 // ":let &option = expr": Set option value.
1967 // ":let &l:option = expr": Set local option value.
1968 // ":let &g:option = expr": Set global option value.
1969 // ":for &ts in range(8)": Set option value for for loop
1970 return ex_let_option(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001971 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001972 else if (*arg == '@')
1973 {
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001974 // ":let @r = expr": Set register contents.
1975 return ex_let_register(arg, tv, flags, endchars, op);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001976 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001977 else if (eval_isnamec1(*arg) || *arg == '{')
1978 {
1979 lval_T lv;
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001980 char_u *p;
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001981 int lval_flags = (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
1982 ? GLV_NO_DECL : 0;
Yegappan Lakshmananb5a07192023-10-05 20:14:43 +02001983 lval_flags |= (flags & ASSIGN_FOR_LOOP) ? GLV_FOR_LOOP : 0;
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001984 if (op != NULL && *op != '=')
1985 lval_flags |= GLV_ASSIGN_WITH_OP;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001986
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001987 // ":let var = expr": Set internal variable.
1988 // ":let var: type = expr": Set internal variable with type.
1989 // ":let {expr} = expr": Idem, name made with curly braces
Bram Moolenaar22ebd172022-04-01 15:26:58 +01001990 p = get_lval(arg, tv, &lv, FALSE, FALSE, lval_flags, FNE_CHECK_START);
Bram Moolenaar822ba242020-05-24 23:00:18 +02001991 if (p != NULL && lv.ll_name != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001992 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001993 if (endchars != NULL && vim_strchr(endchars,
1994 *skipwhite(lv.ll_name_end)) == NULL)
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001995 {
Bram Moolenaar108010a2021-06-27 22:03:33 +02001996 emsg(_(e_unexpected_characters_in_let));
Bram Moolenaar3ccb5792021-11-28 19:53:42 +00001997 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02001998 else
1999 {
Bram Moolenaarf785aa12021-02-11 21:19:34 +01002000 set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
Bram Moolenaara3589a02021-04-14 13:30:46 +02002001 arg_end = lv.ll_name_end;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002002 }
2003 }
2004 clear_lval(&lv);
2005 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002006 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00002007 semsg(_(e_invalid_argument_str), arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002008
2009 return arg_end;
2010}
2011
2012/*
2013 * ":unlet[!] var1 ... " command.
2014 */
2015 void
2016ex_unlet(exarg_T *eap)
2017{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002018 ex_unletlock(eap, eap->arg, 0, 0, do_unlet_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002019}
2020
2021/*
2022 * ":lockvar" and ":unlockvar" commands
2023 */
2024 void
2025ex_lockvar(exarg_T *eap)
2026{
2027 char_u *arg = eap->arg;
2028 int deep = 2;
2029
2030 if (eap->forceit)
2031 deep = -1;
2032 else if (vim_isdigit(*arg))
2033 {
2034 deep = getdigits(&arg);
2035 arg = skipwhite(arg);
2036 }
2037
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002038 ex_unletlock(eap, arg, deep, 0, do_lock_var, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002039}
2040
2041/*
2042 * ":unlet", ":lockvar" and ":unlockvar" are quite similar.
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002043 * Also used for Vim9 script. "callback" is invoked as:
2044 * callback(&lv, name_end, eap, deep, cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002045 */
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002046 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002047ex_unletlock(
2048 exarg_T *eap,
2049 char_u *argstart,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002050 int deep,
2051 int glv_flags,
2052 int (*callback)(lval_T *, char_u *, exarg_T *, int, void *),
2053 void *cookie)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002054{
2055 char_u *arg = argstart;
2056 char_u *name_end;
2057 int error = FALSE;
2058 lval_T lv;
2059
2060 do
2061 {
2062 if (*arg == '$')
2063 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002064 lv.ll_name = arg;
2065 lv.ll_tv = NULL;
2066 ++arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002067 if (get_env_len(&arg) == 0)
2068 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00002069 semsg(_(e_invalid_argument_str), arg - 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002070 return;
2071 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002072 if (!error && !eap->skip
2073 && callback(&lv, arg, eap, deep, cookie) == FAIL)
2074 error = TRUE;
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002075 name_end = arg;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002076 }
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002077 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002078 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002079 // Parse the name and find the end.
2080 name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error,
Bram Moolenaarc3689572021-01-01 19:40:02 +01002081 glv_flags | GLV_NO_DECL, FNE_CHECK_START);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002082 if (lv.ll_name == NULL)
2083 error = TRUE; // error but continue parsing
2084 if (name_end == NULL || (!VIM_ISWHITE(*name_end)
2085 && !ends_excmd(*name_end)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002086 {
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002087 if (name_end != NULL)
2088 {
2089 emsg_severe = TRUE;
Bram Moolenaar74409f62022-01-01 15:58:22 +00002090 semsg(_(e_trailing_characters_str), name_end);
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002091 }
2092 if (!(eap->skip || error))
2093 clear_lval(&lv);
2094 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002095 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002096
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002097 if (!error && !eap->skip
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002098 && callback(&lv, name_end, eap, deep, cookie) == FAIL)
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002099 error = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002100
Bram Moolenaar2bb76ac2020-04-19 22:57:44 +02002101 if (!eap->skip)
2102 clear_lval(&lv);
2103 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002104
2105 arg = skipwhite(name_end);
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002106 } while (!ends_excmd2(name_end, arg));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002107
Bram Moolenaar63b91732021-08-05 20:40:03 +02002108 set_nextcmd(eap, arg);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002109}
2110
2111 static int
2112do_unlet_var(
2113 lval_T *lp,
2114 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002115 exarg_T *eap,
2116 int deep UNUSED,
2117 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002118{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002119 int forceit = eap->forceit;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002120 int ret = OK;
2121 int cc;
2122
2123 if (lp->ll_tv == NULL)
2124 {
2125 cc = *name_end;
2126 *name_end = NUL;
2127
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002128 // Environment variable, normal name or expanded name.
2129 if (*lp->ll_name == '$')
LemonBoy77142312022-04-15 20:50:46 +01002130 vim_unsetenv_ext(lp->ll_name + 1);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002131 else if (do_unlet(lp->ll_name, forceit) == FAIL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002132 ret = FAIL;
2133 *name_end = cc;
2134 }
2135 else if ((lp->ll_list != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02002136 && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002137 || (lp->ll_dict != NULL
Bram Moolenaara187c432020-09-16 21:08:28 +02002138 && value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE)))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002139 return FAIL;
2140 else if (lp->ll_range)
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002141 list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_n1,
2142 !lp->ll_empty2, lp->ll_n2);
2143 else if (lp->ll_list != NULL)
2144 // unlet a List item.
2145 listitem_remove(lp->ll_list, lp->ll_li);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002146 else
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002147 // unlet a Dictionary item.
Bram Moolenaaref2c3252022-11-25 16:31:51 +00002148 dictitem_remove(lp->ll_dict, lp->ll_di, "unlet");
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002149
2150 return ret;
2151}
2152
2153/*
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002154 * Unlet one item or a range of items from a list.
2155 * Return OK or FAIL.
2156 */
Bram Moolenaar6b8c7ba2022-03-20 17:46:06 +00002157 void
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002158list_unlet_range(
2159 list_T *l,
2160 listitem_T *li_first,
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002161 long n1_arg,
2162 int has_n2,
2163 long n2)
2164{
2165 listitem_T *li = li_first;
2166 int n1 = n1_arg;
2167
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002168 // Delete a range of List items.
2169 li = li_first;
2170 n1 = n1_arg;
2171 while (li != NULL && (!has_n2 || n2 >= n1))
2172 {
2173 listitem_T *next = li->li_next;
2174
2175 listitem_remove(l, li);
2176 li = next;
2177 ++n1;
2178 }
Bram Moolenaar5b5ae292021-02-20 17:04:02 +01002179}
2180/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002181 * "unlet" a variable. Return OK if it existed, FAIL if not.
2182 * When "forceit" is TRUE don't complain if the variable doesn't exist.
2183 */
2184 int
2185do_unlet(char_u *name, int forceit)
2186{
2187 hashtab_T *ht;
2188 hashitem_T *hi;
mityu8be36ee2022-05-25 17:29:46 +01002189 char_u *varname = NULL; // init to shut up gcc
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002190 dict_T *d;
2191 dictitem_T *di;
2192
Bram Moolenaar9aed7292020-12-18 15:38:00 +01002193 // can't :unlet a script variable in Vim9 script
Bram Moolenaareb6880b2020-07-12 17:07:05 +02002194 if (in_vim9script() && check_vim9_unlet(name) == FAIL)
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002195 return FAIL;
2196
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002197 ht = find_var_ht(name, &varname);
Bram Moolenaar9aed7292020-12-18 15:38:00 +01002198
2199 // can't :unlet a script variable in Vim9 script from a function
2200 if (ht == get_script_local_ht()
2201 && SCRIPT_ID_VALID(current_sctx.sc_sid)
2202 && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
2203 == SCRIPT_VERSION_VIM9
2204 && check_vim9_unlet(name) == FAIL)
2205 return FAIL;
2206
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002207 if (ht != NULL && *varname != NUL)
2208 {
2209 d = get_current_funccal_dict(ht);
2210 if (d == NULL)
2211 {
2212 if (ht == &globvarht)
2213 d = &globvardict;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002214 else if (ht == &compat_hashtab)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002215 d = &vimvardict;
2216 else
2217 {
2218 di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
2219 d = di == NULL ? NULL : di->di_tv.vval.v_dict;
2220 }
2221 if (d == NULL)
2222 {
2223 internal_error("do_unlet()");
2224 return FAIL;
2225 }
2226 }
2227 hi = hash_find(ht, varname);
2228 if (HASHITEM_EMPTY(hi))
2229 hi = find_hi_in_scoped_ht(name, &ht);
2230 if (hi != NULL && !HASHITEM_EMPTY(hi))
2231 {
2232 di = HI2DI(hi);
2233 if (var_check_fixed(di->di_flags, name, FALSE)
2234 || var_check_ro(di->di_flags, name, FALSE)
Bram Moolenaaref2c3252022-11-25 16:31:51 +00002235 || value_check_lock(d->dv_lock, name, FALSE)
2236 || check_hashtab_frozen(ht, "unlet"))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002237 return FAIL;
2238
2239 delete_var(ht, hi);
2240 return OK;
2241 }
2242 }
2243 if (forceit)
2244 return OK;
Bram Moolenaare1242042021-12-16 20:56:57 +00002245 semsg(_(e_no_such_variable_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002246 return FAIL;
2247}
2248
Ernie Raelee865f32023-09-29 19:53:55 +02002249 static void
2250report_lockvar_member(char *msg, lval_T *lp)
2251{
2252 int did_alloc = FALSE;
2253 char_u *vname = (char_u *)"";
2254 char_u *class_name = lp->ll_class != NULL
2255 ? lp->ll_class->class_name : (char_u *)"";
2256 if (lp->ll_name != NULL)
2257 {
2258 if (lp->ll_name_end == NULL)
2259 vname = lp->ll_name;
2260 else
2261 {
2262 vname = vim_strnsave(lp->ll_name, lp->ll_name_end - lp->ll_name);
2263 if (vname == NULL)
2264 return;
2265 did_alloc = TRUE;
2266 }
2267 }
2268 semsg(_(msg), vname, class_name);
2269 if (did_alloc)
2270 vim_free(vname);
2271}
2272
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002273/*
2274 * Lock or unlock variable indicated by "lp".
2275 * "deep" is the levels to go (-1 for unlimited);
2276 * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
2277 */
2278 static int
2279do_lock_var(
2280 lval_T *lp,
2281 char_u *name_end,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002282 exarg_T *eap,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002283 int deep,
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002284 void *cookie UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002285{
Bram Moolenaard72c1bf2020-04-19 16:28:59 +02002286 int lock = eap->cmdidx == CMD_lockvar;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002287 int ret = OK;
2288 int cc;
2289 dictitem_T *di;
2290
Ernie Raelee865f32023-09-29 19:53:55 +02002291#ifdef LOG_LOCKVAR
2292 ch_log(NULL, "LKVAR: do_lock_var(): name %s, is_root %d", lp->ll_name, lp->ll_is_root);
2293#endif
2294
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002295 if (lp->ll_tv == NULL)
2296 {
2297 cc = *name_end;
2298 *name_end = NUL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002299 if (*lp->ll_name == '$')
2300 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00002301 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002302 ret = FAIL;
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002303 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002304 else
2305 {
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002306 // Normal name or expanded name.
2307 di = find_var(lp->ll_name, NULL, TRUE);
2308 if (di == NULL)
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002309 {
2310 if (in_vim9script())
2311 semsg(_(e_cannot_find_variable_to_unlock_str),
2312 lp->ll_name);
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002313 ret = FAIL;
Bram Moolenaar04b568b2021-11-22 21:58:41 +00002314 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002315 else
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002316 {
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002317 if ((di->di_flags & DI_FLAGS_FIX)
2318 && di->di_tv.v_type != VAR_DICT
2319 && di->di_tv.v_type != VAR_LIST)
2320 {
2321 // For historic reasons this error is not given for a list
2322 // or dict. E.g., the b: dict could be locked/unlocked.
2323 semsg(_(e_cannot_lock_or_unlock_variable_str), lp->ll_name);
2324 ret = FAIL;
2325 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002326 else
Bram Moolenaar7a411a32022-04-04 14:58:06 +01002327 {
2328 if (in_vim9script())
2329 {
2330 svar_T *sv = find_typval_in_script(&di->di_tv,
2331 0, FALSE);
2332
2333 if (sv != NULL && sv->sv_const != 0)
2334 {
2335 semsg(_(e_cannot_change_readonly_variable_str),
2336 lp->ll_name);
2337 ret = FAIL;
2338 }
2339 }
2340
2341 if (ret == OK)
2342 {
2343 if (lock)
2344 di->di_flags |= DI_FLAGS_LOCK;
2345 else
2346 di->di_flags &= ~DI_FLAGS_LOCK;
2347 if (deep != 0)
2348 item_lock(&di->di_tv, deep, lock, FALSE);
2349 }
2350 }
Bram Moolenaar7e0868e2020-04-19 17:24:53 +02002351 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002352 }
2353 *name_end = cc;
2354 }
Ernie Raelee865f32023-09-29 19:53:55 +02002355 else if (deep == 0 && lp->ll_object == NULL && lp->ll_class == NULL)
Bram Moolenaara187c432020-09-16 21:08:28 +02002356 {
2357 // nothing to do
2358 }
Ernie Raelee865f32023-09-29 19:53:55 +02002359 else if (lp->ll_is_root)
2360 // (un)lock the item.
2361 item_lock(lp->ll_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002362 else if (lp->ll_range)
2363 {
2364 listitem_T *li = lp->ll_li;
2365
2366 // (un)lock a range of List items.
2367 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1))
2368 {
Bram Moolenaar021bda52020-08-17 21:07:22 +02002369 item_lock(&li->li_tv, deep, lock, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002370 li = li->li_next;
2371 ++lp->ll_n1;
2372 }
2373 }
2374 else if (lp->ll_list != NULL)
2375 // (un)lock a List item.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002376 item_lock(&lp->ll_li->li_tv, deep, lock, FALSE);
Ernie Raelee865f32023-09-29 19:53:55 +02002377 else if (lp->ll_object != NULL) // This check must be before ll_class.
2378 {
2379 // (un)lock an object variable.
2380 report_lockvar_member(e_cannot_lock_object_variable_str, lp);
2381 ret = FAIL;
2382 }
2383 else if (lp->ll_class != NULL)
2384 {
2385 // (un)lock a class variable.
2386 report_lockvar_member(e_cannot_lock_class_variable_str, lp);
2387 ret = FAIL;
2388 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002389 else
Ernie Raelee865f32023-09-29 19:53:55 +02002390 {
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002391 // (un)lock a Dictionary item.
Ernie Raelee865f32023-09-29 19:53:55 +02002392 if (lp->ll_di == NULL)
2393 {
2394 emsg(_(e_dictionary_required));
2395 ret = FAIL;
2396 }
2397 else
2398 item_lock(&lp->ll_di->di_tv, deep, lock, FALSE);
2399 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002400
2401 return ret;
2402}
2403
2404/*
2405 * Lock or unlock an item. "deep" is nr of levels to go.
Bram Moolenaar021bda52020-08-17 21:07:22 +02002406 * When "check_refcount" is TRUE do not lock a list or dict with a reference
2407 * count larger than 1.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002408 */
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002409 void
Bram Moolenaar021bda52020-08-17 21:07:22 +02002410item_lock(typval_T *tv, int deep, int lock, int check_refcount)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002411{
2412 static int recurse = 0;
2413 list_T *l;
2414 listitem_T *li;
2415 dict_T *d;
2416 blob_T *b;
2417 hashitem_T *hi;
2418 int todo;
2419
Ernie Raelee865f32023-09-29 19:53:55 +02002420#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +02002421 ch_log(NULL, "LKVAR: item_lock(): type %s", vartype_name(tv->v_type));
Ernie Raelee865f32023-09-29 19:53:55 +02002422#endif
2423
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002424 if (recurse >= DICT_MAXNEST)
2425 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002426 emsg(_(e_variable_nested_too_deep_for_unlock));
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002427 return;
2428 }
2429 if (deep == 0)
2430 return;
2431 ++recurse;
2432
2433 // lock/unlock the item itself
2434 if (lock)
2435 tv->v_lock |= VAR_LOCKED;
2436 else
2437 tv->v_lock &= ~VAR_LOCKED;
2438
2439 switch (tv->v_type)
2440 {
2441 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002442 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002443 case VAR_VOID:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002444 case VAR_NUMBER:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002445 case VAR_BOOL:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002446 case VAR_STRING:
2447 case VAR_FUNC:
2448 case VAR_PARTIAL:
2449 case VAR_FLOAT:
2450 case VAR_SPECIAL:
2451 case VAR_JOB:
2452 case VAR_CHANNEL:
Bram Moolenaarf18332f2021-05-07 17:55:55 +02002453 case VAR_INSTR:
Bram Moolenaar00b28d62022-12-08 15:32:33 +00002454 case VAR_CLASS:
2455 case VAR_OBJECT:
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02002456 case VAR_TYPEALIAS:
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002457 break;
2458
2459 case VAR_BLOB:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002460 if ((b = tv->vval.v_blob) != NULL
2461 && !(check_refcount && b->bv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002462 {
2463 if (lock)
2464 b->bv_lock |= VAR_LOCKED;
2465 else
2466 b->bv_lock &= ~VAR_LOCKED;
2467 }
2468 break;
2469 case VAR_LIST:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002470 if ((l = tv->vval.v_list) != NULL
2471 && !(check_refcount && l->lv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002472 {
2473 if (lock)
2474 l->lv_lock |= VAR_LOCKED;
2475 else
2476 l->lv_lock &= ~VAR_LOCKED;
Bram Moolenaar70c43d82022-01-26 21:01:15 +00002477 if (deep < 0 || deep > 1)
2478 {
2479 if (l->lv_first == &range_list_item)
2480 l->lv_lock |= VAR_ITEMS_LOCKED;
2481 else
2482 {
2483 // recursive: lock/unlock the items the List contains
2484 CHECK_LIST_MATERIALIZE(l);
2485 FOR_ALL_LIST_ITEMS(l, li) item_lock(&li->li_tv,
2486 deep - 1, lock, check_refcount);
2487 }
2488 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002489 }
2490 break;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01002491 case VAR_TUPLE:
2492 tuple_lock(tv->vval.v_tuple, deep, lock, check_refcount);
2493 break;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002494 case VAR_DICT:
Bram Moolenaar021bda52020-08-17 21:07:22 +02002495 if ((d = tv->vval.v_dict) != NULL
2496 && !(check_refcount && d->dv_refcount > 1))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002497 {
2498 if (lock)
2499 d->dv_lock |= VAR_LOCKED;
2500 else
2501 d->dv_lock &= ~VAR_LOCKED;
2502 if (deep < 0 || deep > 1)
2503 {
2504 // recursive: lock/unlock the items the List contains
2505 todo = (int)d->dv_hashtab.ht_used;
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +00002506 FOR_ALL_HASHTAB_ITEMS(&d->dv_hashtab, hi, todo)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002507 {
2508 if (!HASHITEM_EMPTY(hi))
2509 {
2510 --todo;
Bram Moolenaar021bda52020-08-17 21:07:22 +02002511 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock,
2512 check_refcount);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002513 }
2514 }
2515 }
2516 }
2517 }
2518 --recurse;
2519}
2520
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002521#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
2522/*
2523 * Delete all "menutrans_" variables.
2524 */
2525 void
2526del_menutrans_vars(void)
2527{
2528 hashitem_T *hi;
2529 int todo;
2530
2531 hash_lock(&globvarht);
2532 todo = (int)globvarht.ht_used;
2533 for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
2534 {
2535 if (!HASHITEM_EMPTY(hi))
2536 {
2537 --todo;
2538 if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
2539 delete_var(&globvarht, hi);
2540 }
2541 }
2542 hash_unlock(&globvarht);
2543}
2544#endif
2545
Bram Moolenaar0522ba02019-08-27 22:48:30 +02002546/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002547 * Local string buffer for the next two functions to store a variable name
2548 * with its prefix. Allocated in cat_prefix_varname(), freed later in
2549 * get_user_var_name().
2550 */
2551
2552static char_u *varnamebuf = NULL;
2553static int varnamebuflen = 0;
2554
2555/*
2556 * Function to concatenate a prefix and a variable name.
2557 */
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01002558 char_u *
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002559cat_prefix_varname(int prefix, char_u *name)
2560{
2561 int len;
2562
2563 len = (int)STRLEN(name) + 3;
2564 if (len > varnamebuflen)
2565 {
2566 vim_free(varnamebuf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002567 len += 10; // some additional space
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002568 varnamebuf = alloc(len);
2569 if (varnamebuf == NULL)
2570 {
2571 varnamebuflen = 0;
2572 return NULL;
2573 }
2574 varnamebuflen = len;
2575 }
2576 *varnamebuf = prefix;
2577 varnamebuf[1] = ':';
2578 STRCPY(varnamebuf + 2, name);
2579 return varnamebuf;
2580}
2581
2582/*
2583 * Function given to ExpandGeneric() to obtain the list of user defined
2584 * (global/buffer/window/built-in) variable names.
2585 */
2586 char_u *
2587get_user_var_name(expand_T *xp, int idx)
2588{
2589 static long_u gdone;
2590 static long_u bdone;
2591 static long_u wdone;
2592 static long_u tdone;
2593 static int vidx;
2594 static hashitem_T *hi;
2595 hashtab_T *ht;
2596
2597 if (idx == 0)
2598 {
2599 gdone = bdone = wdone = vidx = 0;
2600 tdone = 0;
2601 }
2602
2603 // Global variables
2604 if (gdone < globvarht.ht_used)
2605 {
2606 if (gdone++ == 0)
2607 hi = globvarht.ht_array;
2608 else
2609 ++hi;
2610 while (HASHITEM_EMPTY(hi))
2611 ++hi;
2612 if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
2613 return cat_prefix_varname('g', hi->hi_key);
2614 return hi->hi_key;
2615 }
2616
2617 // b: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002618 ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002619 if (bdone < ht->ht_used)
2620 {
2621 if (bdone++ == 0)
2622 hi = ht->ht_array;
2623 else
2624 ++hi;
2625 while (HASHITEM_EMPTY(hi))
2626 ++hi;
2627 return cat_prefix_varname('b', hi->hi_key);
2628 }
2629
2630 // w: variables
Bram Moolenaar0f6e28f2022-02-20 20:49:35 +00002631 ht = &prevwin_curwin()->w_vars->dv_hashtab;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002632 if (wdone < ht->ht_used)
2633 {
2634 if (wdone++ == 0)
2635 hi = ht->ht_array;
2636 else
2637 ++hi;
2638 while (HASHITEM_EMPTY(hi))
2639 ++hi;
2640 return cat_prefix_varname('w', hi->hi_key);
2641 }
2642
2643 // t: variables
2644 ht = &curtab->tp_vars->dv_hashtab;
2645 if (tdone < ht->ht_used)
2646 {
2647 if (tdone++ == 0)
2648 hi = ht->ht_array;
2649 else
2650 ++hi;
2651 while (HASHITEM_EMPTY(hi))
2652 ++hi;
2653 return cat_prefix_varname('t', hi->hi_key);
2654 }
2655
2656 // v: variables
2657 if (vidx < VV_LEN)
2658 return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
2659
2660 VIM_CLEAR(varnamebuf);
2661 varnamebuflen = 0;
2662 return NULL;
2663}
2664
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002665 char *
2666get_var_special_name(int nr)
2667{
2668 switch (nr)
2669 {
Bram Moolenaara8b8af12021-01-01 15:11:04 +01002670 case VVAL_FALSE: return in_vim9script() ? "false" : "v:false";
2671 case VVAL_TRUE: return in_vim9script() ? "true" : "v:true";
Bram Moolenaar67977822021-01-03 21:53:53 +01002672 case VVAL_NULL: return in_vim9script() ? "null" : "v:null";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002673 case VVAL_NONE: return "v:none";
Bram Moolenaarda6c0332019-09-01 16:01:30 +02002674 }
2675 internal_error("get_var_special_name()");
2676 return "42";
2677}
2678
2679/*
2680 * Returns the global variable dictionary
2681 */
2682 dict_T *
2683get_globvar_dict(void)
2684{
2685 return &globvardict;
2686}
2687
2688/*
2689 * Returns the global variable hash table
2690 */
2691 hashtab_T *
2692get_globvar_ht(void)
2693{
2694 return &globvarht;
2695}
2696
2697/*
2698 * Returns the v: variable dictionary
2699 */
2700 dict_T *
2701get_vimvar_dict(void)
2702{
2703 return &vimvardict;
2704}
2705
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002706/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002707 * Returns the index of a v:variable. Negative if not found.
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002708 * Returns DI_ flags in "di_flags".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002709 */
2710 int
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002711find_vim_var(char_u *name, int *di_flags)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002712{
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002713 dictitem_T *di = find_var_in_ht(&vimvarht, 0, name, TRUE);
2714 struct vimvar *vv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002715
2716 if (di == NULL)
2717 return -1;
Bram Moolenaar5da356e2020-04-09 19:34:43 +02002718 *di_flags = di->di_flags;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002719 vv = (struct vimvar *)((char *)di - offsetof(vimvar_T, vv_di));
2720 return (int)(vv - vimvars);
2721}
2722
2723
2724/*
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002725 * Set type of v: variable to "type".
2726 */
2727 void
2728set_vim_var_type(int idx, vartype_T type)
2729{
Bram Moolenaard787e402021-12-24 21:36:12 +00002730 vimvars[idx].vv_tv_type = type;
Bram Moolenaar34ed68d2019-08-29 22:48:24 +02002731}
2732
2733/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002734 * Set number v: variable to "val".
Bram Moolenaar8d71b542019-08-30 15:46:30 +02002735 * Note that this does not set the type, use set_vim_var_type() for that.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002736 */
2737 void
2738set_vim_var_nr(int idx, varnumber_T val)
2739{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002740 vimvars[idx].vv_nr = val;
2741}
2742
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002743 char *
2744get_vim_var_name(int idx)
2745{
2746 return vimvars[idx].vv_name;
2747}
2748
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002749/*
2750 * Get typval_T v: variable value.
2751 */
2752 typval_T *
2753get_vim_var_tv(int idx)
2754{
2755 return &vimvars[idx].vv_tv;
2756}
2757
Bram Moolenaard787e402021-12-24 21:36:12 +00002758 type_T *
2759get_vim_var_type(int idx, garray_T *type_list)
2760{
2761 if (vimvars[idx].vv_type != NULL)
2762 return vimvars[idx].vv_type;
2763 return typval2type_vimvar(&vimvars[idx].vv_tv, type_list);
2764}
2765
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002766/*
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002767 * Set v: variable to "tv". Only accepts the same type.
2768 * Takes over the value of "tv".
2769 */
2770 int
2771set_vim_var_tv(int idx, typval_T *tv)
2772{
Bram Moolenaard787e402021-12-24 21:36:12 +00002773 if (vimvars[idx].vv_tv_type != tv->v_type)
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002774 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +02002775 emsg(_(e_type_mismatch_for_v_variable));
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002776 clear_tv(tv);
2777 return FAIL;
2778 }
Bram Moolenaarcab27672020-04-09 20:10:55 +02002779 // VV_RO is also checked when compiling, but let's check here as well.
2780 if (vimvars[idx].vv_flags & VV_RO)
2781 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02002782 semsg(_(e_cannot_change_readonly_variable_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002783 return FAIL;
2784 }
2785 if (sandbox && (vimvars[idx].vv_flags & VV_RO_SBX))
2786 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00002787 semsg(_(e_cannot_set_variable_in_sandbox_str), vimvars[idx].vv_name);
Bram Moolenaarcab27672020-04-09 20:10:55 +02002788 return FAIL;
2789 }
Bram Moolenaarb283a8a2020-02-02 22:24:04 +01002790 clear_tv(&vimvars[idx].vv_di.di_tv);
2791 vimvars[idx].vv_di.di_tv = *tv;
2792 return OK;
2793}
2794
2795/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002796 * Get number v: variable value.
2797 */
2798 varnumber_T
2799get_vim_var_nr(int idx)
2800{
2801 return vimvars[idx].vv_nr;
2802}
2803
2804/*
2805 * Get string v: variable value. Uses a static buffer, can only be used once.
2806 * If the String variable has never been set, return an empty string.
2807 * Never returns NULL;
2808 */
2809 char_u *
2810get_vim_var_str(int idx)
2811{
2812 return tv_get_string(&vimvars[idx].vv_tv);
2813}
2814
2815/*
2816 * Get List v: variable value. Caller must take care of reference count when
2817 * needed.
2818 */
2819 list_T *
2820get_vim_var_list(int idx)
2821{
2822 return vimvars[idx].vv_list;
2823}
2824
2825/*
2826 * Get Dict v: variable value. Caller must take care of reference count when
2827 * needed.
2828 */
2829 dict_T *
2830get_vim_var_dict(int idx)
2831{
2832 return vimvars[idx].vv_dict;
2833}
2834
2835/*
2836 * Set v:char to character "c".
2837 */
2838 void
2839set_vim_var_char(int c)
2840{
2841 char_u buf[MB_MAXBYTES + 1];
2842
2843 if (has_mbyte)
2844 buf[(*mb_char2bytes)(c, buf)] = NUL;
2845 else
2846 {
2847 buf[0] = c;
2848 buf[1] = NUL;
2849 }
2850 set_vim_var_string(VV_CHAR, buf, -1);
2851}
2852
2853/*
2854 * Set v:count to "count" and v:count1 to "count1".
2855 * When "set_prevcount" is TRUE first set v:prevcount from v:count.
2856 */
2857 void
2858set_vcount(
2859 long count,
2860 long count1,
2861 int set_prevcount)
2862{
2863 if (set_prevcount)
2864 vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
2865 vimvars[VV_COUNT].vv_nr = count;
2866 vimvars[VV_COUNT1].vv_nr = count1;
2867}
2868
2869/*
2870 * Save variables that might be changed as a side effect. Used when executing
2871 * a timer callback.
2872 */
2873 void
2874save_vimvars(vimvars_save_T *vvsave)
2875{
2876 vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
2877 vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
2878 vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
2879}
2880
2881/*
2882 * Restore variables saved by save_vimvars().
2883 */
2884 void
2885restore_vimvars(vimvars_save_T *vvsave)
2886{
2887 vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
2888 vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
2889 vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
2890}
2891
2892/*
2893 * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
2894 * value.
2895 */
2896 void
2897set_vim_var_string(
2898 int idx,
2899 char_u *val,
2900 int len) // length of "val" to use or -1 (whole string)
2901{
2902 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002903 vimvars[idx].vv_tv_type = VAR_STRING;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002904 if (val == NULL)
2905 vimvars[idx].vv_str = NULL;
2906 else if (len == -1)
2907 vimvars[idx].vv_str = vim_strsave(val);
2908 else
2909 vimvars[idx].vv_str = vim_strnsave(val, len);
2910}
2911
2912/*
2913 * Set List v: variable to "val".
2914 */
2915 void
2916set_vim_var_list(int idx, list_T *val)
2917{
2918 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002919 vimvars[idx].vv_tv_type = VAR_LIST;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002920 vimvars[idx].vv_list = val;
2921 if (val != NULL)
2922 ++val->lv_refcount;
2923}
2924
2925/*
2926 * Set Dictionary v: variable to "val".
2927 */
2928 void
2929set_vim_var_dict(int idx, dict_T *val)
2930{
2931 clear_tv(&vimvars[idx].vv_di.di_tv);
Bram Moolenaard787e402021-12-24 21:36:12 +00002932 vimvars[idx].vv_tv_type = VAR_DICT;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002933 vimvars[idx].vv_dict = val;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00002934 if (val == NULL)
2935 return;
2936
2937 ++val->dv_refcount;
2938 dict_set_items_ro(val);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002939}
2940
2941/*
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002942 * Set the v:argv list.
2943 */
2944 void
2945set_argv_var(char **argv, int argc)
2946{
2947 list_T *l = list_alloc();
2948 int i;
2949
2950 if (l == NULL)
2951 getout(1);
2952 l->lv_lock = VAR_FIXED;
2953 for (i = 0; i < argc; ++i)
2954 {
2955 if (list_append_string(l, (char_u *)argv[i], -1) == FAIL)
2956 getout(1);
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01002957 l->lv_u.mat.lv_last->li_tv.v_lock = VAR_FIXED;
Bram Moolenaar69bf6342019-10-29 04:16:57 +01002958 }
2959 set_vim_var_list(VV_ARGV, l);
2960}
2961
2962/*
Bram Moolenaar439c0362020-06-06 15:58:03 +02002963 * Reset v:register, taking the 'clipboard' setting into account.
2964 */
2965 void
2966reset_reg_var(void)
2967{
2968 int regname = 0;
2969
2970 // Adjust the register according to 'clipboard', so that when
2971 // "unnamed" is present it becomes '*' or '+' instead of '"'.
2972#ifdef FEAT_CLIPBOARD
2973 adjust_clip_reg(&regname);
2974#endif
2975 set_reg_var(regname);
2976}
2977
2978/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02002979 * Set v:register if needed.
2980 */
2981 void
2982set_reg_var(int c)
2983{
2984 char_u regname;
2985
2986 if (c == 0 || c == ' ')
2987 regname = '"';
2988 else
2989 regname = c;
2990 // Avoid free/alloc when the value is already right.
2991 if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
2992 set_vim_var_string(VV_REG, &regname, 1);
2993}
2994
2995/*
2996 * Get or set v:exception. If "oldval" == NULL, return the current value.
2997 * Otherwise, restore the value to "oldval" and return NULL.
2998 * Must always be called in pairs to save and restore v:exception! Does not
2999 * take care of memory allocations.
3000 */
3001 char_u *
3002v_exception(char_u *oldval)
3003{
3004 if (oldval == NULL)
3005 return vimvars[VV_EXCEPTION].vv_str;
3006
3007 vimvars[VV_EXCEPTION].vv_str = oldval;
3008 return NULL;
3009}
3010
3011/*
3012 * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
3013 * Otherwise, restore the value to "oldval" and return NULL.
3014 * Must always be called in pairs to save and restore v:throwpoint! Does not
3015 * take care of memory allocations.
3016 */
3017 char_u *
3018v_throwpoint(char_u *oldval)
3019{
3020 if (oldval == NULL)
3021 return vimvars[VV_THROWPOINT].vv_str;
3022
3023 vimvars[VV_THROWPOINT].vv_str = oldval;
3024 return NULL;
3025}
3026
3027/*
3028 * Set v:cmdarg.
3029 * If "eap" != NULL, use "eap" to generate the value and return the old value.
3030 * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
3031 * Must always be called in pairs!
3032 */
3033 char_u *
3034set_cmdarg(exarg_T *eap, char_u *oldarg)
3035{
3036 char_u *oldval;
3037 char_u *newval;
3038 unsigned len;
3039
3040 oldval = vimvars[VV_CMDARG].vv_str;
3041 if (eap == NULL)
3042 {
3043 vim_free(oldval);
3044 vimvars[VV_CMDARG].vv_str = oldarg;
3045 return NULL;
3046 }
3047
3048 if (eap->force_bin == FORCE_BIN)
3049 len = 6;
3050 else if (eap->force_bin == FORCE_NOBIN)
3051 len = 8;
3052 else
3053 len = 0;
3054
3055 if (eap->read_edit)
3056 len += 7;
3057
3058 if (eap->force_ff != 0)
3059 len += 10; // " ++ff=unix"
3060 if (eap->force_enc != 0)
3061 len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
3062 if (eap->bad_char != 0)
3063 len += 7 + 4; // " ++bad=" + "keep" or "drop"
3064
3065 newval = alloc(len + 1);
3066 if (newval == NULL)
3067 return NULL;
3068
3069 if (eap->force_bin == FORCE_BIN)
3070 sprintf((char *)newval, " ++bin");
3071 else if (eap->force_bin == FORCE_NOBIN)
3072 sprintf((char *)newval, " ++nobin");
3073 else
3074 *newval = NUL;
3075
3076 if (eap->read_edit)
3077 STRCAT(newval, " ++edit");
3078
3079 if (eap->force_ff != 0)
3080 sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
3081 eap->force_ff == 'u' ? "unix"
3082 : eap->force_ff == 'd' ? "dos"
3083 : "mac");
3084 if (eap->force_enc != 0)
3085 sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
3086 eap->cmd + eap->force_enc);
3087 if (eap->bad_char == BAD_KEEP)
3088 STRCPY(newval + STRLEN(newval), " ++bad=keep");
3089 else if (eap->bad_char == BAD_DROP)
3090 STRCPY(newval + STRLEN(newval), " ++bad=drop");
3091 else if (eap->bad_char != 0)
3092 sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
3093 vimvars[VV_CMDARG].vv_str = newval;
3094 return oldval;
3095}
3096
3097/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003098 * Get the value of internal variable "name".
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003099 * If "flags" has EVAL_VAR_IMPORT may return a VAR_ANY with v_number set to the
3100 * imported script ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003101 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
3102 */
3103 int
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02003104eval_variable(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003105 char_u *name,
Bram Moolenaar94674f22023-01-06 18:42:20 +00003106 int len, // length of "name" or zero
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003107 scid_T sid, // script ID for imported item or zero
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003108 typval_T *rettv, // NULL when only checking existence
3109 dictitem_T **dip, // non-NULL when typval's dict item is needed
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003110 int flags) // EVAL_VAR_ flags
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003111{
3112 int ret = OK;
3113 typval_T *tv = NULL;
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003114 int found = FALSE;
Bram Moolenaarf055d452021-07-08 20:57:24 +02003115 hashtab_T *ht = NULL;
Bram Moolenaar94674f22023-01-06 18:42:20 +00003116 int cc = 0;
Bram Moolenaarc967d572021-07-08 21:38:50 +02003117 type_T *type = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003118
Bram Moolenaar94674f22023-01-06 18:42:20 +00003119 if (len > 0)
3120 {
3121 // truncate the name, so that we can use strcmp()
3122 cc = name[len];
3123 name[len] = NUL;
3124 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003125
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003126 // Check for local variable when debugging.
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003127 if ((sid == 0) && (tv = lookup_debug_var(name)) == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003128 {
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003129 // Check for user-defined variables.
Bram Moolenaarc967d572021-07-08 21:38:50 +02003130 dictitem_T *v = find_var(name, &ht, flags & EVAL_VAR_NOAUTOLOAD);
3131
Bram Moolenaar1b0a9dd2021-06-14 21:32:21 +02003132 if (v != NULL)
3133 {
3134 tv = &v->di_tv;
3135 if (dip != NULL)
3136 *dip = v;
3137 }
Bram Moolenaarc967d572021-07-08 21:38:50 +02003138 else
3139 ht = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003140 }
3141
Bram Moolenaareb6880b2020-07-12 17:07:05 +02003142 if (tv == NULL && (in_vim9script() || STRNCMP(name, "s:", 2) == 0))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003143 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003144 imported_T *import = NULL;
Bram Moolenaar9721fb42020-06-11 23:10:46 +02003145 char_u *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
3146
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003147 if (sid == 0)
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003148 import = find_imported(p, 0, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003149
3150 // imported variable from another script
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003151 if (import != NULL || sid != 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003152 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003153 if ((flags & EVAL_VAR_IMPORT) == 0)
Bram Moolenaarc620c052020-07-08 15:16:19 +02003154 {
Bram Moolenaar71f21932022-01-07 18:20:55 +00003155 if (SCRIPT_ID_VALID(sid))
Bram Moolenaarc620c052020-07-08 15:16:19 +02003156 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003157 ht = &SCRIPT_VARS(sid);
3158 if (ht != NULL)
3159 {
3160 dictitem_T *v = find_var_in_ht(ht, 0, name,
3161 flags & EVAL_VAR_NOAUTOLOAD);
3162
Yegappan Lakshmanane9ae35f2025-02-27 19:12:00 +01003163 if (v == NULL)
3164 v = find_var_autoload_prefix(name, sid, NULL, NULL);
3165
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003166 if (v != NULL)
3167 {
3168 tv = &v->di_tv;
3169 if (dip != NULL)
3170 *dip = v;
3171 }
3172 else
3173 ht = NULL;
3174 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003175 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003176 else
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003177 {
3178 if (flags & EVAL_VAR_VERBOSE)
Bram Moolenaardd5893b2022-01-20 21:32:54 +00003179 semsg(_(e_expected_dot_after_name_str), name);
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003180 ret = FAIL;
3181 }
Bram Moolenaarf6a44f72020-09-27 13:51:14 +02003182 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003183 else
3184 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003185 if (rettv != NULL)
3186 {
Bram Moolenaar753885b2022-08-24 16:30:36 +01003187 // special value that is used in handle_subscript()
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003188 rettv->v_type = VAR_ANY;
3189 rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
3190 }
3191 found = TRUE;
Bram Moolenaarc620c052020-07-08 15:16:19 +02003192 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003193 }
Bram Moolenaar052ff292021-12-11 13:54:46 +00003194 else if (in_vim9script() && (flags & EVAL_VAR_NO_FUNC) == 0)
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003195 {
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003196 int has_g_prefix = STRNCMP(name, "g:", 2) == 0;
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003197 ufunc_T *ufunc = find_func(name, FALSE);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003198
Bram Moolenaarb033ee22021-08-15 16:08:36 +02003199 // In Vim9 script we can get a function reference by using the
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003200 // function name. For a global non-autoload function "g:" is
3201 // required.
3202 if (ufunc != NULL && (has_g_prefix
3203 || !func_requires_g_prefix(ufunc)))
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003204 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003205 found = TRUE;
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003206 if (rettv != NULL)
3207 {
3208 rettv->v_type = VAR_FUNC;
Bram Moolenaar848fadd2022-01-30 15:28:30 +00003209 if (has_g_prefix)
Bram Moolenaaref082e12021-12-12 21:02:03 +00003210 // Keep the "g:", otherwise script-local may be
3211 // assumed.
3212 rettv->vval.v_string = vim_strsave(name);
3213 else
John Marriottb32800f2025-02-01 15:25:34 +01003214 rettv->vval.v_string = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
Bram Moolenaarb033ee22021-08-15 16:08:36 +02003215 if (rettv->vval.v_string != NULL)
3216 func_ref(ufunc->uf_name);
Bram Moolenaar601e76a2020-08-27 21:33:10 +02003217 }
3218 }
3219 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003220 }
3221
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003222 if (!found)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003223 {
Bram Moolenaarc620c052020-07-08 15:16:19 +02003224 if (tv == NULL)
3225 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01003226 if (rettv != NULL && (flags & EVAL_VAR_VERBOSE))
Bram Moolenaar451c2e32020-08-15 16:33:28 +02003227 semsg(_(e_undefined_variable_str), name);
Bram Moolenaarc620c052020-07-08 15:16:19 +02003228 ret = FAIL;
3229 }
3230 else if (rettv != NULL)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003231 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003232 svar_T *sv = NULL;
3233 int was_assigned = FALSE;
3234
Bram Moolenaar11005b02021-07-11 20:59:00 +02003235 if (ht != NULL && ht == get_script_local_ht()
3236 && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
Bram Moolenaarf055d452021-07-08 20:57:24 +02003237 {
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003238 sv = find_typval_in_script(tv, 0, TRUE);
Bram Moolenaarf055d452021-07-08 20:57:24 +02003239 if (sv != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003240 {
Bram Moolenaarf055d452021-07-08 20:57:24 +02003241 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003242 was_assigned = sv->sv_flags & SVFLAG_ASSIGNED;
3243 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003244 }
3245
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003246 if ((tv->v_type == VAR_TYPEALIAS || tv->v_type == VAR_CLASS)
3247 && sid != 0)
3248 {
3249 // type alias or class imported from another script. Check
3250 // whether it is exported from the other script.
3251 sv = find_typval_in_script(tv, sid, TRUE);
3252 if (sv == NULL)
3253 {
3254 ret = FAIL;
3255 goto done;
3256 }
3257 if ((sv->sv_flags & SVFLAG_EXPORTED) == 0)
3258 {
3259 semsg(_(e_item_not_exported_in_script_str), name);
3260 ret = FAIL;
3261 goto done;
3262 }
3263 }
3264
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01003265 // If a list or tuple or dict variable wasn't initialized and has
3266 // meaningful type, do it now. Not for global variables, they are
3267 // not declared.
Bram Moolenaar7a222242022-03-01 19:23:24 +00003268 if (ht != &globvarht)
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003269 {
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01003270 if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003271 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01003272 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02003273 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00003274 tv->vval.v_dict = dict_alloc();
3275 if (tv->vval.v_dict != NULL)
3276 {
3277 ++tv->vval.v_dict->dv_refcount;
3278 tv->vval.v_dict->dv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003279 if (sv != NULL)
3280 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00003281 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003282 }
Bram Moolenaarec15b1c2022-03-27 16:29:53 +01003283 else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003284 && ((type != NULL && !was_assigned)
Bram Moolenaar501f9782022-03-27 16:51:04 +01003285 || !in_vim9script()))
Bram Moolenaarf055d452021-07-08 20:57:24 +02003286 {
Bram Moolenaar7a222242022-03-01 19:23:24 +00003287 tv->vval.v_list = list_alloc();
3288 if (tv->vval.v_list != NULL)
3289 {
3290 ++tv->vval.v_list->lv_refcount;
3291 tv->vval.v_list->lv_type = alloc_type(type);
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003292 if (sv != NULL)
3293 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar7a222242022-03-01 19:23:24 +00003294 }
Bram Moolenaarf055d452021-07-08 20:57:24 +02003295 }
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01003296 else if (tv->v_type == VAR_TUPLE && tv->vval.v_tuple == NULL
3297 && ((type != NULL && !was_assigned)
3298 || !in_vim9script()))
3299 {
3300 tv->vval.v_tuple = tuple_alloc();
3301 if (tv->vval.v_tuple != NULL)
3302 {
3303 ++tv->vval.v_tuple->tv_refcount;
3304 tv->vval.v_tuple->tv_type = alloc_type(type);
3305 if (sv != NULL)
3306 sv->sv_flags |= SVFLAG_ASSIGNED;
3307 }
3308 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003309 else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003310 && ((type != NULL && !was_assigned)
Bram Moolenaar859cc212022-03-28 15:22:35 +01003311 || !in_vim9script()))
3312 {
3313 tv->vval.v_blob = blob_alloc();
3314 if (tv->vval.v_blob != NULL)
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003315 {
Bram Moolenaar859cc212022-03-28 15:22:35 +01003316 ++tv->vval.v_blob->bv_refcount;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01003317 if (sv != NULL)
3318 sv->sv_flags |= SVFLAG_ASSIGNED;
3319 }
Bram Moolenaar859cc212022-03-28 15:22:35 +01003320 }
Bram Moolenaarb7c21af2021-04-18 14:12:31 +02003321 }
Bram Moolenaarc620c052020-07-08 15:16:19 +02003322 copy_tv(tv, rettv);
Bram Moolenaar348be7e2020-11-04 11:36:35 +01003323 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003324 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003325
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02003326done:
Bram Moolenaar94674f22023-01-06 18:42:20 +00003327 if (len > 0)
3328 name[len] = cc;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003329
3330 return ret;
3331}
3332
3333/*
Bram Moolenaara86655a2023-01-12 17:06:27 +00003334 * Get the value of internal variable "name", also handling "import.name".
3335 * Return OK or FAIL. If OK is returned "rettv" must be cleared.
3336 */
3337 int
3338eval_variable_import(
3339 char_u *name,
3340 typval_T *rettv)
3341{
3342 char_u *s = name;
3343 while (ASCII_ISALNUM(*s) || *s == '_')
3344 ++s;
3345 int len = (int)(s - name);
3346
3347 if (eval_variable(name, len, 0, rettv, NULL, EVAL_VAR_IMPORT) == FAIL)
3348 return FAIL;
3349 if (rettv->v_type == VAR_ANY && *s == '.')
3350 {
Bram Moolenaar40594002023-01-12 20:04:51 +00003351 char_u *ns = s + 1;
3352 s = ns;
3353 while (ASCII_ISALNUM(*s) || *s == '_')
3354 ++s;
Bram Moolenaara86655a2023-01-12 17:06:27 +00003355 int sid = rettv->vval.v_number;
Bram Moolenaar40594002023-01-12 20:04:51 +00003356 return eval_variable(ns, (int)(s - ns), sid, rettv, NULL, 0);
Bram Moolenaara86655a2023-01-12 17:06:27 +00003357 }
3358 return OK;
3359}
3360
3361
3362/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003363 * Check if variable "name[len]" is a local variable or an argument.
3364 * If so, "*eval_lavars_used" is set to TRUE.
3365 */
3366 void
3367check_vars(char_u *name, int len)
3368{
3369 int cc;
3370 char_u *varname;
3371 hashtab_T *ht;
3372
3373 if (eval_lavars_used == NULL)
3374 return;
3375
3376 // truncate the name, so that we can use strcmp()
3377 cc = name[len];
3378 name[len] = NUL;
3379
3380 ht = find_var_ht(name, &varname);
3381 if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
3382 {
3383 if (find_var(name, NULL, TRUE) != NULL)
3384 *eval_lavars_used = TRUE;
3385 }
3386
3387 name[len] = cc;
3388}
3389
3390/*
3391 * Find variable "name" in the list of variables.
3392 * Return a pointer to it if found, NULL if not found.
3393 * Careful: "a:0" variables don't have a name.
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003394 * When "htp" is not NULL set "htp" to the hashtab_T used.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003395 */
3396 dictitem_T *
3397find_var(char_u *name, hashtab_T **htp, int no_autoload)
3398{
3399 char_u *varname;
3400 hashtab_T *ht;
3401 dictitem_T *ret = NULL;
3402
3403 ht = find_var_ht(name, &varname);
3404 if (htp != NULL)
3405 *htp = ht;
3406 if (ht == NULL)
3407 return NULL;
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003408 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003409 if (ret != NULL)
3410 return ret;
3411
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003412 // Search in parent scope for lambda
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003413 ret = find_var_in_scoped_ht(name, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003414 if (ret != NULL)
3415 return ret;
3416
3417 // in Vim9 script items without a scope can be script-local
3418 if (in_vim9script() && name[0] != NUL && name[1] != ':')
3419 {
3420 ht = get_script_local_ht();
3421 if (ht != NULL)
3422 {
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003423 ret = find_var_in_ht(ht, *name, varname, no_autoload);
Bram Moolenaar2ea95b62020-11-19 21:47:56 +01003424 if (ret != NULL)
3425 {
3426 if (htp != NULL)
3427 *htp = ht;
3428 return ret;
3429 }
3430 }
3431 }
3432
Ernie Rael84f6dc72024-04-21 14:45:48 +02003433 // and finally try
3434 return find_var_autoload_prefix(name, 0, htp, NULL);
3435}
3436
3437/*
3438 * Find variable "name" with sn_autoload_prefix.
3439 * Return a pointer to it if found, NULL if not found.
3440 * When "sid" > 0, use it otherwise use "current_sctx.sc_sid".
3441 * When "htp" is not NULL set "htp" to the hashtab_T used.
3442 * When "namep" is not NULL set "namep" to the generated name, and
3443 * then the caller gets ownership and is responsible for freeing the name.
3444 */
3445 dictitem_T *
3446find_var_autoload_prefix(char_u *name, int sid, hashtab_T **htp,
3447 char_u **namep)
3448{
3449 hashtab_T *ht;
3450 dictitem_T *ret = NULL;
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003451 // When using "vim9script autoload" script-local items are prefixed but can
3452 // be used with s:name.
Ernie Rael84f6dc72024-04-21 14:45:48 +02003453 int check_sid = sid > 0 ? sid : current_sctx.sc_sid;
3454 if (SCRIPT_ID_VALID(check_sid)
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003455 && (in_vim9script() || (name[0] == 's' && name[1] == ':')))
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003456 {
Ernie Rael84f6dc72024-04-21 14:45:48 +02003457 scriptitem_T *si = SCRIPT_ITEM(check_sid);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003458
3459 if (si->sn_autoload_prefix != NULL)
3460 {
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003461 char_u *base_name = (name[0] == 's' && name[1] == ':')
3462 ? name + 2 : name;
3463 char_u *auto_name = concat_str(si->sn_autoload_prefix, base_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003464
3465 if (auto_name != NULL)
3466 {
Ernie Rael84f6dc72024-04-21 14:45:48 +02003467 int free_auto_name = TRUE;
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003468 ht = &globvarht;
Bram Moolenaar6c4d4a62022-10-13 17:47:42 +01003469 ret = find_var_in_ht(ht, 'g', auto_name, TRUE);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003470 if (ret != NULL)
3471 {
3472 if (htp != NULL)
3473 *htp = ht;
Ernie Rael84f6dc72024-04-21 14:45:48 +02003474 if (namep != NULL)
3475 {
3476 free_auto_name = FALSE;
3477 *namep = auto_name;
3478 }
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003479 }
Ernie Rael84f6dc72024-04-21 14:45:48 +02003480 if (free_auto_name)
3481 vim_free(auto_name);
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003482 }
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003483 }
3484 }
3485
Ernie Rael84f6dc72024-04-21 14:45:48 +02003486 return ret;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003487}
3488
3489/*
Bram Moolenaar71f21932022-01-07 18:20:55 +00003490 * Like find_var() but if the name starts with <SNR>99_ then look in the
3491 * referenced script (used for a funcref).
3492 */
3493 dictitem_T *
3494find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload)
3495{
Keith Thompson184f71c2024-01-04 21:19:04 +01003496 if (STRNCMP(name, "<SNR>", 5) == 0 && SAFE_isdigit(name[5]))
Bram Moolenaar71f21932022-01-07 18:20:55 +00003497 {
3498 char_u *p = name + 5;
3499 int sid = getdigits(&p);
3500
3501 if (SCRIPT_ID_VALID(sid) && *p == '_')
3502 {
3503 hashtab_T *ht = &SCRIPT_VARS(sid);
3504
3505 if (ht != NULL)
3506 {
3507 dictitem_T *di = find_var_in_ht(ht, 0, p + 1, no_autoload);
3508
3509 if (di != NULL)
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003510 {
3511 if (htp != NULL)
3512 *htp = ht;
Bram Moolenaar71f21932022-01-07 18:20:55 +00003513 return di;
Bram Moolenaaraa9b3ca2022-01-08 15:44:22 +00003514 }
Bram Moolenaar71f21932022-01-07 18:20:55 +00003515 }
3516 }
3517 }
3518
3519 return find_var(name, htp, no_autoload);
3520}
3521
3522/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003523 * Find variable "varname" in hashtab "ht" with name "htname".
Bram Moolenaar52592752020-04-03 18:43:35 +02003524 * When "varname" is empty returns curwin/curtab/etc vars dictionary.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003525 * Returns NULL if not found.
3526 */
3527 dictitem_T *
3528find_var_in_ht(
3529 hashtab_T *ht,
3530 int htname,
3531 char_u *varname,
3532 int no_autoload)
3533{
3534 hashitem_T *hi;
3535
3536 if (*varname == NUL)
3537 {
3538 // Must be something like "s:", otherwise "ht" would be NULL.
3539 switch (htname)
3540 {
3541 case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
3542 case 'g': return &globvars_var;
3543 case 'v': return &vimvars_var;
3544 case 'b': return &curbuf->b_bufvar;
3545 case 'w': return &curwin->w_winvar;
3546 case 't': return &curtab->tp_winvar;
3547 case 'l': return get_funccal_local_var();
3548 case 'a': return get_funccal_args_var();
3549 }
3550 return NULL;
3551 }
3552
3553 hi = hash_find(ht, varname);
3554 if (HASHITEM_EMPTY(hi))
3555 {
3556 // For global variables we may try auto-loading the script. If it
3557 // worked find the variable again. Don't auto-load a script if it was
3558 // loaded already, otherwise it would be loaded every time when
3559 // checking if a function name is a Funcref variable.
3560 if (ht == &globvarht && !no_autoload)
3561 {
3562 // Note: script_autoload() may make "hi" invalid. It must either
3563 // be obtained again or not used.
3564 if (!script_autoload(varname, FALSE) || aborting())
3565 return NULL;
3566 hi = hash_find(ht, varname);
3567 }
3568 if (HASHITEM_EMPTY(hi))
3569 return NULL;
3570 }
3571 return HI2DI(hi);
3572}
3573
3574/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003575 * Get the script-local hashtab. NULL if not in a script context.
3576 */
Bram Moolenaar922acbd2020-10-08 21:30:40 +02003577 hashtab_T *
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003578get_script_local_ht(void)
3579{
3580 scid_T sid = current_sctx.sc_sid;
3581
Bram Moolenaare3d46852020-08-29 13:39:17 +02003582 if (SCRIPT_ID_VALID(sid))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003583 return &SCRIPT_VARS(sid);
3584 return NULL;
3585}
3586
3587/*
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003588 * Look for "name[len]" in script-local variables and functions.
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003589 * When "cmd" is TRUE it must look like a command, a function must be followed
3590 * by "(" or "->".
Bram Moolenaar709664c2020-12-12 14:33:41 +01003591 * Return OK when found, FAIL when not found.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003592 */
Bram Moolenaar709664c2020-12-12 14:33:41 +01003593 int
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003594lookup_scriptitem(
Bram Moolenaar709664c2020-12-12 14:33:41 +01003595 char_u *name,
3596 size_t len,
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003597 int cmd,
Bram Moolenaar709664c2020-12-12 14:33:41 +01003598 cctx_T *dummy UNUSED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003599{
3600 hashtab_T *ht = get_script_local_ht();
3601 char_u buffer[30];
3602 char_u *p;
Bram Moolenaar709664c2020-12-12 14:33:41 +01003603 int res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003604 hashitem_T *hi;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003605 int is_global = FALSE;
3606 char_u *fname = name;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003607
3608 if (ht == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003609 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003610 if (len < sizeof(buffer) - 1)
3611 {
Bram Moolenaar7d3664d2020-05-09 13:06:24 +02003612 // avoid an alloc/free for short names
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003613 vim_strncpy(buffer, name, len);
3614 p = buffer;
3615 }
3616 else
3617 {
Bram Moolenaar71ccd032020-06-12 22:59:11 +02003618 p = vim_strnsave(name, len);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003619 if (p == NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003620 return FAIL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003621 }
3622
3623 hi = hash_find(ht, p);
Bram Moolenaar709664c2020-12-12 14:33:41 +01003624 res = HASHITEM_EMPTY(hi) ? FAIL : OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003625
Ernie Rael84f6dc72024-04-21 14:45:48 +02003626 // if not script-local, then perhaps autoload-exported
3627 if (res == FAIL && find_var_autoload_prefix(p, 0, NULL, NULL) != NULL)
3628 res = OK;
3629
3630 // if not script-local or autoload, then perhaps imported
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00003631 if (res == FAIL && find_imported(p, 0, FALSE) != NULL)
Bram Moolenaar709664c2020-12-12 14:33:41 +01003632 res = OK;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003633 if (p != buffer)
3634 vim_free(p);
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003635
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003636 // Find a function, so that a following "->" works.
3637 // When used as a command require "(" or "->" to follow, "Cmd" is a user
3638 // command while "Cmd()" is a function call.
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003639 if (res != OK)
3640 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003641 p = skipwhite(name + len);
3642
3643 if (!cmd || name[len] == '(' || (p[0] == '-' && p[1] == '>'))
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003644 {
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003645 // Do not check for an internal function, since it might also be a
3646 // valid command, such as ":split" versus "split()".
3647 // Skip "g:" before a function name.
3648 if (name[0] == 'g' && name[1] == ':')
3649 {
3650 is_global = TRUE;
3651 fname = name + 2;
3652 }
Bram Moolenaard9d2fd02022-01-13 21:15:21 +00003653 if (find_func(fname, is_global) != NULL)
Bram Moolenaar77b10ff2021-03-14 13:21:35 +01003654 res = OK;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003655 }
Bram Moolenaar2e2d7582021-03-03 21:22:41 +01003656 }
3657
Bram Moolenaar709664c2020-12-12 14:33:41 +01003658 return res;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003659}
3660
3661/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003662 * Find the hashtab used for a variable name.
3663 * Return NULL if the name is not valid.
3664 * Set "varname" to the start of name without ':'.
3665 */
3666 hashtab_T *
3667find_var_ht(char_u *name, char_u **varname)
3668{
3669 hashitem_T *hi;
3670 hashtab_T *ht;
3671
3672 if (name[0] == NUL)
3673 return NULL;
3674 if (name[1] != ':')
3675 {
3676 // The name must not start with a colon or #.
3677 if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
3678 return NULL;
3679 *varname = name;
3680
3681 // "version" is "v:version" in all scopes if scriptversion < 3.
3682 // Same for a few other variables marked with VV_COMPAT.
Bram Moolenaardd9de502021-08-15 13:49:42 +02003683 if (in_old_script(3))
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003684 {
3685 hi = hash_find(&compat_hashtab, name);
3686 if (!HASHITEM_EMPTY(hi))
3687 return &compat_hashtab;
3688 }
3689
3690 ht = get_funccal_local_ht();
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003691 if (ht != NULL)
3692 return ht; // local variable
3693
Bram Moolenaarf0a40692021-06-11 22:05:47 +02003694 // In Vim9 script items at the script level are script-local, except
3695 // for autoload names.
3696 if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003697 {
3698 ht = get_script_local_ht();
3699 if (ht != NULL)
3700 return ht;
3701 }
3702
3703 return &globvarht; // global variable
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003704 }
3705 *varname = name + 2;
3706 if (*name == 'g') // global variable
3707 return &globvarht;
3708 // There must be no ':' or '#' in the rest of the name, unless g: is used
3709 if (vim_strchr(name + 2, ':') != NULL
3710 || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
3711 return NULL;
3712 if (*name == 'b') // buffer variable
3713 return &curbuf->b_vars->dv_hashtab;
3714 if (*name == 'w') // window variable
3715 return &curwin->w_vars->dv_hashtab;
3716 if (*name == 't') // tab page variable
3717 return &curtab->tp_vars->dv_hashtab;
3718 if (*name == 'v') // v: variable
3719 return &vimvarht;
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003720 if (get_current_funccal() != NULL
Bram Moolenaarca16c602022-09-06 18:57:08 +01003721 && get_current_funccal()->fc_func->uf_def_status
3722 == UF_NOT_COMPILED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003723 {
Bram Moolenaarb35efa52020-02-26 20:15:18 +01003724 // a: and l: are only used in functions defined with ":function"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01003725 if (*name == 'a') // a: function argument
3726 return get_funccal_args_ht();
3727 if (*name == 'l') // l: local function variable
3728 return get_funccal_local_ht();
3729 }
3730 if (*name == 's') // script variable
3731 {
3732 ht = get_script_local_ht();
3733 if (ht != NULL)
3734 return ht;
3735 }
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003736 return NULL;
3737}
3738
3739/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003740 * Get the string value of a (global/local) variable.
3741 * Note: see tv_get_string() for how long the pointer remains valid.
3742 * Returns NULL when it doesn't exist.
3743 */
3744 char_u *
3745get_var_value(char_u *name)
3746{
3747 dictitem_T *v;
3748
3749 v = find_var(name, NULL, FALSE);
3750 if (v == NULL)
3751 return NULL;
3752 return tv_get_string(&v->di_tv);
3753}
3754
3755/*
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003756 * Allocate a new hashtab for a sourced script. It will be used while
3757 * sourcing this script and when executing functions defined in the script.
3758 */
3759 void
3760new_script_vars(scid_T id)
3761{
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003762 scriptvar_T *sv;
3763
Bram Moolenaar7ebcba62020-01-12 17:42:55 +01003764 sv = ALLOC_CLEAR_ONE(scriptvar_T);
3765 if (sv == NULL)
3766 return;
3767 init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
Bram Moolenaar21b9e972020-01-26 19:26:46 +01003768 SCRIPT_ITEM(id)->sn_vars = sv;
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003769}
3770
3771/*
3772 * Initialize dictionary "dict" as a scope and set variable "dict_var" to
3773 * point to it.
3774 */
3775 void
3776init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
3777{
3778 hash_init(&dict->dv_hashtab);
3779 dict->dv_lock = 0;
3780 dict->dv_scope = scope;
3781 dict->dv_refcount = DO_NOT_FREE_CNT;
3782 dict->dv_copyID = 0;
3783 dict_var->di_tv.vval.v_dict = dict;
3784 dict_var->di_tv.v_type = VAR_DICT;
3785 dict_var->di_tv.v_lock = VAR_FIXED;
3786 dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
3787 dict_var->di_key[0] = NUL;
3788}
3789
3790/*
3791 * Unreference a dictionary initialized by init_var_dict().
3792 */
3793 void
3794unref_var_dict(dict_T *dict)
3795{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02003796 // Now the dict needs to be freed if no one else is using it, go back to
3797 // normal reference counting.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02003798 dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
3799 dict_unref(dict);
3800}
3801
3802/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003803 * Clean up a list of internal variables.
3804 * Frees all allocated variables and the value they contain.
3805 * Clears hashtab "ht", does not free it.
3806 */
3807 void
3808vars_clear(hashtab_T *ht)
3809{
3810 vars_clear_ext(ht, TRUE);
3811}
3812
3813/*
3814 * Like vars_clear(), but only free the value if "free_val" is TRUE.
3815 */
3816 void
3817vars_clear_ext(hashtab_T *ht, int free_val)
3818{
3819 int todo;
3820 hashitem_T *hi;
3821 dictitem_T *v;
3822
3823 hash_lock(ht);
3824 todo = (int)ht->ht_used;
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +00003825 FOR_ALL_HASHTAB_ITEMS(ht, hi, todo)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003826 {
3827 if (!HASHITEM_EMPTY(hi))
3828 {
3829 --todo;
3830
3831 // Free the variable. Don't remove it from the hashtab,
3832 // ht_array might change then. hash_clear() takes care of it
3833 // later.
3834 v = HI2DI(hi);
3835 if (free_val)
3836 clear_tv(&v->di_tv);
3837 if (v->di_flags & DI_FLAGS_ALLOC)
3838 vim_free(v);
3839 }
3840 }
3841 hash_clear(ht);
Bram Moolenaar8d739de2020-10-14 19:39:19 +02003842 hash_init(ht);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003843}
3844
3845/*
3846 * Delete a variable from hashtab "ht" at item "hi".
3847 * Clear the variable value and free the dictitem.
3848 */
Bram Moolenaarfcdc5d82020-10-10 19:07:09 +02003849 void
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003850delete_var(hashtab_T *ht, hashitem_T *hi)
3851{
3852 dictitem_T *di = HI2DI(hi);
3853
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00003854 if (hash_remove(ht, hi, "delete variable") != OK)
3855 return;
3856
3857 clear_tv(&di->di_tv);
3858 vim_free(di);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003859}
3860
3861/*
3862 * List the value of one internal variable.
3863 */
3864 static void
3865list_one_var(dictitem_T *v, char *prefix, int *first)
3866{
3867 char_u *tofree;
3868 char_u *s;
3869 char_u numbuf[NUMBUFLEN];
3870
3871 s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
3872 list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
3873 s == NULL ? (char_u *)"" : s, first);
3874 vim_free(tofree);
3875}
3876
3877 static void
3878list_one_var_a(
3879 char *prefix,
3880 char_u *name,
3881 int type,
3882 char_u *string,
3883 int *first) // when TRUE clear rest of screen and set to FALSE
3884{
3885 // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
3886 msg_start();
3887 msg_puts(prefix);
3888 if (name != NULL) // "a:" vars don't have a name stored
3889 msg_puts((char *)name);
3890 msg_putchar(' ');
3891 msg_advance(22);
3892 if (type == VAR_NUMBER)
3893 msg_putchar('#');
3894 else if (type == VAR_FUNC || type == VAR_PARTIAL)
3895 msg_putchar('*');
3896 else if (type == VAR_LIST)
3897 {
3898 msg_putchar('[');
3899 if (*string == '[')
3900 ++string;
3901 }
3902 else if (type == VAR_DICT)
3903 {
3904 msg_putchar('{');
3905 if (*string == '{')
3906 ++string;
3907 }
3908 else
3909 msg_putchar(' ');
3910
3911 msg_outtrans(string);
3912
3913 if (type == VAR_FUNC || type == VAR_PARTIAL)
3914 msg_puts("()");
3915 if (*first)
3916 {
3917 msg_clr_eos();
3918 *first = FALSE;
3919 }
3920}
3921
3922/*
zeertzjqedcba962023-09-24 23:13:51 +02003923 * Addition handling for setting a v: variable.
3924 * Return TRUE if the variable should be set normally,
3925 * FALSE if nothing else needs to be done.
3926 */
3927 int
3928before_set_vvar(
3929 char_u *varname,
3930 dictitem_T *di,
3931 typval_T *tv,
3932 int copy,
3933 int *type_error)
3934{
3935 if (di->di_tv.v_type == VAR_STRING)
3936 {
3937 VIM_CLEAR(di->di_tv.vval.v_string);
3938 if (copy || tv->v_type != VAR_STRING)
3939 {
3940 char_u *val = tv_get_string(tv);
3941
3942 // Careful: when assigning to v:errmsg and
3943 // tv_get_string() causes an error message the variable
3944 // will already be set.
3945 if (di->di_tv.vval.v_string == NULL)
3946 di->di_tv.vval.v_string = vim_strsave(val);
3947 }
3948 else
3949 {
3950 // Take over the string to avoid an extra alloc/free.
3951 di->di_tv.vval.v_string = tv->vval.v_string;
3952 tv->vval.v_string = NULL;
3953 }
3954 return FALSE;
3955 }
3956 else if (di->di_tv.v_type == VAR_NUMBER)
3957 {
3958 di->di_tv.vval.v_number = tv_get_number(tv);
3959 if (STRCMP(varname, "searchforward") == 0)
3960 set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
3961#ifdef FEAT_SEARCH_EXTRA
3962 else if (STRCMP(varname, "hlsearch") == 0)
3963 {
3964 no_hlsearch = !di->di_tv.vval.v_number;
3965 redraw_all_later(UPD_SOME_VALID);
3966 }
3967#endif
3968 return FALSE;
3969 }
3970 else if (di->di_tv.v_type != tv->v_type)
3971 {
3972 *type_error = TRUE;
3973 return FALSE;
3974 }
3975 return TRUE;
3976}
3977
3978/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003979 * Set variable "name" to value in "tv".
3980 * If the variable already exists, the value is updated.
3981 * Otherwise the variable is created.
3982 */
3983 void
3984set_var(
3985 char_u *name,
3986 typval_T *tv,
3987 int copy) // make copy of value in "tv"
3988{
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003989 set_var_const(name, 0, NULL, tv, copy, ASSIGN_DECL, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003990}
3991
3992/*
Bram Moolenaar0e3e7ba2022-01-13 20:18:56 +00003993 * Set variable "name" to value in "tv_arg".
Bram Moolenaard5f400c2022-01-06 21:10:28 +00003994 * When "sid" is non-zero "name" is in the script with this ID.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003995 * If the variable already exists and "is_const" is FALSE the value is updated.
3996 * Otherwise the variable is created.
3997 */
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01003998 int
Bram Moolenaar0522ba02019-08-27 22:48:30 +02003999set_var_const(
4000 char_u *name,
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004001 scid_T sid,
Bram Moolenaar7824fc82021-11-26 17:36:51 +00004002 type_T *type_arg,
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02004003 typval_T *tv_arg,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004004 int copy, // make copy of value in "tv"
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02004005 int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc.
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004006 int var_idx) // index for ":let [a, b] = list"
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004007{
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02004008 typval_T *tv = tv_arg;
Bram Moolenaar7824fc82021-11-26 17:36:51 +00004009 type_T *type = type_arg;
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02004010 typval_T bool_tv;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004011 dictitem_T *di;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004012 typval_T *dest_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004013 char_u *varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004014 char_u *name_tofree = NULL;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004015 hashtab_T *ht = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004016 int is_script_local;
Bram Moolenaardbeecb22020-09-14 18:15:09 +02004017 int vim9script = in_vim9script();
Bram Moolenaare535db82021-03-31 21:07:24 +02004018 int var_in_vim9script;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004019 int var_in_autoload = FALSE;
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02004020 int flags = flags_arg;
Bram Moolenaardd297bc2021-12-10 10:37:38 +00004021 int free_tv_arg = !copy; // free tv_arg if not used
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01004022 int rc = FAIL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004023
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004024 if (sid != 0)
4025 {
Ernie Rael84f6dc72024-04-21 14:45:48 +02004026 varname = NULL;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004027 if (SCRIPT_ID_VALID(sid))
Ernie Rael84f6dc72024-04-21 14:45:48 +02004028 {
4029 char_u *auto_name = NULL;
4030 if (find_var_autoload_prefix(name, sid, &ht, &auto_name) != NULL)
4031 {
4032 var_in_autoload = TRUE;
4033 varname = auto_name;
4034 name_tofree = varname;
4035 }
4036 else
4037 ht = &SCRIPT_VARS(sid);
4038 }
4039 if (varname == NULL)
4040 varname = name;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004041 }
4042 else
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004043 {
Ernie Rael84f6dc72024-04-21 14:45:48 +02004044 scriptitem_T *si;
4045 char_u *auto_name = NULL;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004046
Ernie Rael84f6dc72024-04-21 14:45:48 +02004047 if (in_vim9script()
4048 && SCRIPT_ID_VALID(current_sctx.sc_sid)
4049 && (si = SCRIPT_ITEM(current_sctx.sc_sid))
4050 ->sn_autoload_prefix != NULL
4051 && (is_export
4052 || find_var_autoload_prefix(name, 0, NULL, &auto_name)
4053 != NULL))
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00004054 {
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004055 // In a vim9 autoload script an exported variable is put in the
4056 // global namespace with the autoload prefix.
4057 var_in_autoload = TRUE;
Ernie Rael84f6dc72024-04-21 14:45:48 +02004058 varname = auto_name != NULL ? auto_name
4059 : concat_str(si->sn_autoload_prefix, name);
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004060 if (varname == NULL)
4061 goto failed;
4062 name_tofree = varname;
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004063 ht = &globvarht;
4064 }
4065 else
4066 ht = find_var_ht(name, &varname);
4067 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004068 if (ht == NULL || *varname == NUL)
4069 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004070 semsg(_(e_illegal_variable_name_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004071 goto failed;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004072 }
Bram Moolenaar54969f42022-02-07 13:56:44 +00004073 is_script_local = ht == get_script_local_ht() || sid != 0
4074 || var_in_autoload;
Bram Moolenaare55b1c02020-06-21 15:52:59 +02004075
Bram Moolenaardbeecb22020-09-14 18:15:09 +02004076 if (vim9script
Bram Moolenaare55b1c02020-06-21 15:52:59 +02004077 && !is_script_local
Bram Moolenaar3862ea32021-01-01 21:05:55 +01004078 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
Bram Moolenaar89b474d2020-12-22 21:19:39 +01004079 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
Bram Moolenaare55b1c02020-06-21 15:52:59 +02004080 && name[1] == ':')
Bram Moolenaar67979662020-06-20 22:50:47 +02004081 {
Bram Moolenaare55b1c02020-06-21 15:52:59 +02004082 vim9_declare_error(name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004083 goto failed;
Bram Moolenaar67979662020-06-20 22:50:47 +02004084 }
Bram Moolenaar9510d222022-09-11 15:14:05 +01004085 if ((flags & ASSIGN_FOR_LOOP) && is_scoped_variable(name))
Bram Moolenaarf6a8d422021-04-13 21:48:03 +02004086 // Do not make g:var, w:var, b:var or t:var final.
4087 flags &= ~ASSIGN_FINAL;
4088
Bram Moolenaare535db82021-03-31 21:07:24 +02004089 var_in_vim9script = is_script_local && current_script_is_vim9();
Bram Moolenaar962c43b2021-04-10 17:18:09 +02004090 if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
4091 {
Bram Moolenaarf93bbd02021-04-10 22:35:43 +02004092 // For "[a, _] = list" the underscore is ignored.
4093 if ((flags & ASSIGN_UNPACK) == 0)
4094 emsg(_(e_cannot_use_underscore_here));
Bram Moolenaar962c43b2021-04-10 17:18:09 +02004095 goto failed;
4096 }
Bram Moolenaar67979662020-06-20 22:50:47 +02004097
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004098 di = find_var_in_ht(ht, 0, varname, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004099
Bram Moolenaar24e93162021-07-18 20:40:33 +02004100 if (di == NULL && var_in_vim9script)
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02004101 {
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00004102 imported_T *import = find_imported(varname, 0, FALSE);
Bram Moolenaarc1ec0422020-09-09 22:27:58 +02004103
Bram Moolenaar24e93162021-07-18 20:40:33 +02004104 if (import != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004105 {
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004106 // imported name space cannot be used
Bram Moolenaar24e93162021-07-18 20:40:33 +02004107 if ((flags & ASSIGN_NO_DECL) == 0)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004108 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02004109 semsg(_(e_redefining_imported_item_str), name);
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004110 goto failed;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004111 }
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004112 semsg(_(e_cannot_use_str_itself_it_is_imported), name);
4113 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02004114 }
Bram Moolenaar75e27d72022-02-13 13:56:29 +00004115 if (!in_vim9script())
4116 {
4117 semsg(_(e_cannot_create_vim9_script_variable_in_function_str),
4118 name);
4119 goto failed;
4120 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02004121 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004122
Bram Moolenaar993faa32022-02-21 15:59:11 +00004123 // Search in parent scope which is possible to reference from lambda
4124 if (di == NULL)
4125 di = find_var_in_scoped_ht(name, TRUE);
4126
4127 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
4128 && var_wrong_func_name(name, di == NULL))
4129 goto failed;
4130
4131 if (need_convert_to_bool(type, tv))
Bram Moolenaar24e93162021-07-18 20:40:33 +02004132 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004133 // Destination is a bool and the value is not, but it can be
4134 // converted.
4135 CLEAR_FIELD(bool_tv);
4136 bool_tv.v_type = VAR_BOOL;
4137 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
4138 tv = &bool_tv;
4139 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02004140
Bram Moolenaar993faa32022-02-21 15:59:11 +00004141 if (di != NULL)
4142 {
4143 // Item already exists. Allowed to replace when reloading.
4144 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004145 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004146 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
4147 && (flags & ASSIGN_FOR_LOOP) == 0)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004148 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004149 emsg(_(e_cannot_modify_existing_variable));
4150 goto failed;
Bram Moolenaar24e93162021-07-18 20:40:33 +02004151 }
4152
Bram Moolenaar993faa32022-02-21 15:59:11 +00004153 if (is_script_local && vim9script
4154 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
Bram Moolenaar12be7342021-03-31 21:47:33 +02004155 {
4156 semsg(_(e_redefining_script_item_str), name);
4157 goto failed;
4158 }
4159
Ernie Raele75fde62023-12-21 17:18:54 +01004160 if (check_typval_is_value(&di->di_tv) == FAIL)
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02004161 goto failed;
Yegappan Lakshmananec3cebb2023-10-27 19:35:26 +02004162
Yegappan Lakshmanan1af35632024-02-06 11:03:36 +01004163 // List and Blob types can be modified in-place using the "+="
4164 // compound operator. For other types, this is not allowed.
4165 int type_inplace_modifiable =
4166 (di->di_tv.v_type == VAR_LIST || di->di_tv.v_type == VAR_BLOB);
4167
4168 if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0
4169 && ((flags & ASSIGN_COMPOUND_OP) == 0
4170 || !type_inplace_modifiable))
Bram Moolenaar24e93162021-07-18 20:40:33 +02004171 {
Bram Moolenaar993faa32022-02-21 15:59:11 +00004172 where_T where = WHERE_INIT;
Bram Moolenaar7a411a32022-04-04 14:58:06 +01004173 svar_T *sv = find_typval_in_script(&di->di_tv, sid, TRUE);
Bram Moolenaar993faa32022-02-21 15:59:11 +00004174
4175 if (sv != NULL)
4176 {
4177 // check the type and adjust to bool if needed
LemonBoyc5d27442023-08-19 13:02:35 +02004178 if (var_idx > 0)
4179 {
4180 where.wt_index = var_idx;
4181 where.wt_kind = WT_VARIABLE;
4182 }
Bram Moolenaar993faa32022-02-21 15:59:11 +00004183 if (check_script_var_type(sv, tv, name, where) == FAIL)
4184 goto failed;
4185 if (type == NULL)
4186 type = sv->sv_type;
Bram Moolenaaraa7d0c22022-04-05 21:40:38 +01004187 sv->sv_flags |= SVFLAG_ASSIGNED;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004188 }
Bram Moolenaar24e93162021-07-18 20:40:33 +02004189 }
4190
Yegappan Lakshmanan1af35632024-02-06 11:03:36 +01004191 // Modifying a final variable with a List value using the "+="
4192 // operator is allowed. For other types, it is not allowed.
zeertzjq6b97d7a2024-08-08 21:05:57 +02004193 if ((((flags & ASSIGN_FOR_LOOP) == 0 || (flags & ASSIGN_DECL) == 0)
Yegappan Lakshmanan1af35632024-02-06 11:03:36 +01004194 && ((flags & ASSIGN_COMPOUND_OP) == 0
4195 || !type_inplace_modifiable))
Bram Moolenaar16d2c022023-06-05 19:46:18 +01004196 ? var_check_permission(di, name) == FAIL
4197 : var_check_ro(di->di_flags, name, FALSE))
Bram Moolenaar24e93162021-07-18 20:40:33 +02004198 goto failed;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004199 }
4200 else
4201 {
4202 // can only redefine once
4203 di->di_flags &= ~DI_FLAGS_RELOAD;
Bram Moolenaar24e93162021-07-18 20:40:33 +02004204
Bram Moolenaar993faa32022-02-21 15:59:11 +00004205 // A Vim9 script-local variable is also present in sn_all_vars
4206 // and sn_var_vals. It may set "type" from "tv".
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004207 if (var_in_vim9script || var_in_autoload)
Bram Moolenaar993faa32022-02-21 15:59:11 +00004208 update_vim9_script_var(FALSE, di,
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004209 var_in_autoload ? name : di->di_key, flags,
Bram Moolenaar993faa32022-02-21 15:59:11 +00004210 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar07a65d22020-12-26 20:09:15 +01004211 }
4212
Bram Moolenaar993faa32022-02-21 15:59:11 +00004213 // existing variable, need to clear the value
4214
zeertzjqedcba962023-09-24 23:13:51 +02004215 // Handle setting internal v: variables separately where needed to
Bram Moolenaar993faa32022-02-21 15:59:11 +00004216 // prevent changing the type.
zeertzjqedcba962023-09-24 23:13:51 +02004217 int type_error = FALSE;
4218 if (ht == &vimvarht
4219 && !before_set_vvar(varname, di, tv, copy, &type_error))
Bram Moolenaar993faa32022-02-21 15:59:11 +00004220 {
zeertzjqedcba962023-09-24 23:13:51 +02004221 if (type_error)
4222 semsg(_(e_setting_v_str_to_value_with_wrong_type), varname);
4223 goto failed;
Bram Moolenaar993faa32022-02-21 15:59:11 +00004224 }
4225
4226 clear_tv(&di->di_tv);
Bram Moolenaar766ae5b2022-09-14 00:30:51 +01004227
4228 if ((flags & ASSIGN_UPDATE_BLOCK_ID)
4229 && SCRIPT_ID_VALID(current_sctx.sc_sid))
4230 {
4231 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
4232
4233 update_script_var_block_id(name, si->sn_current_block_id);
4234 }
Bram Moolenaar993faa32022-02-21 15:59:11 +00004235 }
4236 else
4237 {
4238 // Item not found, check if a function already exists.
4239 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
4240 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
4241 {
4242 semsg(_(e_redefining_script_item_str), name);
4243 goto failed;
4244 }
4245
4246 // add a new variable
4247 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
4248 {
4249 semsg(_(e_unknown_variable_str), name);
4250 goto failed;
4251 }
4252
Bram Moolenaaref2c3252022-11-25 16:31:51 +00004253 if (check_hashtab_frozen(ht, "add variable"))
4254 goto failed;
4255
Bram Moolenaar993faa32022-02-21 15:59:11 +00004256 // Can't add "v:" or "a:" variable.
4257 if (ht == &vimvarht || ht == get_funccal_args_ht())
4258 {
4259 semsg(_(e_illegal_variable_name_str), name);
4260 goto failed;
4261 }
4262
4263 // Make sure the variable name is valid. In Vim9 script an
4264 // autoload variable must be prefixed with "g:" unless in an
4265 // autoload script.
4266 if (!valid_varname(varname, -1, !vim9script
4267 || STRNCMP(name, "g:", 2) == 0 || var_in_autoload))
4268 goto failed;
4269
zeertzjq1b438a82023-02-01 13:11:15 +00004270 di = alloc(offsetof(dictitem_T, di_key) + STRLEN(varname) + 1);
Bram Moolenaar993faa32022-02-21 15:59:11 +00004271 if (di == NULL)
4272 goto failed;
4273 STRCPY(di->di_key, varname);
Bram Moolenaaref2c3252022-11-25 16:31:51 +00004274 if (hash_add(ht, DI2HIKEY(di), "add variable") == FAIL)
Bram Moolenaar993faa32022-02-21 15:59:11 +00004275 {
4276 vim_free(di);
4277 goto failed;
4278 }
4279 di->di_flags = DI_FLAGS_ALLOC;
4280 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
4281 di->di_flags |= DI_FLAGS_LOCK;
4282
4283 // A Vim9 script-local variable is also added to sn_all_vars and
4284 // sn_var_vals. It may set "type" from "tv".
4285 if (var_in_vim9script || var_in_autoload)
4286 update_vim9_script_var(TRUE, di,
4287 var_in_autoload ? name : di->di_key, flags,
4288 tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004289 }
4290
Bram Moolenaar993faa32022-02-21 15:59:11 +00004291 dest_tv = &di->di_tv;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004292 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
Bram Moolenaar24e93162021-07-18 20:40:33 +02004293 copy_tv(tv, dest_tv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004294 else
4295 {
Bram Moolenaar24e93162021-07-18 20:40:33 +02004296 *dest_tv = *tv;
4297 dest_tv->v_lock = 0;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004298 init_tv(tv);
4299 }
Bram Moolenaardd297bc2021-12-10 10:37:38 +00004300 free_tv_arg = FALSE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004301
Bram Moolenaaraa210a32021-01-02 15:41:03 +01004302 if (vim9script && type != NULL)
Bram Moolenaar381692b2022-02-02 20:01:27 +00004303 set_tv_type(dest_tv, type);
Bram Moolenaaraa210a32021-01-02 15:41:03 +01004304
Bram Moolenaar1dcf55d2020-12-22 22:07:30 +01004305 // ":const var = value" locks the value
4306 // ":final var = value" locks "var"
Bram Moolenaar30fd8202020-09-26 15:09:30 +02004307 if (flags & ASSIGN_CONST)
Bram Moolenaar021bda52020-08-17 21:07:22 +02004308 // Like :lockvar! name: lock the value and what it contains, but only
4309 // if the reference count is up to one. That locks only literal
4310 // values.
Bram Moolenaar24e93162021-07-18 20:40:33 +02004311 item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
Bram Moolenaar24e93162021-07-18 20:40:33 +02004312
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01004313 rc = OK;
4314
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004315failed:
Bram Moolenaarfe2ef0b2022-01-10 18:08:00 +00004316 vim_free(name_tofree);
Bram Moolenaardd297bc2021-12-10 10:37:38 +00004317 if (free_tv_arg)
Bram Moolenaarb0fa5e12020-09-12 19:51:42 +02004318 clear_tv(tv_arg);
Yegappan Lakshmanan35b867b2024-03-09 15:44:19 +01004319
4320 return rc;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004321}
4322
4323/*
Bram Moolenaar3bdc90b2020-12-22 20:35:40 +01004324 * Check in this order for backwards compatibility:
4325 * - Whether the variable is read-only
4326 * - Whether the variable value is locked
4327 * - Whether the variable is locked
Ernie Rael3f821d62024-04-24 20:07:50 +02004328 * NOTE: "name" is only used for error messages.
Bram Moolenaar3bdc90b2020-12-22 20:35:40 +01004329 */
4330 int
4331var_check_permission(dictitem_T *di, char_u *name)
4332{
4333 if (var_check_ro(di->di_flags, name, FALSE)
4334 || value_check_lock(di->di_tv.v_lock, name, FALSE)
4335 || var_check_lock(di->di_flags, name, FALSE))
4336 return FAIL;
4337 return OK;
4338}
4339
4340/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004341 * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
4342 * Also give an error message.
4343 */
4344 int
4345var_check_ro(int flags, char_u *name, int use_gettext)
4346{
4347 if (flags & DI_FLAGS_RO)
4348 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004349 if (name == NULL)
4350 emsg(_(e_cannot_change_readonly_variable));
4351 else
4352 semsg(_(e_cannot_change_readonly_variable_str),
Bram Moolenaard8e44472021-07-21 22:20:33 +02004353 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004354 return TRUE;
4355 }
4356 if ((flags & DI_FLAGS_RO_SBX) && sandbox)
4357 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004358 if (name == NULL)
4359 emsg(_(e_cannot_set_variable_in_sandbox));
4360 else
4361 semsg(_(e_cannot_set_variable_in_sandbox_str),
4362 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004363 return TRUE;
4364 }
4365 return FALSE;
4366}
4367
4368/*
Bram Moolenaara187c432020-09-16 21:08:28 +02004369 * Return TRUE if di_flags "flags" indicates variable "name" is locked.
4370 * Also give an error message.
4371 */
4372 int
4373var_check_lock(int flags, char_u *name, int use_gettext)
4374{
4375 if (flags & DI_FLAGS_LOCK)
4376 {
4377 semsg(_(e_variable_is_locked_str),
4378 use_gettext ? (char_u *)_(name) : name);
4379 return TRUE;
4380 }
4381 return FALSE;
4382}
4383
4384/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004385 * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
4386 * Also give an error message.
4387 */
4388 int
4389var_check_fixed(int flags, char_u *name, int use_gettext)
4390{
4391 if (flags & DI_FLAGS_FIX)
4392 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004393 if (name == NULL)
4394 emsg(_(e_cannot_delete_variable));
4395 else
4396 semsg(_(e_cannot_delete_variable_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004397 use_gettext ? (char_u *)_(name) : name);
4398 return TRUE;
4399 }
4400 return FALSE;
4401}
4402
4403/*
4404 * Check if a funcref is assigned to a valid variable name.
4405 * Return TRUE and give an error if not.
4406 */
4407 int
Bram Moolenaar98b4f142020-08-08 15:46:01 +02004408var_wrong_func_name(
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004409 char_u *name, // points to start of variable name
4410 int new_var) // TRUE when creating the variable
4411{
Bram Moolenaar32154662021-03-28 21:14:06 +02004412 // Allow for w: b: s: and t:. In Vim9 script s: is not allowed, because
4413 // the name can be used without the s: prefix.
thinca6c667bd2022-09-02 11:25:37 +01004414 // Allow autoload variable.
Bram Moolenaar32154662021-03-28 21:14:06 +02004415 if (!((vim_strchr((char_u *)"wbt", name[0]) != NULL
4416 || (!in_vim9script() && name[0] == 's')) && name[1] == ':')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004417 && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
thinca6c667bd2022-09-02 11:25:37 +01004418 ? name[2] : name[0])
4419 && vim_strchr(name, '#') == NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004420 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00004421 semsg(_(e_funcref_variable_name_must_start_with_capital_str), name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004422 return TRUE;
4423 }
4424 // Don't allow hiding a function. When "v" is not NULL we might be
4425 // assigning another function to the same var, the type is checked
4426 // below.
4427 if (new_var && function_exists(name, FALSE))
4428 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00004429 semsg(_(e_variable_name_conflicts_with_existing_function_str),
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004430 name);
4431 return TRUE;
4432 }
4433 return FALSE;
4434}
4435
4436/*
Bram Moolenaara187c432020-09-16 21:08:28 +02004437 * Return TRUE if "flags" indicates variable "name" has a locked (immutable)
4438 * value. Also give an error message, using "name" or _("name") when
4439 * "use_gettext" is TRUE.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004440 */
4441 int
Bram Moolenaara187c432020-09-16 21:08:28 +02004442value_check_lock(int lock, char_u *name, int use_gettext)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004443{
4444 if (lock & VAR_LOCKED)
4445 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004446 if (name == NULL)
4447 emsg(_(e_value_is_locked));
4448 else
4449 semsg(_(e_value_is_locked_str),
4450 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004451 return TRUE;
4452 }
4453 if (lock & VAR_FIXED)
4454 {
Bram Moolenaar71b76852021-12-17 20:15:38 +00004455 if (name == NULL)
4456 emsg(_(e_cannot_change_value));
4457 else
4458 semsg(_(e_cannot_change_value_of_str),
4459 use_gettext ? (char_u *)_(name) : name);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004460 return TRUE;
4461 }
4462 return FALSE;
4463}
4464
4465/*
Bram Moolenaar03290b82020-12-19 16:30:44 +01004466 * Check if a variable name is valid. When "autoload" is true "#" is allowed.
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004467 * If "len" is -1 use all of "varname", otherwise up to "varname[len]".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004468 * Return FALSE and give an error if not.
4469 */
4470 int
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004471valid_varname(char_u *varname, int len, int autoload)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004472{
4473 char_u *p;
4474
Bram Moolenaar3b3755f2021-11-22 20:10:18 +00004475 for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004476 if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
Bram Moolenaar03290b82020-12-19 16:30:44 +01004477 && !(autoload && *p == AUTOLOAD_CHAR))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004478 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004479 semsg(_(e_illegal_variable_name_str), varname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004480 return FALSE;
4481 }
4482 return TRUE;
4483}
4484
4485/*
LemonBoy47d4e312022-05-04 18:12:55 +01004486 * Implements the logic to retrieve local variable and option values.
4487 * Used by "getwinvar()" "gettabvar()" "gettabwinvar()" "getbufvar()".
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004488 */
4489 static void
LemonBoy47d4e312022-05-04 18:12:55 +01004490get_var_from(
4491 char_u *varname,
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004492 typval_T *rettv,
LemonBoy47d4e312022-05-04 18:12:55 +01004493 typval_T *deftv, // Default value if not found.
4494 int htname, // 't'ab, 'w'indow or 'b'uffer local.
4495 tabpage_T *tp, // can be NULL
4496 win_T *win,
4497 buf_T *buf) // Ignored if htname is not 'b'.
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004498{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004499 dictitem_T *v;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004500 int done = FALSE;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004501 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004502 int need_switch_win;
zeertzjqcd6ad642022-07-25 12:28:09 +01004503 int do_change_curbuf = buf != NULL && htname == 'b';
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004504
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004505 ++emsg_off;
4506
4507 rettv->v_type = VAR_STRING;
4508 rettv->vval.v_string = NULL;
4509
LemonBoy47d4e312022-05-04 18:12:55 +01004510 if (varname != NULL && tp != NULL && win != NULL
4511 && (htname != 'b' || buf != NULL))
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004512 {
4513 // Set curwin to be our win, temporarily. Also set the tabpage,
4514 // otherwise the window is not valid. Only do this when needed,
4515 // autocommands get blocked.
LemonBoy47d4e312022-05-04 18:12:55 +01004516 // If we have a buffer reference avoid the switching, we're saving and
4517 // restoring curbuf directly.
zeertzjqcd6ad642022-07-25 12:28:09 +01004518 need_switch_win = !(tp == curtab && win == curwin) && !do_change_curbuf;
LemonBoy47d4e312022-05-04 18:12:55 +01004519 if (!need_switch_win || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004520 {
LemonBoy47d4e312022-05-04 18:12:55 +01004521 // Handle options. There are no tab-local options.
4522 if (*varname == '&' && htname != 't')
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004523 {
LemonBoy47d4e312022-05-04 18:12:55 +01004524 buf_T *save_curbuf = curbuf;
4525
4526 // Change curbuf so the option is read from the correct buffer.
zeertzjqcd6ad642022-07-25 12:28:09 +01004527 if (do_change_curbuf)
LemonBoy47d4e312022-05-04 18:12:55 +01004528 curbuf = buf;
4529
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004530 if (varname[1] == NUL)
4531 {
zeertzjqcd6ad642022-07-25 12:28:09 +01004532 // get all window-local or buffer-local options in a dict
LemonBoy47d4e312022-05-04 18:12:55 +01004533 dict_T *opts = get_winbuf_options(htname == 'b');
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004534
4535 if (opts != NULL)
4536 {
4537 rettv_dict_set(rettv, opts);
4538 done = TRUE;
4539 }
4540 }
LemonBoy47d4e312022-05-04 18:12:55 +01004541 else if (eval_option(&varname, rettv, TRUE) == OK)
4542 // Local option
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004543 done = TRUE;
LemonBoy47d4e312022-05-04 18:12:55 +01004544
4545 curbuf = save_curbuf;
4546 }
4547 else if (*varname == NUL)
4548 {
4549 // Empty string: return a dict with all the local variables.
4550 if (htname == 'b')
4551 v = &buf->b_bufvar;
4552 else if (htname == 'w')
4553 v = &win->w_winvar;
4554 else
4555 v = &tp->tp_winvar;
4556 copy_tv(&v->di_tv, rettv);
4557 done = TRUE;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004558 }
4559 else
4560 {
LemonBoy47d4e312022-05-04 18:12:55 +01004561 hashtab_T *ht;
4562
4563 if (htname == 'b')
4564 ht = &buf->b_vars->dv_hashtab;
4565 else if (htname == 'w')
4566 ht = &win->w_vars->dv_hashtab;
4567 else
4568 ht = &tp->tp_vars->dv_hashtab;
4569
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004570 // Look up the variable.
LemonBoy47d4e312022-05-04 18:12:55 +01004571 v = find_var_in_ht(ht, htname, varname, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004572 if (v != NULL)
4573 {
4574 copy_tv(&v->di_tv, rettv);
4575 done = TRUE;
4576 }
4577 }
4578 }
4579
4580 if (need_switch_win)
4581 // restore previous notion of curwin
Bram Moolenaar18f47402022-01-06 13:24:51 +00004582 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004583 }
4584
LemonBoy47d4e312022-05-04 18:12:55 +01004585 if (!done && deftv->v_type != VAR_UNKNOWN)
4586 // use the default value
4587 copy_tv(deftv, rettv);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004588
4589 --emsg_off;
4590}
4591
4592/*
LemonBoy47d4e312022-05-04 18:12:55 +01004593 * getwinvar() and gettabwinvar()
4594 */
4595 static void
4596getwinvar(
4597 typval_T *argvars,
4598 typval_T *rettv,
4599 int off) // 1 for gettabwinvar()
4600{
4601 char_u *varname;
4602 tabpage_T *tp;
4603 win_T *win;
4604
4605 if (off == 1)
4606 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4607 else
4608 tp = curtab;
4609 win = find_win_by_nr(&argvars[off], tp);
4610 varname = tv_get_string_chk(&argvars[off + 1]);
4611
4612 get_var_from(varname, rettv, &argvars[off + 2], 'w', tp, win, NULL);
4613}
4614
4615/*
Bram Moolenaar191929b2020-08-19 21:20:49 +02004616 * Set option "varname" to the value of "varp" for the current buffer/window.
4617 */
4618 static void
4619set_option_from_tv(char_u *varname, typval_T *varp)
4620{
4621 long numval = 0;
4622 char_u *strval;
4623 char_u nbuf[NUMBUFLEN];
4624 int error = FALSE;
4625
zeertzjq4c7cb372023-06-14 16:39:54 +01004626 int opt_idx = findoption(varname);
4627 if (opt_idx < 0)
4628 {
4629 semsg(_(e_unknown_option_str_2), varname);
4630 return;
4631 }
4632 int opt_p_flags = get_option_flags(opt_idx);
4633
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004634 if (varp->v_type == VAR_BOOL)
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004635 {
zeertzjq4c7cb372023-06-14 16:39:54 +01004636 if (opt_p_flags & P_STRING)
Bram Moolenaar28f84e12022-07-27 12:30:13 +01004637 {
4638 emsg(_(e_string_required));
4639 return;
4640 }
Bram Moolenaar31a201a2021-01-03 14:47:25 +01004641 numval = (long)varp->vval.v_number;
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004642 strval = (char_u *)"0"; // avoid using "false"
4643 }
4644 else
4645 {
zeertzjq4c7cb372023-06-14 16:39:54 +01004646 if ((opt_p_flags & (P_NUM|P_BOOL))
4647 && (!in_vim9script() || varp->v_type != VAR_STRING))
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004648 numval = (long)tv_get_number_chk(varp, &error);
zeertzjq4c7cb372023-06-14 16:39:54 +01004649 if (!error)
4650 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaarb0d81822021-01-03 15:55:10 +01004651 }
Bram Moolenaar191929b2020-08-19 21:20:49 +02004652 if (!error && strval != NULL)
Bram Moolenaar31e5c602022-04-15 13:53:33 +01004653 set_option_value_give_err(varname, numval, strval, OPT_LOCAL);
Bram Moolenaar191929b2020-08-19 21:20:49 +02004654}
4655
4656/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004657 * "setwinvar()" and "settabwinvar()" functions
4658 */
4659 static void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01004660setwinvar(typval_T *argvars, int off)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004661{
4662 win_T *win;
Bram Moolenaar18f47402022-01-06 13:24:51 +00004663 switchwin_T switchwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004664 int need_switch_win;
4665 char_u *varname, *winvarname;
4666 typval_T *varp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004667 tabpage_T *tp = NULL;
4668
4669 if (check_secure())
4670 return;
4671
4672 if (off == 1)
4673 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
4674 else
4675 tp = curtab;
4676 win = find_win_by_nr(&argvars[off], tp);
4677 varname = tv_get_string_chk(&argvars[off + 1]);
4678 varp = &argvars[off + 2];
4679
zeertzjqea720ae2023-01-03 10:54:09 +00004680 if (win == NULL || varname == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004681 return;
4682
4683 need_switch_win = !(tp == curtab && win == curwin);
4684 if (!need_switch_win
4685 || switch_win(&switchwin, win, tp, TRUE) == OK)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004686 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004687 if (*varname == '&')
4688 set_option_from_tv(varname + 1, varp);
4689 else
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004690 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004691 winvarname = alloc(STRLEN(varname) + 3);
4692 if (winvarname != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004693 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004694 STRCPY(winvarname, "w:");
4695 STRCPY(winvarname + 2, varname);
4696 set_var(winvarname, varp, TRUE);
4697 vim_free(winvarname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004698 }
4699 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004700 }
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00004701 if (need_switch_win)
4702 restore_win(&switchwin, TRUE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004703}
4704
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004705/*
4706 * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
4707 * v:option_type, and v:option_command.
4708 */
4709 void
4710reset_v_option_vars(void)
4711{
4712 set_vim_var_string(VV_OPTION_NEW, NULL, -1);
4713 set_vim_var_string(VV_OPTION_OLD, NULL, -1);
4714 set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
4715 set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
4716 set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
4717 set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
4718}
4719
4720/*
4721 * Add an assert error to v:errors.
4722 */
4723 void
4724assert_error(garray_T *gap)
4725{
4726 struct vimvar *vp = &vimvars[VV_ERRORS];
4727
Bram Moolenaard787e402021-12-24 21:36:12 +00004728 if (vp->vv_tv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02004729 // Make sure v:errors is a list.
Bram Moolenaare5cdf152019-08-29 22:09:46 +02004730 set_vim_var_list(VV_ERRORS, list_alloc());
4731 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
4732}
4733
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004734 int
4735var_exists(char_u *var)
4736{
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004737 char_u *arg = var;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004738 char_u *name;
4739 char_u *tofree;
4740 typval_T tv;
4741 int len = 0;
4742 int n = FALSE;
4743
4744 // get_name_len() takes care of expanding curly braces
4745 name = var;
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004746 len = get_name_len(&arg, &tofree, TRUE, FALSE);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004747 if (len > 0)
4748 {
4749 if (tofree != NULL)
4750 name = tofree;
Bram Moolenaard5f400c2022-01-06 21:10:28 +00004751 n = (eval_variable(name, len, 0, &tv, NULL,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +01004752 EVAL_VAR_NOAUTOLOAD + EVAL_VAR_IMPORT) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004753 if (n)
4754 {
4755 // handle d.key, l[idx], f(expr)
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004756 arg = skipwhite(arg);
Bram Moolenaar32884ad2022-01-07 12:45:29 +00004757 n = (handle_subscript(&arg, name, &tv, &EVALARG_EVALUATE,
4758 FALSE) == OK);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004759 if (n)
4760 clear_tv(&tv);
4761 }
4762 }
Bram Moolenaarbb1b5e22020-08-05 10:53:21 +02004763 if (*arg != NUL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004764 n = FALSE;
4765
4766 vim_free(tofree);
4767 return n;
4768}
4769
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004770static lval_T *redir_lval = NULL;
4771#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
4772static garray_T redir_ga; // only valid when redir_lval is not NULL
4773static char_u *redir_endp = NULL;
4774static char_u *redir_varname = NULL;
4775
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004776 int
4777alloc_redir_lval(void)
4778{
4779 redir_lval = ALLOC_CLEAR_ONE(lval_T);
4780 if (redir_lval == NULL)
4781 return FAIL;
4782 return OK;
4783}
4784
4785 void
4786clear_redir_lval(void)
4787{
4788 VIM_CLEAR(redir_lval);
4789}
4790
4791 void
4792init_redir_ga(void)
4793{
Bram Moolenaar04935fb2022-01-08 16:19:22 +00004794 ga_init2(&redir_ga, sizeof(char), 500);
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004795}
4796
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004797/*
4798 * Start recording command output to a variable
4799 * When "append" is TRUE append to an existing variable.
4800 * Returns OK if successfully completed the setup. FAIL otherwise.
4801 */
4802 int
4803var_redir_start(char_u *name, int append)
4804{
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004805 int called_emsg_before;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004806 typval_T tv;
4807
4808 // Catch a bad name early.
4809 if (!eval_isnamec1(*name))
4810 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004811 emsg(_(e_invalid_argument));
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004812 return FAIL;
4813 }
4814
4815 // Make a copy of the name, it is used in redir_lval until redir ends.
4816 redir_varname = vim_strsave(name);
4817 if (redir_varname == NULL)
4818 return FAIL;
4819
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004820 if (alloc_redir_lval() == FAIL)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004821 {
4822 var_redir_stop();
4823 return FAIL;
4824 }
4825
4826 // The output is stored in growarray "redir_ga" until redirection ends.
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004827 init_redir_ga();
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004828
4829 // Parse the variable name (can be a dict or list entry).
4830 redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
4831 FNE_CHECK_START);
4832 if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
4833 {
4834 clear_lval(redir_lval);
4835 if (redir_endp != NULL && *redir_endp != NUL)
4836 // Trailing characters are present after the variable name
Bram Moolenaar74409f62022-01-01 15:58:22 +00004837 semsg(_(e_trailing_characters_str), redir_endp);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004838 else
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004839 semsg(_(e_invalid_argument_str), name);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004840 redir_endp = NULL; // don't store a value, only cleanup
4841 var_redir_stop();
4842 return FAIL;
4843 }
4844
4845 // check if we can write to the variable: set it to or append an empty
4846 // string
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004847 called_emsg_before = called_emsg;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004848 tv.v_type = VAR_STRING;
4849 tv.vval.v_string = (char_u *)"";
4850 if (append)
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004851 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004852 ASSIGN_NO_DECL, (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004853 else
Bram Moolenaarf4c6e1e2020-10-23 18:02:32 +02004854 set_var_lval(redir_lval, redir_endp, &tv, TRUE,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004855 ASSIGN_NO_DECL, (char_u *)"=", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004856 clear_lval(redir_lval);
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02004857 if (called_emsg > called_emsg_before)
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004858 {
4859 redir_endp = NULL; // don't store a value, only cleanup
4860 var_redir_stop();
4861 return FAIL;
4862 }
4863
4864 return OK;
4865}
4866
4867/*
4868 * Append "value[value_len]" to the variable set by var_redir_start().
4869 * The actual appending is postponed until redirection ends, because the value
4870 * appended may in fact be the string we write to, changing it may cause freed
4871 * memory to be used:
4872 * :redir => foo
4873 * :let foo
4874 * :redir END
4875 */
4876 void
4877var_redir_str(char_u *value, int value_len)
4878{
4879 int len;
4880
4881 if (redir_lval == NULL)
4882 return;
4883
4884 if (value_len == -1)
4885 len = (int)STRLEN(value); // Append the entire string
4886 else
4887 len = value_len; // Append only "value_len" characters
4888
4889 if (ga_grow(&redir_ga, len) == OK)
4890 {
4891 mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
4892 redir_ga.ga_len += len;
4893 }
4894 else
4895 var_redir_stop();
4896}
4897
4898/*
4899 * Stop redirecting command output to a variable.
4900 * Frees the allocated memory.
4901 */
4902 void
4903var_redir_stop(void)
4904{
4905 typval_T tv;
4906
4907 if (EVALCMD_BUSY)
4908 {
4909 redir_lval = NULL;
4910 return;
4911 }
4912
4913 if (redir_lval != NULL)
4914 {
4915 // If there was no error: assign the text to the variable.
4916 if (redir_endp != NULL)
4917 {
4918 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4919 tv.v_type = VAR_STRING;
4920 tv.vval.v_string = redir_ga.ga_data;
4921 // Call get_lval() again, if it's inside a Dict or List it may
4922 // have changed.
4923 redir_endp = get_lval(redir_varname, NULL, redir_lval,
4924 FALSE, FALSE, 0, FNE_CHECK_START);
4925 if (redir_endp != NULL && redir_lval->ll_name != NULL)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004926 set_var_lval(redir_lval, redir_endp, &tv, FALSE, 0,
Bram Moolenaarf785aa12021-02-11 21:19:34 +01004927 (char_u *)".", 0);
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004928 clear_lval(redir_lval);
4929 }
4930
4931 // free the collected output
4932 VIM_CLEAR(redir_ga.ga_data);
4933
4934 VIM_CLEAR(redir_lval);
4935 }
4936 VIM_CLEAR(redir_varname);
4937}
4938
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004939/*
Bram Moolenaar2d1c57e2021-04-19 20:50:03 +02004940 * Get the collected redirected text and clear redir_ga.
4941 */
4942 char_u *
4943get_clear_redir_ga(void)
4944{
4945 char_u *res;
4946
4947 ga_append(&redir_ga, NUL); // Append the trailing NUL.
4948 res = redir_ga.ga_data;
4949 redir_ga.ga_data = NULL;
4950 return res;
4951}
4952
4953/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004954 * "gettabvar()" function
4955 */
4956 void
4957f_gettabvar(typval_T *argvars, typval_T *rettv)
4958{
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004959 char_u *varname;
LemonBoy47d4e312022-05-04 18:12:55 +01004960 tabpage_T *tp;
4961 win_T *win = NULL;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004962
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004963 if (in_vim9script()
4964 && (check_for_number_arg(argvars, 0) == FAIL
4965 || check_for_string_arg(argvars, 1) == FAIL))
4966 return;
4967
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004968 varname = tv_get_string_chk(&argvars[1]);
4969 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
LemonBoy47d4e312022-05-04 18:12:55 +01004970 if (tp != NULL)
4971 win = tp == curtab || tp->tp_firstwin == NULL ? firstwin
4972 : tp->tp_firstwin;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004973
LemonBoy47d4e312022-05-04 18:12:55 +01004974 get_var_from(varname, rettv, &argvars[2], 't', tp, win, NULL);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004975}
4976
4977/*
4978 * "gettabwinvar()" function
4979 */
4980 void
4981f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4982{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004983 if (in_vim9script()
4984 && (check_for_number_arg(argvars, 0) == FAIL
4985 || check_for_number_arg(argvars, 1) == FAIL
4986 || check_for_string_arg(argvars, 2) == FAIL))
4987 return;
4988
Bram Moolenaar0522ba02019-08-27 22:48:30 +02004989 getwinvar(argvars, rettv, 1);
4990}
4991
4992/*
4993 * "getwinvar()" function
4994 */
4995 void
4996f_getwinvar(typval_T *argvars, typval_T *rettv)
4997{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02004998 if (in_vim9script()
4999 && (check_for_number_arg(argvars, 0) == FAIL
5000 || check_for_string_arg(argvars, 1) == FAIL))
5001 return;
5002
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005003 getwinvar(argvars, rettv, 0);
5004}
5005
5006/*
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005007 * "getbufvar()" function
5008 */
5009 void
5010f_getbufvar(typval_T *argvars, typval_T *rettv)
5011{
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005012 char_u *varname;
LemonBoy47d4e312022-05-04 18:12:55 +01005013 buf_T *buf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005014
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02005015 if (in_vim9script()
5016 && (check_for_buffer_arg(argvars, 0) == FAIL
5017 || check_for_string_arg(argvars, 1) == FAIL))
5018 return;
5019
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005020 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02005021 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005022
LemonBoy47d4e312022-05-04 18:12:55 +01005023 get_var_from(varname, rettv, &argvars[2], 'b', curtab, curwin, buf);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005024}
5025
5026/*
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005027 * "settabvar()" function
5028 */
5029 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01005030f_settabvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005031{
5032 tabpage_T *save_curtab;
5033 tabpage_T *tp;
zeertzjqb47fbb42024-02-12 22:50:26 +01005034 tabpage_T *save_lu_tp;
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005035 char_u *varname, *tabvarname;
5036 typval_T *varp;
5037
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005038 if (check_secure())
5039 return;
5040
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02005041 if (in_vim9script()
5042 && (check_for_number_arg(argvars, 0) == FAIL
5043 || check_for_string_arg(argvars, 1) == FAIL))
5044 return;
5045
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005046 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
5047 varname = tv_get_string_chk(&argvars[1]);
5048 varp = &argvars[2];
5049
zeertzjqea720ae2023-01-03 10:54:09 +00005050 if (varname == NULL || tp == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005051 return;
5052
5053 save_curtab = curtab;
zeertzjqb47fbb42024-02-12 22:50:26 +01005054 save_lu_tp = lastused_tabpage;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005055 goto_tabpage_tp(tp, FALSE, FALSE);
5056
5057 tabvarname = alloc(STRLEN(varname) + 3);
5058 if (tabvarname != NULL)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005059 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005060 STRCPY(tabvarname, "t:");
5061 STRCPY(tabvarname + 2, varname);
5062 set_var(tabvarname, varp, TRUE);
5063 vim_free(tabvarname);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005064 }
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005065
zeertzjqb47fbb42024-02-12 22:50:26 +01005066 // Restore current tabpage and last accessed tabpage.
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005067 if (valid_tabpage(save_curtab))
zeertzjqb47fbb42024-02-12 22:50:26 +01005068 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005069 goto_tabpage_tp(save_curtab, FALSE, FALSE);
zeertzjqb47fbb42024-02-12 22:50:26 +01005070 if (valid_tabpage(save_lu_tp))
5071 lastused_tabpage = save_lu_tp;
5072 }
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005073}
5074
5075/*
5076 * "settabwinvar()" function
5077 */
5078 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01005079f_settabwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005080{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02005081 if (in_vim9script()
5082 && (check_for_number_arg(argvars, 0) == FAIL
5083 || check_for_number_arg(argvars, 1) == FAIL
5084 || check_for_string_arg(argvars, 2) == FAIL))
5085 return;
5086
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01005087 setwinvar(argvars, 1);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005088}
5089
5090/*
5091 * "setwinvar()" function
5092 */
5093 void
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01005094f_setwinvar(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005095{
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02005096 if (in_vim9script()
5097 && (check_for_number_arg(argvars, 0) == FAIL
5098 || check_for_string_arg(argvars, 1) == FAIL))
5099 return;
5100
Bram Moolenaar3d8a5132020-01-04 16:13:49 +01005101 setwinvar(argvars, 0);
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005102}
5103
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005104/*
5105 * "setbufvar()" function
5106 */
5107 void
5108f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
5109{
5110 buf_T *buf;
5111 char_u *varname, *bufvarname;
5112 typval_T *varp;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005113
5114 if (check_secure())
5115 return;
Yegappan Lakshmanan7973de32021-07-24 16:16:15 +02005116
5117 if (in_vim9script()
5118 && (check_for_buffer_arg(argvars, 0) == FAIL
5119 || check_for_string_arg(argvars, 1) == FAIL))
5120 return;
5121
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005122 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar6f84b6d2020-09-01 23:16:32 +02005123 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005124 varp = &argvars[2];
5125
zeertzjqea720ae2023-01-03 10:54:09 +00005126 if (buf == NULL || varname == NULL)
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005127 return;
5128
5129 if (*varname == '&')
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005130 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005131 aco_save_T aco;
Christian Brabandtac4cffc2024-01-16 17:22:38 +01005132 // safe the current window position, it could
5133 // change because of 'scrollbind' window-local
5134 // options
5135 linenr_T old_topline = curwin->w_topline;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005136
5137 // Set curbuf to be our buf, temporarily.
5138 aucmd_prepbuf(&aco, buf);
5139 if (curbuf == buf)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005140 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005141 // Only when it worked to set "curbuf".
5142 set_option_from_tv(varname + 1, varp);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005143
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005144 // reset notion of buffer
5145 aucmd_restbuf(&aco);
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005146 }
Christian Brabandtac4cffc2024-01-16 17:22:38 +01005147 curwin->w_topline = old_topline;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005148 }
5149 else
5150 {
5151 bufvarname = alloc(STRLEN(varname) + 3);
5152 if (bufvarname != NULL)
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005153 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005154 buf_T *save_curbuf = curbuf;
Bram Moolenaar86015452020-03-29 15:12:15 +02005155
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005156 curbuf = buf;
5157 STRCPY(bufvarname, "b:");
5158 STRCPY(bufvarname + 2, varname);
5159 set_var(bufvarname, varp, TRUE);
5160 vim_free(bufvarname);
5161 curbuf = save_curbuf;
Bram Moolenaar8d71b542019-08-30 15:46:30 +02005162 }
5163 }
5164}
5165
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005166/*
5167 * Get a callback from "arg". It can be a Funcref or a function name.
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005168 * When "arg" is zero "res.cb_name" is set to an empty string.
5169 * If "res.cb_name" is allocated then "res.cb_free_name" is set to TRUE.
5170 * "res.cb_name" is set to NULL for an invalid argument.
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005171 */
5172 callback_T
5173get_callback(typval_T *arg)
5174{
Bram Moolenaar14e579092020-03-07 16:59:25 +01005175 callback_T res;
5176 int r = OK;
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005177
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005178 CLEAR_FIELD(res);
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005179 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
5180 {
5181 res.cb_partial = arg->vval.v_partial;
5182 ++res.cb_partial->pt_refcount;
5183 res.cb_name = partial_name(res.cb_partial);
5184 }
5185 else
5186 {
Bram Moolenaar14e579092020-03-07 16:59:25 +01005187 if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL
Keith Thompson184f71c2024-01-04 21:19:04 +01005188 && SAFE_isdigit(*arg->vval.v_string))
Bram Moolenaar14e579092020-03-07 16:59:25 +01005189 r = FAIL;
5190 else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005191 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005192 res.cb_name = arg->vval.v_string;
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005193 if (arg->v_type == VAR_STRING)
5194 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005195 char_u *name = get_scriptlocal_funcname(arg->vval.v_string);
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005196 if (name != NULL)
5197 {
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00005198 res.cb_name = name;
5199 res.cb_free_name = TRUE;
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00005200 }
5201 }
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005202 func_ref(res.cb_name);
5203 }
5204 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005205 res.cb_name = (char_u *)"";
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005206 else
Bram Moolenaar14e579092020-03-07 16:59:25 +01005207 r = FAIL;
5208
5209 if (r == FAIL)
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005210 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00005211 emsg(_(e_invalid_callback_argument));
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005212 res.cb_name = NULL;
5213 }
5214 }
5215 return res;
5216}
5217
5218/*
5219 * Copy a callback into a typval_T.
5220 */
5221 void
5222put_callback(callback_T *cb, typval_T *tv)
5223{
5224 if (cb->cb_partial != NULL)
5225 {
5226 tv->v_type = VAR_PARTIAL;
5227 tv->vval.v_partial = cb->cb_partial;
5228 ++tv->vval.v_partial->pt_refcount;
5229 }
5230 else
5231 {
5232 tv->v_type = VAR_FUNC;
5233 tv->vval.v_string = vim_strsave(cb->cb_name);
5234 func_ref(cb->cb_name);
5235 }
5236}
5237
5238/*
5239 * Make a copy of "src" into "dest", allocating the function name if needed,
5240 * without incrementing the refcount.
5241 */
5242 void
5243set_callback(callback_T *dest, callback_T *src)
5244{
5245 if (src->cb_partial == NULL)
5246 {
5247 // just a function name, make a copy
5248 dest->cb_name = vim_strsave(src->cb_name);
5249 dest->cb_free_name = TRUE;
5250 }
5251 else
5252 {
5253 // cb_name is a pointer into cb_partial
5254 dest->cb_name = src->cb_name;
5255 dest->cb_free_name = FALSE;
5256 }
5257 dest->cb_partial = src->cb_partial;
5258}
5259
5260/*
Bram Moolenaard43906d2020-07-20 21:31:32 +02005261 * Copy callback from "src" to "dest", incrementing the refcounts.
5262 */
5263 void
5264copy_callback(callback_T *dest, callback_T *src)
5265{
5266 dest->cb_partial = src->cb_partial;
5267 if (dest->cb_partial != NULL)
5268 {
5269 dest->cb_name = src->cb_name;
5270 dest->cb_free_name = FALSE;
5271 ++dest->cb_partial->pt_refcount;
5272 }
5273 else
5274 {
5275 dest->cb_name = vim_strsave(src->cb_name);
5276 dest->cb_free_name = TRUE;
5277 func_ref(src->cb_name);
5278 }
5279}
5280
5281/*
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005282 * When a callback refers to an autoload import, change the function name to
5283 * the "path#name" form. Uses the current script context.
5284 * Only works when the name is allocated.
5285 */
5286 void
5287expand_autload_callback(callback_T *cb)
5288{
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005289 char_u *name;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005290 char_u *p;
5291 imported_T *import;
5292
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005293 if (!in_vim9script() || cb->cb_name == NULL
5294 || (!cb->cb_free_name
5295 && (cb->cb_partial == NULL || cb->cb_partial->pt_name == NULL)))
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005296 return;
Bram Moolenaar3e93a2b2022-01-24 21:28:01 +00005297 if (cb->cb_partial != NULL)
5298 name = cb->cb_partial->pt_name;
5299 else
5300 name = cb->cb_name;
5301 p = vim_strchr(name, '.');
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005302 if (p == NULL)
5303 return;
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005304
Bram Moolenaar4b1d9632022-02-13 21:51:08 +00005305 import = find_imported(name, p - name, FALSE);
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005306 if (import == NULL || !SCRIPT_ID_VALID(import->imp_sid))
5307 return;
5308
5309 scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
5310 if (si->sn_autoload_prefix == NULL)
5311 return;
5312
5313 char_u *newname = concat_str(si->sn_autoload_prefix, p + 1);
5314 if (newname == NULL)
5315 return;
5316
5317 if (cb->cb_partial != NULL)
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005318 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +00005319 if (cb->cb_name == cb->cb_partial->pt_name)
5320 cb->cb_name = newname;
5321 vim_free(cb->cb_partial->pt_name);
5322 cb->cb_partial->pt_name = newname;
5323 }
5324 else
5325 {
5326 vim_free(cb->cb_name);
5327 cb->cb_name = newname;
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00005328 }
5329}
5330
5331/*
Bram Moolenaaraf7645d2019-09-05 22:33:28 +02005332 * Unref/free "callback" returned by get_callback() or set_callback().
5333 */
5334 void
5335free_callback(callback_T *callback)
5336{
5337 if (callback->cb_partial != NULL)
5338 {
5339 partial_unref(callback->cb_partial);
5340 callback->cb_partial = NULL;
5341 }
5342 else if (callback->cb_name != NULL)
5343 func_unref(callback->cb_name);
5344 if (callback->cb_free_name)
5345 {
5346 vim_free(callback->cb_name);
5347 callback->cb_free_name = FALSE;
5348 }
5349 callback->cb_name = NULL;
5350}
5351
Bram Moolenaar0522ba02019-08-27 22:48:30 +02005352#endif // FEAT_EVAL