1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * evalfunc.c: Builtin functions
12  */
13 #define USING_FLOAT_STUFF
14 
15 #include "vim.h"
16 
17 #if defined(FEAT_EVAL) || defined(PROTO)
18 
19 #ifdef VMS
20 # include <float.h>
21 #endif
22 
23 static void f_and(typval_T *argvars, typval_T *rettv);
24 #ifdef FEAT_BEVAL
25 static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
26 static void f_balloon_show(typval_T *argvars, typval_T *rettv);
27 # if defined(FEAT_BEVAL_TERM)
28 static void f_balloon_split(typval_T *argvars, typval_T *rettv);
29 # endif
30 #endif
31 static void f_byte2line(typval_T *argvars, typval_T *rettv);
32 static void f_call(typval_T *argvars, typval_T *rettv);
33 static void f_changenr(typval_T *argvars, typval_T *rettv);
34 static void f_char2nr(typval_T *argvars, typval_T *rettv);
35 static void f_charcol(typval_T *argvars, typval_T *rettv);
36 static void f_col(typval_T *argvars, typval_T *rettv);
37 static void f_confirm(typval_T *argvars, typval_T *rettv);
38 static void f_copy(typval_T *argvars, typval_T *rettv);
39 static void f_cursor(typval_T *argsvars, typval_T *rettv);
40 #ifdef MSWIN
41 static void f_debugbreak(typval_T *argvars, typval_T *rettv);
42 #endif
43 static void f_deepcopy(typval_T *argvars, typval_T *rettv);
44 static void f_did_filetype(typval_T *argvars, typval_T *rettv);
45 static void f_echoraw(typval_T *argvars, typval_T *rettv);
46 static void f_empty(typval_T *argvars, typval_T *rettv);
47 static void f_environ(typval_T *argvars, typval_T *rettv);
48 static void f_escape(typval_T *argvars, typval_T *rettv);
49 static void f_eval(typval_T *argvars, typval_T *rettv);
50 static void f_eventhandler(typval_T *argvars, typval_T *rettv);
51 static void f_execute(typval_T *argvars, typval_T *rettv);
52 static void f_exists_compiled(typval_T *argvars, typval_T *rettv);
53 static void f_expand(typval_T *argvars, typval_T *rettv);
54 static void f_expandcmd(typval_T *argvars, typval_T *rettv);
55 static void f_feedkeys(typval_T *argvars, typval_T *rettv);
56 static void f_fnameescape(typval_T *argvars, typval_T *rettv);
57 static void f_foreground(typval_T *argvars, typval_T *rettv);
58 static void f_funcref(typval_T *argvars, typval_T *rettv);
59 static void f_function(typval_T *argvars, typval_T *rettv);
60 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
61 static void f_get(typval_T *argvars, typval_T *rettv);
62 static void f_getchangelist(typval_T *argvars, typval_T *rettv);
63 static void f_getcharpos(typval_T *argvars, typval_T *rettv);
64 static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
65 static void f_getenv(typval_T *argvars, typval_T *rettv);
66 static void f_getfontname(typval_T *argvars, typval_T *rettv);
67 static void f_getjumplist(typval_T *argvars, typval_T *rettv);
68 static void f_getpid(typval_T *argvars, typval_T *rettv);
69 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
70 static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv);
71 static void f_getpos(typval_T *argvars, typval_T *rettv);
72 static void f_getreg(typval_T *argvars, typval_T *rettv);
73 static void f_getreginfo(typval_T *argvars, typval_T *rettv);
74 static void f_getregtype(typval_T *argvars, typval_T *rettv);
75 static void f_gettagstack(typval_T *argvars, typval_T *rettv);
76 static void f_gettext(typval_T *argvars, typval_T *rettv);
77 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
78 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
79 static void f_hlID(typval_T *argvars, typval_T *rettv);
80 static void f_hlexists(typval_T *argvars, typval_T *rettv);
81 static void f_hostname(typval_T *argvars, typval_T *rettv);
82 static void f_index(typval_T *argvars, typval_T *rettv);
83 static void f_input(typval_T *argvars, typval_T *rettv);
84 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
85 static void f_inputlist(typval_T *argvars, typval_T *rettv);
86 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
87 static void f_inputsave(typval_T *argvars, typval_T *rettv);
88 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
89 static void f_interrupt(typval_T *argvars, typval_T *rettv);
90 static void f_invert(typval_T *argvars, typval_T *rettv);
91 static void f_islocked(typval_T *argvars, typval_T *rettv);
92 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
93 static void f_len(typval_T *argvars, typval_T *rettv);
94 static void f_libcall(typval_T *argvars, typval_T *rettv);
95 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
96 static void f_line(typval_T *argvars, typval_T *rettv);
97 static void f_line2byte(typval_T *argvars, typval_T *rettv);
98 #ifdef FEAT_LUA
99 static void f_luaeval(typval_T *argvars, typval_T *rettv);
100 #endif
101 static void f_match(typval_T *argvars, typval_T *rettv);
102 static void f_matchend(typval_T *argvars, typval_T *rettv);
103 static void f_matchlist(typval_T *argvars, typval_T *rettv);
104 static void f_matchstr(typval_T *argvars, typval_T *rettv);
105 static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
106 static void f_max(typval_T *argvars, typval_T *rettv);
107 static void f_min(typval_T *argvars, typval_T *rettv);
108 #ifdef FEAT_MZSCHEME
109 static void f_mzeval(typval_T *argvars, typval_T *rettv);
110 #endif
111 static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
112 static void f_nr2char(typval_T *argvars, typval_T *rettv);
113 static void f_or(typval_T *argvars, typval_T *rettv);
114 #ifdef FEAT_PERL
115 static void f_perleval(typval_T *argvars, typval_T *rettv);
116 #endif
117 static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
118 static void f_printf(typval_T *argvars, typval_T *rettv);
119 static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
120 static void f_pumvisible(typval_T *argvars, typval_T *rettv);
121 #ifdef FEAT_PYTHON3
122 static void f_py3eval(typval_T *argvars, typval_T *rettv);
123 #endif
124 #ifdef FEAT_PYTHON
125 static void f_pyeval(typval_T *argvars, typval_T *rettv);
126 #endif
127 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
128 static void f_pyxeval(typval_T *argvars, typval_T *rettv);
129 #endif
130 static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
131 static void f_rand(typval_T *argvars, typval_T *rettv);
132 static void f_range(typval_T *argvars, typval_T *rettv);
133 static void f_reg_executing(typval_T *argvars, typval_T *rettv);
134 static void f_reg_recording(typval_T *argvars, typval_T *rettv);
135 static void f_rename(typval_T *argvars, typval_T *rettv);
136 static void f_repeat(typval_T *argvars, typval_T *rettv);
137 #ifdef FEAT_RUBY
138 static void f_rubyeval(typval_T *argvars, typval_T *rettv);
139 #endif
140 static void f_screenattr(typval_T *argvars, typval_T *rettv);
141 static void f_screenchar(typval_T *argvars, typval_T *rettv);
142 static void f_screenchars(typval_T *argvars, typval_T *rettv);
143 static void f_screencol(typval_T *argvars, typval_T *rettv);
144 static void f_screenrow(typval_T *argvars, typval_T *rettv);
145 static void f_screenstring(typval_T *argvars, typval_T *rettv);
146 static void f_search(typval_T *argvars, typval_T *rettv);
147 static void f_searchdecl(typval_T *argvars, typval_T *rettv);
148 static void f_searchpair(typval_T *argvars, typval_T *rettv);
149 static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
150 static void f_searchpos(typval_T *argvars, typval_T *rettv);
151 static void f_setcharpos(typval_T *argvars, typval_T *rettv);
152 static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
153 static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv);
154 static void f_setenv(typval_T *argvars, typval_T *rettv);
155 static void f_setfperm(typval_T *argvars, typval_T *rettv);
156 static void f_setpos(typval_T *argvars, typval_T *rettv);
157 static void f_setreg(typval_T *argvars, typval_T *rettv);
158 static void f_settagstack(typval_T *argvars, typval_T *rettv);
159 #ifdef FEAT_CRYPT
160 static void f_sha256(typval_T *argvars, typval_T *rettv);
161 #endif
162 static void f_shellescape(typval_T *argvars, typval_T *rettv);
163 static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
164 static void f_soundfold(typval_T *argvars, typval_T *rettv);
165 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
166 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
167 static void f_split(typval_T *argvars, typval_T *rettv);
168 static void f_srand(typval_T *argvars, typval_T *rettv);
169 static void f_submatch(typval_T *argvars, typval_T *rettv);
170 static void f_substitute(typval_T *argvars, typval_T *rettv);
171 static void f_swapinfo(typval_T *argvars, typval_T *rettv);
172 static void f_swapname(typval_T *argvars, typval_T *rettv);
173 static void f_synID(typval_T *argvars, typval_T *rettv);
174 static void f_synIDattr(typval_T *argvars, typval_T *rettv);
175 static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
176 static void f_synstack(typval_T *argvars, typval_T *rettv);
177 static void f_synconcealed(typval_T *argvars, typval_T *rettv);
178 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
179 static void f_taglist(typval_T *argvars, typval_T *rettv);
180 static void f_tagfiles(typval_T *argvars, typval_T *rettv);
181 static void f_type(typval_T *argvars, typval_T *rettv);
182 static void f_virtcol(typval_T *argvars, typval_T *rettv);
183 static void f_visualmode(typval_T *argvars, typval_T *rettv);
184 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
185 static void f_windowsversion(typval_T *argvars, typval_T *rettv);
186 static void f_wordcount(typval_T *argvars, typval_T *rettv);
187 static void f_xor(typval_T *argvars, typval_T *rettv);
188 
189 
190 /*
191  * Functions that check the argument type of a builtin function.
192  * Each function returns FAIL and gives an error message if the type is wrong.
193  */
194 
195 // Context passed to an arg_ function.
196 typedef struct {
197     int		arg_count;	// actual argument count
198     type_T	**arg_types;	// list of argument types
199     int		arg_idx;	// current argument index (first arg is zero)
200     cctx_T	*arg_cctx;
201 } argcontext_T;
202 
203 // A function to check one argument type.  The first argument is the type to
204 // check.  If needed, other argument types can be obtained with the context.
205 // E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
206 typedef int (*argcheck_T)(type_T *, argcontext_T *);
207 
208 /*
209  * Call need_type() to check an argument type.
210  */
211     static int
check_arg_type(type_T * expected,type_T * actual,argcontext_T * context)212 check_arg_type(
213 	type_T		*expected,
214 	type_T		*actual,
215 	argcontext_T	*context)
216 {
217     // TODO: would be useful to know if "actual" is a constant and pass it to
218     // need_type() to get a compile time error if possible.
219     return need_type(actual, expected,
220 	    context->arg_idx - context->arg_count, context->arg_idx + 1,
221 	    context->arg_cctx, FALSE, FALSE);
222 }
223 
224 /*
225  * Check "type" is a float or a number.
226  */
227     static int
arg_float_or_nr(type_T * type,argcontext_T * context)228 arg_float_or_nr(type_T *type, argcontext_T *context)
229 {
230     if (type->tt_type == VAR_ANY
231 		  || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER)
232 	return OK;
233     arg_type_mismatch(&t_number, type, context->arg_idx + 1);
234     return FAIL;
235 }
236 
237 /*
238  * Check "type" is a number.
239  */
240     static int
arg_number(type_T * type,argcontext_T * context)241 arg_number(type_T *type, argcontext_T *context)
242 {
243     return check_arg_type(&t_number, type, context);
244 }
245 
246 /*
247  * Check "type" is a dict of 'any'.
248  */
249     static int
arg_dict_any(type_T * type,argcontext_T * context)250 arg_dict_any(type_T *type, argcontext_T *context)
251 {
252     return check_arg_type(&t_dict_any, type, context);
253 }
254 
255 /*
256  * Check "type" is a list of 'any'.
257  */
258     static int
arg_list_any(type_T * type,argcontext_T * context)259 arg_list_any(type_T *type, argcontext_T *context)
260 {
261     return check_arg_type(&t_list_any, type, context);
262 }
263 
264 /*
265  * Check "type" is a list of numbers.
266  */
267     static int
arg_list_number(type_T * type,argcontext_T * context)268 arg_list_number(type_T *type, argcontext_T *context)
269 {
270     return check_arg_type(&t_list_number, type, context);
271 }
272 
273 /*
274  * Check "type" is a list of strings.
275  */
276     static int
arg_list_string(type_T * type,argcontext_T * context)277 arg_list_string(type_T *type, argcontext_T *context)
278 {
279     return check_arg_type(&t_list_string, type, context);
280 }
281 
282 /*
283  * Check "type" is a string.
284  */
285     static int
arg_string(type_T * type,argcontext_T * context)286 arg_string(type_T *type, argcontext_T *context)
287 {
288     return check_arg_type(&t_string, type, context);
289 }
290 
291 /*
292  * Check "type" is a blob
293  */
294     static int
arg_blob(type_T * type,argcontext_T * context)295 arg_blob(type_T *type, argcontext_T *context)
296 {
297     return check_arg_type(&t_blob, type, context);
298 }
299 
300 /*
301  * Check "type" is a bool or number 0 or 1.
302  */
303     static int
arg_bool(type_T * type,argcontext_T * context)304 arg_bool(type_T *type, argcontext_T *context)
305 {
306     return check_arg_type(&t_bool, type, context);
307 }
308 
309 /*
310  * Check "type" is a list of 'any' or a blob.
311  */
312     static int
arg_list_or_blob(type_T * type,argcontext_T * context)313 arg_list_or_blob(type_T *type, argcontext_T *context)
314 {
315     if (type->tt_type == VAR_ANY
316 		     || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB)
317 	return OK;
318     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
319     return FAIL;
320 }
321 
322 /*
323  * Check "type" is a string or a number
324  */
325     static int
arg_string_or_nr(type_T * type,argcontext_T * context)326 arg_string_or_nr(type_T *type, argcontext_T *context)
327 {
328     if (type->tt_type == VAR_ANY
329 	    || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
330 	return OK;
331     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
332     return FAIL;
333 }
334 
335 /*
336  * Check "type" is a buffer (string or a number)
337  */
338     static int
arg_buffer(type_T * type,argcontext_T * context)339 arg_buffer(type_T *type, argcontext_T *context)
340 {
341     if (type->tt_type == VAR_ANY
342 	    || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
343 	return OK;
344     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
345     return FAIL;
346 }
347 
348 /*
349  * Check "type" is a buffer or a dict of any
350  */
351     static int
arg_buffer_or_dict_any(type_T * type,argcontext_T * context)352 arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
353 {
354     if (type->tt_type == VAR_ANY
355 	    || type->tt_type == VAR_STRING
356 	    || type->tt_type == VAR_NUMBER
357 	    || type->tt_type == VAR_DICT)
358 	return OK;
359     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
360     return FAIL;
361 }
362 
363 /*
364  * Check "type" is a line (string or a number)
365  */
366     static int
arg_lnum(type_T * type,argcontext_T * context)367 arg_lnum(type_T *type, argcontext_T *context)
368 {
369     if (type->tt_type == VAR_ANY
370 	    || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
371 	return OK;
372     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
373     return FAIL;
374 }
375 
376 /*
377  * Check "type" is a string or a list of strings.
378  */
379     static int
arg_string_or_list_string(type_T * type,argcontext_T * context)380 arg_string_or_list_string(type_T *type, argcontext_T *context)
381 {
382     if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING)
383 	return OK;
384     if (type->tt_type != VAR_LIST)
385     {
386 	arg_type_mismatch(&t_string, type, context->arg_idx + 1);
387 	return FAIL;
388     }
389     if (type->tt_member->tt_type == VAR_ANY
390 		    || type->tt_member->tt_type == VAR_STRING)
391 	return OK;
392 
393     arg_type_mismatch(&t_list_string, type, context->arg_idx + 1);
394     return FAIL;
395 }
396 
397 /*
398  * Check "type" is a string or a list of 'any'
399  */
400     static int
arg_string_or_list_any(type_T * type,argcontext_T * context)401 arg_string_or_list_any(type_T *type, argcontext_T *context)
402 {
403     if (type->tt_type == VAR_ANY
404 	    || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST)
405 	return OK;
406     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
407     return FAIL;
408 }
409 
410 /*
411  * Check "type" is a string or a blob
412  */
413     static int
arg_string_or_blob(type_T * type,argcontext_T * context)414 arg_string_or_blob(type_T *type, argcontext_T *context)
415 {
416     if (type->tt_type == VAR_ANY
417 	    || type->tt_type == VAR_STRING || type->tt_type == VAR_BLOB)
418 	return OK;
419     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
420     return FAIL;
421 }
422 
423 /*
424  * Check "type" is a list of 'any' or a dict of 'any'.
425  */
426     static int
arg_list_or_dict(type_T * type,argcontext_T * context)427 arg_list_or_dict(type_T *type, argcontext_T *context)
428 {
429     if (type->tt_type == VAR_ANY
430 		     || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
431 	return OK;
432     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
433     return FAIL;
434 }
435 
436 /*
437  * Check "type" is a list of 'any' or a dict of 'any' or a blob.
438  */
439     static int
arg_list_or_dict_or_blob(type_T * type,argcontext_T * context)440 arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
441 {
442     if (type->tt_type == VAR_ANY
443 		     || type->tt_type == VAR_LIST
444 		     || type->tt_type == VAR_DICT
445 		     || type->tt_type == VAR_BLOB)
446 	return OK;
447     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
448     return FAIL;
449 }
450 
451 /*
452  * Check "type" is a job.
453  */
454     static int
arg_job(type_T * type,argcontext_T * context)455 arg_job(type_T *type, argcontext_T *context)
456 {
457     return check_arg_type(&t_job, type, context);
458 }
459 
460 /*
461  * Check "type" is a channel or a job.
462  */
463     static int
arg_chan_or_job(type_T * type,argcontext_T * context)464 arg_chan_or_job(type_T *type, argcontext_T *context)
465 {
466     if (type->tt_type == VAR_ANY
467 	    || type->tt_type == VAR_CHANNEL
468 	    || type->tt_type == VAR_JOB)
469 	return OK;
470     arg_type_mismatch(&t_channel, type, context->arg_idx + 1);
471     return FAIL;
472 }
473 
474 /*
475  * Check "type" is the same type as the previous argument.
476  * Must not be used for the first argcheck_T entry.
477  */
478     static int
arg_same_as_prev(type_T * type,argcontext_T * context)479 arg_same_as_prev(type_T *type, argcontext_T *context)
480 {
481     type_T *prev_type = context->arg_types[context->arg_idx - 1];
482 
483     return check_arg_type(prev_type, type, context);
484 }
485 
486 /*
487  * Check "type" is the same basic type as the previous argument, checks list or
488  * dict vs other type, but not member type.
489  * Must not be used for the first argcheck_T entry.
490  */
491     static int
arg_same_struct_as_prev(type_T * type,argcontext_T * context)492 arg_same_struct_as_prev(type_T *type, argcontext_T *context)
493 {
494     type_T *prev_type = context->arg_types[context->arg_idx - 1];
495 
496     if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
497 	return check_arg_type(prev_type, type, context);
498     return OK;
499 }
500 
501 /*
502  * Check "type" is an item of the list or blob of the previous arg.
503  * Must not be used for the first argcheck_T entry.
504  */
505     static int
arg_item_of_prev(type_T * type,argcontext_T * context)506 arg_item_of_prev(type_T *type, argcontext_T *context)
507 {
508     type_T *prev_type = context->arg_types[context->arg_idx - 1];
509     type_T *expected;
510 
511     if (prev_type->tt_type == VAR_LIST)
512 	expected = prev_type->tt_member;
513     else if (prev_type->tt_type == VAR_BLOB)
514 	expected = &t_number;
515     else
516 	// probably VAR_ANY, can't check
517 	return OK;
518 
519     return check_arg_type(expected, type, context);
520 }
521 
522 /*
523  * Check "type" is a string or a number or a list
524  */
525     static int
arg_str_or_nr_or_list(type_T * type,argcontext_T * context)526 arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
527 {
528     if (type->tt_type == VAR_ANY
529 		|| type->tt_type == VAR_STRING
530 		|| type->tt_type == VAR_NUMBER
531 		|| type->tt_type == VAR_LIST)
532 	return OK;
533     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
534     return FAIL;
535 }
536 
537 /*
538  * Check "type" is a dict of 'any' or a string
539  */
540     static int
arg_dict_any_or_string(type_T * type,argcontext_T * context)541 arg_dict_any_or_string(type_T *type, argcontext_T *context)
542 {
543     if (type->tt_type == VAR_ANY
544 		|| type->tt_type == VAR_DICT
545 		|| type->tt_type == VAR_STRING)
546 	return OK;
547     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
548     return FAIL;
549 }
550 
551 /*
552  * Check "type" which is the third argument of extend() (number or string or
553  * any)
554  */
555     static int
arg_extend3(type_T * type,argcontext_T * context)556 arg_extend3(type_T *type, argcontext_T *context)
557 {
558     type_T *first_type = context->arg_types[context->arg_idx - 2];
559 
560     if (first_type->tt_type == VAR_LIST)
561 	return arg_number(type, context);
562     if (first_type->tt_type == VAR_DICT)
563 	return arg_string(type, context);
564     return OK;
565 }
566 
567 /*
568  * Check "type" which is the first argument of get() (blob or list or dict or
569  * funcref)
570  */
571     static int
arg_get1(type_T * type,argcontext_T * context)572 arg_get1(type_T *type, argcontext_T *context)
573 {
574     if (type->tt_type == VAR_ANY
575 	    || type->tt_type == VAR_BLOB
576 	    || type->tt_type == VAR_LIST
577 	    || type->tt_type == VAR_DICT
578 	    || type->tt_type == VAR_FUNC
579 	    || type->tt_type == VAR_PARTIAL)
580 	return OK;
581 
582     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
583     return FAIL;
584 }
585 
586 /*
587  * Check "type" which is the first argument of len() (number or string or
588  * blob or list or dict)
589  */
590     static int
arg_len1(type_T * type,argcontext_T * context)591 arg_len1(type_T *type, argcontext_T *context)
592 {
593     if (type->tt_type == VAR_ANY
594 	    || type->tt_type == VAR_STRING
595 	    || type->tt_type == VAR_NUMBER
596 	    || type->tt_type == VAR_BLOB
597 	    || type->tt_type == VAR_LIST
598 	    || type->tt_type == VAR_DICT)
599 	return OK;
600 
601     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
602     return FAIL;
603 }
604 
605 /*
606  * Check "type" which is the second argument of remove() (number or string or
607  * any)
608  */
609     static int
arg_remove2(type_T * type,argcontext_T * context)610 arg_remove2(type_T *type, argcontext_T *context)
611 {
612     type_T *first_type = context->arg_types[context->arg_idx - 1];
613 
614     if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB)
615 	return arg_number(type, context);
616     if (first_type->tt_type == VAR_DICT)
617 	return arg_string_or_nr(type, context);
618     return OK;
619 }
620 
621 /*
622  * Check "type" which is the first argument of repeat() (string or number or
623  * list or any)
624  */
625     static int
arg_repeat1(type_T * type,argcontext_T * context)626 arg_repeat1(type_T *type, argcontext_T *context)
627 {
628     if (type->tt_type == VAR_ANY
629 	    || type->tt_type == VAR_STRING
630 	    || type->tt_type == VAR_NUMBER
631 	    || type->tt_type == VAR_LIST)
632 	return OK;
633 
634     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
635     return FAIL;
636 }
637 
638 /*
639  * Check "type" which is the first argument of slice() (list or blob or string
640  * or any)
641  */
642     static int
arg_slice1(type_T * type,argcontext_T * context)643 arg_slice1(type_T *type, argcontext_T *context)
644 {
645     if (type->tt_type == VAR_ANY
646 	    || type->tt_type == VAR_LIST
647 	    || type->tt_type == VAR_BLOB
648 	    || type->tt_type == VAR_STRING)
649 	return OK;
650 
651     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
652     return FAIL;
653 }
654 
655 /*
656  * Check "type" which is the first argument of count() (string or list or dict
657  * or any)
658  */
659     static int
arg_count1(type_T * type,argcontext_T * context)660 arg_count1(type_T *type, argcontext_T *context)
661 {
662     if (type->tt_type == VAR_ANY
663 	    || type->tt_type == VAR_STRING
664 	    || type->tt_type == VAR_LIST
665 	    || type->tt_type == VAR_DICT)
666 	return OK;
667 
668     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
669     return FAIL;
670 }
671 
672 /*
673  * Check "type" which is the first argument of cursor() (number or string or
674  * list or any)
675  */
676     static int
arg_cursor1(type_T * type,argcontext_T * context)677 arg_cursor1(type_T *type, argcontext_T *context)
678 {
679     if (type->tt_type == VAR_ANY
680 	    || type->tt_type == VAR_NUMBER
681 	    || type->tt_type == VAR_STRING
682 	    || type->tt_type == VAR_LIST)
683 	return OK;
684 
685     arg_type_mismatch(&t_number, type, context->arg_idx + 1);
686     return FAIL;
687 }
688 
689 /*
690  * Lists of functions that check the argument types of a builtin function.
691  */
692 static argcheck_T arg1_blob[] = {arg_blob};
693 static argcheck_T arg1_bool[] = {arg_bool};
694 static argcheck_T arg1_buffer[] = {arg_buffer};
695 static argcheck_T arg1_buffer_or_dict_any[] = {arg_buffer_or_dict_any};
696 static argcheck_T arg1_chan_or_job[] = {arg_chan_or_job};
697 static argcheck_T arg1_dict_any[] = {arg_dict_any};
698 static argcheck_T arg1_dict_or_string[] = {arg_dict_any_or_string};
699 static argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
700 static argcheck_T arg1_job[] = {arg_job};
701 static argcheck_T arg1_list_any[] = {arg_list_any};
702 static argcheck_T arg1_list_number[] = {arg_list_number};
703 static argcheck_T arg1_list_or_blob[] = {arg_list_or_blob};
704 static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict};
705 static argcheck_T arg1_list_string[] = {arg_list_string};
706 static argcheck_T arg1_lnum[] = {arg_lnum};
707 static argcheck_T arg1_number[] = {arg_number};
708 static argcheck_T arg1_string[] = {arg_string};
709 static argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any};
710 static argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string};
711 static argcheck_T arg1_string_or_nr[] = {arg_string_or_nr};
712 static argcheck_T arg2_any_buffer[] = {NULL, arg_buffer};
713 static argcheck_T arg2_buffer_any[] = {arg_buffer, NULL};
714 static argcheck_T arg2_buffer_bool[] = {arg_buffer, arg_bool};
715 static argcheck_T arg2_buffer_list_any[] = {arg_buffer, arg_list_any};
716 static argcheck_T arg2_buffer_lnum[] = {arg_buffer, arg_lnum};
717 static argcheck_T arg2_buffer_number[] = {arg_buffer, arg_number};
718 static argcheck_T arg2_buffer_string[] = {arg_buffer, arg_string};
719 static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any};
720 static argcheck_T arg2_chan_or_job_string[] = {arg_chan_or_job, arg_string};
721 static argcheck_T arg2_dict_any_list_any[] = {arg_dict_any, arg_list_any};
722 static argcheck_T arg2_dict_any_string_or_nr[] = {arg_dict_any, arg_string_or_nr};
723 static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string};
724 static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr};
725 static argcheck_T arg2_job_dict[] = {arg_job, arg_dict_any};
726 static argcheck_T arg2_job_string_or_number[] = {arg_job, arg_string_or_nr};
727 static argcheck_T arg2_list_any_number[] = {arg_list_any, arg_number};
728 static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string};
729 static argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number};
730 static argcheck_T arg2_list_number_bool[] = {arg_list_number, arg_bool};
731 static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
732 static argcheck_T arg2_lnum[] = {arg_lnum, arg_lnum};
733 static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number};
734 static argcheck_T arg2_number[] = {arg_number, arg_number};
735 static argcheck_T arg2_number_any[] = {arg_number, NULL};
736 static argcheck_T arg2_number_bool[] = {arg_number, arg_bool};
737 static argcheck_T arg2_number_dict_any[] = {arg_number, arg_dict_any};
738 static argcheck_T arg2_number_list[] = {arg_number, arg_list_any};
739 static argcheck_T arg2_number_string[] = {arg_number, arg_string};
740 static argcheck_T arg2_number_string_or_list[] = {arg_number, arg_string_or_list_any};
741 static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any};
742 static argcheck_T arg2_string[] = {arg_string, arg_string};
743 static argcheck_T arg2_string_any[] = {arg_string, NULL};
744 static argcheck_T arg2_string_bool[] = {arg_string, arg_bool};
745 static argcheck_T arg2_string_chan_or_job[] = {arg_string, arg_chan_or_job};
746 static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any};
747 static argcheck_T arg2_string_list_number[] = {arg_string, arg_list_number};
748 static argcheck_T arg2_string_number[] = {arg_string, arg_number};
749 static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any};
750 static argcheck_T arg2_string_string_or_number[] = {arg_string, arg_string_or_nr};
751 static argcheck_T arg3_any_list_dict[] = {NULL, arg_list_any, arg_dict_any};
752 static argcheck_T arg3_buffer_lnum_lnum[] = {arg_buffer, arg_lnum, arg_lnum};
753 static argcheck_T arg3_buffer_number_number[] = {arg_buffer, arg_number, arg_number};
754 static argcheck_T arg3_buffer_string_any[] = {arg_buffer, arg_string, NULL};
755 static argcheck_T arg3_buffer_string_dict[] = {arg_buffer, arg_string, arg_dict_any};
756 static argcheck_T arg3_dict_number_number[] = {arg_dict_any, arg_number, arg_number};
757 static argcheck_T arg3_list_string_dict[] = {arg_list_any, arg_string, arg_dict_any};
758 static argcheck_T arg3_lnum_number_bool[] = {arg_lnum, arg_number, arg_bool};
759 static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number};
760 static argcheck_T arg3_number_any_dict[] = {arg_number, NULL, arg_dict_any};
761 static argcheck_T arg3_number_number_dict[] = {arg_number, arg_number, arg_dict_any};
762 static argcheck_T arg3_number_string_any[] = {arg_number, arg_string, NULL};
763 static argcheck_T arg3_number_string_buffer[] = {arg_number, arg_string, arg_buffer};
764 static argcheck_T arg3_number_string_string[] = {arg_number, arg_string, arg_string};
765 static argcheck_T arg3_string[] = {arg_string, arg_string, arg_string};
766 static argcheck_T arg3_string_any_dict[] = {arg_string, NULL, arg_dict_any};
767 static argcheck_T arg3_string_any_string[] = {arg_string, NULL, arg_string};
768 static argcheck_T arg3_string_bool_bool[] = {arg_string, arg_bool, arg_bool};
769 static argcheck_T arg3_string_bool_dict[] = {arg_string, arg_bool, arg_dict_any};
770 static argcheck_T arg3_string_number_bool[] = {arg_string, arg_number, arg_bool};
771 static argcheck_T arg3_string_number_number[] = {arg_string, arg_number, arg_number};
772 static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, arg_bool};
773 static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, arg_dict_any};
774 static argcheck_T arg3_string_string_number[] = {arg_string, arg_string, arg_number};
775 static argcheck_T arg4_list_number_number_number[] = {arg_list_string, arg_number, arg_number, arg_number};
776 static argcheck_T arg4_number_number_string_any[] = {arg_number, arg_number, arg_string, NULL};
777 static argcheck_T arg4_string_string_any_string[] = {arg_string, arg_string, NULL, arg_string};
778 static argcheck_T arg4_string_string_number_string[] = {arg_string, arg_string, arg_number, arg_string};
779 static argcheck_T arg5_number[] = {arg_number, arg_number, arg_number, arg_number, arg_number};
780 /* Function specific argument types (not covered by the above) */
781 static argcheck_T arg15_assert_fails[] = {arg_string_or_nr, arg_string_or_list_any, NULL, arg_number, arg_string};
782 static argcheck_T arg34_assert_inrange[] = {arg_float_or_nr, arg_float_or_nr, arg_float_or_nr, arg_string};
783 static argcheck_T arg4_browse[] = {arg_bool, arg_string, arg_string, arg_string};
784 static argcheck_T arg23_chanexpr[] = {arg_chan_or_job, NULL, arg_dict_any};
785 static argcheck_T arg23_chanraw[] = {arg_chan_or_job, arg_string_or_blob, arg_dict_any};
786 static argcheck_T arg24_count[] = {arg_count1, NULL, arg_bool, arg_number};
787 static argcheck_T arg13_cursor[] = {arg_cursor1, arg_number, arg_number};
788 static argcheck_T arg12_deepcopy[] = {NULL, arg_bool};
789 static argcheck_T arg12_execute[] = {arg_string_or_list_string, arg_string};
790 static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
791 static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
792 static argcheck_T arg23_get[] = {arg_get1, arg_string_or_nr, NULL};
793 static argcheck_T arg14_glob[] = {arg_string, arg_bool, arg_bool, arg_bool};
794 static argcheck_T arg25_globpath[] = {arg_string, arg_string, arg_bool, arg_bool, arg_bool};
795 static argcheck_T arg24_index[] = {arg_list_or_blob, arg_item_of_prev, arg_number, arg_bool};
796 static argcheck_T arg23_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
797 static argcheck_T arg1_len[] = {arg_len1};
798 static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr};
799 static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool};
800 static argcheck_T arg2_mapfilter[] = {arg_list_or_dict_or_blob, NULL};
801 static argcheck_T arg25_matchadd[] = {arg_string, arg_string, arg_number, arg_number, arg_dict_any};
802 static argcheck_T arg25_matchaddpos[] = {arg_string, arg_list_any, arg_number, arg_number, arg_dict_any};
803 static argcheck_T arg119_printf[] = {arg_string_or_nr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
804 static argcheck_T arg23_reduce[] = {arg_list_or_blob, NULL, NULL};
805 static argcheck_T arg24_remote_expr[] = {arg_string, arg_string, arg_string, arg_number};
806 static argcheck_T arg23_remove[] = {arg_list_or_dict_or_blob, arg_remove2, arg_number};
807 static argcheck_T arg2_repeat[] = {arg_repeat1, arg_number};
808 static argcheck_T arg15_search[] = {arg_string, arg_string, arg_number, arg_number, NULL};
809 static argcheck_T arg37_searchpair[] = {arg_string, arg_string, arg_string, arg_string, NULL, arg_number, arg_number};
810 static argcheck_T arg3_setbufline[] = {arg_buffer, arg_lnum, arg_str_or_nr_or_list};
811 static argcheck_T arg2_setline[] = {arg_lnum, NULL};
812 static argcheck_T arg24_setloclist[] = {arg_number, arg_list_any, arg_string, arg_dict_any};
813 static argcheck_T arg13_setqflist[] = {arg_list_any, arg_string, arg_dict_any};
814 static argcheck_T arg23_settagstack[] = {arg_number, arg_dict_any, arg_string};
815 static argcheck_T arg02_sign_getplaced[] = {arg_buffer, arg_dict_any};
816 static argcheck_T arg45_sign_place[] = {arg_number, arg_string, arg_string, arg_buffer, arg_dict_any};
817 static argcheck_T arg23_slice[] = {arg_slice1, arg_number, arg_number};
818 static argcheck_T arg13_sortuniq[] = {arg_list_any, NULL, arg_dict_any};
819 static argcheck_T arg24_strpart[] = {arg_string, arg_number, arg_number, arg_bool};
820 static argcheck_T arg12_system[] = {arg_string, arg_str_or_nr_or_list};
821 static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string};
822 static argcheck_T arg23_writefile[] = {arg_list_or_blob, arg_string, arg_string};
823 static argcheck_T arg24_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number};
824 
825 
826 /*
827  * Functions that return the return type of a builtin function.
828  * Note that "argtypes" is NULL if "argcount" is zero.
829  */
830     static type_T *
ret_void(int argcount UNUSED,type_T ** argtypes UNUSED)831 ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
832 {
833     return &t_void;
834 }
835     static type_T *
ret_any(int argcount UNUSED,type_T ** argtypes UNUSED)836 ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
837 {
838     return &t_any;
839 }
840     static type_T *
ret_bool(int argcount UNUSED,type_T ** argtypes UNUSED)841 ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
842 {
843     return &t_bool;
844 }
845     static type_T *
ret_number_bool(int argcount UNUSED,type_T ** argtypes UNUSED)846 ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED)
847 {
848     return &t_number_bool;
849 }
850     static type_T *
ret_number(int argcount UNUSED,type_T ** argtypes UNUSED)851 ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
852 {
853     return &t_number;
854 }
855     static type_T *
ret_float(int argcount UNUSED,type_T ** argtypes UNUSED)856 ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
857 {
858     return &t_float;
859 }
860     static type_T *
ret_string(int argcount UNUSED,type_T ** argtypes UNUSED)861 ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
862 {
863     return &t_string;
864 }
865     static type_T *
ret_list_any(int argcount UNUSED,type_T ** argtypes UNUSED)866 ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
867 {
868     return &t_list_any;
869 }
870     static type_T *
ret_list_number(int argcount UNUSED,type_T ** argtypes UNUSED)871 ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
872 {
873     return &t_list_number;
874 }
875     static type_T *
ret_list_string(int argcount UNUSED,type_T ** argtypes UNUSED)876 ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
877 {
878     return &t_list_string;
879 }
880     static type_T *
ret_list_dict_any(int argcount UNUSED,type_T ** argtypes UNUSED)881 ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
882 {
883     return &t_list_dict_any;
884 }
885     static type_T *
ret_list_items(int argcount UNUSED,type_T ** argtypes UNUSED)886 ret_list_items(int argcount UNUSED, type_T **argtypes UNUSED)
887 {
888     return &t_list_list_any;
889 }
890 
891     static type_T *
ret_list_string_items(int argcount UNUSED,type_T ** argtypes UNUSED)892 ret_list_string_items(int argcount UNUSED, type_T **argtypes UNUSED)
893 {
894     return &t_list_list_string;
895 }
896     static type_T *
ret_dict_any(int argcount UNUSED,type_T ** argtypes UNUSED)897 ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
898 {
899     return &t_dict_any;
900 }
901     static type_T *
ret_job_info(int argcount,type_T ** argtypes UNUSED)902 ret_job_info(int argcount, type_T **argtypes UNUSED)
903 {
904     if (argcount == 0)
905 	return &t_list_job;
906     return &t_dict_any;
907 }
908     static type_T *
ret_dict_number(int argcount UNUSED,type_T ** argtypes UNUSED)909 ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
910 {
911     return &t_dict_number;
912 }
913     static type_T *
ret_dict_string(int argcount UNUSED,type_T ** argtypes UNUSED)914 ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
915 {
916     return &t_dict_string;
917 }
918     static type_T *
ret_blob(int argcount UNUSED,type_T ** argtypes UNUSED)919 ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
920 {
921     return &t_blob;
922 }
923     static type_T *
ret_func_any(int argcount UNUSED,type_T ** argtypes UNUSED)924 ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
925 {
926     return &t_func_any;
927 }
928     static type_T *
ret_channel(int argcount UNUSED,type_T ** argtypes UNUSED)929 ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
930 {
931     return &t_channel;
932 }
933     static type_T *
ret_job(int argcount UNUSED,type_T ** argtypes UNUSED)934 ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
935 {
936     return &t_job;
937 }
938     static type_T *
ret_first_arg(int argcount,type_T ** argtypes)939 ret_first_arg(int argcount, type_T **argtypes)
940 {
941     if (argcount > 0)
942 	return argtypes[0];
943     return &t_void;
944 }
945     static type_T *
ret_repeat(int argcount,type_T ** argtypes)946 ret_repeat(int argcount, type_T **argtypes)
947 {
948     if (argcount == 0)
949 	return &t_any;
950     if (argtypes[0] == &t_number)
951 	return &t_string;
952     return argtypes[0];
953 }
954 // for map(): returns first argument but item type may differ
955     static type_T *
ret_first_cont(int argcount,type_T ** argtypes)956 ret_first_cont(int argcount, type_T **argtypes)
957 {
958     if (argcount > 0)
959     {
960 	if (argtypes[0]->tt_type == VAR_LIST)
961 	    return &t_list_any;
962 	if (argtypes[0]->tt_type == VAR_DICT)
963 	    return &t_dict_any;
964 	if (argtypes[0]->tt_type == VAR_BLOB)
965 	    return argtypes[0];
966     }
967     return &t_any;
968 }
969 
970 /*
971  * Used for getqflist(): returns list if there is no argument, dict if there is
972  * one.
973  */
974     static type_T *
ret_list_or_dict_0(int argcount,type_T ** argtypes UNUSED)975 ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
976 {
977     if (argcount > 0)
978 	return &t_dict_any;
979     return &t_list_dict_any;
980 }
981 
982 /*
983  * Used for getloclist(): returns list if there is one argument, dict if there
984  * are two.
985  */
986     static type_T *
ret_list_or_dict_1(int argcount,type_T ** argtypes UNUSED)987 ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
988 {
989     if (argcount > 1)
990 	return &t_dict_any;
991     return &t_list_dict_any;
992 }
993 
994     static type_T *
ret_argv(int argcount,type_T ** argtypes UNUSED)995 ret_argv(int argcount, type_T **argtypes UNUSED)
996 {
997     // argv() returns list of strings
998     if (argcount == 0)
999 	return &t_list_string;
1000 
1001     // argv(0) returns a string, but argv(-1] returns a list
1002     return &t_any;
1003 }
1004 
1005     static type_T *
ret_remove(int argcount,type_T ** argtypes)1006 ret_remove(int argcount, type_T **argtypes)
1007 {
1008     if (argcount > 0)
1009     {
1010 	if (argtypes[0]->tt_type == VAR_LIST
1011 		|| argtypes[0]->tt_type == VAR_DICT)
1012 	    return argtypes[0]->tt_member;
1013 	if (argtypes[0]->tt_type == VAR_BLOB)
1014 	    return &t_number;
1015     }
1016     return &t_any;
1017 }
1018 
1019     static type_T *
ret_getreg(int argcount,type_T ** argtypes UNUSED)1020 ret_getreg(int argcount, type_T **argtypes UNUSED)
1021 {
1022     // Assume that if the third argument is passed it's non-zero
1023     if (argcount == 3)
1024 	return &t_list_string;
1025     return &t_string;
1026 }
1027 
1028     static type_T *
ret_maparg(int argcount,type_T ** argtypes UNUSED)1029 ret_maparg(int argcount, type_T **argtypes UNUSED)
1030 {
1031     // Assume that if the fourth argument is passed it's non-zero
1032     if (argcount == 4)
1033 	return &t_dict_any;
1034     return &t_string;
1035 }
1036 
1037 static type_T *ret_f_function(int argcount, type_T **argtypes);
1038 
1039 /*
1040  * Array with names and number of arguments of all internal functions
1041  * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
1042  */
1043 typedef struct
1044 {
1045     char	*f_name;	// function name
1046     char	f_min_argc;	// minimal number of arguments
1047     char	f_max_argc;	// maximal number of arguments
1048     char	f_argtype;	// for method: FEARG_ values
1049     argcheck_T	*f_argcheck;	// list of functions to check argument types
1050     type_T	*(*f_retfunc)(int argcount, type_T **argtypes);
1051 				// return type function
1052     void	(*f_func)(typval_T *args, typval_T *rvar);
1053 				// implementation of function
1054 } funcentry_T;
1055 
1056 // values for f_argtype; zero means it cannot be used as a method
1057 #define FEARG_1    1	    // base is the first argument
1058 #define FEARG_2    2	    // base is the second argument
1059 #define FEARG_3    3	    // base is the third argument
1060 #define FEARG_4    4	    // base is the fourth argument
1061 #define FEARG_LAST 9	    // base is the last argument
1062 
1063 #ifdef FEAT_FLOAT
1064 # define FLOAT_FUNC(name) name
1065 #else
1066 # define FLOAT_FUNC(name) NULL
1067 #endif
1068 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
1069 # define MATH_FUNC(name) name
1070 #else
1071 # define MATH_FUNC(name) NULL
1072 #endif
1073 #ifdef FEAT_TIMERS
1074 # define TIMER_FUNC(name) name
1075 #else
1076 # define TIMER_FUNC(name) NULL
1077 #endif
1078 #ifdef FEAT_JOB_CHANNEL
1079 # define JOB_FUNC(name) name
1080 #else
1081 # define JOB_FUNC(name) NULL
1082 #endif
1083 #ifdef FEAT_PROP_POPUP
1084 # define PROP_FUNC(name) name
1085 #else
1086 # define PROP_FUNC(name) NULL
1087 #endif
1088 #ifdef FEAT_SIGNS
1089 # define SIGN_FUNC(name) name
1090 #else
1091 # define SIGN_FUNC(name) NULL
1092 #endif
1093 #ifdef FEAT_SOUND
1094 # define SOUND_FUNC(name) name
1095 #else
1096 # define SOUND_FUNC(name) NULL
1097 #endif
1098 #ifdef FEAT_TERMINAL
1099 # define TERM_FUNC(name) name
1100 #else
1101 # define TERM_FUNC(name) NULL
1102 #endif
1103 
1104 static funcentry_T global_functions[] =
1105 {
1106     {"abs",		1, 1, FEARG_1,	    arg1_float_or_nr,
1107 			ret_any,	    FLOAT_FUNC(f_abs)},
1108     {"acos",		1, 1, FEARG_1,	    arg1_float_or_nr,
1109 			ret_float,	    FLOAT_FUNC(f_acos)},
1110     {"add",		2, 2, FEARG_1,	    arg2_listblob_item,
1111 			ret_first_arg,	    f_add},
1112     {"and",		2, 2, FEARG_1,	    arg2_number,
1113 			ret_number,	    f_and},
1114     {"append",		2, 2, FEARG_2,	    arg2_setline,
1115 			ret_number_bool,    f_append},
1116     {"appendbufline",	3, 3, FEARG_3,	    arg3_setbufline,
1117 			ret_number_bool,    f_appendbufline},
1118     {"argc",		0, 1, 0,	    arg1_number,
1119 			ret_number,	    f_argc},
1120     {"argidx",		0, 0, 0,	    NULL,
1121 			ret_number,	    f_argidx},
1122     {"arglistid",	0, 2, 0,	    arg2_number,
1123 			ret_number,	    f_arglistid},
1124     {"argv",		0, 2, 0,	    arg2_number,
1125 			ret_argv,	    f_argv},
1126     {"asin",		1, 1, FEARG_1,	    arg1_float_or_nr,
1127 			ret_float,	    FLOAT_FUNC(f_asin)},
1128     {"assert_beeps",	1, 1, FEARG_1,	    arg1_string,
1129 			ret_number_bool,    f_assert_beeps},
1130     {"assert_equal",	2, 3, FEARG_2,	    NULL,
1131 			ret_number_bool,    f_assert_equal},
1132     {"assert_equalfile", 2, 3, FEARG_1,	    arg3_string,
1133 			ret_number_bool,    f_assert_equalfile},
1134     {"assert_exception", 1, 2, 0,	    arg2_string,
1135 			ret_number_bool,    f_assert_exception},
1136     {"assert_fails",	1, 5, FEARG_1,	    arg15_assert_fails,
1137 			ret_number_bool,    f_assert_fails},
1138     {"assert_false",	1, 2, FEARG_1,	    NULL,
1139 			ret_number_bool,    f_assert_false},
1140     {"assert_inrange",	3, 4, FEARG_3,	    arg34_assert_inrange,
1141 			ret_number_bool,    f_assert_inrange},
1142     {"assert_match",	2, 3, FEARG_2,	    arg3_string,
1143 			ret_number_bool,    f_assert_match},
1144     {"assert_nobeep",	1, 1, FEARG_1,	    arg1_string,
1145 			ret_number_bool,    f_assert_nobeep},
1146     {"assert_notequal",	2, 3, FEARG_2,	    NULL,
1147 			ret_number_bool,    f_assert_notequal},
1148     {"assert_notmatch",	2, 3, FEARG_2,	    arg3_string,
1149 			ret_number_bool,    f_assert_notmatch},
1150     {"assert_report",	1, 1, FEARG_1,	    arg1_string,
1151 			ret_number_bool,    f_assert_report},
1152     {"assert_true",	1, 2, FEARG_1,	    NULL,
1153 			ret_number_bool,    f_assert_true},
1154     {"atan",		1, 1, FEARG_1,	    arg1_float_or_nr,
1155 			ret_float,	    FLOAT_FUNC(f_atan)},
1156     {"atan2",		2, 2, FEARG_1,	    arg2_float_or_nr,
1157 			ret_float,	    FLOAT_FUNC(f_atan2)},
1158     {"balloon_gettext",	0, 0, 0,	    NULL,
1159 			ret_string,
1160 #ifdef FEAT_BEVAL
1161 	    f_balloon_gettext
1162 #else
1163 	    NULL
1164 #endif
1165 			},
1166     {"balloon_show",	1, 1, FEARG_1,	    arg1_string_or_list_any,
1167 			ret_void,
1168 #ifdef FEAT_BEVAL
1169 	    f_balloon_show
1170 #else
1171 	    NULL
1172 #endif
1173 			},
1174     {"balloon_split",	1, 1, FEARG_1,	    arg1_string,
1175 			ret_list_string,
1176 #if defined(FEAT_BEVAL_TERM)
1177 	    f_balloon_split
1178 #else
1179 	    NULL
1180 #endif
1181 			},
1182     {"blob2list",	1, 1, FEARG_1,	    arg1_blob,
1183 			ret_list_number,    f_blob2list},
1184     {"browse",		4, 4, 0,	    arg4_browse,
1185 			ret_string,	    f_browse},
1186     {"browsedir",	2, 2, 0,	    arg2_string,
1187 			ret_string,	    f_browsedir},
1188     {"bufadd",		1, 1, FEARG_1,	    arg1_string,
1189 			ret_number,	    f_bufadd},
1190     {"bufexists",	1, 1, FEARG_1,	    arg1_buffer,
1191 			ret_number_bool,    f_bufexists},
1192     {"buffer_exists",	1, 1, FEARG_1,	    arg1_buffer,	// obsolete
1193 			ret_number_bool,    f_bufexists},
1194     {"buffer_name",	0, 1, FEARG_1,	    arg1_buffer,	// obsolete
1195 			ret_string,	    f_bufname},
1196     {"buffer_number",	0, 1, FEARG_1,	    arg1_buffer,	// obsolete
1197 			ret_number,	    f_bufnr},
1198     {"buflisted",	1, 1, FEARG_1,	    arg1_buffer,
1199 			ret_number_bool,    f_buflisted},
1200     {"bufload",		1, 1, FEARG_1,	    arg1_buffer,
1201 			ret_void,	    f_bufload},
1202     {"bufloaded",	1, 1, FEARG_1,	    arg1_buffer,
1203 			ret_number_bool,    f_bufloaded},
1204     {"bufname",		0, 1, FEARG_1,	    arg1_buffer,
1205 			ret_string,	    f_bufname},
1206     {"bufnr",		0, 2, FEARG_1,	    arg2_buffer_bool,
1207 			ret_number,	    f_bufnr},
1208     {"bufwinid",	1, 1, FEARG_1,	    arg1_buffer,
1209 			ret_number,	    f_bufwinid},
1210     {"bufwinnr",	1, 1, FEARG_1,	    arg1_buffer,
1211 			ret_number,	    f_bufwinnr},
1212     {"byte2line",	1, 1, FEARG_1,	    arg1_number,
1213 			ret_number,	    f_byte2line},
1214     {"byteidx",		2, 2, FEARG_1,	    arg2_string_number,
1215 			ret_number,	    f_byteidx},
1216     {"byteidxcomp",	2, 2, FEARG_1,	    arg2_string_number,
1217 			ret_number,	    f_byteidxcomp},
1218     {"call",		2, 3, FEARG_1,	    arg3_any_list_dict,
1219 			ret_any,	    f_call},
1220     {"ceil",		1, 1, FEARG_1,	    arg1_float_or_nr,
1221 			ret_float,	    FLOAT_FUNC(f_ceil)},
1222     {"ch_canread",	1, 1, FEARG_1,	    arg1_chan_or_job,
1223 			ret_number_bool,    JOB_FUNC(f_ch_canread)},
1224     {"ch_close",	1, 1, FEARG_1,	    arg1_chan_or_job,
1225 			ret_void,	    JOB_FUNC(f_ch_close)},
1226     {"ch_close_in",	1, 1, FEARG_1,	    arg1_chan_or_job,
1227 			ret_void,	    JOB_FUNC(f_ch_close_in)},
1228     {"ch_evalexpr",	2, 3, FEARG_1,	    arg23_chanexpr,
1229 			ret_any,	    JOB_FUNC(f_ch_evalexpr)},
1230     {"ch_evalraw",	2, 3, FEARG_1,	    arg23_chanraw,
1231 			ret_any,	    JOB_FUNC(f_ch_evalraw)},
1232     {"ch_getbufnr",	2, 2, FEARG_1,	    arg2_chan_or_job_string,
1233 			ret_number,	    JOB_FUNC(f_ch_getbufnr)},
1234     {"ch_getjob",	1, 1, FEARG_1,	    arg1_chan_or_job,
1235 			ret_job,	    JOB_FUNC(f_ch_getjob)},
1236     {"ch_info",		1, 1, FEARG_1,	    arg1_chan_or_job,
1237 			ret_dict_any,	    JOB_FUNC(f_ch_info)},
1238     {"ch_log",		1, 2, FEARG_1,	    arg2_string_chan_or_job,
1239 			ret_void,	    JOB_FUNC(f_ch_log)},
1240     {"ch_logfile",	1, 2, FEARG_1,	    arg2_string,
1241 			ret_void,	    JOB_FUNC(f_ch_logfile)},
1242     {"ch_open",		1, 2, FEARG_1,	    arg2_string_dict,
1243 			ret_channel,	    JOB_FUNC(f_ch_open)},
1244     {"ch_read",		1, 2, FEARG_1,	    arg2_chan_or_job_dict,
1245 			ret_string,	    JOB_FUNC(f_ch_read)},
1246     {"ch_readblob",	1, 2, FEARG_1,	    arg2_chan_or_job_dict,
1247 			ret_blob,	    JOB_FUNC(f_ch_readblob)},
1248     {"ch_readraw",	1, 2, FEARG_1,	    arg2_chan_or_job_dict,
1249 			ret_string,	    JOB_FUNC(f_ch_readraw)},
1250     {"ch_sendexpr",	2, 3, FEARG_1,	    arg23_chanexpr,
1251 			ret_void,	    JOB_FUNC(f_ch_sendexpr)},
1252     {"ch_sendraw",	2, 3, FEARG_1,	    arg23_chanraw,
1253 			ret_void,	    JOB_FUNC(f_ch_sendraw)},
1254     {"ch_setoptions",	2, 2, FEARG_1,	    arg2_chan_or_job_dict,
1255 			ret_void,	    JOB_FUNC(f_ch_setoptions)},
1256     {"ch_status",	1, 2, FEARG_1,	    arg2_chan_or_job_dict,
1257 			ret_string,	    JOB_FUNC(f_ch_status)},
1258     {"changenr",	0, 0, 0,	    NULL,
1259 			ret_number,	    f_changenr},
1260     {"char2nr",		1, 2, FEARG_1,	    arg2_string_bool,
1261 			ret_number,	    f_char2nr},
1262     {"charclass",	1, 1, FEARG_1,	    arg1_string,
1263 			ret_number,	    f_charclass},
1264     {"charcol",		1, 1, FEARG_1,	    arg1_string_or_list_any,
1265 			ret_number,	    f_charcol},
1266     {"charidx",		2, 3, FEARG_1,	    arg3_string_number_bool,
1267 			ret_number,	    f_charidx},
1268     {"chdir",		1, 1, FEARG_1,	    arg1_string,
1269 			ret_string,	    f_chdir},
1270     {"cindent",		1, 1, FEARG_1,	    arg1_lnum,
1271 			ret_number,	    f_cindent},
1272     {"clearmatches",	0, 1, FEARG_1,	    arg1_number,
1273 			ret_void,	    f_clearmatches},
1274     {"col",		1, 1, FEARG_1,	    arg1_string_or_list_any,
1275 			ret_number,	    f_col},
1276     {"complete",	2, 2, FEARG_2,	    arg2_number_list,
1277 			ret_void,	    f_complete},
1278     {"complete_add",	1, 1, FEARG_1,	    arg1_dict_or_string,
1279 			ret_number,	    f_complete_add},
1280     {"complete_check",	0, 0, 0,	    NULL,
1281 			ret_number_bool,    f_complete_check},
1282     {"complete_info",	0, 1, FEARG_1,	    arg1_list_string,
1283 			ret_dict_any,	    f_complete_info},
1284     {"confirm",		1, 4, FEARG_1,	    arg4_string_string_number_string,
1285 			ret_number,	    f_confirm},
1286     {"copy",		1, 1, FEARG_1,	    NULL,
1287 			ret_first_arg,	    f_copy},
1288     {"cos",		1, 1, FEARG_1,	    arg1_float_or_nr,
1289 			ret_float,	    FLOAT_FUNC(f_cos)},
1290     {"cosh",		1, 1, FEARG_1,	    arg1_float_or_nr,
1291 			ret_float,	    FLOAT_FUNC(f_cosh)},
1292     {"count",		2, 4, FEARG_1,	    arg24_count,
1293 			ret_number,	    f_count},
1294     {"cscope_connection",0,3, 0,	    arg3_number_string_string,
1295 			ret_number,	    f_cscope_connection},
1296     {"cursor",		1, 3, FEARG_1,	    arg13_cursor,
1297 			ret_number,	    f_cursor},
1298     {"debugbreak",	1, 1, FEARG_1,	    arg1_number,
1299 			ret_number,
1300 #ifdef MSWIN
1301 	    f_debugbreak
1302 #else
1303 	    NULL
1304 #endif
1305 			},
1306     {"deepcopy",	1, 2, FEARG_1,	    arg12_deepcopy,
1307 			ret_first_arg,	    f_deepcopy},
1308     {"delete",		1, 2, FEARG_1,	    arg2_string,
1309 			ret_number_bool,    f_delete},
1310     {"deletebufline",	2, 3, FEARG_1,	    arg3_buffer_lnum_lnum,
1311 			ret_number_bool,    f_deletebufline},
1312     {"did_filetype",	0, 0, 0,	    NULL,
1313 			ret_number_bool,    f_did_filetype},
1314     {"diff_filler",	1, 1, FEARG_1,	    arg1_lnum,
1315 			ret_number,	    f_diff_filler},
1316     {"diff_hlID",	2, 2, FEARG_1,	    arg2_lnum_number,
1317 			ret_number,	    f_diff_hlID},
1318     {"digraph_get",	1, 1, FEARG_1,	    arg1_string,
1319 			ret_string,	    f_digraph_get},
1320     {"digraph_getlist",0, 1, FEARG_1,	    arg1_bool,
1321 			ret_list_string_items, f_digraph_getlist},
1322     {"digraph_set",	2, 2, FEARG_1,	    arg2_string,
1323 			ret_bool,	f_digraph_set},
1324     {"digraph_setlist",1, 1, FEARG_1,	    arg1_list_string,
1325 			ret_bool,	    f_digraph_setlist},
1326     {"echoraw",		1, 1, FEARG_1,	    arg1_string,
1327 			ret_void,	    f_echoraw},
1328     {"empty",		1, 1, FEARG_1,	    NULL,
1329 			ret_number_bool,    f_empty},
1330     {"environ",		0, 0, 0,	    NULL,
1331 			ret_dict_string,    f_environ},
1332     {"escape",		2, 2, FEARG_1,	    arg2_string,
1333 			ret_string,	    f_escape},
1334     {"eval",		1, 1, FEARG_1,	    arg1_string,
1335 			ret_any,	    f_eval},
1336     {"eventhandler",	0, 0, 0,	    NULL,
1337 			ret_number_bool,    f_eventhandler},
1338     {"executable",	1, 1, FEARG_1,	    arg1_string,
1339 			ret_number,	    f_executable},
1340     {"execute",		1, 2, FEARG_1,	    arg12_execute,
1341 			ret_string,	    f_execute},
1342     {"exepath",		1, 1, FEARG_1,	    arg1_string,
1343 			ret_string,	    f_exepath},
1344     {"exists",		1, 1, FEARG_1,	    arg1_string,
1345 			ret_number_bool,    f_exists},
1346     {"exists_compiled",	1, 1, FEARG_1,	    arg1_string,
1347 			ret_number_bool,    f_exists_compiled},
1348     {"exp",		1, 1, FEARG_1,	    arg1_float_or_nr,
1349 			ret_float,	    FLOAT_FUNC(f_exp)},
1350     {"expand",		1, 3, FEARG_1,	    arg3_string_bool_bool,
1351 			ret_any,	    f_expand},
1352     {"expandcmd",	1, 1, FEARG_1,	    arg1_string,
1353 			ret_string,	    f_expandcmd},
1354     {"extend",		2, 3, FEARG_1,	    arg23_extend,
1355 			ret_first_arg,	    f_extend},
1356     {"extendnew",	2, 3, FEARG_1,	    arg23_extendnew,
1357 			ret_first_cont,	    f_extendnew},
1358     {"feedkeys",	1, 2, FEARG_1,	    arg2_string,
1359 			ret_void,	    f_feedkeys},
1360     {"file_readable",	1, 1, FEARG_1,	    arg1_string,	// obsolete
1361 			ret_number_bool,    f_filereadable},
1362     {"filereadable",	1, 1, FEARG_1,	    arg1_string,
1363 			ret_number_bool,    f_filereadable},
1364     {"filewritable",	1, 1, FEARG_1,	    arg1_string,
1365 			ret_number,	    f_filewritable},
1366     {"filter",		2, 2, FEARG_1,	    arg2_mapfilter,
1367 			ret_first_arg,	    f_filter},
1368     {"finddir",		1, 3, FEARG_1,	    arg3_string_string_number,
1369 			ret_any,	    f_finddir},
1370     {"findfile",	1, 3, FEARG_1,	    arg3_string_string_number,
1371 			ret_any,	    f_findfile},
1372     {"flatten",		1, 2, FEARG_1,	    arg2_list_any_number,
1373 			ret_list_any,	    f_flatten},
1374     {"flattennew",	1, 2, FEARG_1,	    arg2_list_any_number,
1375 			ret_list_any,	    f_flattennew},
1376     {"float2nr",	1, 1, FEARG_1,	    arg1_float_or_nr,
1377 			ret_number,	    FLOAT_FUNC(f_float2nr)},
1378     {"floor",		1, 1, FEARG_1,	    arg1_float_or_nr,
1379 			ret_float,	    FLOAT_FUNC(f_floor)},
1380     {"fmod",		2, 2, FEARG_1,	    arg2_float_or_nr,
1381 			ret_float,	    FLOAT_FUNC(f_fmod)},
1382     {"fnameescape",	1, 1, FEARG_1,	    arg1_string,
1383 			ret_string,	    f_fnameescape},
1384     {"fnamemodify",	2, 2, FEARG_1,	    arg2_string,
1385 			ret_string,	    f_fnamemodify},
1386     {"foldclosed",	1, 1, FEARG_1,	    arg1_lnum,
1387 			ret_number,	    f_foldclosed},
1388     {"foldclosedend",	1, 1, FEARG_1,	    arg1_lnum,
1389 			ret_number,	    f_foldclosedend},
1390     {"foldlevel",	1, 1, FEARG_1,	    arg1_lnum,
1391 			ret_number,	    f_foldlevel},
1392     {"foldtext",	0, 0, 0,	    NULL,
1393 			ret_string,	    f_foldtext},
1394     {"foldtextresult",	1, 1, FEARG_1,	    arg1_lnum,
1395 			ret_string,	    f_foldtextresult},
1396     {"foreground",	0, 0, 0,	    NULL,
1397 			ret_void,	    f_foreground},
1398     {"fullcommand",	1, 1, FEARG_1,	    arg1_string,
1399 			ret_string,	    f_fullcommand},
1400     {"funcref",		1, 3, FEARG_1,	    arg3_any_list_dict,
1401 			ret_func_any,	    f_funcref},
1402     {"function",	1, 3, FEARG_1,	    arg3_any_list_dict,
1403 			ret_f_function,	    f_function},
1404     {"garbagecollect",	0, 1, 0,	    arg1_bool,
1405 			ret_void,	    f_garbagecollect},
1406     {"get",		2, 3, FEARG_1,	    arg23_get,
1407 			ret_any,	    f_get},
1408     {"getbufinfo",	0, 1, FEARG_1,	    arg1_buffer_or_dict_any,
1409 			ret_list_dict_any,  f_getbufinfo},
1410     {"getbufline",	2, 3, FEARG_1,	    arg3_buffer_lnum_lnum,
1411 			ret_list_string,    f_getbufline},
1412     {"getbufvar",	2, 3, FEARG_1,	    arg3_buffer_string_any,
1413 			ret_any,	    f_getbufvar},
1414     {"getchangelist",	0, 1, FEARG_1,	    arg1_buffer,
1415 			ret_list_any,	    f_getchangelist},
1416     {"getchar",		0, 1, 0,	    arg1_bool,
1417 			ret_any,	    f_getchar},
1418     {"getcharmod",	0, 0, 0,	    NULL,
1419 			ret_number,	    f_getcharmod},
1420     {"getcharpos",	1, 1, FEARG_1,	    arg1_string,
1421 			ret_list_number,    f_getcharpos},
1422     {"getcharsearch",	0, 0, 0,	    NULL,
1423 			ret_dict_any,	    f_getcharsearch},
1424     {"getcharstr",	0, 1, 0,	    arg1_bool,
1425 			ret_string,	    f_getcharstr},
1426     {"getcmdline",	0, 0, 0,	    NULL,
1427 			ret_string,	    f_getcmdline},
1428     {"getcmdpos",	0, 0, 0,	    NULL,
1429 			ret_number,	    f_getcmdpos},
1430     {"getcmdtype",	0, 0, 0,	    NULL,
1431 			ret_string,	    f_getcmdtype},
1432     {"getcmdwintype",	0, 0, 0,	    NULL,
1433 			ret_string,	    f_getcmdwintype},
1434     {"getcompletion",	2, 3, FEARG_1,	    arg3_string_string_bool,
1435 			ret_list_string,    f_getcompletion},
1436     {"getcurpos",	0, 1, FEARG_1,	    arg1_number,
1437 			ret_list_number,    f_getcurpos},
1438     {"getcursorcharpos",	0, 1, FEARG_1,	    arg1_number,
1439 			ret_list_number,    f_getcursorcharpos},
1440     {"getcwd",		0, 2, FEARG_1,	    arg2_number,
1441 			ret_string,	    f_getcwd},
1442     {"getenv",		1, 1, FEARG_1,	    arg1_string,
1443 			ret_any,	    f_getenv},
1444     {"getfontname",	0, 1, 0,	    arg1_string,
1445 			ret_string,	    f_getfontname},
1446     {"getfperm",	1, 1, FEARG_1,	    arg1_string,
1447 			ret_string,	    f_getfperm},
1448     {"getfsize",	1, 1, FEARG_1,	    arg1_string,
1449 			ret_number,	    f_getfsize},
1450     {"getftime",	1, 1, FEARG_1,	    arg1_string,
1451 			ret_number,	    f_getftime},
1452     {"getftype",	1, 1, FEARG_1,	    arg1_string,
1453 			ret_string,	    f_getftype},
1454     {"getimstatus",	0, 0, 0,	    NULL,
1455 			ret_number_bool,    f_getimstatus},
1456     {"getjumplist",	0, 2, FEARG_1,	    arg2_number,
1457 			ret_list_any,	    f_getjumplist},
1458     {"getline",		1, 2, FEARG_1,	    arg2_lnum,
1459 			ret_f_getline,	    f_getline},
1460     {"getloclist",	1, 2, 0,	    arg2_number_dict_any,
1461 			ret_list_or_dict_1, f_getloclist},
1462     {"getmarklist",	0, 1, FEARG_1,	    arg1_buffer,
1463 			ret_list_dict_any,  f_getmarklist},
1464     {"getmatches",	0, 1, 0,	    arg1_number,
1465 			ret_list_dict_any,  f_getmatches},
1466     {"getmousepos",	0, 0, 0,	    NULL,
1467 			ret_dict_number,    f_getmousepos},
1468     {"getpid",		0, 0, 0,	    NULL,
1469 			ret_number,	    f_getpid},
1470     {"getpos",		1, 1, FEARG_1,	    arg1_string,
1471 			ret_list_number,    f_getpos},
1472     {"getqflist",	0, 1, 0,	    arg1_dict_any,
1473 			ret_list_or_dict_0, f_getqflist},
1474     {"getreg",		0, 3, FEARG_1,	    arg3_string_bool_bool,
1475 			ret_getreg,	    f_getreg},
1476     {"getreginfo",	0, 1, FEARG_1,	    arg1_string,
1477 			ret_dict_any,	    f_getreginfo},
1478     {"getregtype",	0, 1, FEARG_1,	    arg1_string,
1479 			ret_string,	    f_getregtype},
1480     {"gettabinfo",	0, 1, FEARG_1,	    arg1_number,
1481 			ret_list_dict_any,  f_gettabinfo},
1482     {"gettabvar",	2, 3, FEARG_1,	    arg3_number_string_any,
1483 			ret_any,	    f_gettabvar},
1484     {"gettabwinvar",	3, 4, FEARG_1,	    arg4_number_number_string_any,
1485 			ret_any,	    f_gettabwinvar},
1486     {"gettagstack",	0, 1, FEARG_1,	    arg1_number,
1487 			ret_dict_any,	    f_gettagstack},
1488     {"gettext",		1, 1, FEARG_1,	    arg1_string,
1489 			ret_string,	    f_gettext},
1490     {"getwininfo",	0, 1, FEARG_1,	    arg1_number,
1491 			ret_list_dict_any,  f_getwininfo},
1492     {"getwinpos",	0, 1, FEARG_1,	    arg1_number,
1493 			ret_list_number,    f_getwinpos},
1494     {"getwinposx",	0, 0, 0,	    NULL,
1495 			ret_number,	    f_getwinposx},
1496     {"getwinposy",	0, 0, 0,	    NULL,
1497 			ret_number,	    f_getwinposy},
1498     {"getwinvar",	2, 3, FEARG_1,	    arg3_number_string_any,
1499 			ret_any,	    f_getwinvar},
1500     {"glob",		1, 4, FEARG_1,	    arg14_glob,
1501 			ret_any,	    f_glob},
1502     {"glob2regpat",	1, 1, FEARG_1,	    arg1_string,
1503 			ret_string,	    f_glob2regpat},
1504     {"globpath",	2, 5, FEARG_2,	    arg25_globpath,
1505 			ret_any,	    f_globpath},
1506     {"has",		1, 2, 0,	    arg2_string_bool,
1507 			ret_number_bool,    f_has},
1508     {"has_key",		2, 2, FEARG_1,	    arg2_dict_any_string_or_nr,
1509 			ret_number_bool,    f_has_key},
1510     {"haslocaldir",	0, 2, FEARG_1,	    arg2_number,
1511 			ret_number,	    f_haslocaldir},
1512     {"hasmapto",	1, 3, FEARG_1,	    arg3_string_string_bool,
1513 			ret_number_bool,    f_hasmapto},
1514     {"highlightID",	1, 1, FEARG_1,	    arg1_string,	// obsolete
1515 			ret_number,	    f_hlID},
1516     {"highlight_exists",1, 1, FEARG_1,	    arg1_string,	// obsolete
1517 			ret_number_bool,    f_hlexists},
1518     {"histadd",		2, 2, FEARG_2,	    arg2_string,
1519 			ret_number_bool,    f_histadd},
1520     {"histdel",		1, 2, FEARG_1,	    arg2_string_string_or_number,
1521 			ret_number_bool,    f_histdel},
1522     {"histget",		1, 2, FEARG_1,	    arg2_string_number,
1523 			ret_string,	    f_histget},
1524     {"histnr",		1, 1, FEARG_1,	    arg1_string,
1525 			ret_number,	    f_histnr},
1526     {"hlID",		1, 1, FEARG_1,	    arg1_string,
1527 			ret_number,	    f_hlID},
1528     {"hlexists",	1, 1, FEARG_1,	    arg1_string,
1529 			ret_number_bool,    f_hlexists},
1530     {"hlget",		0, 2, FEARG_1,	    arg2_string_bool,
1531 			ret_list_dict_any,  f_hlget},
1532     {"hlset",		1, 1, FEARG_1,	    arg1_list_any,
1533 			ret_number_bool,    f_hlset},
1534     {"hostname",	0, 0, 0,	    NULL,
1535 			ret_string,	    f_hostname},
1536     {"iconv",		3, 3, FEARG_1,	    arg3_string,
1537 			ret_string,	    f_iconv},
1538     {"indent",		1, 1, FEARG_1,	    arg1_lnum,
1539 			ret_number,	    f_indent},
1540     {"index",		2, 4, FEARG_1,	    arg24_index,
1541 			ret_number,	    f_index},
1542     {"input",		1, 3, FEARG_1,	    arg3_string,
1543 			ret_string,	    f_input},
1544     {"inputdialog",	1, 3, FEARG_1,	    arg3_string,
1545 			ret_string,	    f_inputdialog},
1546     {"inputlist",	1, 1, FEARG_1,	    arg1_list_string,
1547 			ret_number,	    f_inputlist},
1548     {"inputrestore",	0, 0, 0,	    NULL,
1549 			ret_number_bool,    f_inputrestore},
1550     {"inputsave",	0, 0, 0,	    NULL,
1551 			ret_number_bool,    f_inputsave},
1552     {"inputsecret",	1, 2, FEARG_1,	    arg2_string,
1553 			ret_string,	    f_inputsecret},
1554     {"insert",		2, 3, FEARG_1,	    arg23_insert,
1555 			ret_first_arg,	    f_insert},
1556     {"interrupt",	0, 0, 0,	    NULL,
1557 			ret_void,	    f_interrupt},
1558     {"invert",		1, 1, FEARG_1,	    arg1_number,
1559 			ret_number,	    f_invert},
1560     {"isdirectory",	1, 1, FEARG_1,	    arg1_string,
1561 			ret_number_bool,    f_isdirectory},
1562     {"isinf",		1, 1, FEARG_1,	    arg1_float_or_nr,
1563 			ret_number,	    MATH_FUNC(f_isinf)},
1564     {"islocked",	1, 1, FEARG_1,	    arg1_string,
1565 			ret_number_bool,    f_islocked},
1566     {"isnan",		1, 1, FEARG_1,	    arg1_float_or_nr,
1567 			ret_number_bool,    MATH_FUNC(f_isnan)},
1568     {"items",		1, 1, FEARG_1,	    arg1_dict_any,
1569 			ret_list_items,	    f_items},
1570     {"job_getchannel",	1, 1, FEARG_1,	    arg1_job,
1571 			ret_channel,	    JOB_FUNC(f_job_getchannel)},
1572     {"job_info",	0, 1, FEARG_1,	    arg1_job,
1573 			ret_job_info,	    JOB_FUNC(f_job_info)},
1574     {"job_setoptions",	2, 2, FEARG_1,	    arg2_job_dict,
1575 			ret_void,	    JOB_FUNC(f_job_setoptions)},
1576     {"job_start",	1, 2, FEARG_1,	    arg2_string_or_list_dict,
1577 			ret_job,	    JOB_FUNC(f_job_start)},
1578     {"job_status",	1, 1, FEARG_1,	    arg1_job,
1579 			ret_string,	    JOB_FUNC(f_job_status)},
1580     {"job_stop",	1, 2, FEARG_1,	    arg2_job_string_or_number,
1581 			ret_number_bool,    JOB_FUNC(f_job_stop)},
1582     {"join",		1, 2, FEARG_1,	    arg2_list_any_string,
1583 			ret_string,	    f_join},
1584     {"js_decode",	1, 1, FEARG_1,	    arg1_string,
1585 			ret_any,	    f_js_decode},
1586     {"js_encode",	1, 1, FEARG_1,	    NULL,
1587 			ret_string,	    f_js_encode},
1588     {"json_decode",	1, 1, FEARG_1,	    arg1_string,
1589 			ret_any,	    f_json_decode},
1590     {"json_encode",	1, 1, FEARG_1,	    NULL,
1591 			ret_string,	    f_json_encode},
1592     {"keys",		1, 1, FEARG_1,	    arg1_dict_any,
1593 			ret_list_string,    f_keys},
1594     {"last_buffer_nr",	0, 0, 0,	    NULL,	// obsolete
1595 			ret_number,	    f_last_buffer_nr},
1596     {"len",		1, 1, FEARG_1,	    arg1_len,
1597 			ret_number,	    f_len},
1598     {"libcall",		3, 3, FEARG_3,	    arg3_libcall,
1599 			ret_string,	    f_libcall},
1600     {"libcallnr",	3, 3, FEARG_3,	    arg3_libcall,
1601 			ret_number,	    f_libcallnr},
1602     {"line",		1, 2, FEARG_1,	    arg2_string_number,
1603 			ret_number,	    f_line},
1604     {"line2byte",	1, 1, FEARG_1,	    arg1_lnum,
1605 			ret_number,	    f_line2byte},
1606     {"lispindent",	1, 1, FEARG_1,	    arg1_lnum,
1607 			ret_number,	    f_lispindent},
1608     {"list2blob",	1, 1, FEARG_1,	    arg1_list_number,
1609 			ret_blob,	    f_list2blob},
1610     {"list2str",	1, 2, FEARG_1,	    arg2_list_number_bool,
1611 			ret_string,	    f_list2str},
1612     {"listener_add",	1, 2, FEARG_2,	    arg2_any_buffer,
1613 			ret_number,	    f_listener_add},
1614     {"listener_flush",	0, 1, FEARG_1,	    arg1_buffer,
1615 			ret_void,	    f_listener_flush},
1616     {"listener_remove",	1, 1, FEARG_1,	    arg1_number,
1617 			ret_number_bool,    f_listener_remove},
1618     {"localtime",	0, 0, 0,	    NULL,
1619 			ret_number,	    f_localtime},
1620     {"log",		1, 1, FEARG_1,	    arg1_float_or_nr,
1621 			ret_float,	    FLOAT_FUNC(f_log)},
1622     {"log10",		1, 1, FEARG_1,	    arg1_float_or_nr,
1623 			ret_float,	    FLOAT_FUNC(f_log10)},
1624     {"luaeval",		1, 2, FEARG_1,	    arg2_string_any,
1625 			ret_any,
1626 #ifdef FEAT_LUA
1627 		f_luaeval
1628 #else
1629 		NULL
1630 #endif
1631 			},
1632     {"map",		2, 2, FEARG_1,	    arg2_mapfilter,
1633 			ret_first_cont,	    f_map},
1634     {"maparg",		1, 4, FEARG_1,	    arg14_maparg,
1635 			ret_maparg,	    f_maparg},
1636     {"mapcheck",	1, 3, FEARG_1,	    arg3_string_string_bool,
1637 			ret_string,	    f_mapcheck},
1638     {"mapnew",		2, 2, FEARG_1,	    arg2_mapfilter,
1639 			ret_first_cont,	    f_mapnew},
1640     {"mapset",		3, 3, FEARG_1,	    arg3_string_bool_dict,
1641 			ret_void,	    f_mapset},
1642     {"match",		2, 4, FEARG_1,	    arg24_match_func,
1643 			ret_any,	    f_match},
1644     {"matchadd",	2, 5, FEARG_1,	    arg25_matchadd,
1645 			ret_number,	    f_matchadd},
1646     {"matchaddpos",	2, 5, FEARG_1,	    arg25_matchaddpos,
1647 			ret_number,	    f_matchaddpos},
1648     {"matcharg",	1, 1, FEARG_1,	    arg1_number,
1649 			ret_list_string,    f_matcharg},
1650     {"matchdelete",	1, 2, FEARG_1,	    arg2_number,
1651 			ret_number_bool,    f_matchdelete},
1652     {"matchend",	2, 4, FEARG_1,	    arg24_match_func,
1653 			ret_number,	    f_matchend},
1654     {"matchfuzzy",	2, 3, FEARG_1,	    arg3_list_string_dict,
1655 			ret_list_string,    f_matchfuzzy},
1656     {"matchfuzzypos",	2, 3, FEARG_1,	    arg3_list_string_dict,
1657 			ret_list_any,	    f_matchfuzzypos},
1658     {"matchlist",	2, 4, FEARG_1,	    arg24_match_func,
1659 			ret_list_string,    f_matchlist},
1660     {"matchstr",	2, 4, FEARG_1,	    arg24_match_func,
1661 			ret_string,	    f_matchstr},
1662     {"matchstrpos",	2, 4, FEARG_1,	    arg24_match_func,
1663 			ret_list_any,	    f_matchstrpos},
1664     {"max",		1, 1, FEARG_1,	    arg1_list_or_dict,
1665 			ret_number,	    f_max},
1666     {"menu_info",	1, 2, FEARG_1,	    arg2_string,
1667 			ret_dict_any,
1668 #ifdef FEAT_MENU
1669 	    f_menu_info
1670 #else
1671 	    NULL
1672 #endif
1673 			},
1674     {"min",		1, 1, FEARG_1,	    arg1_list_or_dict,
1675 			ret_number,	    f_min},
1676     {"mkdir",		1, 3, FEARG_1,	    arg3_string_string_number,
1677 			ret_number_bool,    f_mkdir},
1678     {"mode",		0, 1, FEARG_1,	    arg1_bool,
1679 			ret_string,	    f_mode},
1680     {"mzeval",		1, 1, FEARG_1,	    arg1_string,
1681 			ret_any,
1682 #ifdef FEAT_MZSCHEME
1683 	    f_mzeval
1684 #else
1685 	    NULL
1686 #endif
1687 			},
1688     {"nextnonblank",	1, 1, FEARG_1,	    arg1_lnum,
1689 			ret_number,	    f_nextnonblank},
1690     {"nr2char",		1, 2, FEARG_1,	    arg2_number_bool,
1691 			ret_string,	    f_nr2char},
1692     {"or",		2, 2, FEARG_1,	    arg2_number,
1693 			ret_number,	    f_or},
1694     {"pathshorten",	1, 2, FEARG_1,	    arg2_string_number,
1695 			ret_string,	    f_pathshorten},
1696     {"perleval",	1, 1, FEARG_1,	    arg1_string,
1697 			ret_any,
1698 #ifdef FEAT_PERL
1699 	    f_perleval
1700 #else
1701 	    NULL
1702 #endif
1703 			},
1704     {"popup_atcursor",	2, 2, FEARG_1,	    arg2_str_or_nr_or_list_dict,
1705 			ret_number,	    PROP_FUNC(f_popup_atcursor)},
1706     {"popup_beval",	2, 2, FEARG_1,	    arg2_str_or_nr_or_list_dict,
1707 			ret_number,	    PROP_FUNC(f_popup_beval)},
1708     {"popup_clear",	0, 1, 0,	    arg1_bool,
1709 			ret_void,	    PROP_FUNC(f_popup_clear)},
1710     {"popup_close",	1, 2, FEARG_1,	    arg2_number_any,
1711 			ret_void,	    PROP_FUNC(f_popup_close)},
1712     {"popup_create",	2, 2, FEARG_1,	    arg2_str_or_nr_or_list_dict,
1713 			ret_number,	    PROP_FUNC(f_popup_create)},
1714     {"popup_dialog",	2, 2, FEARG_1,	    arg2_str_or_nr_or_list_dict,
1715 			ret_number,	    PROP_FUNC(f_popup_dialog)},
1716     {"popup_filter_menu", 2, 2, 0,	    arg2_number_string,
1717 			ret_bool,	    PROP_FUNC(f_popup_filter_menu)},
1718     {"popup_filter_yesno", 2, 2, 0,	    arg2_number_string,
1719 			ret_bool,	    PROP_FUNC(f_popup_filter_yesno)},
1720     {"popup_findinfo",	0, 0, 0,	    NULL,
1721 			ret_number,	    PROP_FUNC(f_popup_findinfo)},
1722     {"popup_findpreview", 0, 0, 0,	    NULL,
1723 			ret_number,	    PROP_FUNC(f_popup_findpreview)},
1724     {"popup_getoptions", 1, 1, FEARG_1,	    arg1_number,
1725 			ret_dict_any,	    PROP_FUNC(f_popup_getoptions)},
1726     {"popup_getpos",	1, 1, FEARG_1,	    arg1_number,
1727 			ret_dict_any,	    PROP_FUNC(f_popup_getpos)},
1728     {"popup_hide",	1, 1, FEARG_1,	    arg1_number,
1729 			ret_void,	    PROP_FUNC(f_popup_hide)},
1730     {"popup_list",	0, 0, 0,	    NULL,
1731 			ret_list_number,    PROP_FUNC(f_popup_list)},
1732     {"popup_locate",	2, 2, 0,	    arg2_number,
1733 			ret_number,	    PROP_FUNC(f_popup_locate)},
1734     {"popup_menu",	2, 2, FEARG_1,	    arg2_str_or_nr_or_list_dict,
1735 			ret_number,	    PROP_FUNC(f_popup_menu)},
1736     {"popup_move",	2, 2, FEARG_1,	    arg2_number_dict_any,
1737 			ret_void,	    PROP_FUNC(f_popup_move)},
1738     {"popup_notification", 2, 2, FEARG_1,   arg2_str_or_nr_or_list_dict,
1739 			ret_number,	    PROP_FUNC(f_popup_notification)},
1740     {"popup_setoptions", 2, 2, FEARG_1,	    arg2_number_dict_any,
1741 			ret_void,	    PROP_FUNC(f_popup_setoptions)},
1742     {"popup_settext",	2, 2, FEARG_1,	    arg2_number_string_or_list,
1743 			ret_void,	    PROP_FUNC(f_popup_settext)},
1744     {"popup_show",	1, 1, FEARG_1,	    arg1_number,
1745 			ret_void,	    PROP_FUNC(f_popup_show)},
1746     {"pow",		2, 2, FEARG_1,	    arg2_float_or_nr,
1747 			ret_float,	    FLOAT_FUNC(f_pow)},
1748     {"prevnonblank",	1, 1, FEARG_1,	    arg1_lnum,
1749 			ret_number,	    f_prevnonblank},
1750     {"printf",		1, 19, FEARG_2,	    arg119_printf,
1751 			ret_string,	    f_printf},
1752     {"prompt_getprompt", 1, 1, FEARG_1,	    arg1_buffer,
1753 			ret_string,	    JOB_FUNC(f_prompt_getprompt)},
1754     {"prompt_setcallback", 2, 2, FEARG_1,   arg2_buffer_any,
1755 			ret_void,	    JOB_FUNC(f_prompt_setcallback)},
1756     {"prompt_setinterrupt", 2, 2, FEARG_1,  arg2_buffer_any,
1757 			ret_void,	    JOB_FUNC(f_prompt_setinterrupt)},
1758     {"prompt_setprompt", 2, 2, FEARG_1,	    arg2_buffer_string,
1759 			ret_void,	    JOB_FUNC(f_prompt_setprompt)},
1760     {"prop_add",	3, 3, FEARG_1,	    arg3_number_number_dict,
1761 			ret_void,	    PROP_FUNC(f_prop_add)},
1762     {"prop_add_list",	2, 2, FEARG_1,	    arg2_dict_any_list_any,
1763 			ret_void,	    PROP_FUNC(f_prop_add_list)},
1764     {"prop_clear",	1, 3, FEARG_1,	    arg3_number_number_dict,
1765 			ret_void,	    PROP_FUNC(f_prop_clear)},
1766     {"prop_find",	1, 2, FEARG_1,	    arg2_dict_string,
1767 			ret_dict_any,	    PROP_FUNC(f_prop_find)},
1768     {"prop_list",	1, 2, FEARG_1,	    arg2_number_dict_any,
1769 			ret_list_dict_any,  PROP_FUNC(f_prop_list)},
1770     {"prop_remove",	1, 3, FEARG_1,	    arg3_dict_number_number,
1771 			ret_number,	    PROP_FUNC(f_prop_remove)},
1772     {"prop_type_add",	2, 2, FEARG_1,	    arg2_string_dict,
1773 			ret_void,	    PROP_FUNC(f_prop_type_add)},
1774     {"prop_type_change", 2, 2, FEARG_1,	    arg2_string_dict,
1775 			ret_void,	    PROP_FUNC(f_prop_type_change)},
1776     {"prop_type_delete", 1, 2, FEARG_1,	    arg2_string_dict,
1777 			ret_void,	    PROP_FUNC(f_prop_type_delete)},
1778     {"prop_type_get",	1, 2, FEARG_1,	    arg2_string_dict,
1779 			ret_dict_any,	    PROP_FUNC(f_prop_type_get)},
1780     {"prop_type_list",	0, 1, FEARG_1,	    arg1_dict_any,
1781 			ret_list_string,    PROP_FUNC(f_prop_type_list)},
1782     {"pum_getpos",	0, 0, 0,	    NULL,
1783 			ret_dict_number,    f_pum_getpos},
1784     {"pumvisible",	0, 0, 0,	    NULL,
1785 			ret_number_bool,    f_pumvisible},
1786     {"py3eval",		1, 1, FEARG_1,	    arg1_string,
1787 			ret_any,
1788 #ifdef FEAT_PYTHON3
1789 	    f_py3eval
1790 #else
1791 	    NULL
1792 #endif
1793 	    },
1794     {"pyeval",		1, 1, FEARG_1,	    arg1_string,
1795 			ret_any,
1796 #ifdef FEAT_PYTHON
1797 	    f_pyeval
1798 #else
1799 	    NULL
1800 #endif
1801 			},
1802     {"pyxeval",		1, 1, FEARG_1,	    arg1_string,
1803 			ret_any,
1804 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
1805 	    f_pyxeval
1806 #else
1807 	    NULL
1808 #endif
1809 			},
1810     {"rand",		0, 1, FEARG_1,	    arg1_list_number,
1811 			ret_number,	    f_rand},
1812     {"range",		1, 3, FEARG_1,	    arg3_number,
1813 			ret_list_number,    f_range},
1814     {"readblob",	1, 1, FEARG_1,	    arg1_string,
1815 			ret_blob,	    f_readblob},
1816     {"readdir",		1, 3, FEARG_1,	    arg3_string_any_dict,
1817 			ret_list_string,    f_readdir},
1818     {"readdirex",	1, 3, FEARG_1,	    arg3_string_any_dict,
1819 			ret_list_dict_any,  f_readdirex},
1820     {"readfile",	1, 3, FEARG_1,	    arg3_string_string_number,
1821 			ret_list_string,    f_readfile},
1822     {"reduce",		2, 3, FEARG_1,	    arg23_reduce,
1823 			ret_any,	    f_reduce},
1824     {"reg_executing",	0, 0, 0,	    NULL,
1825 			ret_string,	    f_reg_executing},
1826     {"reg_recording",	0, 0, 0,	    NULL,
1827 			ret_string,	    f_reg_recording},
1828     {"reltime",		0, 2, FEARG_1,	    arg2_list_number,
1829 			ret_list_any,	    f_reltime},
1830     {"reltimefloat",	1, 1, FEARG_1,	    arg1_list_number,
1831 			ret_float,	    FLOAT_FUNC(f_reltimefloat)},
1832     {"reltimestr",	1, 1, FEARG_1,	    arg1_list_number,
1833 			ret_string,	    f_reltimestr},
1834     {"remote_expr",	2, 4, FEARG_1,	    arg24_remote_expr,
1835 			ret_string,	    f_remote_expr},
1836     {"remote_foreground", 1, 1, FEARG_1,    arg1_string,
1837 			ret_string,	    f_remote_foreground},
1838     {"remote_peek",	1, 2, FEARG_1,	    arg2_string,
1839 			ret_number,	    f_remote_peek},
1840     {"remote_read",	1, 2, FEARG_1,	    arg2_string_number,
1841 			ret_string,	    f_remote_read},
1842     {"remote_send",	2, 3, FEARG_1,	    arg3_string,
1843 			ret_string,	    f_remote_send},
1844     {"remote_startserver", 1, 1, FEARG_1,   arg1_string,
1845 			ret_void,	    f_remote_startserver},
1846     {"remove",		2, 3, FEARG_1,	    arg23_remove,
1847 			ret_remove,	    f_remove},
1848     {"rename",		2, 2, FEARG_1,	    arg2_string,
1849 			ret_number_bool,    f_rename},
1850     {"repeat",		2, 2, FEARG_1,	    arg2_repeat,
1851 			ret_repeat,	    f_repeat},
1852     {"resolve",		1, 1, FEARG_1,	    arg1_string,
1853 			ret_string,	    f_resolve},
1854     {"reverse",		1, 1, FEARG_1,	    arg1_list_or_blob,
1855 			ret_first_arg,	    f_reverse},
1856     {"round",		1, 1, FEARG_1,	    arg1_float_or_nr,
1857 			ret_float,	    FLOAT_FUNC(f_round)},
1858     {"rubyeval",	1, 1, FEARG_1,	    arg1_string,
1859 			ret_any,
1860 #ifdef FEAT_RUBY
1861 	    f_rubyeval
1862 #else
1863 	    NULL
1864 #endif
1865 			},
1866     {"screenattr",	2, 2, FEARG_1,	    arg2_number,
1867 			ret_number,	    f_screenattr},
1868     {"screenchar",	2, 2, FEARG_1,	    arg2_number,
1869 			ret_number,	    f_screenchar},
1870     {"screenchars",	2, 2, FEARG_1,	    arg2_number,
1871 			ret_list_number,    f_screenchars},
1872     {"screencol",	0, 0, 0,	    NULL,
1873 			ret_number,	    f_screencol},
1874     {"screenpos",	3, 3, FEARG_1,	    arg3_number,
1875 			ret_dict_number,    f_screenpos},
1876     {"screenrow",	0, 0, 0,	    NULL,
1877 			ret_number,	    f_screenrow},
1878     {"screenstring",	2, 2, FEARG_1,	    arg2_number,
1879 			ret_string,	    f_screenstring},
1880     {"search",		1, 5, FEARG_1,	    arg15_search,
1881 			ret_number,	    f_search},
1882     {"searchcount",	0, 1, FEARG_1,	    arg1_dict_any,
1883 			ret_dict_any,	    f_searchcount},
1884     {"searchdecl",	1, 3, FEARG_1,	    arg3_string_bool_bool,
1885 			ret_number_bool,    f_searchdecl},
1886     {"searchpair",	3, 7, 0,	    arg37_searchpair,
1887 			ret_number,	    f_searchpair},
1888     {"searchpairpos",	3, 7, 0,	    arg37_searchpair,
1889 			ret_list_number,    f_searchpairpos},
1890     {"searchpos",	1, 5, FEARG_1,	    arg15_search,
1891 			ret_list_number,    f_searchpos},
1892     {"server2client",	2, 2, FEARG_1,	    arg2_string,
1893 			ret_number_bool,    f_server2client},
1894     {"serverlist",	0, 0, 0,	    NULL,
1895 			ret_string,	    f_serverlist},
1896     {"setbufline",	3, 3, FEARG_3,	    arg3_setbufline,
1897 			ret_number_bool,    f_setbufline},
1898     {"setbufvar",	3, 3, FEARG_3,	    arg3_buffer_string_any,
1899 			ret_void,	    f_setbufvar},
1900     {"setcellwidths",	1, 1, FEARG_1,	    arg1_list_any,
1901 			ret_void,	    f_setcellwidths},
1902     {"setcharpos",	2, 2, FEARG_2,	    arg2_string_list_number,
1903 			ret_number_bool,    f_setcharpos},
1904     {"setcharsearch",	1, 1, FEARG_1,	    arg1_dict_any,
1905 			ret_void,	    f_setcharsearch},
1906     {"setcmdpos",	1, 1, FEARG_1,	    arg1_number,
1907 			ret_number_bool,    f_setcmdpos},
1908     {"setcursorcharpos", 1, 3, FEARG_1,	    arg13_cursor,
1909 			ret_number_bool,    f_setcursorcharpos},
1910     {"setenv",		2, 2, FEARG_2,	    arg2_string_any,
1911 			ret_void,	    f_setenv},
1912     {"setfperm",	2, 2, FEARG_1,	    arg2_string,
1913 			ret_number_bool,    f_setfperm},
1914     {"setline",		2, 2, FEARG_2,	    arg2_setline,
1915 			ret_number_bool,    f_setline},
1916     {"setloclist",	2, 4, FEARG_2,	    arg24_setloclist,
1917 			ret_number_bool,    f_setloclist},
1918     {"setmatches",	1, 2, FEARG_1,	    arg2_list_any_number,
1919 			ret_number_bool,    f_setmatches},
1920     {"setpos",		2, 2, FEARG_2,	    arg2_string_list_number,
1921 			ret_number_bool,    f_setpos},
1922     {"setqflist",	1, 3, FEARG_1,	    arg13_setqflist,
1923 			ret_number_bool,    f_setqflist},
1924     {"setreg",		2, 3, FEARG_2,	    arg3_string_any_string,
1925 			ret_number_bool,    f_setreg},
1926     {"settabvar",	3, 3, FEARG_3,	    arg3_number_string_any,
1927 			ret_void,	    f_settabvar},
1928     {"settabwinvar",	4, 4, FEARG_4,	    arg4_number_number_string_any,
1929 			ret_void,	    f_settabwinvar},
1930     {"settagstack",	2, 3, FEARG_2,	    arg23_settagstack,
1931 			ret_number_bool,    f_settagstack},
1932     {"setwinvar",	3, 3, FEARG_3,	    arg3_number_string_any,
1933 			ret_void,	    f_setwinvar},
1934     {"sha256",		1, 1, FEARG_1,	    arg1_string,
1935 			ret_string,
1936 #ifdef FEAT_CRYPT
1937 	    f_sha256
1938 #else
1939 	    NULL
1940 #endif
1941 			},
1942     {"shellescape",	1, 2, FEARG_1,	    arg2_string_bool,
1943 			ret_string,	    f_shellescape},
1944     {"shiftwidth",	0, 1, FEARG_1,	    arg1_number,
1945 			ret_number,	    f_shiftwidth},
1946     {"sign_define",	1, 2, FEARG_1,	    arg2_string_or_list_dict,
1947 			ret_any,	    SIGN_FUNC(f_sign_define)},
1948     {"sign_getdefined",	0, 1, FEARG_1,	    arg1_string,
1949 			ret_list_dict_any,  SIGN_FUNC(f_sign_getdefined)},
1950     {"sign_getplaced",	0, 2, FEARG_1,	    arg02_sign_getplaced,
1951 			ret_list_dict_any,  SIGN_FUNC(f_sign_getplaced)},
1952     {"sign_jump",	3, 3, FEARG_1,	    arg3_number_string_buffer,
1953 			ret_number,	    SIGN_FUNC(f_sign_jump)},
1954     {"sign_place",	4, 5, FEARG_1,	    arg45_sign_place,
1955 			ret_number,	    SIGN_FUNC(f_sign_place)},
1956     {"sign_placelist",	1, 1, FEARG_1,	    arg1_list_any,
1957 			ret_list_number,    SIGN_FUNC(f_sign_placelist)},
1958     {"sign_undefine",	0, 1, FEARG_1,	    arg1_string_or_list_string,
1959 			ret_number_bool,    SIGN_FUNC(f_sign_undefine)},
1960     {"sign_unplace",	1, 2, FEARG_1,	    arg2_string_dict,
1961 			ret_number_bool,    SIGN_FUNC(f_sign_unplace)},
1962     {"sign_unplacelist", 1, 1, FEARG_1,	    arg1_list_any,
1963 			ret_list_number,    SIGN_FUNC(f_sign_unplacelist)},
1964     {"simplify",	1, 1, FEARG_1,	    arg1_string,
1965 			ret_string,	    f_simplify},
1966     {"sin",		1, 1, FEARG_1,	    arg1_float_or_nr,
1967 			ret_float,	    FLOAT_FUNC(f_sin)},
1968     {"sinh",		1, 1, FEARG_1,	    arg1_float_or_nr,
1969 			ret_float,	    FLOAT_FUNC(f_sinh)},
1970     {"slice",		2, 3, FEARG_1,	    arg23_slice,
1971 			ret_first_arg,	    f_slice},
1972     {"sort",		1, 3, FEARG_1,	    arg13_sortuniq,
1973 			ret_first_arg,	    f_sort},
1974     {"sound_clear",	0, 0, 0,	    NULL,
1975 			ret_void,	    SOUND_FUNC(f_sound_clear)},
1976     {"sound_playevent",	1, 2, FEARG_1,	    arg2_string_any,
1977 			ret_number,	    SOUND_FUNC(f_sound_playevent)},
1978     {"sound_playfile",	1, 2, FEARG_1,	    arg2_string_any,
1979 			ret_number,	    SOUND_FUNC(f_sound_playfile)},
1980     {"sound_stop",	1, 1, FEARG_1,	    arg1_number,
1981 			ret_void,	    SOUND_FUNC(f_sound_stop)},
1982     {"soundfold",	1, 1, FEARG_1,	    arg1_string,
1983 			ret_string,	    f_soundfold},
1984     {"spellbadword",	0, 1, FEARG_1,	    arg1_string,
1985 			ret_list_string,    f_spellbadword},
1986     {"spellsuggest",	1, 3, FEARG_1,	    arg3_string_number_bool,
1987 			ret_list_string,    f_spellsuggest},
1988     {"split",		1, 3, FEARG_1,	    arg3_string_string_bool,
1989 			ret_list_string,    f_split},
1990     {"sqrt",		1, 1, FEARG_1,	    arg1_float_or_nr,
1991 			ret_float,	    FLOAT_FUNC(f_sqrt)},
1992     {"srand",		0, 1, FEARG_1,	    arg1_number,
1993 			ret_list_number,    f_srand},
1994     {"state",		0, 1, FEARG_1,	    arg1_string,
1995 			ret_string,	    f_state},
1996     {"str2float",	1, 2, FEARG_1,	    arg2_string_bool,
1997 			ret_float,	    FLOAT_FUNC(f_str2float)},
1998     {"str2list",	1, 2, FEARG_1,	    arg2_string_bool,
1999 			ret_list_number,    f_str2list},
2000     {"str2nr",		1, 3, FEARG_1,	    arg3_string_number_bool,
2001 			ret_number,	    f_str2nr},
2002     {"strcharlen",	1, 1, FEARG_1,	    arg1_string_or_nr,
2003 			ret_number,	    f_strcharlen},
2004     {"strcharpart",	2, 4, FEARG_1,	    arg24_strpart,
2005 			ret_string,	    f_strcharpart},
2006     {"strchars",	1, 2, FEARG_1,	    arg2_string_bool,
2007 			ret_number,	    f_strchars},
2008     {"strdisplaywidth",	1, 2, FEARG_1,	    arg2_string_number,
2009 			ret_number,	    f_strdisplaywidth},
2010     {"strftime",	1, 2, FEARG_1,	    arg2_string_number,
2011 			ret_string,
2012 #ifdef HAVE_STRFTIME
2013 	    f_strftime
2014 #else
2015 	    NULL
2016 #endif
2017 			},
2018     {"strgetchar",	2, 2, FEARG_1,	    arg2_string_number,
2019 			ret_number,	    f_strgetchar},
2020     {"stridx",		2, 3, FEARG_1,	    arg3_string_string_number,
2021 			ret_number,	    f_stridx},
2022     {"string",		1, 1, FEARG_1,	    NULL,
2023 			ret_string,	    f_string},
2024     {"strlen",		1, 1, FEARG_1,	    arg1_string_or_nr,
2025 			ret_number,	    f_strlen},
2026     {"strpart",		2, 4, FEARG_1,	    arg24_strpart,
2027 			ret_string,	    f_strpart},
2028     {"strptime",	2, 2, FEARG_1,	    arg2_string,
2029 			ret_number,
2030 #ifdef HAVE_STRPTIME
2031 	    f_strptime
2032 #else
2033 	    NULL
2034 #endif
2035 			},
2036     {"strridx",		2, 3, FEARG_1,	    arg3_string_string_number,
2037 			ret_number,	    f_strridx},
2038     {"strtrans",	1, 1, FEARG_1,	    arg1_string,
2039 			ret_string,	    f_strtrans},
2040     {"strwidth",	1, 1, FEARG_1,	    arg1_string,
2041 			ret_number,	    f_strwidth},
2042     {"submatch",	1, 2, FEARG_1,	    arg2_number_bool,
2043 			ret_string,	    f_submatch},
2044     {"substitute",	4, 4, FEARG_1,	    arg4_string_string_any_string,
2045 			ret_string,	    f_substitute},
2046     {"swapinfo",	1, 1, FEARG_1,	    arg1_string,
2047 			ret_dict_any,	    f_swapinfo},
2048     {"swapname",	1, 1, FEARG_1,	    arg1_buffer,
2049 			ret_string,	    f_swapname},
2050     {"synID",		3, 3, 0,	    arg3_lnum_number_bool,
2051 			ret_number,	    f_synID},
2052     {"synIDattr",	2, 3, FEARG_1,	    arg3_number_string_string,
2053 			ret_string,	    f_synIDattr},
2054     {"synIDtrans",	1, 1, FEARG_1,	    arg1_number,
2055 			ret_number,	    f_synIDtrans},
2056     {"synconcealed",	2, 2, 0,	    arg2_lnum_number,
2057 			ret_list_any,	    f_synconcealed},
2058     {"synstack",	2, 2, 0,	    arg2_lnum_number,
2059 			ret_list_number,    f_synstack},
2060     {"system",		1, 2, FEARG_1,	    arg12_system,
2061 			ret_string,	    f_system},
2062     {"systemlist",	1, 2, FEARG_1,	    arg12_system,
2063 			ret_list_string,    f_systemlist},
2064     {"tabpagebuflist",	0, 1, FEARG_1,	    arg1_number,
2065 			ret_list_number,    f_tabpagebuflist},
2066     {"tabpagenr",	0, 1, 0,	    arg1_string,
2067 			ret_number,	    f_tabpagenr},
2068     {"tabpagewinnr",	1, 2, FEARG_1,	    arg2_number_string,
2069 			ret_number,	    f_tabpagewinnr},
2070     {"tagfiles",	0, 0, 0,	    NULL,
2071 			ret_list_string,    f_tagfiles},
2072     {"taglist",		1, 2, FEARG_1,	    arg2_string,
2073 			ret_list_dict_any,  f_taglist},
2074     {"tan",		1, 1, FEARG_1,	    arg1_float_or_nr,
2075 			ret_float,	    FLOAT_FUNC(f_tan)},
2076     {"tanh",		1, 1, FEARG_1,	    arg1_float_or_nr,
2077 			ret_float,	    FLOAT_FUNC(f_tanh)},
2078     {"tempname",	0, 0, 0,	    NULL,
2079 			ret_string,	    f_tempname},
2080     {"term_dumpdiff",	2, 3, FEARG_1,	    arg3_string_string_dict,
2081 			ret_number,	    TERM_FUNC(f_term_dumpdiff)},
2082     {"term_dumpload",	1, 2, FEARG_1,	    arg2_string_dict,
2083 			ret_number,	    TERM_FUNC(f_term_dumpload)},
2084     {"term_dumpwrite",	2, 3, FEARG_2,	    arg3_buffer_string_dict,
2085 			ret_void,	    TERM_FUNC(f_term_dumpwrite)},
2086     {"term_getaltscreen", 1, 1, FEARG_1,    arg1_buffer,
2087 			ret_number,	    TERM_FUNC(f_term_getaltscreen)},
2088     {"term_getansicolors", 1, 1, FEARG_1,   arg1_buffer,
2089 			ret_list_string,
2090 #if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
2091 	    f_term_getansicolors
2092 #else
2093 	    NULL
2094 #endif
2095 			},
2096     {"term_getattr",	2, 2, FEARG_1,	    arg2_number_string,
2097 			ret_number,	    TERM_FUNC(f_term_getattr)},
2098     {"term_getcursor",	1, 1, FEARG_1,	    arg1_buffer,
2099 			ret_list_any,	    TERM_FUNC(f_term_getcursor)},
2100     {"term_getjob",	1, 1, FEARG_1,	    arg1_buffer,
2101 			ret_job,	    TERM_FUNC(f_term_getjob)},
2102     {"term_getline",	2, 2, FEARG_1,	    arg2_buffer_lnum,
2103 			ret_string,	    TERM_FUNC(f_term_getline)},
2104     {"term_getscrolled", 1, 1, FEARG_1,	    arg1_buffer,
2105 			ret_number,	    TERM_FUNC(f_term_getscrolled)},
2106     {"term_getsize",	1, 1, FEARG_1,	    arg1_buffer,
2107 			ret_list_number,    TERM_FUNC(f_term_getsize)},
2108     {"term_getstatus",	1, 1, FEARG_1,	    arg1_buffer,
2109 			ret_string,	    TERM_FUNC(f_term_getstatus)},
2110     {"term_gettitle",	1, 1, FEARG_1,	    arg1_buffer,
2111 			ret_string,	    TERM_FUNC(f_term_gettitle)},
2112     {"term_gettty",	1, 2, FEARG_1,	    arg2_buffer_bool,
2113 			ret_string,	    TERM_FUNC(f_term_gettty)},
2114     {"term_list",	0, 0, 0,	    NULL,
2115 			ret_list_number,    TERM_FUNC(f_term_list)},
2116     {"term_scrape",	2, 2, FEARG_1,	    arg2_buffer_lnum,
2117 			ret_list_dict_any,  TERM_FUNC(f_term_scrape)},
2118     {"term_sendkeys",	2, 2, FEARG_1,	    arg2_buffer_string,
2119 			ret_void,	    TERM_FUNC(f_term_sendkeys)},
2120     {"term_setansicolors", 2, 2, FEARG_1,   arg2_buffer_list_any,
2121 			ret_void,
2122 #if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
2123 	    f_term_setansicolors
2124 #else
2125 	    NULL
2126 #endif
2127 			},
2128     {"term_setapi",	2, 2, FEARG_1,	    arg2_buffer_string,
2129 			ret_void,	    TERM_FUNC(f_term_setapi)},
2130     {"term_setkill",	2, 2, FEARG_1,	    arg2_buffer_string,
2131 			ret_void,	    TERM_FUNC(f_term_setkill)},
2132     {"term_setrestore",	2, 2, FEARG_1,	    arg2_buffer_string,
2133 			ret_void,	    TERM_FUNC(f_term_setrestore)},
2134     {"term_setsize",	3, 3, FEARG_1,	    arg3_buffer_number_number,
2135 			ret_void,	    TERM_FUNC(f_term_setsize)},
2136     {"term_start",	1, 2, FEARG_1,	    arg2_string_or_list_dict,
2137 			ret_number,	    TERM_FUNC(f_term_start)},
2138     {"term_wait",	1, 2, FEARG_1,	    arg2_buffer_number,
2139 			ret_void,	    TERM_FUNC(f_term_wait)},
2140     {"terminalprops",	0, 0, 0,	    NULL,
2141 			ret_dict_string,    f_terminalprops},
2142     {"test_alloc_fail",	3, 3, FEARG_1,	    arg3_number,
2143 			ret_void,	    f_test_alloc_fail},
2144     {"test_autochdir",	0, 0, 0,	    NULL,
2145 			ret_void,	    f_test_autochdir},
2146     {"test_feedinput",	1, 1, FEARG_1,	    arg1_string,
2147 			ret_void,	    f_test_feedinput},
2148     {"test_garbagecollect_now",	0, 0, 0,    NULL,
2149 			ret_void,	    f_test_garbagecollect_now},
2150     {"test_garbagecollect_soon", 0, 0, 0,   NULL,
2151 			ret_void,	    f_test_garbagecollect_soon},
2152     {"test_getvalue",	1, 1, FEARG_1,	    arg1_string,
2153 			ret_number,	    f_test_getvalue},
2154     {"test_gui_drop_files",	4, 4, 0,    arg4_list_number_number_number,
2155 			ret_void,	    f_test_gui_drop_files},
2156     {"test_gui_mouse_event",	5, 5, 0,    arg5_number,
2157 			ret_void,	    f_test_gui_mouse_event},
2158     {"test_ignore_error", 1, 1, FEARG_1,    arg1_string,
2159 			ret_void,	    f_test_ignore_error},
2160     {"test_null_blob",	0, 0, 0,	    NULL,
2161 			ret_blob,	    f_test_null_blob},
2162     {"test_null_channel", 0, 0, 0,	    NULL,
2163 			ret_channel,	    JOB_FUNC(f_test_null_channel)},
2164     {"test_null_dict",	0, 0, 0,	    NULL,
2165 			ret_dict_any,	    f_test_null_dict},
2166     {"test_null_function", 0, 0, 0,	    NULL,
2167 			ret_func_any,	    f_test_null_function},
2168     {"test_null_job",	0, 0, 0,	    NULL,
2169 			ret_job,	    JOB_FUNC(f_test_null_job)},
2170     {"test_null_list",	0, 0, 0,	    NULL,
2171 			ret_list_any,	    f_test_null_list},
2172     {"test_null_partial", 0, 0, 0,	    NULL,
2173 			ret_func_any,	    f_test_null_partial},
2174     {"test_null_string", 0, 0, 0,	    NULL,
2175 			ret_string,	    f_test_null_string},
2176     {"test_option_not_set", 1, 1, FEARG_1,  arg1_string,
2177 			ret_void,	    f_test_option_not_set},
2178     {"test_override",	2, 2, FEARG_2,	    arg2_string_number,
2179 			ret_void,	    f_test_override},
2180     {"test_refcount",	1, 1, FEARG_1,	    NULL,
2181 			ret_number,	    f_test_refcount},
2182     {"test_scrollbar",	3, 3, FEARG_2,	    arg3_string_number_number,
2183 			ret_void,
2184 #ifdef FEAT_GUI
2185 	f_test_scrollbar
2186 #else
2187 	NULL
2188 #endif
2189 			},
2190     {"test_setmouse",	2, 2, 0,	    arg2_number,
2191 			ret_void,	    f_test_setmouse},
2192     {"test_settime",	1, 1, FEARG_1,	    arg1_number,
2193 			ret_void,	    f_test_settime},
2194     {"test_srand_seed",	0, 1, FEARG_1,	    arg1_number,
2195 			ret_void,	    f_test_srand_seed},
2196     {"test_unknown",	0, 0, 0,	    NULL,
2197 			ret_any,	    f_test_unknown},
2198     {"test_void",	0, 0, 0,	    NULL,
2199 			ret_void,	    f_test_void},
2200     {"timer_info",	0, 1, FEARG_1,	    arg1_number,
2201 			ret_list_dict_any,  TIMER_FUNC(f_timer_info)},
2202     {"timer_pause",	2, 2, FEARG_1,	    arg2_number_bool,
2203 			ret_void,	    TIMER_FUNC(f_timer_pause)},
2204     {"timer_start",	2, 3, FEARG_1,	    arg3_number_any_dict,
2205 			ret_number,	    TIMER_FUNC(f_timer_start)},
2206     {"timer_stop",	1, 1, FEARG_1,	    arg1_number,
2207 			ret_void,	    TIMER_FUNC(f_timer_stop)},
2208     {"timer_stopall",	0, 0, 0,	    NULL,
2209 			ret_void,	    TIMER_FUNC(f_timer_stopall)},
2210     {"tolower",		1, 1, FEARG_1,	    arg1_string,
2211 			ret_string,	    f_tolower},
2212     {"toupper",		1, 1, FEARG_1,	    arg1_string,
2213 			ret_string,	    f_toupper},
2214     {"tr",		3, 3, FEARG_1,	    arg3_string,
2215 			ret_string,	    f_tr},
2216     {"trim",		1, 3, FEARG_1,	    arg3_string_string_number,
2217 			ret_string,	    f_trim},
2218     {"trunc",		1, 1, FEARG_1,	    arg1_float_or_nr,
2219 			ret_float,	    FLOAT_FUNC(f_trunc)},
2220     {"type",		1, 1, FEARG_1,	    NULL,
2221 			ret_number,	    f_type},
2222     {"typename",	1, 1, FEARG_1,	    NULL,
2223 			ret_string,	    f_typename},
2224     {"undofile",	1, 1, FEARG_1,	    arg1_string,
2225 			ret_string,	    f_undofile},
2226     {"undotree",	0, 0, 0,	    NULL,
2227 			ret_dict_any,	    f_undotree},
2228     {"uniq",		1, 3, FEARG_1,	    arg13_sortuniq,
2229 			ret_list_any,	    f_uniq},
2230     {"values",		1, 1, FEARG_1,	    arg1_dict_any,
2231 			ret_list_any,	    f_values},
2232     {"virtcol",		1, 1, FEARG_1,	    arg1_string_or_list_any,
2233 			ret_number,	    f_virtcol},
2234     {"visualmode",	0, 1, 0,	    arg1_bool,
2235 			ret_string,	    f_visualmode},
2236     {"wildmenumode",	0, 0, 0,	    NULL,
2237 			ret_number,	    f_wildmenumode},
2238     {"win_execute",	2, 3, FEARG_2,	    arg23_win_execute,
2239 			ret_string,	    f_win_execute},
2240     {"win_findbuf",	1, 1, FEARG_1,	    arg1_number,
2241 			ret_list_number,    f_win_findbuf},
2242     {"win_getid",	0, 2, FEARG_1,	    arg2_number,
2243 			ret_number,	    f_win_getid},
2244     {"win_gettype",	0, 1, FEARG_1,	    arg1_number,
2245 			ret_string,	    f_win_gettype},
2246     {"win_gotoid",	1, 1, FEARG_1,	    arg1_number,
2247 			ret_number_bool,    f_win_gotoid},
2248     {"win_id2tabwin",	1, 1, FEARG_1,	    arg1_number,
2249 			ret_list_number,    f_win_id2tabwin},
2250     {"win_id2win",	1, 1, FEARG_1,	    arg1_number,
2251 			ret_number,	    f_win_id2win},
2252     {"win_screenpos",	1, 1, FEARG_1,	    arg1_number,
2253 			ret_list_number,    f_win_screenpos},
2254     {"win_splitmove",   2, 3, FEARG_1,	    arg3_number_number_dict,
2255 			ret_number_bool,    f_win_splitmove},
2256     {"winbufnr",	1, 1, FEARG_1,	    arg1_number,
2257 			ret_number,	    f_winbufnr},
2258     {"wincol",		0, 0, 0,	    NULL,
2259 			ret_number,	    f_wincol},
2260     {"windowsversion",	0, 0, 0,	    NULL,
2261 			ret_string,	    f_windowsversion},
2262     {"winheight",	1, 1, FEARG_1,	    arg1_number,
2263 			ret_number,	    f_winheight},
2264     {"winlayout",	0, 1, FEARG_1,	    arg1_number,
2265 			ret_list_any,	    f_winlayout},
2266     {"winline",		0, 0, 0,	    NULL,
2267 			ret_number,	    f_winline},
2268     {"winnr",		0, 1, FEARG_1,	    arg1_string,
2269 			ret_number,	    f_winnr},
2270     {"winrestcmd",	0, 0, 0,	    NULL,
2271 			ret_string,	    f_winrestcmd},
2272     {"winrestview",	1, 1, FEARG_1,	    arg1_dict_any,
2273 			ret_void,	    f_winrestview},
2274     {"winsaveview",	0, 0, 0,	    NULL,
2275 			ret_dict_number,    f_winsaveview},
2276     {"winwidth",	1, 1, FEARG_1,	    arg1_number,
2277 			ret_number,	    f_winwidth},
2278     {"wordcount",	0, 0, 0,	    NULL,
2279 			ret_dict_number,    f_wordcount},
2280     {"writefile",	2, 3, FEARG_1,	    arg23_writefile,
2281 			ret_number_bool,    f_writefile},
2282     {"xor",		2, 2, FEARG_1,	    arg2_number,
2283 			ret_number,	    f_xor},
2284 };
2285 
2286 #if defined(EBCDIC) || defined(PROTO)
2287 /*
2288  * Compare funcentry_T by function name.
2289  */
2290     static int
compare_func_name(const void * s1,const void * s2)2291 compare_func_name(const void *s1, const void *s2)
2292 {
2293     funcentry_T *p1 = (funcentry_T *)s1;
2294     funcentry_T *p2 = (funcentry_T *)s2;
2295 
2296     return STRCMP(p1->f_name, p2->f_name);
2297 }
2298 
2299 /*
2300  * Sort the function table by function name.
2301  * The sorting of the table above is ASCII dependent.
2302  * On machines using EBCDIC we have to sort it.
2303  */
2304     void
sortFunctions(void)2305 sortFunctions(void)
2306 {
2307     size_t	funcCnt = ARRAY_LENGTH(global_functions);
2308 
2309     qsort(global_functions, funcCnt, sizeof(funcentry_T), compare_func_name);
2310 }
2311 #endif
2312 
2313 /*
2314  * Function given to ExpandGeneric() to obtain the list of internal
2315  * or user defined function names.
2316  */
2317     char_u *
get_function_name(expand_T * xp,int idx)2318 get_function_name(expand_T *xp, int idx)
2319 {
2320     static int	intidx = -1;
2321     char_u	*name;
2322 
2323     if (idx == 0)
2324 	intidx = -1;
2325     if (intidx < 0)
2326     {
2327 	name = get_user_func_name(xp, idx);
2328 	if (name != NULL)
2329 	{
2330 	    if (*name != NUL && *name != '<'
2331 				      && STRNCMP("g:", xp->xp_pattern, 2) == 0)
2332 		return cat_prefix_varname('g', name);
2333 	    return name;
2334 	}
2335     }
2336     if (++intidx < (int)ARRAY_LENGTH(global_functions))
2337     {
2338 	STRCPY(IObuff, global_functions[intidx].f_name);
2339 	STRCAT(IObuff, "(");
2340 	if (global_functions[intidx].f_max_argc == 0)
2341 	    STRCAT(IObuff, ")");
2342 	return IObuff;
2343     }
2344 
2345     return NULL;
2346 }
2347 
2348 /*
2349  * Function given to ExpandGeneric() to obtain the list of internal or
2350  * user defined variable or function names.
2351  */
2352     char_u *
get_expr_name(expand_T * xp,int idx)2353 get_expr_name(expand_T *xp, int idx)
2354 {
2355     static int	intidx = -1;
2356     char_u	*name;
2357 
2358     if (idx == 0)
2359 	intidx = -1;
2360     if (intidx < 0)
2361     {
2362 	name = get_function_name(xp, idx);
2363 	if (name != NULL)
2364 	    return name;
2365     }
2366     return get_user_var_name(xp, ++intidx);
2367 }
2368 
2369 /*
2370  * Find internal function "name" in table "global_functions".
2371  * Return index, or -1 if not found or "implemented" is TRUE and the function
2372  * is not implemented.
2373  */
2374     static int
find_internal_func_opt(char_u * name,int implemented)2375 find_internal_func_opt(char_u *name, int implemented)
2376 {
2377     int		first = 0;
2378     int		last;
2379     int		cmp;
2380     int		x;
2381 
2382     last = (int)ARRAY_LENGTH(global_functions) - 1;
2383 
2384     // Find the function name in the table. Binary search.
2385     while (first <= last)
2386     {
2387 	x = first + ((unsigned)(last - first) >> 1);
2388 	cmp = STRCMP(name, global_functions[x].f_name);
2389 	if (cmp < 0)
2390 	    last = x - 1;
2391 	else if (cmp > 0)
2392 	    first = x + 1;
2393 	else if (implemented && global_functions[x].f_func == NULL)
2394 	    break;
2395 	else
2396 	    return x;
2397     }
2398     return -1;
2399 }
2400 
2401 /*
2402  * Find internal function "name" in table "global_functions".
2403  * Return index, or -1 if not found or the function is not implemented.
2404  */
2405     int
find_internal_func(char_u * name)2406 find_internal_func(char_u *name)
2407 {
2408     return find_internal_func_opt(name, TRUE);
2409 }
2410 
2411     int
has_internal_func(char_u * name)2412 has_internal_func(char_u *name)
2413 {
2414     return find_internal_func_opt(name, TRUE) >= 0;
2415 }
2416 
2417     static int
has_internal_func_name(char_u * name)2418 has_internal_func_name(char_u *name)
2419 {
2420     return find_internal_func_opt(name, FALSE) >= 0;
2421 }
2422 
2423     char *
internal_func_name(int idx)2424 internal_func_name(int idx)
2425 {
2426     return global_functions[idx].f_name;
2427 }
2428 
2429 /*
2430  * Check the argument types for builtin function "idx".
2431  * Uses the list of types on the type stack: "types".
2432  * Return FAIL and gives an error message when a type is wrong.
2433  */
2434     int
internal_func_check_arg_types(type_T ** types,int idx,int argcount,cctx_T * cctx)2435 internal_func_check_arg_types(
2436 	type_T	**types,
2437 	int	idx,
2438 	int	argcount,
2439 	cctx_T	*cctx)
2440 {
2441     argcheck_T	*argchecks = global_functions[idx].f_argcheck;
2442     int		i;
2443 
2444     if (argchecks != NULL)
2445     {
2446 	argcontext_T context;
2447 
2448 	context.arg_count = argcount;
2449 	context.arg_types = types;
2450 	context.arg_cctx = cctx;
2451 	for (i = 0; i < argcount; ++i)
2452 	    if (argchecks[i] != NULL)
2453 	    {
2454 		context.arg_idx = i;
2455 		if (argchecks[i](types[i], &context) == FAIL)
2456 		    return FAIL;
2457 	    }
2458     }
2459     return OK;
2460 }
2461 
2462 /*
2463  * Get the argument count for function "idx".
2464  * "argcount" is the total argument count, "min_argcount" the non-optional
2465  * argument count.
2466  */
2467     void
internal_func_get_argcount(int idx,int * argcount,int * min_argcount)2468 internal_func_get_argcount(int idx, int *argcount, int *min_argcount)
2469 {
2470     *argcount = global_functions[idx].f_max_argc;
2471     *min_argcount = global_functions[idx].f_min_argc;
2472 }
2473 
2474 /*
2475  * Call the "f_retfunc" function to obtain the return type of function "idx".
2476  * "argtypes" is the list of argument types or NULL when there are no
2477  * arguments.
2478  * "argcount" may be less than the actual count when only getting the type.
2479  */
2480     type_T *
internal_func_ret_type(int idx,int argcount,type_T ** argtypes)2481 internal_func_ret_type(int idx, int argcount, type_T **argtypes)
2482 {
2483     return global_functions[idx].f_retfunc(argcount, argtypes);
2484 }
2485 
2486 /*
2487  * Return TRUE if "idx" is for the map() function.
2488  */
2489     int
internal_func_is_map(int idx)2490 internal_func_is_map(int idx)
2491 {
2492     return global_functions[idx].f_func == f_map;
2493 }
2494 
2495 /*
2496  * Check the argument count to use for internal function "idx".
2497  * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
2498  * first argument, 2 if method base is second argument, etc.  9 if method base
2499  * is last argument.
2500  */
2501     int
check_internal_func(int idx,int argcount)2502 check_internal_func(int idx, int argcount)
2503 {
2504     int	    res;
2505     char    *name;
2506 
2507     if (argcount < global_functions[idx].f_min_argc)
2508 	res = FCERR_TOOFEW;
2509     else if (argcount > global_functions[idx].f_max_argc)
2510 	res = FCERR_TOOMANY;
2511     else
2512 	return global_functions[idx].f_argtype;
2513 
2514     name = internal_func_name(idx);
2515     if (res == FCERR_TOOMANY)
2516 	semsg(_(e_toomanyarg), name);
2517     else
2518 	semsg(_(e_toofewarg), name);
2519     return -1;
2520 }
2521 
2522     int
call_internal_func(char_u * name,int argcount,typval_T * argvars,typval_T * rettv)2523 call_internal_func(
2524 	char_u	    *name,
2525 	int	    argcount,
2526 	typval_T    *argvars,
2527 	typval_T    *rettv)
2528 {
2529     int i;
2530 
2531     i = find_internal_func(name);
2532     if (i < 0)
2533 	return FCERR_UNKNOWN;
2534     if (argcount < global_functions[i].f_min_argc)
2535 	return FCERR_TOOFEW;
2536     if (argcount > global_functions[i].f_max_argc)
2537 	return FCERR_TOOMANY;
2538     argvars[argcount].v_type = VAR_UNKNOWN;
2539     global_functions[i].f_func(argvars, rettv);
2540     return FCERR_NONE;
2541 }
2542 
2543     void
call_internal_func_by_idx(int idx,typval_T * argvars,typval_T * rettv)2544 call_internal_func_by_idx(
2545 	int	    idx,
2546 	typval_T    *argvars,
2547 	typval_T    *rettv)
2548 {
2549     global_functions[idx].f_func(argvars, rettv);
2550 }
2551 
2552 /*
2553  * Invoke a method for base->method().
2554  */
2555     int
call_internal_method(char_u * name,int argcount,typval_T * argvars,typval_T * rettv,typval_T * basetv)2556 call_internal_method(
2557 	char_u	    *name,
2558 	int	    argcount,
2559 	typval_T    *argvars,
2560 	typval_T    *rettv,
2561 	typval_T    *basetv)
2562 {
2563     int		i;
2564     int		fi;
2565     typval_T	argv[MAX_FUNC_ARGS + 1];
2566 
2567     fi = find_internal_func(name);
2568     if (fi < 0)
2569 	return FCERR_UNKNOWN;
2570     if (global_functions[fi].f_argtype == 0)
2571 	return FCERR_NOTMETHOD;
2572     if (argcount + 1 < global_functions[fi].f_min_argc)
2573 	return FCERR_TOOFEW;
2574     if (argcount + 1 > global_functions[fi].f_max_argc)
2575 	return FCERR_TOOMANY;
2576 
2577     if (global_functions[fi].f_argtype == FEARG_LAST)
2578     {
2579 	// base value goes last
2580 	for (i = 0; i < argcount; ++i)
2581 	    argv[i] = argvars[i];
2582 	argv[argcount] = *basetv;
2583     }
2584     else if (global_functions[fi].f_argtype == FEARG_2)
2585     {
2586 	// base value goes second
2587 	argv[0] = argvars[0];
2588 	argv[1] = *basetv;
2589 	for (i = 1; i < argcount; ++i)
2590 	    argv[i + 1] = argvars[i];
2591     }
2592     else if (global_functions[fi].f_argtype == FEARG_3)
2593     {
2594 	// base value goes third
2595 	argv[0] = argvars[0];
2596 	argv[1] = argvars[1];
2597 	argv[2] = *basetv;
2598 	for (i = 2; i < argcount; ++i)
2599 	    argv[i + 1] = argvars[i];
2600     }
2601     else if (global_functions[fi].f_argtype == FEARG_4)
2602     {
2603 	// base value goes fourth
2604 	argv[0] = argvars[0];
2605 	argv[1] = argvars[1];
2606 	argv[2] = argvars[2];
2607 	argv[3] = *basetv;
2608 	for (i = 3; i < argcount; ++i)
2609 	    argv[i + 1] = argvars[i];
2610     }
2611     else
2612     {
2613 	// FEARG_1: base value goes first
2614 	argv[0] = *basetv;
2615 	for (i = 0; i < argcount; ++i)
2616 	    argv[i + 1] = argvars[i];
2617     }
2618     argv[argcount + 1].v_type = VAR_UNKNOWN;
2619 
2620     global_functions[fi].f_func(argv, rettv);
2621     return FCERR_NONE;
2622 }
2623 
2624 /*
2625  * Return TRUE for a non-zero Number and a non-empty String.
2626  */
2627     int
non_zero_arg(typval_T * argvars)2628 non_zero_arg(typval_T *argvars)
2629 {
2630     return ((argvars[0].v_type == VAR_NUMBER
2631 		&& argvars[0].vval.v_number != 0)
2632 	    || (argvars[0].v_type == VAR_BOOL
2633 		&& argvars[0].vval.v_number == VVAL_TRUE)
2634 	    || (argvars[0].v_type == VAR_STRING
2635 		&& argvars[0].vval.v_string != NULL
2636 		&& *argvars[0].vval.v_string != NUL));
2637 }
2638 
2639 /*
2640  * "and(expr, expr)" function
2641  */
2642     static void
f_and(typval_T * argvars,typval_T * rettv)2643 f_and(typval_T *argvars, typval_T *rettv)
2644 {
2645     if (in_vim9script()
2646 	    && (check_for_number_arg(argvars, 0) == FAIL
2647 		|| check_for_number_arg(argvars, 1) == FAIL))
2648 	return;
2649 
2650     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
2651 					& tv_get_number_chk(&argvars[1], NULL);
2652 }
2653 
2654 /*
2655  * "balloon_show()" function
2656  */
2657 #ifdef FEAT_BEVAL
2658     static void
f_balloon_gettext(typval_T * argvars UNUSED,typval_T * rettv)2659 f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
2660 {
2661     rettv->v_type = VAR_STRING;
2662     if (balloonEval != NULL)
2663     {
2664 	if (balloonEval->msg == NULL)
2665 	    rettv->vval.v_string = NULL;
2666 	else
2667 	    rettv->vval.v_string = vim_strsave(balloonEval->msg);
2668     }
2669 }
2670 
2671     static void
f_balloon_show(typval_T * argvars,typval_T * rettv UNUSED)2672 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
2673 {
2674     if (balloonEval != NULL)
2675     {
2676 	if (in_vim9script()
2677 		&& check_for_string_or_list_arg(argvars, 0) == FAIL)
2678 	    return;
2679 
2680 	if (argvars[0].v_type == VAR_LIST
2681 # ifdef FEAT_GUI
2682 		&& !gui.in_use
2683 # endif
2684 	   )
2685 	{
2686 	    list_T *l = argvars[0].vval.v_list;
2687 
2688 	    // empty list removes the balloon
2689 	    post_balloon(balloonEval, NULL,
2690 				       l == NULL || l->lv_len == 0 ? NULL : l);
2691 	}
2692 	else
2693 	{
2694 	    char_u *mesg;
2695 
2696 	    if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2697 		return;
2698 
2699 	    mesg = tv_get_string_chk(&argvars[0]);
2700 	    if (mesg != NULL)
2701 		// empty string removes the balloon
2702 		post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
2703 	}
2704     }
2705 }
2706 
2707 # if defined(FEAT_BEVAL_TERM)
2708     static void
f_balloon_split(typval_T * argvars,typval_T * rettv UNUSED)2709 f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
2710 {
2711     if (rettv_list_alloc(rettv) == OK)
2712     {
2713 	char_u *msg;
2714 
2715 	if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2716 	    return;
2717 	msg = tv_get_string_chk(&argvars[0]);
2718 	if (msg != NULL)
2719 	{
2720 	    pumitem_T	*array;
2721 	    int		size = split_message(msg, &array);
2722 	    int		i;
2723 
2724 	    // Skip the first and last item, they are always empty.
2725 	    for (i = 1; i < size - 1; ++i)
2726 		list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
2727 	    while (size > 0)
2728 		vim_free(array[--size].pum_text);
2729 	    vim_free(array);
2730 	}
2731     }
2732 }
2733 # endif
2734 #endif
2735 
2736 /*
2737  * Get the buffer from "arg" and give an error and return NULL if it is not
2738  * valid.
2739  */
2740     buf_T *
get_buf_arg(typval_T * arg)2741 get_buf_arg(typval_T *arg)
2742 {
2743     buf_T *buf;
2744 
2745     ++emsg_off;
2746     buf = tv_get_buf(arg, FALSE);
2747     --emsg_off;
2748     if (buf == NULL)
2749 	semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
2750     return buf;
2751 }
2752 
2753 /*
2754  * "byte2line(byte)" function
2755  */
2756     static void
f_byte2line(typval_T * argvars UNUSED,typval_T * rettv)2757 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2758 {
2759 #ifndef FEAT_BYTEOFF
2760     rettv->vval.v_number = -1;
2761 #else
2762     long	boff = 0;
2763 
2764     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
2765 	return;
2766 
2767     boff = tv_get_number(&argvars[0]) - 1;  // boff gets -1 on type error
2768     if (boff < 0)
2769 	rettv->vval.v_number = -1;
2770     else
2771 	rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2772 							  (linenr_T)0, &boff);
2773 #endif
2774 }
2775 
2776 /*
2777  * "call(func, arglist [, dict])" function
2778  */
2779     static void
f_call(typval_T * argvars,typval_T * rettv)2780 f_call(typval_T *argvars, typval_T *rettv)
2781 {
2782     char_u	*func;
2783     partial_T   *partial = NULL;
2784     dict_T	*selfdict = NULL;
2785 
2786     if (in_vim9script()
2787 	    && (check_for_list_arg(argvars, 1) == FAIL
2788 		|| check_for_opt_dict_arg(argvars, 2) == FAIL))
2789 	return;
2790 
2791     if (argvars[1].v_type != VAR_LIST)
2792     {
2793 	emsg(_(e_listreq));
2794 	return;
2795     }
2796     if (argvars[1].vval.v_list == NULL)
2797 	return;
2798 
2799     if (argvars[0].v_type == VAR_FUNC)
2800 	func = argvars[0].vval.v_string;
2801     else if (argvars[0].v_type == VAR_PARTIAL)
2802     {
2803 	partial = argvars[0].vval.v_partial;
2804 	func = partial_name(partial);
2805     }
2806     else
2807 	func = tv_get_string(&argvars[0]);
2808     if (func == NULL || *func == NUL)
2809 	return;		// type error, empty name or null function
2810 
2811     if (argvars[2].v_type != VAR_UNKNOWN)
2812     {
2813 	if (argvars[2].v_type != VAR_DICT)
2814 	{
2815 	    emsg(_(e_dictreq));
2816 	    return;
2817 	}
2818 	selfdict = argvars[2].vval.v_dict;
2819     }
2820 
2821     (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2822 }
2823 
2824 /*
2825  * "changenr()" function
2826  */
2827     static void
f_changenr(typval_T * argvars UNUSED,typval_T * rettv)2828 f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2829 {
2830     rettv->vval.v_number = curbuf->b_u_seq_cur;
2831 }
2832 
2833 /*
2834  * "char2nr(string)" function
2835  */
2836     static void
f_char2nr(typval_T * argvars,typval_T * rettv)2837 f_char2nr(typval_T *argvars, typval_T *rettv)
2838 {
2839     if (in_vim9script()
2840 	    && (check_for_string_arg(argvars, 0) == FAIL
2841 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
2842 	return;
2843 
2844     if (has_mbyte)
2845     {
2846 	int	utf8 = 0;
2847 
2848 	if (argvars[1].v_type != VAR_UNKNOWN)
2849 	    utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
2850 
2851 	if (utf8)
2852 	    rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
2853 	else
2854 	    rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
2855     }
2856     else
2857 	rettv->vval.v_number = tv_get_string(&argvars[0])[0];
2858 }
2859 
2860 /*
2861  * Get the current cursor column and store it in 'rettv'. If 'charcol' is TRUE,
2862  * returns the character index of the column. Otherwise, returns the byte index
2863  * of the column.
2864  */
2865     static void
get_col(typval_T * argvars,typval_T * rettv,int charcol)2866 get_col(typval_T *argvars, typval_T *rettv, int charcol)
2867 {
2868     colnr_T	col = 0;
2869     pos_T	*fp;
2870     int		fnum = curbuf->b_fnum;
2871 
2872     if (in_vim9script()
2873 	    && check_for_string_or_list_arg(argvars, 0) == FAIL)
2874 	return;
2875 
2876     fp = var2fpos(&argvars[0], FALSE, &fnum, charcol);
2877     if (fp != NULL && fnum == curbuf->b_fnum)
2878     {
2879 	if (fp->col == MAXCOL)
2880 	{
2881 	    // '> can be MAXCOL, get the length of the line then
2882 	    if (fp->lnum <= curbuf->b_ml.ml_line_count)
2883 		col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2884 	    else
2885 		col = MAXCOL;
2886 	}
2887 	else
2888 	{
2889 	    col = fp->col + 1;
2890 	    // col(".") when the cursor is on the NUL at the end of the line
2891 	    // because of "coladd" can be seen as an extra column.
2892 	    if (virtual_active() && fp == &curwin->w_cursor)
2893 	    {
2894 		char_u	*p = ml_get_cursor();
2895 
2896 		if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2897 				 curwin->w_virtcol - curwin->w_cursor.coladd))
2898 		{
2899 		    int		l;
2900 
2901 		    if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2902 			col += l;
2903 		}
2904 	    }
2905 	}
2906     }
2907     rettv->vval.v_number = col;
2908 }
2909 
2910 /*
2911  * "charcol()" function
2912  */
2913     static void
f_charcol(typval_T * argvars,typval_T * rettv)2914 f_charcol(typval_T *argvars, typval_T *rettv)
2915 {
2916     get_col(argvars, rettv, TRUE);
2917 }
2918 
2919     win_T *
get_optional_window(typval_T * argvars,int idx)2920 get_optional_window(typval_T *argvars, int idx)
2921 {
2922     win_T   *win = curwin;
2923 
2924     if (argvars[idx].v_type != VAR_UNKNOWN)
2925     {
2926 	win = find_win_by_nr_or_id(&argvars[idx]);
2927 	if (win == NULL)
2928 	{
2929 	    emsg(_(e_invalwindow));
2930 	    return NULL;
2931 	}
2932     }
2933     return win;
2934 }
2935 
2936 /*
2937  * "col(string)" function
2938  */
2939     static void
f_col(typval_T * argvars,typval_T * rettv)2940 f_col(typval_T *argvars, typval_T *rettv)
2941 {
2942     get_col(argvars, rettv, FALSE);
2943 }
2944 
2945 /*
2946  * "confirm(message, buttons[, default [, type]])" function
2947  */
2948     static void
f_confirm(typval_T * argvars UNUSED,typval_T * rettv UNUSED)2949 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2950 {
2951 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2952     char_u	*message;
2953     char_u	*buttons = NULL;
2954     char_u	buf[NUMBUFLEN];
2955     char_u	buf2[NUMBUFLEN];
2956     int		def = 1;
2957     int		type = VIM_GENERIC;
2958     char_u	*typestr;
2959     int		error = FALSE;
2960 
2961     if (in_vim9script()
2962 	    && (check_for_string_arg(argvars, 0) == FAIL
2963 		|| (check_for_opt_string_arg(argvars, 1) == FAIL
2964 		    || (argvars[1].v_type != VAR_UNKNOWN
2965 			&& (check_for_opt_number_arg(argvars, 2) == FAIL
2966 			    || (argvars[2].v_type != VAR_UNKNOWN
2967 				&& check_for_opt_string_arg(argvars, 3) == FAIL))))))
2968 	return;
2969 
2970     message = tv_get_string_chk(&argvars[0]);
2971     if (message == NULL)
2972 	error = TRUE;
2973     if (argvars[1].v_type != VAR_UNKNOWN)
2974     {
2975 	buttons = tv_get_string_buf_chk(&argvars[1], buf);
2976 	if (buttons == NULL)
2977 	    error = TRUE;
2978 	if (argvars[2].v_type != VAR_UNKNOWN)
2979 	{
2980 	    def = (int)tv_get_number_chk(&argvars[2], &error);
2981 	    if (argvars[3].v_type != VAR_UNKNOWN)
2982 	    {
2983 		typestr = tv_get_string_buf_chk(&argvars[3], buf2);
2984 		if (typestr == NULL)
2985 		    error = TRUE;
2986 		else
2987 		{
2988 		    switch (TOUPPER_ASC(*typestr))
2989 		    {
2990 			case 'E': type = VIM_ERROR; break;
2991 			case 'Q': type = VIM_QUESTION; break;
2992 			case 'I': type = VIM_INFO; break;
2993 			case 'W': type = VIM_WARNING; break;
2994 			case 'G': type = VIM_GENERIC; break;
2995 		    }
2996 		}
2997 	    }
2998 	}
2999     }
3000 
3001     if (buttons == NULL || *buttons == NUL)
3002 	buttons = (char_u *)_("&Ok");
3003 
3004     if (!error)
3005 	rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
3006 							    def, NULL, FALSE);
3007 #endif
3008 }
3009 
3010 /*
3011  * "copy()" function
3012  */
3013     static void
f_copy(typval_T * argvars,typval_T * rettv)3014 f_copy(typval_T *argvars, typval_T *rettv)
3015 {
3016     item_copy(&argvars[0], rettv, FALSE, 0);
3017 }
3018 
3019 /*
3020  * Set the cursor position.
3021  * If 'charcol' is TRUE, then use the column number as a character offset.
3022  * Otherwise use the column number as a byte offset.
3023  */
3024     static void
set_cursorpos(typval_T * argvars,typval_T * rettv,int charcol)3025 set_cursorpos(typval_T *argvars, typval_T *rettv, int charcol)
3026 {
3027     long	line, col;
3028     long	coladd = 0;
3029     int		set_curswant = TRUE;
3030 
3031     if (in_vim9script()
3032 	    && (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
3033 		|| check_for_opt_number_arg(argvars, 1) == FAIL
3034 		|| (argvars[1].v_type != VAR_UNKNOWN
3035 		    && check_for_opt_number_arg(argvars, 2) == FAIL)))
3036 	return;
3037 
3038     rettv->vval.v_number = -1;
3039     if (argvars[0].v_type == VAR_LIST)
3040     {
3041 	pos_T	    pos;
3042 	colnr_T	    curswant = -1;
3043 
3044 	if (list2fpos(argvars, &pos, NULL, &curswant, charcol) == FAIL)
3045 	{
3046 	    emsg(_(e_invarg));
3047 	    return;
3048 	}
3049 	line = pos.lnum;
3050 	col = pos.col;
3051 	coladd = pos.coladd;
3052 	if (curswant >= 0)
3053 	{
3054 	    curwin->w_curswant = curswant - 1;
3055 	    set_curswant = FALSE;
3056 	}
3057     }
3058     else if ((argvars[0].v_type == VAR_NUMBER ||
3059 					argvars[0].v_type == VAR_STRING)
3060 	    && (argvars[1].v_type == VAR_NUMBER ||
3061 					argvars[1].v_type == VAR_STRING))
3062     {
3063 	line = tv_get_lnum(argvars);
3064 	if (line < 0)
3065 	    semsg(_(e_invarg2), tv_get_string(&argvars[0]));
3066 	col = (long)tv_get_number_chk(&argvars[1], NULL);
3067 	if (charcol)
3068 	    col = buf_charidx_to_byteidx(curbuf, line, col) + 1;
3069 	if (argvars[2].v_type != VAR_UNKNOWN)
3070 	    coladd = (long)tv_get_number_chk(&argvars[2], NULL);
3071     }
3072     else
3073     {
3074 	emsg(_(e_invarg));
3075 	return;
3076     }
3077     if (line < 0 || col < 0 || coladd < 0)
3078 	return;		// type error; errmsg already given
3079     if (line > 0)
3080 	curwin->w_cursor.lnum = line;
3081     if (col > 0)
3082 	curwin->w_cursor.col = col - 1;
3083     curwin->w_cursor.coladd = coladd;
3084 
3085     // Make sure the cursor is in a valid position.
3086     check_cursor();
3087     // Correct cursor for multi-byte character.
3088     if (has_mbyte)
3089 	mb_adjust_cursor();
3090 
3091     curwin->w_set_curswant = set_curswant;
3092     rettv->vval.v_number = 0;
3093 }
3094 
3095 /*
3096  * "cursor(lnum, col)" function, or
3097  * "cursor(list)"
3098  *
3099  * Moves the cursor to the specified line and column.
3100  * Returns 0 when the position could be set, -1 otherwise.
3101  */
3102     static void
f_cursor(typval_T * argvars,typval_T * rettv)3103 f_cursor(typval_T *argvars, typval_T *rettv)
3104 {
3105     set_cursorpos(argvars, rettv, FALSE);
3106 }
3107 
3108 #ifdef MSWIN
3109 /*
3110  * "debugbreak()" function
3111  */
3112     static void
f_debugbreak(typval_T * argvars,typval_T * rettv)3113 f_debugbreak(typval_T *argvars, typval_T *rettv)
3114 {
3115     int		pid;
3116 
3117     rettv->vval.v_number = FAIL;
3118     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
3119 	return;
3120 
3121     pid = (int)tv_get_number(&argvars[0]);
3122     if (pid == 0)
3123 	emsg(_(e_invarg));
3124     else
3125     {
3126 	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
3127 
3128 	if (hProcess != NULL)
3129 	{
3130 	    DebugBreakProcess(hProcess);
3131 	    CloseHandle(hProcess);
3132 	    rettv->vval.v_number = OK;
3133 	}
3134     }
3135 }
3136 #endif
3137 
3138 /*
3139  * "deepcopy()" function
3140  */
3141     static void
f_deepcopy(typval_T * argvars,typval_T * rettv)3142 f_deepcopy(typval_T *argvars, typval_T *rettv)
3143 {
3144     varnumber_T	noref = 0;
3145     int		copyID;
3146 
3147     if (in_vim9script()
3148 	    && (check_for_opt_bool_arg(argvars, 1) == FAIL))
3149 	return;
3150 
3151     if (argvars[1].v_type != VAR_UNKNOWN)
3152 	noref = tv_get_bool_chk(&argvars[1], NULL);
3153     if (noref < 0 || noref > 1)
3154 	semsg(_(e_using_number_as_bool_nr), noref);
3155     else
3156     {
3157 	copyID = get_copyID();
3158 	item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
3159     }
3160 }
3161 
3162 /*
3163  * "did_filetype()" function
3164  */
3165     static void
f_did_filetype(typval_T * argvars UNUSED,typval_T * rettv UNUSED)3166 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3167 {
3168     rettv->vval.v_number = did_filetype;
3169 }
3170 
3171 /*
3172  * "echoraw({expr})" function
3173  */
3174     static void
f_echoraw(typval_T * argvars,typval_T * rettv UNUSED)3175 f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
3176 {
3177     char_u *str;
3178 
3179     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
3180 	return;
3181 
3182     str = tv_get_string_chk(&argvars[0]);
3183     if (str != NULL && *str != NUL)
3184     {
3185 	out_str(str);
3186 	out_flush();
3187     }
3188 }
3189 
3190 /*
3191  * "empty({expr})" function
3192  */
3193     static void
f_empty(typval_T * argvars,typval_T * rettv)3194 f_empty(typval_T *argvars, typval_T *rettv)
3195 {
3196     int		n = FALSE;
3197 
3198     switch (argvars[0].v_type)
3199     {
3200 	case VAR_STRING:
3201 	case VAR_FUNC:
3202 	    n = argvars[0].vval.v_string == NULL
3203 					  || *argvars[0].vval.v_string == NUL;
3204 	    break;
3205 	case VAR_PARTIAL:
3206 	    n = FALSE;
3207 	    break;
3208 	case VAR_NUMBER:
3209 	    n = argvars[0].vval.v_number == 0;
3210 	    break;
3211 	case VAR_FLOAT:
3212 #ifdef FEAT_FLOAT
3213 	    n = argvars[0].vval.v_float == 0.0;
3214 	    break;
3215 #endif
3216 	case VAR_LIST:
3217 	    n = argvars[0].vval.v_list == NULL
3218 					|| argvars[0].vval.v_list->lv_len == 0;
3219 	    break;
3220 	case VAR_DICT:
3221 	    n = argvars[0].vval.v_dict == NULL
3222 			|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3223 	    break;
3224 	case VAR_BOOL:
3225 	case VAR_SPECIAL:
3226 	    n = argvars[0].vval.v_number != VVAL_TRUE;
3227 	    break;
3228 
3229 	case VAR_BLOB:
3230 	    n = argvars[0].vval.v_blob == NULL
3231 		|| argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3232 	    break;
3233 
3234 	case VAR_JOB:
3235 #ifdef FEAT_JOB_CHANNEL
3236 	    n = argvars[0].vval.v_job == NULL
3237 			   || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3238 	    break;
3239 #endif
3240 	case VAR_CHANNEL:
3241 #ifdef FEAT_JOB_CHANNEL
3242 	    n = argvars[0].vval.v_channel == NULL
3243 			       || !channel_is_open(argvars[0].vval.v_channel);
3244 	    break;
3245 #endif
3246 	case VAR_UNKNOWN:
3247 	case VAR_ANY:
3248 	case VAR_VOID:
3249 	case VAR_INSTR:
3250 	    internal_error_no_abort("f_empty(UNKNOWN)");
3251 	    n = TRUE;
3252 	    break;
3253     }
3254 
3255     rettv->vval.v_number = n;
3256 }
3257 
3258 /*
3259  * "environ()" function
3260  */
3261     static void
f_environ(typval_T * argvars UNUSED,typval_T * rettv)3262 f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3263 {
3264 #if !defined(AMIGA)
3265     int			i = 0;
3266     char_u		*entry, *value;
3267 # ifdef MSWIN
3268     extern wchar_t	**_wenviron;
3269 # else
3270     extern char		**environ;
3271 # endif
3272 
3273     if (rettv_dict_alloc(rettv) != OK)
3274 	return;
3275 
3276 # ifdef MSWIN
3277     if (*_wenviron == NULL)
3278 	return;
3279 # else
3280     if (*environ == NULL)
3281 	return;
3282 # endif
3283 
3284     for (i = 0; ; ++i)
3285     {
3286 # ifdef MSWIN
3287 	short_u		*p;
3288 
3289 	if ((p = (short_u *)_wenviron[i]) == NULL)
3290 	    return;
3291 	entry = utf16_to_enc(p, NULL);
3292 # else
3293 	if ((entry = (char_u *)environ[i]) == NULL)
3294 	    return;
3295 	entry = vim_strsave(entry);
3296 # endif
3297 	if (entry == NULL) // out of memory
3298 	    return;
3299 	if ((value = vim_strchr(entry, '=')) == NULL)
3300 	{
3301 	    vim_free(entry);
3302 	    continue;
3303 	}
3304 	*value++ = NUL;
3305 	dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3306 	vim_free(entry);
3307     }
3308 #endif
3309 }
3310 
3311 /*
3312  * "escape({string}, {chars})" function
3313  */
3314     static void
f_escape(typval_T * argvars,typval_T * rettv)3315 f_escape(typval_T *argvars, typval_T *rettv)
3316 {
3317     char_u	buf[NUMBUFLEN];
3318 
3319     if (in_vim9script()
3320 	    && (check_for_string_arg(argvars, 0) == FAIL
3321 		|| check_for_string_arg(argvars, 1) == FAIL))
3322 	return;
3323 
3324     rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3325 					 tv_get_string_buf(&argvars[1], buf));
3326     rettv->v_type = VAR_STRING;
3327 }
3328 
3329 /*
3330  * "eval()" function
3331  */
3332     static void
f_eval(typval_T * argvars,typval_T * rettv)3333 f_eval(typval_T *argvars, typval_T *rettv)
3334 {
3335     char_u	*s, *p;
3336 
3337     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
3338 	return;
3339 
3340     s = tv_get_string_chk(&argvars[0]);
3341     if (s != NULL)
3342 	s = skipwhite(s);
3343 
3344     p = s;
3345     if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
3346     {
3347 	if (p != NULL && !aborting())
3348 	    semsg(_(e_invalid_expression_str), p);
3349 	need_clr_eos = FALSE;
3350 	rettv->v_type = VAR_NUMBER;
3351 	rettv->vval.v_number = 0;
3352     }
3353     else if (*s != NUL)
3354 	semsg(_(e_trailing_arg), s);
3355 }
3356 
3357 /*
3358  * "eventhandler()" function
3359  */
3360     static void
f_eventhandler(typval_T * argvars UNUSED,typval_T * rettv)3361 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3362 {
3363     rettv->vval.v_number = vgetc_busy || input_busy;
3364 }
3365 
3366 static garray_T	redir_execute_ga;
3367 
3368 /*
3369  * Append "value[value_len]" to the execute() output.
3370  */
3371     void
execute_redir_str(char_u * value,int value_len)3372 execute_redir_str(char_u *value, int value_len)
3373 {
3374     int		len;
3375 
3376     if (value_len == -1)
3377 	len = (int)STRLEN(value);	// Append the entire string
3378     else
3379 	len = value_len;		// Append only "value_len" characters
3380     if (ga_grow(&redir_execute_ga, len) == OK)
3381     {
3382 	mch_memmove((char *)redir_execute_ga.ga_data
3383 				       + redir_execute_ga.ga_len, value, len);
3384 	redir_execute_ga.ga_len += len;
3385     }
3386 }
3387 
3388 /*
3389  * Get next line from a string containing NL separated lines.
3390  * Called by do_cmdline() to get the next line.
3391  * Returns an allocated string, or NULL when at the end of the string.
3392  */
3393     static char_u *
get_str_line(int c UNUSED,void * cookie,int indent UNUSED,getline_opt_T options UNUSED)3394 get_str_line(
3395     int	    c UNUSED,
3396     void    *cookie,
3397     int	    indent UNUSED,
3398     getline_opt_T options UNUSED)
3399 {
3400     char_u	*start = *(char_u **)cookie;
3401     char_u	*line;
3402     char_u	*p;
3403 
3404     p = start;
3405     if (p == NULL || *p == NUL)
3406 	return NULL;
3407     p = vim_strchr(p, '\n');
3408     if (p == NULL)
3409 	line = vim_strsave(start);
3410     else
3411     {
3412 	line = vim_strnsave(start, p - start);
3413 	p++;
3414     }
3415 
3416     *(char_u **)cookie = p;
3417     return line;
3418 }
3419 
3420 /*
3421  * Execute a series of Ex commands in 'str'
3422  */
3423     void
execute_cmds_from_string(char_u * str)3424 execute_cmds_from_string(char_u *str)
3425 {
3426     do_cmdline(NULL, get_str_line, (void *)&str,
3427 	    DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3428 }
3429 
3430 /*
3431  * Get next line from a list.
3432  * Called by do_cmdline() to get the next line.
3433  * Returns allocated string, or NULL for end of function.
3434  */
3435     static char_u *
get_list_line(int c UNUSED,void * cookie,int indent UNUSED,getline_opt_T options UNUSED)3436 get_list_line(
3437     int	    c UNUSED,
3438     void    *cookie,
3439     int	    indent UNUSED,
3440     getline_opt_T options UNUSED)
3441 {
3442     listitem_T **p = (listitem_T **)cookie;
3443     listitem_T *item = *p;
3444     char_u	buf[NUMBUFLEN];
3445     char_u	*s;
3446 
3447     if (item == NULL)
3448 	return NULL;
3449     s = tv_get_string_buf_chk(&item->li_tv, buf);
3450     *p = item->li_next;
3451     return s == NULL ? NULL : vim_strsave(s);
3452 }
3453 
3454 /*
3455  * "execute()" function
3456  */
3457     void
execute_common(typval_T * argvars,typval_T * rettv,int arg_off)3458 execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
3459 {
3460     char_u	*cmd = NULL;
3461     list_T	*list = NULL;
3462     int		save_msg_silent = msg_silent;
3463     int		save_emsg_silent = emsg_silent;
3464     int		save_emsg_noredir = emsg_noredir;
3465     int		save_redir_execute = redir_execute;
3466     int		save_redir_off = redir_off;
3467     garray_T	save_ga;
3468     int		save_msg_col = msg_col;
3469     int		echo_output = FALSE;
3470 
3471     rettv->vval.v_string = NULL;
3472     rettv->v_type = VAR_STRING;
3473 
3474     if (argvars[arg_off].v_type == VAR_LIST)
3475     {
3476 	list = argvars[arg_off].vval.v_list;
3477 	if (list == NULL || list->lv_len == 0)
3478 	    // empty list, no commands, empty output
3479 	    return;
3480 	++list->lv_refcount;
3481     }
3482     else if (argvars[arg_off].v_type == VAR_JOB
3483 	    || argvars[arg_off].v_type == VAR_CHANNEL)
3484     {
3485 	semsg(_(e_using_invalid_value_as_string_str),
3486 				       vartype_name(argvars[arg_off].v_type));
3487 	return;
3488     }
3489     else
3490     {
3491 	cmd = tv_get_string_chk(&argvars[arg_off]);
3492 	if (cmd == NULL)
3493 	    return;
3494     }
3495 
3496     if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
3497     {
3498 	char_u	buf[NUMBUFLEN];
3499 	char_u  *s = tv_get_string_buf_chk_strict(&argvars[arg_off + 1], buf,
3500 							      in_vim9script());
3501 
3502 	if (s == NULL)
3503 	    return;
3504 	if (*s == NUL)
3505 	    echo_output = TRUE;
3506 	if (STRNCMP(s, "silent", 6) == 0)
3507 	    ++msg_silent;
3508 	if (STRCMP(s, "silent!") == 0)
3509 	{
3510 	    emsg_silent = TRUE;
3511 	    emsg_noredir = TRUE;
3512 	}
3513     }
3514     else
3515 	++msg_silent;
3516 
3517     if (redir_execute)
3518 	save_ga = redir_execute_ga;
3519     ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3520     redir_execute = TRUE;
3521     redir_off = FALSE;
3522     if (!echo_output)
3523 	msg_col = 0;  // prevent leading spaces
3524 
3525     if (cmd != NULL)
3526 	do_cmdline_cmd(cmd);
3527     else
3528     {
3529 	listitem_T	*item;
3530 
3531 	CHECK_LIST_MATERIALIZE(list);
3532 	item = list->lv_first;
3533 	do_cmdline(NULL, get_list_line, (void *)&item,
3534 		      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3535 	--list->lv_refcount;
3536     }
3537 
3538     // Need to append a NUL to the result.
3539     if (ga_grow(&redir_execute_ga, 1) == OK)
3540     {
3541 	((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3542 	rettv->vval.v_string = redir_execute_ga.ga_data;
3543     }
3544     else
3545     {
3546 	ga_clear(&redir_execute_ga);
3547 	rettv->vval.v_string = NULL;
3548     }
3549     msg_silent = save_msg_silent;
3550     emsg_silent = save_emsg_silent;
3551     emsg_noredir = save_emsg_noredir;
3552 
3553     redir_execute = save_redir_execute;
3554     if (redir_execute)
3555 	redir_execute_ga = save_ga;
3556     redir_off = save_redir_off;
3557 
3558     // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
3559     if (echo_output)
3560 	// When not working silently: put it in column zero.  A following
3561 	// "echon" will overwrite the message, unavoidably.
3562 	msg_col = 0;
3563     else
3564 	// When working silently: Put it back where it was, since nothing
3565 	// should have been written.
3566 	msg_col = save_msg_col;
3567 }
3568 
3569 /*
3570  * "execute()" function
3571  */
3572     static void
f_execute(typval_T * argvars,typval_T * rettv)3573 f_execute(typval_T *argvars, typval_T *rettv)
3574 {
3575     if (in_vim9script()
3576 	    && (check_for_string_or_list_arg(argvars, 0) == FAIL
3577 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
3578 	return;
3579 
3580     execute_common(argvars, rettv, 0);
3581 }
3582 
3583 /*
3584  * "exists()" function
3585  */
3586     void
f_exists(typval_T * argvars,typval_T * rettv)3587 f_exists(typval_T *argvars, typval_T *rettv)
3588 {
3589     char_u	*p;
3590     int		n = FALSE;
3591 
3592     if (in_vim9script() && check_for_nonempty_string_arg(argvars, 0) == FAIL)
3593 	return;
3594 
3595     p = tv_get_string(&argvars[0]);
3596     if (*p == '$')			// environment variable
3597     {
3598 	// first try "normal" environment variables (fast)
3599 	if (mch_getenv(p + 1) != NULL)
3600 	    n = TRUE;
3601 	else
3602 	{
3603 	    // try expanding things like $VIM and ${HOME}
3604 	    p = expand_env_save(p);
3605 	    if (p != NULL && *p != '$')
3606 		n = TRUE;
3607 	    vim_free(p);
3608 	}
3609     }
3610     else if (*p == '&' || *p == '+')			// option
3611     {
3612 	n = (eval_option(&p, NULL, TRUE) == OK);
3613 	if (*skipwhite(p) != NUL)
3614 	    n = FALSE;			// trailing garbage
3615     }
3616     else if (*p == '*')			// internal or user defined function
3617     {
3618 	int save_version = current_sctx.sc_version;
3619 
3620 	// Vim9 script assumes a function is script-local, but here we want to
3621 	// find any matching function.
3622 	if (current_sctx.sc_version == SCRIPT_VERSION_VIM9)
3623 	    current_sctx.sc_version = SCRIPT_VERSION_MAX;
3624 	n = function_exists(p + 1, FALSE);
3625 	current_sctx.sc_version = save_version;
3626     }
3627     else if (*p == '?')			// internal function only
3628     {
3629 	n = has_internal_func_name(p + 1);
3630     }
3631     else if (*p == ':')
3632     {
3633 	n = cmd_exists(p + 1);
3634     }
3635     else if (*p == '#')
3636     {
3637 	if (p[1] == '#')
3638 	    n = autocmd_supported(p + 2);
3639 	else
3640 	    n = au_exists(p + 1);
3641     }
3642     else				// internal variable
3643     {
3644 	n = var_exists(p);
3645     }
3646 
3647     rettv->vval.v_number = n;
3648 }
3649 
3650     static void
f_exists_compiled(typval_T * argvars UNUSED,typval_T * rettv UNUSED)3651 f_exists_compiled(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3652 {
3653     emsg(_(e_exists_compiled_can_only_be_used_in_def_function));
3654 }
3655 
3656 /*
3657  * "expand()" function
3658  */
3659     static void
f_expand(typval_T * argvars,typval_T * rettv)3660 f_expand(typval_T *argvars, typval_T *rettv)
3661 {
3662     char_u	*s;
3663     int		len;
3664     char	*errormsg;
3665     int		options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3666     expand_T	xpc;
3667     int		error = FALSE;
3668     char_u	*result;
3669 #ifdef BACKSLASH_IN_FILENAME
3670     char_u	*p_csl_save = p_csl;
3671 #endif
3672 
3673     if (in_vim9script()
3674 	    && (check_for_string_arg(argvars, 0) == FAIL
3675 		|| check_for_opt_bool_arg(argvars, 1) == FAIL
3676 		|| (argvars[1].v_type != VAR_UNKNOWN
3677 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
3678 	return;
3679 
3680 #ifdef BACKSLASH_IN_FILENAME
3681     // avoid using 'completeslash' here
3682     p_csl = empty_option;
3683 #endif
3684 
3685     rettv->v_type = VAR_STRING;
3686     if (argvars[1].v_type != VAR_UNKNOWN
3687 	    && argvars[2].v_type != VAR_UNKNOWN
3688 	    && tv_get_bool_chk(&argvars[2], &error)
3689 	    && !error)
3690 	rettv_list_set(rettv, NULL);
3691 
3692     s = tv_get_string(&argvars[0]);
3693     if (*s == '%' || *s == '#' || *s == '<')
3694     {
3695 	++emsg_off;
3696 	result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3697 	--emsg_off;
3698 	if (rettv->v_type == VAR_LIST)
3699 	{
3700 	    if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3701 		list_append_string(rettv->vval.v_list, result, -1);
3702 	    vim_free(result);
3703 	}
3704 	else
3705 	    rettv->vval.v_string = result;
3706     }
3707     else
3708     {
3709 	// When the optional second argument is non-zero, don't remove matches
3710 	// for 'wildignore' and don't put matches for 'suffixes' at the end.
3711 	if (argvars[1].v_type != VAR_UNKNOWN
3712 				    && tv_get_bool_chk(&argvars[1], &error))
3713 	    options |= WILD_KEEP_ALL;
3714 	if (!error)
3715 	{
3716 	    ExpandInit(&xpc);
3717 	    xpc.xp_context = EXPAND_FILES;
3718 	    if (p_wic)
3719 		options += WILD_ICASE;
3720 	    if (rettv->v_type == VAR_STRING)
3721 		rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3722 							   options, WILD_ALL);
3723 	    else if (rettv_list_alloc(rettv) != FAIL)
3724 	    {
3725 		int i;
3726 
3727 		ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3728 		for (i = 0; i < xpc.xp_numfiles; i++)
3729 		    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3730 		ExpandCleanup(&xpc);
3731 	    }
3732 	}
3733 	else
3734 	    rettv->vval.v_string = NULL;
3735     }
3736 #ifdef BACKSLASH_IN_FILENAME
3737     p_csl = p_csl_save;
3738 #endif
3739 }
3740 
3741 /*
3742  * "expandcmd()" function
3743  * Expand all the special characters in a command string.
3744  */
3745     static void
f_expandcmd(typval_T * argvars,typval_T * rettv)3746 f_expandcmd(typval_T *argvars, typval_T *rettv)
3747 {
3748     exarg_T	eap;
3749     char_u	*cmdstr;
3750     char	*errormsg = NULL;
3751 
3752     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
3753 	return;
3754 
3755     rettv->v_type = VAR_STRING;
3756     cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3757 
3758     memset(&eap, 0, sizeof(eap));
3759     eap.cmd = cmdstr;
3760     eap.arg = cmdstr;
3761     eap.argt |= EX_NOSPC;
3762     eap.usefilter = FALSE;
3763     eap.nextcmd = NULL;
3764     eap.cmdidx = CMD_USER;
3765 
3766     expand_filename(&eap, &cmdstr, &errormsg);
3767     if (errormsg != NULL && *errormsg != NUL)
3768 	emsg(errormsg);
3769 
3770     rettv->vval.v_string = cmdstr;
3771 }
3772 
3773 /*
3774  * "feedkeys()" function
3775  */
3776     static void
f_feedkeys(typval_T * argvars,typval_T * rettv UNUSED)3777 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3778 {
3779     int		remap = TRUE;
3780     int		insert = FALSE;
3781     char_u	*keys, *flags;
3782     char_u	nbuf[NUMBUFLEN];
3783     int		typed = FALSE;
3784     int		execute = FALSE;
3785     int		dangerous = FALSE;
3786     int		lowlevel = FALSE;
3787     char_u	*keys_esc;
3788 
3789     // This is not allowed in the sandbox.  If the commands would still be
3790     // executed in the sandbox it would be OK, but it probably happens later,
3791     // when "sandbox" is no longer set.
3792     if (check_secure())
3793 	return;
3794 
3795     if (in_vim9script()
3796 	    && (check_for_string_arg(argvars, 0) == FAIL
3797 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
3798 	return;
3799 
3800     keys = tv_get_string(&argvars[0]);
3801 
3802     if (argvars[1].v_type != VAR_UNKNOWN)
3803     {
3804 	flags = tv_get_string_buf(&argvars[1], nbuf);
3805 	for ( ; *flags != NUL; ++flags)
3806 	{
3807 	    switch (*flags)
3808 	    {
3809 		case 'n': remap = FALSE; break;
3810 		case 'm': remap = TRUE; break;
3811 		case 't': typed = TRUE; break;
3812 		case 'i': insert = TRUE; break;
3813 		case 'x': execute = TRUE; break;
3814 		case '!': dangerous = TRUE; break;
3815 		case 'L': lowlevel = TRUE; break;
3816 	    }
3817 	}
3818     }
3819 
3820     if (*keys != NUL || execute)
3821     {
3822 	// Need to escape K_SPECIAL and CSI before putting the string in the
3823 	// typeahead buffer.
3824 	keys_esc = vim_strsave_escape_csi(keys);
3825 	if (keys_esc != NULL)
3826 	{
3827 	    if (lowlevel)
3828 	    {
3829 #ifdef USE_INPUT_BUF
3830 		int idx;
3831 		int len = (int)STRLEN(keys);
3832 
3833 		for (idx = 0; idx < len; ++idx)
3834 		{
3835 		    // if a CTRL-C was typed, set got_int, similar to what
3836 		    // happens in fill_input_buf()
3837 		    if (keys[idx] == 3 && ctrl_c_interrupts && typed)
3838 			got_int = TRUE;
3839 		    add_to_input_buf(keys + idx, 1);
3840 		}
3841 #else
3842 		emsg(_("E980: lowlevel input not supported"));
3843 #endif
3844 	    }
3845 	    else
3846 	    {
3847 		ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3848 				  insert ? 0 : typebuf.tb_len, !typed, FALSE);
3849 		if (vgetc_busy
3850 #ifdef FEAT_TIMERS
3851 			|| timer_busy
3852 #endif
3853 			|| input_busy)
3854 		    typebuf_was_filled = TRUE;
3855 	    }
3856 	    vim_free(keys_esc);
3857 
3858 	    if (execute)
3859 	    {
3860 		int save_msg_scroll = msg_scroll;
3861 
3862 		// Avoid a 1 second delay when the keys start Insert mode.
3863 		msg_scroll = FALSE;
3864 
3865 		if (!dangerous)
3866 		{
3867 		    ++ex_normal_busy;
3868 		    ++in_feedkeys;
3869 		}
3870 		exec_normal(TRUE, lowlevel, TRUE);
3871 		if (!dangerous)
3872 		{
3873 		    --ex_normal_busy;
3874 		    --in_feedkeys;
3875 		}
3876 
3877 		msg_scroll |= save_msg_scroll;
3878 	    }
3879 	}
3880     }
3881 }
3882 
3883 /*
3884  * "fnameescape({string})" function
3885  */
3886     static void
f_fnameescape(typval_T * argvars,typval_T * rettv)3887 f_fnameescape(typval_T *argvars, typval_T *rettv)
3888 {
3889     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
3890 	return;
3891 
3892     rettv->vval.v_string = vim_strsave_fnameescape(
3893 					 tv_get_string(&argvars[0]), VSE_NONE);
3894     rettv->v_type = VAR_STRING;
3895 }
3896 
3897 /*
3898  * "foreground()" function
3899  */
3900     static void
f_foreground(typval_T * argvars UNUSED,typval_T * rettv UNUSED)3901 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3902 {
3903 #ifdef FEAT_GUI
3904     if (gui.in_use)
3905     {
3906 	gui_mch_set_foreground();
3907 	return;
3908     }
3909 #endif
3910 #if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
3911     win32_set_foreground();
3912 #endif
3913 }
3914 
3915     static void
common_function(typval_T * argvars,typval_T * rettv,int is_funcref)3916 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
3917 {
3918     char_u	*s;
3919     char_u	*name;
3920     int		use_string = FALSE;
3921     partial_T   *arg_pt = NULL;
3922     char_u	*trans_name = NULL;
3923     int		is_global = FALSE;
3924 
3925     if (in_vim9script()
3926 	    && (check_for_opt_list_arg(argvars, 1) == FAIL
3927 		|| (argvars[1].v_type != VAR_UNKNOWN
3928 		    && check_for_opt_dict_arg(argvars, 2) == FAIL)))
3929 	return;
3930 
3931     if (argvars[0].v_type == VAR_FUNC)
3932     {
3933 	// function(MyFunc, [arg], dict)
3934 	s = argvars[0].vval.v_string;
3935     }
3936     else if (argvars[0].v_type == VAR_PARTIAL
3937 					 && argvars[0].vval.v_partial != NULL)
3938     {
3939 	// function(dict.MyFunc, [arg])
3940 	arg_pt = argvars[0].vval.v_partial;
3941 	s = partial_name(arg_pt);
3942     }
3943     else
3944     {
3945 	// function('MyFunc', [arg], dict)
3946 	s = tv_get_string(&argvars[0]);
3947 	use_string = TRUE;
3948     }
3949     if (s == NULL)
3950     {
3951 	semsg(_(e_invarg2), "NULL");
3952 	return;
3953     }
3954 
3955     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
3956     {
3957 	name = s;
3958 	trans_name = save_function_name(&name, &is_global, FALSE,
3959 		   TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL);
3960 	if (*name != NUL)
3961 	    s = NULL;
3962     }
3963 
3964     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3965 					 || (is_funcref && trans_name == NULL))
3966 	semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
3967     // Don't check an autoload name for existence here.
3968     else if (trans_name != NULL && (is_funcref
3969 			 ? find_func(trans_name, is_global, NULL) == NULL
3970 			 : !translated_function_exists(trans_name, is_global)))
3971 	semsg(_("E700: Unknown function: %s"), s);
3972     else
3973     {
3974 	int	dict_idx = 0;
3975 	int	arg_idx = 0;
3976 	list_T	*list = NULL;
3977 
3978 	if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3979 	{
3980 	    char	sid_buf[25];
3981 	    int		off = *s == 's' ? 2 : 5;
3982 
3983 	    // Expand s: and <SID> into <SNR>nr_, so that the function can
3984 	    // also be called from another script. Using trans_function_name()
3985 	    // would also work, but some plugins depend on the name being
3986 	    // printable text.
3987 	    sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
3988 	    name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
3989 	    if (name != NULL)
3990 	    {
3991 		STRCPY(name, sid_buf);
3992 		STRCAT(name, s + off);
3993 	    }
3994 	}
3995 	else
3996 	    name = vim_strsave(s);
3997 
3998 	if (argvars[1].v_type != VAR_UNKNOWN)
3999 	{
4000 	    if (argvars[2].v_type != VAR_UNKNOWN)
4001 	    {
4002 		// function(name, [args], dict)
4003 		arg_idx = 1;
4004 		dict_idx = 2;
4005 	    }
4006 	    else if (argvars[1].v_type == VAR_DICT)
4007 		// function(name, dict)
4008 		dict_idx = 1;
4009 	    else
4010 		// function(name, [args])
4011 		arg_idx = 1;
4012 	    if (dict_idx > 0)
4013 	    {
4014 		if (argvars[dict_idx].v_type != VAR_DICT)
4015 		{
4016 		    emsg(_("E922: expected a dict"));
4017 		    vim_free(name);
4018 		    goto theend;
4019 		}
4020 		if (argvars[dict_idx].vval.v_dict == NULL)
4021 		    dict_idx = 0;
4022 	    }
4023 	    if (arg_idx > 0)
4024 	    {
4025 		if (argvars[arg_idx].v_type != VAR_LIST)
4026 		{
4027 		    emsg(_("E923: Second argument of function() must be a list or a dict"));
4028 		    vim_free(name);
4029 		    goto theend;
4030 		}
4031 		list = argvars[arg_idx].vval.v_list;
4032 		if (list == NULL || list->lv_len == 0)
4033 		    arg_idx = 0;
4034 		else if (list->lv_len > MAX_FUNC_ARGS)
4035 		{
4036 		    emsg_funcname((char *)e_toomanyarg, s);
4037 		    vim_free(name);
4038 		    goto theend;
4039 		}
4040 	    }
4041 	}
4042 	if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
4043 	{
4044 	    partial_T	*pt = ALLOC_CLEAR_ONE(partial_T);
4045 
4046 	    // result is a VAR_PARTIAL
4047 	    if (pt == NULL)
4048 		vim_free(name);
4049 	    else
4050 	    {
4051 		if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4052 		{
4053 		    listitem_T	*li;
4054 		    int		i = 0;
4055 		    int		arg_len = 0;
4056 		    int		lv_len = 0;
4057 
4058 		    if (arg_pt != NULL)
4059 			arg_len = arg_pt->pt_argc;
4060 		    if (list != NULL)
4061 			lv_len = list->lv_len;
4062 		    pt->pt_argc = arg_len + lv_len;
4063 		    pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
4064 		    if (pt->pt_argv == NULL)
4065 		    {
4066 			vim_free(pt);
4067 			vim_free(name);
4068 			goto theend;
4069 		    }
4070 		    for (i = 0; i < arg_len; i++)
4071 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4072 		    if (lv_len > 0)
4073 		    {
4074 			CHECK_LIST_MATERIALIZE(list);
4075 			FOR_ALL_LIST_ITEMS(list, li)
4076 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
4077 		    }
4078 		}
4079 
4080 		// For "function(dict.func, [], dict)" and "func" is a partial
4081 		// use "dict".  That is backwards compatible.
4082 		if (dict_idx > 0)
4083 		{
4084 		    // The dict is bound explicitly, pt_auto is FALSE.
4085 		    pt->pt_dict = argvars[dict_idx].vval.v_dict;
4086 		    ++pt->pt_dict->dv_refcount;
4087 		}
4088 		else if (arg_pt != NULL)
4089 		{
4090 		    // If the dict was bound automatically the result is also
4091 		    // bound automatically.
4092 		    pt->pt_dict = arg_pt->pt_dict;
4093 		    pt->pt_auto = arg_pt->pt_auto;
4094 		    if (pt->pt_dict != NULL)
4095 			++pt->pt_dict->dv_refcount;
4096 		}
4097 
4098 		pt->pt_refcount = 1;
4099 		if (arg_pt != NULL && arg_pt->pt_func != NULL)
4100 		{
4101 		    pt->pt_func = arg_pt->pt_func;
4102 		    func_ptr_ref(pt->pt_func);
4103 		    vim_free(name);
4104 		}
4105 		else if (is_funcref)
4106 		{
4107 		    pt->pt_func = find_func(trans_name, is_global, NULL);
4108 		    func_ptr_ref(pt->pt_func);
4109 		    vim_free(name);
4110 		}
4111 		else
4112 		{
4113 		    pt->pt_name = name;
4114 		    func_ref(name);
4115 		}
4116 	    }
4117 	    rettv->v_type = VAR_PARTIAL;
4118 	    rettv->vval.v_partial = pt;
4119 	}
4120 	else
4121 	{
4122 	    // result is a VAR_FUNC
4123 	    rettv->v_type = VAR_FUNC;
4124 	    rettv->vval.v_string = name;
4125 	    func_ref(name);
4126 	}
4127     }
4128 theend:
4129     vim_free(trans_name);
4130 }
4131 
4132 /*
4133  * "funcref()" function
4134  */
4135     static void
f_funcref(typval_T * argvars,typval_T * rettv)4136 f_funcref(typval_T *argvars, typval_T *rettv)
4137 {
4138     common_function(argvars, rettv, TRUE);
4139 }
4140 
4141     static type_T *
ret_f_function(int argcount,type_T ** argtypes)4142 ret_f_function(int argcount, type_T **argtypes)
4143 {
4144     if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
4145 	return &t_func_any;
4146     // Need to check the type at runtime, the function may be defined later.
4147     return &t_func_unknown;
4148 }
4149 
4150 /*
4151  * "function()" function
4152  */
4153     static void
f_function(typval_T * argvars,typval_T * rettv)4154 f_function(typval_T *argvars, typval_T *rettv)
4155 {
4156     common_function(argvars, rettv, FALSE);
4157 }
4158 
4159 /*
4160  * "garbagecollect()" function
4161  */
4162     static void
f_garbagecollect(typval_T * argvars,typval_T * rettv UNUSED)4163 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4164 {
4165     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
4166 	return;
4167 
4168     // This is postponed until we are back at the toplevel, because we may be
4169     // using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]".
4170     want_garbage_collect = TRUE;
4171 
4172     if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
4173 	garbage_collect_at_exit = TRUE;
4174 }
4175 
4176 /*
4177  * "get()" function
4178  */
4179     static void
f_get(typval_T * argvars,typval_T * rettv)4180 f_get(typval_T *argvars, typval_T *rettv)
4181 {
4182     listitem_T	*li;
4183     list_T	*l;
4184     dictitem_T	*di;
4185     dict_T	*d;
4186     typval_T	*tv = NULL;
4187     int		what_is_dict = FALSE;
4188 
4189     if (argvars[0].v_type == VAR_BLOB)
4190     {
4191 	int error = FALSE;
4192 	int idx = tv_get_number_chk(&argvars[1], &error);
4193 
4194 	if (!error)
4195 	{
4196 	    rettv->v_type = VAR_NUMBER;
4197 	    if (idx < 0)
4198 		idx = blob_len(argvars[0].vval.v_blob) + idx;
4199 	    if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4200 		rettv->vval.v_number = -1;
4201 	    else
4202 	    {
4203 		rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
4204 		tv = rettv;
4205 	    }
4206 	}
4207     }
4208     else if (argvars[0].v_type == VAR_LIST)
4209     {
4210 	if ((l = argvars[0].vval.v_list) != NULL)
4211 	{
4212 	    int		error = FALSE;
4213 
4214 	    li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
4215 	    if (!error && li != NULL)
4216 		tv = &li->li_tv;
4217 	}
4218     }
4219     else if (argvars[0].v_type == VAR_DICT)
4220     {
4221 	if ((d = argvars[0].vval.v_dict) != NULL)
4222 	{
4223 	    di = dict_find(d, tv_get_string(&argvars[1]), -1);
4224 	    if (di != NULL)
4225 		tv = &di->di_tv;
4226 	}
4227     }
4228     else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4229     {
4230 	partial_T	*pt;
4231 	partial_T	fref_pt;
4232 
4233 	if (argvars[0].v_type == VAR_PARTIAL)
4234 	    pt = argvars[0].vval.v_partial;
4235 	else
4236 	{
4237 	    CLEAR_FIELD(fref_pt);
4238 	    fref_pt.pt_name = argvars[0].vval.v_string;
4239 	    pt = &fref_pt;
4240 	}
4241 
4242 	if (pt != NULL)
4243 	{
4244 	    char_u *what = tv_get_string(&argvars[1]);
4245 	    char_u *n;
4246 
4247 	    if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4248 	    {
4249 		rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
4250 		n = partial_name(pt);
4251 		if (n == NULL)
4252 		    rettv->vval.v_string = NULL;
4253 		else
4254 		{
4255 		    rettv->vval.v_string = vim_strsave(n);
4256 		    if (rettv->v_type == VAR_FUNC)
4257 			func_ref(rettv->vval.v_string);
4258 		}
4259 	    }
4260 	    else if (STRCMP(what, "dict") == 0)
4261 	    {
4262 		what_is_dict = TRUE;
4263 		if (pt->pt_dict != NULL)
4264 		    rettv_dict_set(rettv, pt->pt_dict);
4265 	    }
4266 	    else if (STRCMP(what, "args") == 0)
4267 	    {
4268 		rettv->v_type = VAR_LIST;
4269 		if (rettv_list_alloc(rettv) == OK)
4270 		{
4271 		    int i;
4272 
4273 		    for (i = 0; i < pt->pt_argc; ++i)
4274 			list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4275 		}
4276 	    }
4277 	    else
4278 		semsg(_(e_invarg2), what);
4279 
4280 	    // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4281 	    // third argument
4282 	    if (!what_is_dict)
4283 		return;
4284 	}
4285     }
4286     else
4287 	semsg(_(e_listdictblobarg), "get()");
4288 
4289     if (tv == NULL)
4290     {
4291 	if (argvars[2].v_type != VAR_UNKNOWN)
4292 	    copy_tv(&argvars[2], rettv);
4293     }
4294     else
4295 	copy_tv(tv, rettv);
4296 }
4297 
4298 /*
4299  * "getchangelist()" function
4300  */
4301     static void
f_getchangelist(typval_T * argvars,typval_T * rettv)4302 f_getchangelist(typval_T *argvars, typval_T *rettv)
4303 {
4304 #ifdef FEAT_JUMPLIST
4305     buf_T	*buf;
4306     int		i;
4307     list_T	*l;
4308     dict_T	*d;
4309 #endif
4310 
4311     if (rettv_list_alloc(rettv) != OK)
4312 	return;
4313 
4314     if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL)
4315 	return;
4316 
4317 #ifdef FEAT_JUMPLIST
4318     if (argvars[0].v_type == VAR_UNKNOWN)
4319 	buf = curbuf;
4320     else
4321 	buf = tv_get_buf_from_arg(&argvars[0]);
4322     if (buf == NULL)
4323 	return;
4324 
4325     l = list_alloc();
4326     if (l == NULL)
4327 	return;
4328 
4329     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4330 	return;
4331     /*
4332      * The current window change list index tracks only the position in the
4333      * current buffer change list. For other buffers, use the change list
4334      * length as the current index.
4335      */
4336     list_append_number(rettv->vval.v_list,
4337 	    (varnumber_T)((buf == curwin->w_buffer)
4338 		? curwin->w_changelistidx : buf->b_changelistlen));
4339 
4340     for (i = 0; i < buf->b_changelistlen; ++i)
4341     {
4342 	if (buf->b_changelist[i].lnum == 0)
4343 	    continue;
4344 	if ((d = dict_alloc()) == NULL)
4345 	    return;
4346 	if (list_append_dict(l, d) == FAIL)
4347 	    return;
4348 	dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4349 	dict_add_number(d, "col", (long)buf->b_changelist[i].col);
4350 	dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
4351     }
4352 #endif
4353 }
4354 
4355     static void
getpos_both(typval_T * argvars,typval_T * rettv,int getcurpos,int charcol)4356 getpos_both(
4357     typval_T	*argvars,
4358     typval_T	*rettv,
4359     int		getcurpos,
4360     int		charcol)
4361 {
4362     pos_T	*fp = NULL;
4363     pos_T	pos;
4364     win_T	*wp = curwin;
4365     list_T	*l;
4366     int		fnum = -1;
4367 
4368     if (rettv_list_alloc(rettv) == OK)
4369     {
4370 	l = rettv->vval.v_list;
4371 	if (getcurpos)
4372 	{
4373 	    if (argvars[0].v_type != VAR_UNKNOWN)
4374 	    {
4375 		wp = find_win_by_nr_or_id(&argvars[0]);
4376 		if (wp != NULL)
4377 		    fp = &wp->w_cursor;
4378 	    }
4379 	    else
4380 		fp = &curwin->w_cursor;
4381 	    if (fp != NULL && charcol)
4382 	    {
4383 		pos = *fp;
4384 		pos.col =
4385 		    buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col);
4386 		fp = &pos;
4387 	    }
4388 	}
4389 	else
4390 	    fp = var2fpos(&argvars[0], TRUE, &fnum, charcol);
4391 	if (fnum != -1)
4392 	    list_append_number(l, (varnumber_T)fnum);
4393 	else
4394 	    list_append_number(l, (varnumber_T)0);
4395 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4396 							    : (varnumber_T)0);
4397 	list_append_number(l, (fp != NULL)
4398 		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4399 							    : (varnumber_T)0);
4400 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
4401 							      (varnumber_T)0);
4402 	if (getcurpos)
4403 	{
4404 	    int	    save_set_curswant = curwin->w_set_curswant;
4405 	    colnr_T save_curswant = curwin->w_curswant;
4406 	    colnr_T save_virtcol = curwin->w_virtcol;
4407 
4408 	    if (wp == curwin)
4409 		update_curswant();
4410 	    list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
4411 		    ?  (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
4412 
4413 	    // Do not change "curswant", as it is unexpected that a get
4414 	    // function has a side effect.
4415 	    if (wp == curwin && save_set_curswant)
4416 	    {
4417 		curwin->w_set_curswant = save_set_curswant;
4418 		curwin->w_curswant = save_curswant;
4419 		curwin->w_virtcol = save_virtcol;
4420 		curwin->w_valid &= ~VALID_VIRTCOL;
4421 	    }
4422 	}
4423     }
4424     else
4425 	rettv->vval.v_number = FALSE;
4426 }
4427 
4428 /*
4429  * "getcharpos()" function
4430  */
4431     static void
f_getcharpos(typval_T * argvars UNUSED,typval_T * rettv)4432 f_getcharpos(typval_T *argvars UNUSED, typval_T *rettv)
4433 {
4434     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4435 	return;
4436 
4437     getpos_both(argvars, rettv, FALSE, TRUE);
4438 }
4439 
4440 /*
4441  * "getcharsearch()" function
4442  */
4443     static void
f_getcharsearch(typval_T * argvars UNUSED,typval_T * rettv)4444 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4445 {
4446     if (rettv_dict_alloc(rettv) != FAIL)
4447     {
4448 	dict_T *dict = rettv->vval.v_dict;
4449 
4450 	dict_add_string(dict, "char", last_csearch());
4451 	dict_add_number(dict, "forward", last_csearch_forward());
4452 	dict_add_number(dict, "until", last_csearch_until());
4453     }
4454 }
4455 
4456 /*
4457  * "getenv()" function
4458  */
4459     static void
f_getenv(typval_T * argvars,typval_T * rettv)4460 f_getenv(typval_T *argvars, typval_T *rettv)
4461 {
4462     int	    mustfree = FALSE;
4463     char_u  *p;
4464 
4465     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4466 	return;
4467 
4468     p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4469     if (p == NULL)
4470     {
4471 	rettv->v_type = VAR_SPECIAL;
4472 	rettv->vval.v_number = VVAL_NULL;
4473 	return;
4474     }
4475     if (!mustfree)
4476 	p = vim_strsave(p);
4477     rettv->vval.v_string = p;
4478     rettv->v_type = VAR_STRING;
4479 }
4480 
4481 /*
4482  * "getfontname()" function
4483  */
4484     static void
f_getfontname(typval_T * argvars UNUSED,typval_T * rettv)4485 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4486 {
4487     rettv->v_type = VAR_STRING;
4488     rettv->vval.v_string = NULL;
4489 
4490     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
4491 	return;
4492 
4493 #ifdef FEAT_GUI
4494     if (gui.in_use)
4495     {
4496 	GuiFont font;
4497 	char_u	*name = NULL;
4498 
4499 	if (argvars[0].v_type == VAR_UNKNOWN)
4500 	{
4501 	    // Get the "Normal" font.  Either the name saved by
4502 	    // hl_set_font_name() or from the font ID.
4503 	    font = gui.norm_font;
4504 	    name = hl_get_font_name();
4505 	}
4506 	else
4507 	{
4508 	    name = tv_get_string(&argvars[0]);
4509 	    if (STRCMP(name, "*") == 0)	    // don't use font dialog
4510 		return;
4511 	    font = gui_mch_get_font(name, FALSE);
4512 	    if (font == NOFONT)
4513 		return;	    // Invalid font name, return empty string.
4514 	}
4515 	rettv->vval.v_string = gui_mch_get_fontname(font, name);
4516 	if (argvars[0].v_type != VAR_UNKNOWN)
4517 	    gui_mch_free_font(font);
4518     }
4519 #endif
4520 }
4521 
4522 /*
4523  * "getjumplist()" function
4524  */
4525     static void
f_getjumplist(typval_T * argvars,typval_T * rettv)4526 f_getjumplist(typval_T *argvars, typval_T *rettv)
4527 {
4528 #ifdef FEAT_JUMPLIST
4529     win_T	*wp;
4530     int		i;
4531     list_T	*l;
4532     dict_T	*d;
4533 #endif
4534 
4535     if (rettv_list_alloc(rettv) != OK)
4536 	return;
4537 
4538     if (in_vim9script()
4539 	    && (check_for_opt_number_arg(argvars, 0) == FAIL
4540 		|| (argvars[0].v_type != VAR_UNKNOWN
4541 		    && check_for_opt_number_arg(argvars, 1) == FAIL)))
4542 	return;
4543 
4544 #ifdef FEAT_JUMPLIST
4545     wp = find_tabwin(&argvars[0], &argvars[1], NULL);
4546     if (wp == NULL)
4547 	return;
4548 
4549     cleanup_jumplist(wp, TRUE);
4550 
4551     l = list_alloc();
4552     if (l == NULL)
4553 	return;
4554 
4555     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4556 	return;
4557     list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4558 
4559     for (i = 0; i < wp->w_jumplistlen; ++i)
4560     {
4561 	if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4562 	    continue;
4563 	if ((d = dict_alloc()) == NULL)
4564 	    return;
4565 	if (list_append_dict(l, d) == FAIL)
4566 	    return;
4567 	dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4568 	dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
4569 	dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
4570 	dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
4571 	if (wp->w_jumplist[i].fname != NULL)
4572 	    dict_add_string(d, "filename", wp->w_jumplist[i].fname);
4573     }
4574 #endif
4575 }
4576 
4577 /*
4578  * "getpid()" function
4579  */
4580     static void
f_getpid(typval_T * argvars UNUSED,typval_T * rettv)4581 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4582 {
4583     rettv->vval.v_number = mch_get_pid();
4584 }
4585 
4586 /*
4587  * "getcurpos()" function
4588  */
4589     static void
f_getcurpos(typval_T * argvars,typval_T * rettv)4590 f_getcurpos(typval_T *argvars, typval_T *rettv)
4591 {
4592     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4593 	return;
4594 
4595     getpos_both(argvars, rettv, TRUE, FALSE);
4596 }
4597 
4598     static void
f_getcursorcharpos(typval_T * argvars,typval_T * rettv)4599 f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
4600 {
4601     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4602 	return;
4603 
4604     getpos_both(argvars, rettv, TRUE, TRUE);
4605 }
4606 
4607 /*
4608  * "getpos(string)" function
4609  */
4610     static void
f_getpos(typval_T * argvars,typval_T * rettv)4611 f_getpos(typval_T *argvars, typval_T *rettv)
4612 {
4613     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4614 	return;
4615 
4616     getpos_both(argvars, rettv, FALSE, FALSE);
4617 }
4618 
4619 /*
4620  * "getreg()" function
4621  */
4622     static void
f_getreg(typval_T * argvars,typval_T * rettv)4623 f_getreg(typval_T *argvars, typval_T *rettv)
4624 {
4625     char_u	*strregname;
4626     int		regname;
4627     int		arg2 = FALSE;
4628     int		return_list = FALSE;
4629     int		error = FALSE;
4630 
4631     if (in_vim9script()
4632 	    && (check_for_opt_string_arg(argvars, 0) == FAIL
4633 		|| (argvars[0].v_type != VAR_UNKNOWN
4634 		    && (check_for_opt_bool_arg(argvars, 1) == FAIL
4635 			|| (argvars[1].v_type != VAR_UNKNOWN
4636 			    && check_for_opt_bool_arg(argvars, 2) == FAIL)))))
4637 	return;
4638 
4639     if (argvars[0].v_type != VAR_UNKNOWN)
4640     {
4641 	strregname = tv_get_string_chk(&argvars[0]);
4642 	if (strregname == NULL)
4643 	    error = TRUE;
4644 	else if (in_vim9script() && STRLEN(strregname) > 1)
4645 	{
4646 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
4647 	    error = TRUE;
4648 	}
4649 	if (argvars[1].v_type != VAR_UNKNOWN)
4650 	{
4651 	    arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
4652 	    if (!error && argvars[2].v_type != VAR_UNKNOWN)
4653 		return_list = (int)tv_get_bool_chk(&argvars[2], &error);
4654 	}
4655     }
4656     else
4657 	strregname = get_vim_var_str(VV_REG);
4658 
4659     if (error)
4660 	return;
4661 
4662     regname = (strregname == NULL ? '"' : *strregname);
4663     if (regname == 0)
4664 	regname = '"';
4665 
4666     if (return_list)
4667     {
4668 	rettv->v_type = VAR_LIST;
4669 	rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4670 				      (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4671 	if (rettv->vval.v_list == NULL)
4672 	    (void)rettv_list_alloc(rettv);
4673 	else
4674 	    ++rettv->vval.v_list->lv_refcount;
4675     }
4676     else
4677     {
4678 	rettv->v_type = VAR_STRING;
4679 	rettv->vval.v_string = get_reg_contents(regname,
4680 						    arg2 ? GREG_EXPR_SRC : 0);
4681     }
4682 }
4683 
4684 /*
4685  * "getregtype()" function
4686  */
4687     static void
f_getregtype(typval_T * argvars,typval_T * rettv)4688 f_getregtype(typval_T *argvars, typval_T *rettv)
4689 {
4690     char_u	*strregname;
4691     int		regname;
4692     char_u	buf[NUMBUFLEN + 2];
4693     long	reglen = 0;
4694 
4695     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
4696 	return;
4697 
4698     if (argvars[0].v_type != VAR_UNKNOWN)
4699     {
4700 	strregname = tv_get_string_chk(&argvars[0]);
4701 	if (strregname != NULL && in_vim9script() && STRLEN(strregname) > 1)
4702 	{
4703 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
4704 	    strregname = NULL;
4705 	}
4706 	if (strregname == NULL)	    // type error; errmsg already given
4707 	{
4708 	    rettv->v_type = VAR_STRING;
4709 	    rettv->vval.v_string = NULL;
4710 	    return;
4711 	}
4712     }
4713     else
4714 	// Default to v:register
4715 	strregname = get_vim_var_str(VV_REG);
4716 
4717     regname = (strregname == NULL ? '"' : *strregname);
4718     if (regname == 0)
4719 	regname = '"';
4720 
4721     buf[0] = NUL;
4722     buf[1] = NUL;
4723     switch (get_reg_type(regname, &reglen))
4724     {
4725 	case MLINE: buf[0] = 'V'; break;
4726 	case MCHAR: buf[0] = 'v'; break;
4727 	case MBLOCK:
4728 		buf[0] = Ctrl_V;
4729 		sprintf((char *)buf + 1, "%ld", reglen + 1);
4730 		break;
4731     }
4732     rettv->v_type = VAR_STRING;
4733     rettv->vval.v_string = vim_strsave(buf);
4734 }
4735 
4736 /*
4737  * "gettagstack()" function
4738  */
4739     static void
f_gettagstack(typval_T * argvars,typval_T * rettv)4740 f_gettagstack(typval_T *argvars, typval_T *rettv)
4741 {
4742     win_T	*wp = curwin;			// default is current window
4743 
4744     if (rettv_dict_alloc(rettv) != OK)
4745 	return;
4746 
4747     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4748 	return;
4749 
4750     if (argvars[0].v_type != VAR_UNKNOWN)
4751     {
4752 	wp = find_win_by_nr_or_id(&argvars[0]);
4753 	if (wp == NULL)
4754 	    return;
4755     }
4756 
4757     get_tagstack(wp, rettv->vval.v_dict);
4758 }
4759 
4760 /*
4761  * "gettext()" function
4762  */
4763     static void
f_gettext(typval_T * argvars,typval_T * rettv)4764 f_gettext(typval_T *argvars, typval_T *rettv)
4765 {
4766     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4767 	return;
4768 
4769     if (argvars[0].v_type != VAR_STRING
4770 	    || argvars[0].vval.v_string == NULL
4771 	    || *argvars[0].vval.v_string == NUL)
4772     {
4773 	semsg(_(e_invarg2), tv_get_string(&argvars[0]));
4774     }
4775     else
4776     {
4777 	rettv->v_type = VAR_STRING;
4778 	rettv->vval.v_string = vim_strsave(
4779 					(char_u *)_(argvars[0].vval.v_string));
4780     }
4781 }
4782 
4783 // for VIM_VERSION_ defines
4784 #include "version.h"
4785 
4786 /*
4787  * "has()" function
4788  */
4789     void
f_has(typval_T * argvars,typval_T * rettv)4790 f_has(typval_T *argvars, typval_T *rettv)
4791 {
4792     int		i;
4793     char_u	*name;
4794     int		x = FALSE;
4795     int		n = FALSE;
4796     typedef struct {
4797 	char *name;
4798 	short present;
4799     } has_item_T;
4800     static has_item_T has_list[] =
4801     {
4802 	{"amiga",
4803 #ifdef AMIGA
4804 		1
4805 #else
4806 		0
4807 #endif
4808 		},
4809 	{"arp",
4810 #if defined(AMIGA) && defined(FEAT_ARP)
4811 		1
4812 #else
4813 		0
4814 #endif
4815 		},
4816 	{"haiku",
4817 #ifdef __HAIKU__
4818 		1
4819 #else
4820 		0
4821 #endif
4822 		},
4823 	{"bsd",
4824 #if defined(BSD) && !defined(MACOS_X)
4825 		1
4826 #else
4827 		0
4828 #endif
4829 		},
4830 	{"hpux",
4831 #ifdef hpux
4832 		1
4833 #else
4834 		0
4835 #endif
4836 		},
4837 	{"linux",
4838 #ifdef __linux__
4839 		1
4840 #else
4841 		0
4842 #endif
4843 		},
4844 	{"mac",		// Mac OS X (and, once, Mac OS Classic)
4845 #ifdef MACOS_X
4846 		1
4847 #else
4848 		0
4849 #endif
4850 		},
4851 	{"osx",		// Mac OS X
4852 #ifdef MACOS_X
4853 		1
4854 #else
4855 		0
4856 #endif
4857 		},
4858 	{"macunix",	// Mac OS X, with the darwin feature
4859 #if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4860 		1
4861 #else
4862 		0
4863 #endif
4864 		},
4865 	{"osxdarwin",	// synonym for macunix
4866 #if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4867 		1
4868 #else
4869 		0
4870 #endif
4871 		},
4872 	{"qnx",
4873 #ifdef __QNX__
4874 		1
4875 #else
4876 		0
4877 #endif
4878 		},
4879 	{"sun",
4880 #ifdef SUN_SYSTEM
4881 		1
4882 #else
4883 		0
4884 #endif
4885 		},
4886 	{"unix",
4887 #ifdef UNIX
4888 		1
4889 #else
4890 		0
4891 #endif
4892 		},
4893 	{"vms",
4894 #ifdef VMS
4895 		1
4896 #else
4897 		0
4898 #endif
4899 		},
4900 	{"win32",
4901 #ifdef MSWIN
4902 		1
4903 #else
4904 		0
4905 #endif
4906 		},
4907 	{"win32unix",
4908 #if defined(UNIX) && defined(__CYGWIN__)
4909 		1
4910 #else
4911 		0
4912 #endif
4913 		},
4914 	{"win64",
4915 #ifdef _WIN64
4916 		1
4917 #else
4918 		0
4919 #endif
4920 		},
4921 	{"ebcdic",
4922 #ifdef EBCDIC
4923 		1
4924 #else
4925 		0
4926 #endif
4927 		},
4928 	{"fname_case",
4929 #ifndef CASE_INSENSITIVE_FILENAME
4930 		1
4931 #else
4932 		0
4933 #endif
4934 		},
4935 	{"acl",
4936 #ifdef HAVE_ACL
4937 		1
4938 #else
4939 		0
4940 #endif
4941 		},
4942 	{"arabic",
4943 #ifdef FEAT_ARABIC
4944 		1
4945 #else
4946 		0
4947 #endif
4948 		},
4949 	{"autocmd", 1},
4950 	{"autochdir",
4951 #ifdef FEAT_AUTOCHDIR
4952 		1
4953 #else
4954 		0
4955 #endif
4956 		},
4957 	{"autoservername",
4958 #ifdef FEAT_AUTOSERVERNAME
4959 		1
4960 #else
4961 		0
4962 #endif
4963 		},
4964 	{"balloon_eval",
4965 #ifdef FEAT_BEVAL_GUI
4966 		1
4967 #else
4968 		0
4969 #endif
4970 		},
4971 	{"balloon_multiline",
4972 #if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
4973 			// MS-Windows requires runtime check, see below
4974 		1
4975 #else
4976 		0
4977 #endif
4978 		},
4979 	{"balloon_eval_term",
4980 #ifdef FEAT_BEVAL_TERM
4981 		1
4982 #else
4983 		0
4984 #endif
4985 		},
4986 	{"builtin_terms",
4987 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
4988 		1
4989 #else
4990 		0
4991 #endif
4992 		},
4993 	{"all_builtin_terms",
4994 #if defined(ALL_BUILTIN_TCAPS)
4995 		1
4996 #else
4997 		0
4998 #endif
4999 		},
5000 	{"browsefilter",
5001 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5002 	|| defined(FEAT_GUI_MSWIN) \
5003 	|| defined(FEAT_GUI_MOTIF))
5004 		1
5005 #else
5006 		0
5007 #endif
5008 		},
5009 	{"byte_offset",
5010 #ifdef FEAT_BYTEOFF
5011 		1
5012 #else
5013 		0
5014 #endif
5015 		},
5016 	{"channel",
5017 #ifdef FEAT_JOB_CHANNEL
5018 		1
5019 #else
5020 		0
5021 #endif
5022 		},
5023 	{"cindent",
5024 #ifdef FEAT_CINDENT
5025 		1
5026 #else
5027 		0
5028 #endif
5029 		},
5030 	{"clientserver",
5031 #ifdef FEAT_CLIENTSERVER
5032 		1
5033 #else
5034 		0
5035 #endif
5036 		},
5037 	{"clipboard",
5038 #ifdef FEAT_CLIPBOARD
5039 		1
5040 #else
5041 		0
5042 #endif
5043 		},
5044 	{"cmdline_compl", 1},
5045 	{"cmdline_hist", 1},
5046 	{"cmdwin",
5047 #ifdef FEAT_CMDWIN
5048 		1
5049 #else
5050 		0
5051 #endif
5052 		},
5053 	{"comments", 1},
5054 	{"conceal",
5055 #ifdef FEAT_CONCEAL
5056 		1
5057 #else
5058 		0
5059 #endif
5060 		},
5061 	{"cryptv",
5062 #ifdef FEAT_CRYPT
5063 		1
5064 #else
5065 		0
5066 #endif
5067 		},
5068 	{"crypt-blowfish",
5069 #ifdef FEAT_CRYPT
5070 		1
5071 #else
5072 		0
5073 #endif
5074 		},
5075 	{"crypt-blowfish2",
5076 #ifdef FEAT_CRYPT
5077 		1
5078 #else
5079 		0
5080 #endif
5081 		},
5082 	{"cscope",
5083 #ifdef FEAT_CSCOPE
5084 		1
5085 #else
5086 		0
5087 #endif
5088 		},
5089 	{"cursorbind", 1},
5090 	{"cursorshape",
5091 #ifdef CURSOR_SHAPE
5092 		1
5093 #else
5094 		0
5095 #endif
5096 		},
5097 	{"debug",
5098 #ifdef DEBUG
5099 		1
5100 #else
5101 		0
5102 #endif
5103 		},
5104 	{"dialog_con",
5105 #ifdef FEAT_CON_DIALOG
5106 		1
5107 #else
5108 		0
5109 #endif
5110 		},
5111 	{"dialog_gui",
5112 #ifdef FEAT_GUI_DIALOG
5113 		1
5114 #else
5115 		0
5116 #endif
5117 		},
5118 	{"diff",
5119 #ifdef FEAT_DIFF
5120 		1
5121 #else
5122 		0
5123 #endif
5124 		},
5125 	{"digraphs",
5126 #ifdef FEAT_DIGRAPHS
5127 		1
5128 #else
5129 		0
5130 #endif
5131 		},
5132 	{"directx",
5133 #ifdef FEAT_DIRECTX
5134 		1
5135 #else
5136 		0
5137 #endif
5138 		},
5139 	{"dnd",
5140 #ifdef FEAT_DND
5141 		1
5142 #else
5143 		0
5144 #endif
5145 		},
5146 	{"drop_file",
5147 #ifdef HAVE_DROP_FILE
5148 		1
5149 #else
5150 		0
5151 #endif
5152 		},
5153 	{"emacs_tags",
5154 #ifdef FEAT_EMACS_TAGS
5155 		1
5156 #else
5157 		0
5158 #endif
5159 		},
5160 	{"eval", 1},		// always present, of course!
5161 	{"ex_extra", 1},	// graduated feature
5162 	{"extra_search",
5163 #ifdef FEAT_SEARCH_EXTRA
5164 		1
5165 #else
5166 		0
5167 #endif
5168 		},
5169 	{"file_in_path",
5170 #ifdef FEAT_SEARCHPATH
5171 		1
5172 #else
5173 		0
5174 #endif
5175 		},
5176 	{"filterpipe",
5177 #if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
5178 		1
5179 #else
5180 		0
5181 #endif
5182 		},
5183 	{"find_in_path",
5184 #ifdef FEAT_FIND_ID
5185 		1
5186 #else
5187 		0
5188 #endif
5189 		},
5190 	{"float",
5191 #ifdef FEAT_FLOAT
5192 		1
5193 #else
5194 		0
5195 #endif
5196 		},
5197 	{"folding",
5198 #ifdef FEAT_FOLDING
5199 		1
5200 #else
5201 		0
5202 #endif
5203 		},
5204 	{"footer",
5205 #ifdef FEAT_FOOTER
5206 		1
5207 #else
5208 		0
5209 #endif
5210 		},
5211 	{"fork",
5212 #if !defined(USE_SYSTEM) && defined(UNIX)
5213 		1
5214 #else
5215 		0
5216 #endif
5217 		},
5218 	{"gettext",
5219 #ifdef FEAT_GETTEXT
5220 		1
5221 #else
5222 		0
5223 #endif
5224 		},
5225 	{"gui",
5226 #ifdef FEAT_GUI
5227 		1
5228 #else
5229 		0
5230 #endif
5231 		},
5232 	{"gui_neXtaw",
5233 #if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
5234 		1
5235 #else
5236 		0
5237 #endif
5238 		},
5239 	{"gui_athena",
5240 #if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
5241 		1
5242 #else
5243 		0
5244 #endif
5245 		},
5246 	{"gui_gtk",
5247 #ifdef FEAT_GUI_GTK
5248 		1
5249 #else
5250 		0
5251 #endif
5252 		},
5253 	{"gui_gtk2",
5254 #if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
5255 		1
5256 #else
5257 		0
5258 #endif
5259 		},
5260 	{"gui_gtk3",
5261 #if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
5262 		1
5263 #else
5264 		0
5265 #endif
5266 		},
5267 	{"gui_gnome",
5268 #ifdef FEAT_GUI_GNOME
5269 		1
5270 #else
5271 		0
5272 #endif
5273 		},
5274 	{"gui_haiku",
5275 #ifdef FEAT_GUI_HAIKU
5276 		1
5277 #else
5278 		0
5279 #endif
5280 		},
5281 	{"gui_mac", 0},
5282 	{"gui_motif",
5283 #ifdef FEAT_GUI_MOTIF
5284 		1
5285 #else
5286 		0
5287 #endif
5288 		},
5289 	{"gui_photon",
5290 #ifdef FEAT_GUI_PHOTON
5291 		1
5292 #else
5293 		0
5294 #endif
5295 		},
5296 	{"gui_win32",
5297 #ifdef FEAT_GUI_MSWIN
5298 		1
5299 #else
5300 		0
5301 #endif
5302 		},
5303 	{"iconv",
5304 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5305 		1
5306 #else
5307 		0
5308 #endif
5309 		},
5310 	{"insert_expand", 1},
5311 	{"ipv6",
5312 #ifdef FEAT_IPV6
5313 		1
5314 #else
5315 		0
5316 #endif
5317 	},
5318 	{"job",
5319 #ifdef FEAT_JOB_CHANNEL
5320 		1
5321 #else
5322 		0
5323 #endif
5324 		},
5325 	{"jumplist",
5326 #ifdef FEAT_JUMPLIST
5327 		1
5328 #else
5329 		0
5330 #endif
5331 		},
5332 	{"keymap",
5333 #ifdef FEAT_KEYMAP
5334 		1
5335 #else
5336 		0
5337 #endif
5338 		},
5339 	{"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
5340 	{"langmap",
5341 #ifdef FEAT_LANGMAP
5342 		1
5343 #else
5344 		0
5345 #endif
5346 		},
5347 	{"libcall",
5348 #ifdef FEAT_LIBCALL
5349 		1
5350 #else
5351 		0
5352 #endif
5353 		},
5354 	{"linebreak",
5355 #ifdef FEAT_LINEBREAK
5356 		1
5357 #else
5358 		0
5359 #endif
5360 		},
5361 	{"lispindent",
5362 #ifdef FEAT_LISP
5363 		1
5364 #else
5365 		0
5366 #endif
5367 		},
5368 	{"listcmds", 1},
5369 	{"localmap", 1},
5370 	{"lua",
5371 #if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
5372 		1
5373 #else
5374 		0
5375 #endif
5376 		},
5377 	{"menu",
5378 #ifdef FEAT_MENU
5379 		1
5380 #else
5381 		0
5382 #endif
5383 		},
5384 	{"mksession",
5385 #ifdef FEAT_SESSION
5386 		1
5387 #else
5388 		0
5389 #endif
5390 		},
5391 	{"modify_fname", 1},
5392 	{"mouse", 1},
5393 	{"mouseshape",
5394 #ifdef FEAT_MOUSESHAPE
5395 		1
5396 #else
5397 		0
5398 #endif
5399 		},
5400 	{"mouse_dec",
5401 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
5402 		1
5403 #else
5404 		0
5405 #endif
5406 		},
5407 	{"mouse_gpm",
5408 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
5409 		1
5410 #else
5411 		0
5412 #endif
5413 		},
5414 	{"mouse_jsbterm",
5415 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
5416 		1
5417 #else
5418 		0
5419 #endif
5420 		},
5421 	{"mouse_netterm",
5422 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
5423 		1
5424 #else
5425 		0
5426 #endif
5427 		},
5428 	{"mouse_pterm",
5429 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
5430 		1
5431 #else
5432 		0
5433 #endif
5434 		},
5435 	{"mouse_sgr",
5436 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5437 		1
5438 #else
5439 		0
5440 #endif
5441 		},
5442 	{"mouse_sysmouse",
5443 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
5444 		1
5445 #else
5446 		0
5447 #endif
5448 		},
5449 	{"mouse_urxvt",
5450 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
5451 		1
5452 #else
5453 		0
5454 #endif
5455 		},
5456 	{"mouse_xterm",
5457 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5458 		1
5459 #else
5460 		0
5461 #endif
5462 		},
5463 	{"multi_byte", 1},
5464 	{"multi_byte_ime",
5465 #ifdef FEAT_MBYTE_IME
5466 		1
5467 #else
5468 		0
5469 #endif
5470 		},
5471 	{"multi_lang",
5472 #ifdef FEAT_MULTI_LANG
5473 		1
5474 #else
5475 		0
5476 #endif
5477 		},
5478 	{"mzscheme",
5479 #if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
5480 		1
5481 #else
5482 		0
5483 #endif
5484 		},
5485 	{"nanotime",
5486 #ifdef ST_MTIM_NSEC
5487 		1
5488 #else
5489 		0
5490 #endif
5491 	},
5492 	{"num64", 1},
5493 	{"ole",
5494 #ifdef FEAT_OLE
5495 		1
5496 #else
5497 		0
5498 #endif
5499 		},
5500 	{"packages",
5501 #ifdef FEAT_EVAL
5502 		1
5503 #else
5504 		0
5505 #endif
5506 		},
5507 	{"path_extra",
5508 #ifdef FEAT_PATH_EXTRA
5509 		1
5510 #else
5511 		0
5512 #endif
5513 		},
5514 	{"perl",
5515 #if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
5516 		1
5517 #else
5518 		0
5519 #endif
5520 		},
5521 	{"persistent_undo",
5522 #ifdef FEAT_PERSISTENT_UNDO
5523 		1
5524 #else
5525 		0
5526 #endif
5527 		},
5528 	{"python_compiled",
5529 #if defined(FEAT_PYTHON)
5530 		1
5531 #else
5532 		0
5533 #endif
5534 		},
5535 	{"python_dynamic",
5536 #if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
5537 		1
5538 #else
5539 		0
5540 #endif
5541 		},
5542 	{"python",
5543 #if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
5544 		1
5545 #else
5546 		0
5547 #endif
5548 		},
5549 	{"pythonx",
5550 #if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
5551 	|| (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
5552 		1
5553 #else
5554 		0
5555 #endif
5556 		},
5557 	{"python3_compiled",
5558 #if defined(FEAT_PYTHON3)
5559 		1
5560 #else
5561 		0
5562 #endif
5563 		},
5564 	{"python3_dynamic",
5565 #if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
5566 		1
5567 #else
5568 		0
5569 #endif
5570 		},
5571 	{"python3",
5572 #if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
5573 		1
5574 #else
5575 		0
5576 #endif
5577 		},
5578 	{"popupwin",
5579 #ifdef FEAT_PROP_POPUP
5580 		1
5581 #else
5582 		0
5583 #endif
5584 		},
5585 	{"postscript",
5586 #ifdef FEAT_POSTSCRIPT
5587 		1
5588 #else
5589 		0
5590 #endif
5591 		},
5592 	{"printer",
5593 #ifdef FEAT_PRINTER
5594 		1
5595 #else
5596 		0
5597 #endif
5598 		},
5599 	{"profile",
5600 #ifdef FEAT_PROFILE
5601 		1
5602 #else
5603 		0
5604 #endif
5605 		},
5606 	{"reltime",
5607 #ifdef FEAT_RELTIME
5608 		1
5609 #else
5610 		0
5611 #endif
5612 		},
5613 	{"quickfix",
5614 #ifdef FEAT_QUICKFIX
5615 		1
5616 #else
5617 		0
5618 #endif
5619 		},
5620 	{"rightleft",
5621 #ifdef FEAT_RIGHTLEFT
5622 		1
5623 #else
5624 		0
5625 #endif
5626 		},
5627 	{"ruby",
5628 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5629 		1
5630 #else
5631 		0
5632 #endif
5633 		},
5634 	{"scrollbind", 1},
5635 	{"showcmd",
5636 #ifdef FEAT_CMDL_INFO
5637 		1
5638 #else
5639 		0
5640 #endif
5641 		},
5642 	{"cmdline_info",
5643 #ifdef FEAT_CMDL_INFO
5644 		1
5645 #else
5646 		0
5647 #endif
5648 		},
5649 	{"signs",
5650 #ifdef FEAT_SIGNS
5651 		1
5652 #else
5653 		0
5654 #endif
5655 		},
5656 	{"smartindent",
5657 #ifdef FEAT_SMARTINDENT
5658 		1
5659 #else
5660 		0
5661 #endif
5662 		},
5663 	{"startuptime",
5664 #ifdef STARTUPTIME
5665 		1
5666 #else
5667 		0
5668 #endif
5669 		},
5670 	{"statusline",
5671 #ifdef FEAT_STL_OPT
5672 		1
5673 #else
5674 		0
5675 #endif
5676 		},
5677 	{"netbeans_intg",
5678 #ifdef FEAT_NETBEANS_INTG
5679 		1
5680 #else
5681 		0
5682 #endif
5683 		},
5684 	{"sodium",
5685 #ifdef FEAT_SODIUM
5686 		1
5687 #else
5688 		0
5689 #endif
5690 		},
5691 	{"sound",
5692 #ifdef FEAT_SOUND
5693 		1
5694 #else
5695 		0
5696 #endif
5697 		},
5698 	{"spell",
5699 #ifdef FEAT_SPELL
5700 		1
5701 #else
5702 		0
5703 #endif
5704 		},
5705 	{"syntax",
5706 #ifdef FEAT_SYN_HL
5707 		1
5708 #else
5709 		0
5710 #endif
5711 		},
5712 	{"system",
5713 #if defined(USE_SYSTEM) || !defined(UNIX)
5714 		1
5715 #else
5716 		0
5717 #endif
5718 		},
5719 	{"tag_binary",
5720 #ifdef FEAT_TAG_BINS
5721 		1
5722 #else
5723 		0
5724 #endif
5725 		},
5726 	{"tcl",
5727 #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
5728 		1
5729 #else
5730 		0
5731 #endif
5732 		},
5733 	{"termguicolors",
5734 #ifdef FEAT_TERMGUICOLORS
5735 		1
5736 #else
5737 		0
5738 #endif
5739 		},
5740 	{"terminal",
5741 #if defined(FEAT_TERMINAL) && !defined(MSWIN)
5742 		1
5743 #else
5744 		0
5745 #endif
5746 		},
5747 	{"terminfo",
5748 #ifdef TERMINFO
5749 		1
5750 #else
5751 		0
5752 #endif
5753 		},
5754 	{"termresponse",
5755 #ifdef FEAT_TERMRESPONSE
5756 		1
5757 #else
5758 		0
5759 #endif
5760 		},
5761 	{"textobjects",
5762 #ifdef FEAT_TEXTOBJ
5763 		1
5764 #else
5765 		0
5766 #endif
5767 		},
5768 	{"textprop",
5769 #ifdef FEAT_PROP_POPUP
5770 		1
5771 #else
5772 		0
5773 #endif
5774 		},
5775 	{"tgetent",
5776 #ifdef HAVE_TGETENT
5777 		1
5778 #else
5779 		0
5780 #endif
5781 		},
5782 	{"timers",
5783 #ifdef FEAT_TIMERS
5784 		1
5785 #else
5786 		0
5787 #endif
5788 		},
5789 	{"title", 1},
5790 	{"toolbar",
5791 #ifdef FEAT_TOOLBAR
5792 		1
5793 #else
5794 		0
5795 #endif
5796 		},
5797 	{"unnamedplus",
5798 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5799 		1
5800 #else
5801 		0
5802 #endif
5803 		},
5804 	{"user-commands", 1},    // was accidentally included in 5.4
5805 	{"user_commands", 1},
5806 	{"vartabs",
5807 #ifdef FEAT_VARTABS
5808 		1
5809 #else
5810 		0
5811 #endif
5812 		},
5813 	{"vertsplit", 1},
5814 	{"viminfo",
5815 #ifdef FEAT_VIMINFO
5816 		1
5817 #else
5818 		0
5819 #endif
5820 		},
5821 	{"vimscript-1", 1},
5822 	{"vimscript-2", 1},
5823 	{"vimscript-3", 1},
5824 	{"vimscript-4", 1},
5825 	{"virtualedit", 1},
5826 	{"visual", 1},
5827 	{"visualextra", 1},
5828 	{"vreplace", 1},
5829 	{"vtp",
5830 #ifdef FEAT_VTP
5831 		1
5832 #else
5833 		0
5834 #endif
5835 		},
5836 	{"wildignore",
5837 #ifdef FEAT_WILDIGN
5838 		1
5839 #else
5840 		0
5841 #endif
5842 		},
5843 	{"wildmenu",
5844 #ifdef FEAT_WILDMENU
5845 		1
5846 #else
5847 		0
5848 #endif
5849 		},
5850 	{"windows", 1},
5851 	{"winaltkeys",
5852 #ifdef FEAT_WAK
5853 		1
5854 #else
5855 		0
5856 #endif
5857 		},
5858 	{"writebackup",
5859 #ifdef FEAT_WRITEBACKUP
5860 		1
5861 #else
5862 		0
5863 #endif
5864 		},
5865 	{"xim",
5866 #ifdef FEAT_XIM
5867 		1
5868 #else
5869 		0
5870 #endif
5871 		},
5872 	{"xfontset",
5873 #ifdef FEAT_XFONTSET
5874 		1
5875 #else
5876 		0
5877 #endif
5878 		},
5879 	{"xpm",
5880 #if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
5881 		1
5882 #else
5883 		0
5884 #endif
5885 		},
5886 	{"xpm_w32",	// for backward compatibility
5887 #ifdef FEAT_XPM_W32
5888 		1
5889 #else
5890 		0
5891 #endif
5892 		},
5893 	{"xsmp",
5894 #ifdef USE_XSMP
5895 		1
5896 #else
5897 		0
5898 #endif
5899 		},
5900 	{"xsmp_interact",
5901 #ifdef USE_XSMP_INTERACT
5902 		1
5903 #else
5904 		0
5905 #endif
5906 		},
5907 	{"xterm_clipboard",
5908 #ifdef FEAT_XCLIPBOARD
5909 		1
5910 #else
5911 		0
5912 #endif
5913 		},
5914 	{"xterm_save",
5915 #ifdef FEAT_XTERM_SAVE
5916 		1
5917 #else
5918 		0
5919 #endif
5920 		},
5921 	{"X11",
5922 #if defined(UNIX) && defined(FEAT_X11)
5923 		1
5924 #else
5925 		0
5926 #endif
5927 		},
5928 	{NULL, 0}
5929     };
5930 
5931     if (in_vim9script()
5932 	    && (check_for_string_arg(argvars, 0) == FAIL
5933 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
5934 	return;
5935 
5936     name = tv_get_string(&argvars[0]);
5937     for (i = 0; has_list[i].name != NULL; ++i)
5938 	if (STRICMP(name, has_list[i].name) == 0)
5939 	{
5940 	    x = TRUE;
5941 	    n = has_list[i].present;
5942 	    break;
5943 	}
5944 
5945     // features also in has_list[] but sometimes enabled at runtime
5946     if (x == TRUE && n == FALSE)
5947     {
5948 	if (0)
5949 	{
5950 	    // intentionally empty
5951 	}
5952 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
5953 	else if (STRICMP(name, "balloon_multiline") == 0)
5954 	    n = multiline_balloon_available();
5955 #endif
5956 #ifdef VIMDLL
5957 	else if (STRICMP(name, "filterpipe") == 0)
5958 	    n = gui.in_use || gui.starting;
5959 #endif
5960 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5961 	else if (STRICMP(name, "iconv") == 0)
5962 	    n = iconv_enabled(FALSE);
5963 #endif
5964 #ifdef DYNAMIC_LUA
5965 	else if (STRICMP(name, "lua") == 0)
5966 	    n = lua_enabled(FALSE);
5967 #endif
5968 #ifdef DYNAMIC_MZSCHEME
5969 	else if (STRICMP(name, "mzscheme") == 0)
5970 	    n = mzscheme_enabled(FALSE);
5971 #endif
5972 #ifdef DYNAMIC_PERL
5973 	else if (STRICMP(name, "perl") == 0)
5974 	    n = perl_enabled(FALSE);
5975 #endif
5976 #ifdef DYNAMIC_PYTHON
5977 	else if (STRICMP(name, "python") == 0)
5978 	    n = python_enabled(FALSE);
5979 #endif
5980 #ifdef DYNAMIC_PYTHON3
5981 	else if (STRICMP(name, "python3") == 0)
5982 	    n = python3_enabled(FALSE);
5983 #endif
5984 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5985 	else if (STRICMP(name, "pythonx") == 0)
5986 	{
5987 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5988 	    if (p_pyx == 0)
5989 		n = python3_enabled(FALSE) || python_enabled(FALSE);
5990 	    else if (p_pyx == 3)
5991 		n = python3_enabled(FALSE);
5992 	    else if (p_pyx == 2)
5993 		n = python_enabled(FALSE);
5994 # elif defined(DYNAMIC_PYTHON)
5995 	    n = python_enabled(FALSE);
5996 # elif defined(DYNAMIC_PYTHON3)
5997 	    n = python3_enabled(FALSE);
5998 # endif
5999 	}
6000 #endif
6001 #ifdef DYNAMIC_RUBY
6002 	else if (STRICMP(name, "ruby") == 0)
6003 	    n = ruby_enabled(FALSE);
6004 #endif
6005 #ifdef DYNAMIC_TCL
6006 	else if (STRICMP(name, "tcl") == 0)
6007 	    n = tcl_enabled(FALSE);
6008 #endif
6009 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6010 	else if (STRICMP(name, "terminal") == 0)
6011 	    n = terminal_enabled();
6012 #endif
6013     }
6014 
6015     // features not in has_list[]
6016     if (x == FALSE)
6017     {
6018 	if (STRNICMP(name, "patch", 5) == 0)
6019 	{
6020 	    x = TRUE;
6021 	    if (name[5] == '-'
6022 		    && STRLEN(name) >= 11
6023 		    && vim_isdigit(name[6])
6024 		    && vim_isdigit(name[8])
6025 		    && vim_isdigit(name[10]))
6026 	    {
6027 		int major = atoi((char *)name + 6);
6028 		int minor = atoi((char *)name + 8);
6029 
6030 		// Expect "patch-9.9.01234".
6031 		n = (major < VIM_VERSION_MAJOR
6032 		     || (major == VIM_VERSION_MAJOR
6033 			 && (minor < VIM_VERSION_MINOR
6034 			     || (minor == VIM_VERSION_MINOR
6035 				 && has_patch(atoi((char *)name + 10))))));
6036 	    }
6037 	    else
6038 		n = has_patch(atoi((char *)name + 5));
6039 	}
6040 	else if (STRICMP(name, "vim_starting") == 0)
6041 	{
6042 	    x = TRUE;
6043 	    n = (starting != 0);
6044 	}
6045 	else if (STRICMP(name, "ttyin") == 0)
6046 	{
6047 	    x = TRUE;
6048 	    n = mch_input_isatty();
6049 	}
6050 	else if (STRICMP(name, "ttyout") == 0)
6051 	{
6052 	    x = TRUE;
6053 	    n = stdout_isatty;
6054 	}
6055 	else if (STRICMP(name, "multi_byte_encoding") == 0)
6056 	{
6057 	    x = TRUE;
6058 	    n = has_mbyte;
6059 	}
6060 	else if (STRICMP(name, "gui_running") == 0)
6061 	{
6062 	    x = TRUE;
6063 #ifdef FEAT_GUI
6064 	    n = (gui.in_use || gui.starting);
6065 #endif
6066 	}
6067 	else if (STRICMP(name, "browse") == 0)
6068 	{
6069 	    x = TRUE;
6070 #if defined(FEAT_GUI) && defined(FEAT_BROWSE)
6071 	    n = gui.in_use;	// gui_mch_browse() works when GUI is running
6072 #endif
6073 	}
6074 	else if (STRICMP(name, "syntax_items") == 0)
6075 	{
6076 	    x = TRUE;
6077 #ifdef FEAT_SYN_HL
6078 	    n = syntax_present(curwin);
6079 #endif
6080 	}
6081 	else if (STRICMP(name, "vcon") == 0)
6082 	{
6083 	    x = TRUE;
6084 #ifdef FEAT_VTP
6085 	    n = is_term_win32() && has_vtp_working();
6086 #endif
6087 	}
6088 	else if (STRICMP(name, "netbeans_enabled") == 0)
6089 	{
6090 	    x = TRUE;
6091 #ifdef FEAT_NETBEANS_INTG
6092 	    n = netbeans_active();
6093 #endif
6094 	}
6095 	else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6096 	{
6097 	    x = TRUE;
6098 #ifdef FEAT_MOUSE_GPM
6099 	    n = gpm_enabled();
6100 #endif
6101 	}
6102 	else if (STRICMP(name, "conpty") == 0)
6103 	{
6104 	    x = TRUE;
6105 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6106 	    n = use_conpty();
6107 #endif
6108 	}
6109 	else if (STRICMP(name, "clipboard_working") == 0)
6110 	{
6111 	    x = TRUE;
6112 #ifdef FEAT_CLIPBOARD
6113 	    n = clip_star.available;
6114 #endif
6115 	}
6116     }
6117 
6118     if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
6119 	// return whether feature could ever be enabled
6120 	rettv->vval.v_number = x;
6121     else
6122 	// return whether feature is enabled
6123 	rettv->vval.v_number = n;
6124 }
6125 
6126 /*
6127  * Return TRUE if "feature" can change later.
6128  * Also when checking for the feature has side effects, such as loading a DLL.
6129  */
6130     int
dynamic_feature(char_u * feature)6131 dynamic_feature(char_u *feature)
6132 {
6133     return (feature == NULL
6134 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
6135 	    || STRICMP(feature, "balloon_multiline") == 0
6136 #endif
6137 #if defined(FEAT_GUI) && defined(FEAT_BROWSE)
6138 	    || (STRICMP(feature, "browse") == 0 && !gui.in_use)
6139 #endif
6140 #ifdef VIMDLL
6141 	    || STRICMP(feature, "filterpipe") == 0
6142 #endif
6143 #if defined(FEAT_GUI) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL)
6144 	    // this can only change on Unix where the ":gui" command could be
6145 	    // used.
6146 	    || (STRICMP(feature, "gui_running") == 0 && !gui.in_use)
6147 #endif
6148 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6149 	    || STRICMP(feature, "iconv") == 0
6150 #endif
6151 #ifdef DYNAMIC_LUA
6152 	    || STRICMP(feature, "lua") == 0
6153 #endif
6154 #ifdef FEAT_MOUSE_GPM
6155 	    || (STRICMP(feature, "mouse_gpm_enabled") == 0 && !gpm_enabled())
6156 #endif
6157 #ifdef DYNAMIC_MZSCHEME
6158 	    || STRICMP(feature, "mzscheme") == 0
6159 #endif
6160 #ifdef FEAT_NETBEANS_INTG
6161 	    || STRICMP(feature, "netbeans_enabled") == 0
6162 #endif
6163 #ifdef DYNAMIC_PERL
6164 	    || STRICMP(feature, "perl") == 0
6165 #endif
6166 #ifdef DYNAMIC_PYTHON
6167 	    || STRICMP(feature, "python") == 0
6168 #endif
6169 #ifdef DYNAMIC_PYTHON3
6170 	    || STRICMP(feature, "python3") == 0
6171 #endif
6172 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6173 	    || STRICMP(feature, "pythonx") == 0
6174 #endif
6175 #ifdef DYNAMIC_RUBY
6176 	    || STRICMP(feature, "ruby") == 0
6177 #endif
6178 #ifdef FEAT_SYN_HL
6179 	    || STRICMP(feature, "syntax_items") == 0
6180 #endif
6181 #ifdef DYNAMIC_TCL
6182 	    || STRICMP(feature, "tcl") == 0
6183 #endif
6184 	    // once "starting" is zero it will stay that way
6185 	    || (STRICMP(feature, "vim_starting") == 0 && starting != 0)
6186 	    || STRICMP(feature, "multi_byte_encoding") == 0
6187 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6188 	    || STRICMP(feature, "conpty") == 0
6189 #endif
6190 	    );
6191 }
6192 
6193 /*
6194  * "haslocaldir()" function
6195  */
6196     static void
f_haslocaldir(typval_T * argvars,typval_T * rettv)6197 f_haslocaldir(typval_T *argvars, typval_T *rettv)
6198 {
6199     tabpage_T	*tp = NULL;
6200     win_T	*wp = NULL;
6201 
6202     if (in_vim9script()
6203 	    && (check_for_opt_number_arg(argvars, 0) == FAIL
6204 		|| (argvars[0].v_type != VAR_UNKNOWN
6205 		    && check_for_opt_number_arg(argvars, 1) == FAIL)))
6206 	return;
6207 
6208     wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6209 
6210     // Check for window-local and tab-local directories
6211     if (wp != NULL && wp->w_localdir != NULL)
6212 	rettv->vval.v_number = 1;
6213     else if (tp != NULL && tp->tp_localdir != NULL)
6214 	rettv->vval.v_number = 2;
6215     else
6216 	rettv->vval.v_number = 0;
6217 }
6218 
6219 /*
6220  * "hasmapto()" function
6221  */
6222     static void
f_hasmapto(typval_T * argvars,typval_T * rettv)6223 f_hasmapto(typval_T *argvars, typval_T *rettv)
6224 {
6225     char_u	*name;
6226     char_u	*mode;
6227     char_u	buf[NUMBUFLEN];
6228     int		abbr = FALSE;
6229 
6230     if (in_vim9script()
6231 	    && (check_for_string_arg(argvars, 0) == FAIL
6232 		|| check_for_opt_string_arg(argvars, 1) == FAIL
6233 		|| (argvars[1].v_type != VAR_UNKNOWN
6234 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
6235 	return;
6236 
6237     name = tv_get_string(&argvars[0]);
6238     if (argvars[1].v_type == VAR_UNKNOWN)
6239 	mode = (char_u *)"nvo";
6240     else
6241     {
6242 	mode = tv_get_string_buf(&argvars[1], buf);
6243 	if (argvars[2].v_type != VAR_UNKNOWN)
6244 	    abbr = (int)tv_get_bool(&argvars[2]);
6245     }
6246 
6247     if (map_to_exists(name, mode, abbr))
6248 	rettv->vval.v_number = TRUE;
6249     else
6250 	rettv->vval.v_number = FALSE;
6251 }
6252 
6253 /*
6254  * "highlightID(name)" function
6255  */
6256     static void
f_hlID(typval_T * argvars,typval_T * rettv)6257 f_hlID(typval_T *argvars, typval_T *rettv)
6258 {
6259     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6260 	return;
6261 
6262     rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
6263 }
6264 
6265 /*
6266  * "highlight_exists()" function
6267  */
6268     static void
f_hlexists(typval_T * argvars,typval_T * rettv)6269 f_hlexists(typval_T *argvars, typval_T *rettv)
6270 {
6271     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6272 	return;
6273 
6274     rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
6275 }
6276 
6277 /*
6278  * "hostname()" function
6279  */
6280     static void
f_hostname(typval_T * argvars UNUSED,typval_T * rettv)6281 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6282 {
6283     char_u hostname[256];
6284 
6285     mch_get_host_name(hostname, 256);
6286     rettv->v_type = VAR_STRING;
6287     rettv->vval.v_string = vim_strsave(hostname);
6288 }
6289 
6290 /*
6291  * "index()" function
6292  */
6293     static void
f_index(typval_T * argvars,typval_T * rettv)6294 f_index(typval_T *argvars, typval_T *rettv)
6295 {
6296     list_T	*l;
6297     listitem_T	*item;
6298     blob_T	*b;
6299     long	idx = 0;
6300     int		ic = FALSE;
6301     int		error = FALSE;
6302 
6303     rettv->vval.v_number = -1;
6304 
6305     if (in_vim9script()
6306 	    && (check_for_list_or_blob_arg(argvars, 0) == FAIL
6307 		|| (argvars[0].v_type == VAR_BLOB
6308 		    && check_for_number_arg(argvars, 1) == FAIL)
6309 		|| check_for_opt_number_arg(argvars, 2) == FAIL
6310 		|| (argvars[2].v_type != VAR_UNKNOWN
6311 		    && check_for_opt_bool_arg(argvars, 3) == FAIL)))
6312 	return;
6313 
6314     if (argvars[0].v_type == VAR_BLOB)
6315     {
6316 	typval_T	tv;
6317 	int		start = 0;
6318 
6319 	if (argvars[2].v_type != VAR_UNKNOWN)
6320 	{
6321 	    start = tv_get_number_chk(&argvars[2], &error);
6322 	    if (error)
6323 		return;
6324 	}
6325 	b = argvars[0].vval.v_blob;
6326 	if (b == NULL)
6327 	    return;
6328 	if (start < 0)
6329 	{
6330 	    start = blob_len(b) + start;
6331 	    if (start < 0)
6332 		start = 0;
6333 	}
6334 
6335 	for (idx = start; idx < blob_len(b); ++idx)
6336 	{
6337 	    tv.v_type = VAR_NUMBER;
6338 	    tv.vval.v_number = blob_get(b, idx);
6339 	    if (tv_equal(&tv, &argvars[1], ic, FALSE))
6340 	    {
6341 		rettv->vval.v_number = idx;
6342 		return;
6343 	    }
6344 	}
6345 	return;
6346     }
6347     else if (argvars[0].v_type != VAR_LIST)
6348     {
6349 	emsg(_(e_listblobreq));
6350 	return;
6351     }
6352 
6353     l = argvars[0].vval.v_list;
6354     if (l != NULL)
6355     {
6356 	CHECK_LIST_MATERIALIZE(l);
6357 	item = l->lv_first;
6358 	if (argvars[2].v_type != VAR_UNKNOWN)
6359 	{
6360 	    // Start at specified item.  Use the cached index that list_find()
6361 	    // sets, so that a negative number also works.
6362 	    item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
6363 	    idx = l->lv_u.mat.lv_idx;
6364 	    if (argvars[3].v_type != VAR_UNKNOWN)
6365 		ic = (int)tv_get_bool_chk(&argvars[3], &error);
6366 	    if (error)
6367 		item = NULL;
6368 	}
6369 
6370 	for ( ; item != NULL; item = item->li_next, ++idx)
6371 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6372 	    {
6373 		rettv->vval.v_number = idx;
6374 		break;
6375 	    }
6376     }
6377 }
6378 
6379 static int inputsecret_flag = 0;
6380 
6381 /*
6382  * "input()" function
6383  *     Also handles inputsecret() when inputsecret is set.
6384  */
6385     static void
f_input(typval_T * argvars,typval_T * rettv)6386 f_input(typval_T *argvars, typval_T *rettv)
6387 {
6388     get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6389 }
6390 
6391 /*
6392  * "inputdialog()" function
6393  */
6394     static void
f_inputdialog(typval_T * argvars,typval_T * rettv)6395 f_inputdialog(typval_T *argvars, typval_T *rettv)
6396 {
6397 #if defined(FEAT_GUI_TEXTDIALOG)
6398     // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
6399     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6400     {
6401 	char_u	*message;
6402 	char_u	buf[NUMBUFLEN];
6403 	char_u	*defstr = (char_u *)"";
6404 
6405 	if (in_vim9script()
6406 		&& (check_for_string_arg(argvars, 0) == FAIL
6407 		    || check_for_opt_string_arg(argvars, 1) == FAIL
6408 		    || (argvars[1].v_type != VAR_UNKNOWN
6409 			&& check_for_opt_string_arg(argvars, 2) == FAIL)))
6410 	    return;
6411 
6412 	message = tv_get_string_chk(&argvars[0]);
6413 	if (argvars[1].v_type != VAR_UNKNOWN
6414 		&& (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
6415 	    vim_strncpy(IObuff, defstr, IOSIZE - 1);
6416 	else
6417 	    IObuff[0] = NUL;
6418 	if (message != NULL && defstr != NULL
6419 		&& do_dialog(VIM_QUESTION, NULL, message,
6420 			  (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6421 	    rettv->vval.v_string = vim_strsave(IObuff);
6422 	else
6423 	{
6424 	    if (message != NULL && defstr != NULL
6425 					&& argvars[1].v_type != VAR_UNKNOWN
6426 					&& argvars[2].v_type != VAR_UNKNOWN)
6427 		rettv->vval.v_string = vim_strsave(
6428 				      tv_get_string_buf(&argvars[2], buf));
6429 	    else
6430 		rettv->vval.v_string = NULL;
6431 	}
6432 	rettv->v_type = VAR_STRING;
6433     }
6434     else
6435 #endif
6436 	get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6437 }
6438 
6439 /*
6440  * "inputlist()" function
6441  */
6442     static void
f_inputlist(typval_T * argvars,typval_T * rettv)6443 f_inputlist(typval_T *argvars, typval_T *rettv)
6444 {
6445     list_T	*l;
6446     listitem_T	*li;
6447     int		selected;
6448     int		mouse_used;
6449 
6450 #ifdef NO_CONSOLE_INPUT
6451     // While starting up, there is no place to enter text. When running tests
6452     // with --not-a-term we assume feedkeys() will be used.
6453     if (no_console_input() && !is_not_a_term())
6454 	return;
6455 #endif
6456     if (in_vim9script() && check_for_list_arg(argvars, 0) == FAIL)
6457 	return;
6458 
6459     if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6460     {
6461 	semsg(_(e_listarg), "inputlist()");
6462 	return;
6463     }
6464 
6465     msg_start();
6466     msg_row = Rows - 1;	// for when 'cmdheight' > 1
6467     lines_left = Rows;	// avoid more prompt
6468     msg_scroll = TRUE;
6469     msg_clr_eos();
6470 
6471     l = argvars[0].vval.v_list;
6472     CHECK_LIST_MATERIALIZE(l);
6473     FOR_ALL_LIST_ITEMS(l, li)
6474     {
6475 	msg_puts((char *)tv_get_string(&li->li_tv));
6476 	msg_putchar('\n');
6477     }
6478 
6479     // Ask for choice.
6480     selected = prompt_for_number(&mouse_used);
6481     if (mouse_used)
6482 	selected -= lines_left;
6483 
6484     rettv->vval.v_number = selected;
6485 }
6486 
6487 static garray_T	    ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6488 
6489 /*
6490  * "inputrestore()" function
6491  */
6492     static void
f_inputrestore(typval_T * argvars UNUSED,typval_T * rettv)6493 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6494 {
6495     if (ga_userinput.ga_len > 0)
6496     {
6497 	--ga_userinput.ga_len;
6498 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6499 						  + ga_userinput.ga_len, TRUE);
6500 	// default return is zero == OK
6501     }
6502     else if (p_verbose > 1)
6503     {
6504 	verb_msg(_("called inputrestore() more often than inputsave()"));
6505 	rettv->vval.v_number = 1; // Failed
6506     }
6507 }
6508 
6509 /*
6510  * "inputsave()" function
6511  */
6512     static void
f_inputsave(typval_T * argvars UNUSED,typval_T * rettv)6513 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6514 {
6515     // Add an entry to the stack of typeahead storage.
6516     if (ga_grow(&ga_userinput, 1) == OK)
6517     {
6518 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
6519 						       + ga_userinput.ga_len);
6520 	++ga_userinput.ga_len;
6521 	// default return is zero == OK
6522     }
6523     else
6524 	rettv->vval.v_number = 1; // Failed
6525 }
6526 
6527 /*
6528  * "inputsecret()" function
6529  */
6530     static void
f_inputsecret(typval_T * argvars,typval_T * rettv)6531 f_inputsecret(typval_T *argvars, typval_T *rettv)
6532 {
6533     if (in_vim9script()
6534 	    && (check_for_string_arg(argvars, 0) == FAIL
6535 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
6536 	return;
6537 
6538     ++cmdline_star;
6539     ++inputsecret_flag;
6540     f_input(argvars, rettv);
6541     --cmdline_star;
6542     --inputsecret_flag;
6543 }
6544 
6545 /*
6546  * "interrupt()" function
6547  */
6548     static void
f_interrupt(typval_T * argvars UNUSED,typval_T * rettv UNUSED)6549 f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6550 {
6551     got_int = TRUE;
6552 }
6553 
6554 /*
6555  * "invert(expr)" function
6556  */
6557     static void
f_invert(typval_T * argvars,typval_T * rettv)6558 f_invert(typval_T *argvars, typval_T *rettv)
6559 {
6560     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
6561 	return;
6562 
6563     rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
6564 }
6565 
6566 /*
6567  * "islocked()" function
6568  */
6569     static void
f_islocked(typval_T * argvars,typval_T * rettv)6570 f_islocked(typval_T *argvars, typval_T *rettv)
6571 {
6572     lval_T	lv;
6573     char_u	*end;
6574     dictitem_T	*di;
6575 
6576     rettv->vval.v_number = -1;
6577 
6578     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6579 	return;
6580 
6581     end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6582 			     GLV_NO_AUTOLOAD | GLV_READ_ONLY | GLV_NO_DECL,
6583 			     FNE_CHECK_START);
6584     if (end != NULL && lv.ll_name != NULL)
6585     {
6586 	if (*end != NUL)
6587 	{
6588 	    semsg(_(lv.ll_name == lv.ll_name_end
6589 					   ? e_invarg2 : e_trailing_arg), end);
6590 	}
6591 	else
6592 	{
6593 	    if (lv.ll_tv == NULL)
6594 	    {
6595 		di = find_var(lv.ll_name, NULL, TRUE);
6596 		if (di != NULL)
6597 		{
6598 		    // Consider a variable locked when:
6599 		    // 1. the variable itself is locked
6600 		    // 2. the value of the variable is locked.
6601 		    // 3. the List or Dict value is locked.
6602 		    rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6603 						   || tv_islocked(&di->di_tv));
6604 		}
6605 	    }
6606 	    else if (lv.ll_range)
6607 		emsg(_("E786: Range not allowed"));
6608 	    else if (lv.ll_newkey != NULL)
6609 		semsg(_(e_dictkey), lv.ll_newkey);
6610 	    else if (lv.ll_list != NULL)
6611 		// List item.
6612 		rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6613 	    else
6614 		// Dictionary item.
6615 		rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6616 	}
6617     }
6618 
6619     clear_lval(&lv);
6620 }
6621 
6622 /*
6623  * "last_buffer_nr()" function.
6624  */
6625     static void
f_last_buffer_nr(typval_T * argvars UNUSED,typval_T * rettv)6626 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6627 {
6628     int		n = 0;
6629     buf_T	*buf;
6630 
6631     FOR_ALL_BUFFERS(buf)
6632 	if (n < buf->b_fnum)
6633 	    n = buf->b_fnum;
6634 
6635     rettv->vval.v_number = n;
6636 }
6637 
6638 /*
6639  * "len()" function
6640  */
6641     static void
f_len(typval_T * argvars,typval_T * rettv)6642 f_len(typval_T *argvars, typval_T *rettv)
6643 {
6644     switch (argvars[0].v_type)
6645     {
6646 	case VAR_STRING:
6647 	case VAR_NUMBER:
6648 	    rettv->vval.v_number = (varnumber_T)STRLEN(
6649 					       tv_get_string(&argvars[0]));
6650 	    break;
6651 	case VAR_BLOB:
6652 	    rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6653 	    break;
6654 	case VAR_LIST:
6655 	    rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6656 	    break;
6657 	case VAR_DICT:
6658 	    rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6659 	    break;
6660 	case VAR_UNKNOWN:
6661 	case VAR_ANY:
6662 	case VAR_VOID:
6663 	case VAR_BOOL:
6664 	case VAR_SPECIAL:
6665 	case VAR_FLOAT:
6666 	case VAR_FUNC:
6667 	case VAR_PARTIAL:
6668 	case VAR_JOB:
6669 	case VAR_CHANNEL:
6670 	case VAR_INSTR:
6671 	    emsg(_("E701: Invalid type for len()"));
6672 	    break;
6673     }
6674 }
6675 
6676     static void
libcall_common(typval_T * argvars UNUSED,typval_T * rettv,int type)6677 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
6678 {
6679 #ifdef FEAT_LIBCALL
6680     char_u		*string_in;
6681     char_u		**string_result;
6682     int			nr_result;
6683 #endif
6684 
6685     rettv->v_type = type;
6686     if (type != VAR_NUMBER)
6687 	rettv->vval.v_string = NULL;
6688 
6689     if (check_restricted() || check_secure())
6690 	return;
6691 
6692     if (in_vim9script()
6693 	    && (check_for_string_arg(argvars, 0) == FAIL
6694 		|| check_for_string_arg(argvars, 1) == FAIL
6695 		|| check_for_string_or_number_arg(argvars, 2) == FAIL))
6696 	return;
6697 
6698 #ifdef FEAT_LIBCALL
6699     // The first two args must be strings, otherwise it's meaningless
6700     if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6701     {
6702 	string_in = NULL;
6703 	if (argvars[2].v_type == VAR_STRING)
6704 	    string_in = argvars[2].vval.v_string;
6705 	if (type == VAR_NUMBER)
6706 	{
6707 	    string_result = NULL;
6708 	}
6709 	else
6710 	{
6711 	    rettv->vval.v_string = NULL;
6712 	    string_result = &rettv->vval.v_string;
6713 	}
6714 	if (mch_libcall(argvars[0].vval.v_string,
6715 			     argvars[1].vval.v_string,
6716 			     string_in,
6717 			     argvars[2].vval.v_number,
6718 			     string_result,
6719 			     &nr_result) == OK
6720 		&& type == VAR_NUMBER)
6721 	    rettv->vval.v_number = nr_result;
6722     }
6723 #endif
6724 }
6725 
6726 /*
6727  * "libcall()" function
6728  */
6729     static void
f_libcall(typval_T * argvars,typval_T * rettv)6730 f_libcall(typval_T *argvars, typval_T *rettv)
6731 {
6732     libcall_common(argvars, rettv, VAR_STRING);
6733 }
6734 
6735 /*
6736  * "libcallnr()" function
6737  */
6738     static void
f_libcallnr(typval_T * argvars,typval_T * rettv)6739 f_libcallnr(typval_T *argvars, typval_T *rettv)
6740 {
6741     libcall_common(argvars, rettv, VAR_NUMBER);
6742 }
6743 
6744 /*
6745  * "line(string, [winid])" function
6746  */
6747     static void
f_line(typval_T * argvars,typval_T * rettv)6748 f_line(typval_T *argvars, typval_T *rettv)
6749 {
6750     linenr_T	lnum = 0;
6751     pos_T	*fp = NULL;
6752     int		fnum;
6753     int		id;
6754     tabpage_T	*tp;
6755     win_T	*wp;
6756     win_T	*save_curwin;
6757     tabpage_T	*save_curtab;
6758 
6759     if (in_vim9script()
6760 	    && (check_for_string_arg(argvars, 0) == FAIL
6761 		|| check_for_opt_number_arg(argvars, 1) == FAIL))
6762 	return;
6763 
6764     if (argvars[1].v_type != VAR_UNKNOWN)
6765     {
6766 	// use window specified in the second argument
6767 	id = (int)tv_get_number(&argvars[1]);
6768 	wp = win_id2wp_tp(id, &tp);
6769 	if (wp != NULL && tp != NULL)
6770 	{
6771 	    if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
6772 									 == OK)
6773 	    {
6774 		check_cursor();
6775 		fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
6776 	    }
6777 	    restore_win_noblock(save_curwin, save_curtab, TRUE);
6778 	}
6779     }
6780     else
6781 	// use current window
6782 	fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
6783 
6784     if (fp != NULL)
6785 	lnum = fp->lnum;
6786     rettv->vval.v_number = lnum;
6787 }
6788 
6789 /*
6790  * "line2byte(lnum)" function
6791  */
6792     static void
f_line2byte(typval_T * argvars UNUSED,typval_T * rettv)6793 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6794 {
6795 #ifndef FEAT_BYTEOFF
6796     rettv->vval.v_number = -1;
6797 #else
6798     linenr_T	lnum;
6799 
6800     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
6801 	return;
6802 
6803     lnum = tv_get_lnum(argvars);
6804     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6805 	rettv->vval.v_number = -1;
6806     else
6807 	rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6808     if (rettv->vval.v_number >= 0)
6809 	++rettv->vval.v_number;
6810 #endif
6811 }
6812 
6813 #ifdef FEAT_LUA
6814 /*
6815  * "luaeval()" function
6816  */
6817     static void
f_luaeval(typval_T * argvars,typval_T * rettv)6818 f_luaeval(typval_T *argvars, typval_T *rettv)
6819 {
6820     char_u	*str;
6821     char_u	buf[NUMBUFLEN];
6822 
6823     if (check_restricted() || check_secure())
6824 	return;
6825 
6826     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6827 	return;
6828 
6829     str = tv_get_string_buf(&argvars[0], buf);
6830     do_luaeval(str, argvars + 1, rettv);
6831 }
6832 #endif
6833 
6834 typedef enum
6835 {
6836     MATCH_END,	    // matchend()
6837     MATCH_MATCH,    // match()
6838     MATCH_STR,	    // matchstr()
6839     MATCH_LIST,	    // matchlist()
6840     MATCH_POS	    // matchstrpos()
6841 } matchtype_T;
6842 
6843     static void
find_some_match(typval_T * argvars,typval_T * rettv,matchtype_T type)6844 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
6845 {
6846     char_u	*str = NULL;
6847     long	len = 0;
6848     char_u	*expr = NULL;
6849     char_u	*pat;
6850     regmatch_T	regmatch;
6851     char_u	patbuf[NUMBUFLEN];
6852     char_u	strbuf[NUMBUFLEN];
6853     char_u	*save_cpo;
6854     long	start = 0;
6855     long	nth = 1;
6856     colnr_T	startcol = 0;
6857     int		match = 0;
6858     list_T	*l = NULL;
6859     listitem_T	*li = NULL;
6860     long	idx = 0;
6861     char_u	*tofree = NULL;
6862 
6863     // Make 'cpoptions' empty, the 'l' flag should not be used here.
6864     save_cpo = p_cpo;
6865     p_cpo = empty_option;
6866 
6867     rettv->vval.v_number = -1;
6868     if (type == MATCH_LIST || type == MATCH_POS)
6869     {
6870 	// type MATCH_LIST: return empty list when there are no matches.
6871 	// type MATCH_POS: return ["", -1, -1, -1]
6872 	if (rettv_list_alloc(rettv) == FAIL)
6873 	    goto theend;
6874 	if (type == MATCH_POS
6875 		&& (list_append_string(rettv->vval.v_list,
6876 					    (char_u *)"", 0) == FAIL
6877 		    || list_append_number(rettv->vval.v_list,
6878 					    (varnumber_T)-1) == FAIL
6879 		    || list_append_number(rettv->vval.v_list,
6880 					    (varnumber_T)-1) == FAIL
6881 		    || list_append_number(rettv->vval.v_list,
6882 					    (varnumber_T)-1) == FAIL))
6883 	{
6884 		list_free(rettv->vval.v_list);
6885 		rettv->vval.v_list = NULL;
6886 		goto theend;
6887 	}
6888     }
6889     else if (type == MATCH_STR)
6890     {
6891 	rettv->v_type = VAR_STRING;
6892 	rettv->vval.v_string = NULL;
6893     }
6894 
6895     if (in_vim9script()
6896 	    && (check_for_string_or_list_arg(argvars, 0) == FAIL
6897 		|| check_for_string_arg(argvars, 1) == FAIL
6898 		|| check_for_opt_number_arg(argvars, 2) == FAIL
6899 		|| (argvars[2].v_type != VAR_UNKNOWN
6900 		    && check_for_opt_number_arg(argvars, 3) == FAIL)))
6901 	goto theend;
6902 
6903     if (argvars[0].v_type == VAR_LIST)
6904     {
6905 	if ((l = argvars[0].vval.v_list) == NULL)
6906 	    goto theend;
6907 	CHECK_LIST_MATERIALIZE(l);
6908 	li = l->lv_first;
6909     }
6910     else
6911     {
6912 	expr = str = tv_get_string(&argvars[0]);
6913 	len = (long)STRLEN(str);
6914     }
6915 
6916     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
6917     if (pat == NULL)
6918 	goto theend;
6919 
6920     if (argvars[2].v_type != VAR_UNKNOWN)
6921     {
6922 	int	    error = FALSE;
6923 
6924 	start = (long)tv_get_number_chk(&argvars[2], &error);
6925 	if (error)
6926 	    goto theend;
6927 	if (l != NULL)
6928 	{
6929 	    li = list_find(l, start);
6930 	    if (li == NULL)
6931 		goto theend;
6932 	    idx = l->lv_u.mat.lv_idx;	// use the cached index
6933 	}
6934 	else
6935 	{
6936 	    if (start < 0)
6937 		start = 0;
6938 	    if (start > len)
6939 		goto theend;
6940 	    // When "count" argument is there ignore matches before "start",
6941 	    // otherwise skip part of the string.  Differs when pattern is "^"
6942 	    // or "\<".
6943 	    if (argvars[3].v_type != VAR_UNKNOWN)
6944 		startcol = start;
6945 	    else
6946 	    {
6947 		str += start;
6948 		len -= start;
6949 	    }
6950 	}
6951 
6952 	if (argvars[3].v_type != VAR_UNKNOWN)
6953 	    nth = (long)tv_get_number_chk(&argvars[3], &error);
6954 	if (error)
6955 	    goto theend;
6956     }
6957 
6958     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6959     if (regmatch.regprog != NULL)
6960     {
6961 	regmatch.rm_ic = p_ic;
6962 
6963 	for (;;)
6964 	{
6965 	    if (l != NULL)
6966 	    {
6967 		if (li == NULL)
6968 		{
6969 		    match = FALSE;
6970 		    break;
6971 		}
6972 		vim_free(tofree);
6973 		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6974 		if (str == NULL)
6975 		    break;
6976 	    }
6977 
6978 	    match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6979 
6980 	    if (match && --nth <= 0)
6981 		break;
6982 	    if (l == NULL && !match)
6983 		break;
6984 
6985 	    // Advance to just after the match.
6986 	    if (l != NULL)
6987 	    {
6988 		li = li->li_next;
6989 		++idx;
6990 	    }
6991 	    else
6992 	    {
6993 		startcol = (colnr_T)(regmatch.startp[0]
6994 				    + (*mb_ptr2len)(regmatch.startp[0]) - str);
6995 		if (startcol > (colnr_T)len
6996 				      || str + startcol <= regmatch.startp[0])
6997 		{
6998 		    match = FALSE;
6999 		    break;
7000 		}
7001 	    }
7002 	}
7003 
7004 	if (match)
7005 	{
7006 	    if (type == MATCH_POS)
7007 	    {
7008 		listitem_T *li1 = rettv->vval.v_list->lv_first;
7009 		listitem_T *li2 = li1->li_next;
7010 		listitem_T *li3 = li2->li_next;
7011 		listitem_T *li4 = li3->li_next;
7012 
7013 		vim_free(li1->li_tv.vval.v_string);
7014 		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7015 					regmatch.endp[0] - regmatch.startp[0]);
7016 		li3->li_tv.vval.v_number =
7017 				      (varnumber_T)(regmatch.startp[0] - expr);
7018 		li4->li_tv.vval.v_number =
7019 					(varnumber_T)(regmatch.endp[0] - expr);
7020 		if (l != NULL)
7021 		    li2->li_tv.vval.v_number = (varnumber_T)idx;
7022 	    }
7023 	    else if (type == MATCH_LIST)
7024 	    {
7025 		int i;
7026 
7027 		// return list with matched string and submatches
7028 		for (i = 0; i < NSUBEXP; ++i)
7029 		{
7030 		    if (regmatch.endp[i] == NULL)
7031 		    {
7032 			if (list_append_string(rettv->vval.v_list,
7033 						     (char_u *)"", 0) == FAIL)
7034 			    break;
7035 		    }
7036 		    else if (list_append_string(rettv->vval.v_list,
7037 				regmatch.startp[i],
7038 				(int)(regmatch.endp[i] - regmatch.startp[i]))
7039 			    == FAIL)
7040 			break;
7041 		}
7042 	    }
7043 	    else if (type == MATCH_STR)
7044 	    {
7045 		// return matched string
7046 		if (l != NULL)
7047 		    copy_tv(&li->li_tv, rettv);
7048 		else
7049 		    rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7050 					regmatch.endp[0] - regmatch.startp[0]);
7051 	    }
7052 	    else if (l != NULL)
7053 		rettv->vval.v_number = idx;
7054 	    else
7055 	    {
7056 		if (type != MATCH_END)
7057 		    rettv->vval.v_number =
7058 				      (varnumber_T)(regmatch.startp[0] - str);
7059 		else
7060 		    rettv->vval.v_number =
7061 					(varnumber_T)(regmatch.endp[0] - str);
7062 		rettv->vval.v_number += (varnumber_T)(str - expr);
7063 	    }
7064 	}
7065 	vim_regfree(regmatch.regprog);
7066     }
7067 
7068 theend:
7069     if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
7070 	// matchstrpos() without a list: drop the second item.
7071 	listitem_remove(rettv->vval.v_list,
7072 				       rettv->vval.v_list->lv_first->li_next);
7073     vim_free(tofree);
7074     p_cpo = save_cpo;
7075 }
7076 
7077 /*
7078  * "match()" function
7079  */
7080     static void
f_match(typval_T * argvars,typval_T * rettv)7081 f_match(typval_T *argvars, typval_T *rettv)
7082 {
7083     find_some_match(argvars, rettv, MATCH_MATCH);
7084 }
7085 
7086 /*
7087  * "matchend()" function
7088  */
7089     static void
f_matchend(typval_T * argvars,typval_T * rettv)7090 f_matchend(typval_T *argvars, typval_T *rettv)
7091 {
7092     find_some_match(argvars, rettv, MATCH_END);
7093 }
7094 
7095 /*
7096  * "matchlist()" function
7097  */
7098     static void
f_matchlist(typval_T * argvars,typval_T * rettv)7099 f_matchlist(typval_T *argvars, typval_T *rettv)
7100 {
7101     find_some_match(argvars, rettv, MATCH_LIST);
7102 }
7103 
7104 /*
7105  * "matchstr()" function
7106  */
7107     static void
f_matchstr(typval_T * argvars,typval_T * rettv)7108 f_matchstr(typval_T *argvars, typval_T *rettv)
7109 {
7110     find_some_match(argvars, rettv, MATCH_STR);
7111 }
7112 
7113 /*
7114  * "matchstrpos()" function
7115  */
7116     static void
f_matchstrpos(typval_T * argvars,typval_T * rettv)7117 f_matchstrpos(typval_T *argvars, typval_T *rettv)
7118 {
7119     find_some_match(argvars, rettv, MATCH_POS);
7120 }
7121 
7122     static void
max_min(typval_T * argvars,typval_T * rettv,int domax)7123 max_min(typval_T *argvars, typval_T *rettv, int domax)
7124 {
7125     varnumber_T	n = 0;
7126     varnumber_T	i;
7127     int		error = FALSE;
7128 
7129     if (in_vim9script() && check_for_list_or_dict_arg(argvars, 0) == FAIL)
7130 	return;
7131 
7132     if (argvars[0].v_type == VAR_LIST)
7133     {
7134 	list_T		*l;
7135 	listitem_T	*li;
7136 
7137 	l = argvars[0].vval.v_list;
7138 	if (l != NULL && l->lv_len > 0)
7139 	{
7140 	    if (l->lv_first == &range_list_item)
7141 	    {
7142 		if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
7143 		    n = l->lv_u.nonmat.lv_start;
7144 		else
7145 		    n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
7146 						    * l->lv_u.nonmat.lv_stride;
7147 	    }
7148 	    else
7149 	    {
7150 		li = l->lv_first;
7151 		if (li != NULL)
7152 		{
7153 		    n = tv_get_number_chk(&li->li_tv, &error);
7154 		    if (error)
7155 			return; // type error; errmsg already given
7156 		    for (;;)
7157 		    {
7158 			li = li->li_next;
7159 			if (li == NULL)
7160 			    break;
7161 			i = tv_get_number_chk(&li->li_tv, &error);
7162 			if (error)
7163 			    return; // type error; errmsg already given
7164 			if (domax ? i > n : i < n)
7165 			    n = i;
7166 		    }
7167 		}
7168 	    }
7169 	}
7170     }
7171     else if (argvars[0].v_type == VAR_DICT)
7172     {
7173 	dict_T		*d;
7174 	int		first = TRUE;
7175 	hashitem_T	*hi;
7176 	int		todo;
7177 
7178 	d = argvars[0].vval.v_dict;
7179 	if (d != NULL)
7180 	{
7181 	    todo = (int)d->dv_hashtab.ht_used;
7182 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7183 	    {
7184 		if (!HASHITEM_EMPTY(hi))
7185 		{
7186 		    --todo;
7187 		    i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
7188 		    if (error)
7189 			return; // type error; errmsg already given
7190 		    if (first)
7191 		    {
7192 			n = i;
7193 			first = FALSE;
7194 		    }
7195 		    else if (domax ? i > n : i < n)
7196 			n = i;
7197 		}
7198 	    }
7199 	}
7200     }
7201     else
7202 	semsg(_(e_listdictarg), domax ? "max()" : "min()");
7203 
7204     rettv->vval.v_number = n;
7205 }
7206 
7207 /*
7208  * "max()" function
7209  */
7210     static void
f_max(typval_T * argvars,typval_T * rettv)7211 f_max(typval_T *argvars, typval_T *rettv)
7212 {
7213     max_min(argvars, rettv, TRUE);
7214 }
7215 
7216 /*
7217  * "min()" function
7218  */
7219     static void
f_min(typval_T * argvars,typval_T * rettv)7220 f_min(typval_T *argvars, typval_T *rettv)
7221 {
7222     max_min(argvars, rettv, FALSE);
7223 }
7224 
7225 #if defined(FEAT_MZSCHEME) || defined(PROTO)
7226 /*
7227  * "mzeval()" function
7228  */
7229     static void
f_mzeval(typval_T * argvars,typval_T * rettv)7230 f_mzeval(typval_T *argvars, typval_T *rettv)
7231 {
7232     char_u	*str;
7233     char_u	buf[NUMBUFLEN];
7234 
7235     if (check_restricted() || check_secure())
7236 	return;
7237 
7238     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7239 	return;
7240 
7241     str = tv_get_string_buf(&argvars[0], buf);
7242     do_mzeval(str, rettv);
7243 }
7244 
7245     void
mzscheme_call_vim(char_u * name,typval_T * args,typval_T * rettv)7246 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7247 {
7248     typval_T argvars[3];
7249 
7250     argvars[0].v_type = VAR_STRING;
7251     argvars[0].vval.v_string = name;
7252     copy_tv(args, &argvars[1]);
7253     argvars[2].v_type = VAR_UNKNOWN;
7254     f_call(argvars, rettv);
7255     clear_tv(&argvars[1]);
7256 }
7257 #endif
7258 
7259 /*
7260  * "nextnonblank()" function
7261  */
7262     static void
f_nextnonblank(typval_T * argvars,typval_T * rettv)7263 f_nextnonblank(typval_T *argvars, typval_T *rettv)
7264 {
7265     linenr_T	lnum;
7266 
7267     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
7268 	return;
7269 
7270     for (lnum = tv_get_lnum(argvars); ; ++lnum)
7271     {
7272 	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7273 	{
7274 	    lnum = 0;
7275 	    break;
7276 	}
7277 	if (*skipwhite(ml_get(lnum)) != NUL)
7278 	    break;
7279     }
7280     rettv->vval.v_number = lnum;
7281 }
7282 
7283 /*
7284  * "nr2char()" function
7285  */
7286     static void
f_nr2char(typval_T * argvars,typval_T * rettv)7287 f_nr2char(typval_T *argvars, typval_T *rettv)
7288 {
7289     char_u	buf[NUMBUFLEN];
7290 
7291     if (in_vim9script()
7292 	    && (check_for_number_arg(argvars, 0) == FAIL
7293 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
7294 	return;
7295 
7296     if (has_mbyte)
7297     {
7298 	int	utf8 = 0;
7299 
7300 	if (argvars[1].v_type != VAR_UNKNOWN)
7301 	    utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
7302 	if (utf8)
7303 	    buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
7304 	else
7305 	    buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
7306     }
7307     else
7308     {
7309 	buf[0] = (char_u)tv_get_number(&argvars[0]);
7310 	buf[1] = NUL;
7311     }
7312     rettv->v_type = VAR_STRING;
7313     rettv->vval.v_string = vim_strsave(buf);
7314 }
7315 
7316 /*
7317  * "or(expr, expr)" function
7318  */
7319     static void
f_or(typval_T * argvars,typval_T * rettv)7320 f_or(typval_T *argvars, typval_T *rettv)
7321 {
7322     if (in_vim9script()
7323 	    && (check_for_number_arg(argvars, 0) == FAIL
7324 		|| check_for_number_arg(argvars, 1) == FAIL))
7325 	return;
7326 
7327     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7328 					| tv_get_number_chk(&argvars[1], NULL);
7329 }
7330 
7331 #ifdef FEAT_PERL
7332 /*
7333  * "perleval()" function
7334  */
7335     static void
f_perleval(typval_T * argvars,typval_T * rettv)7336 f_perleval(typval_T *argvars, typval_T *rettv)
7337 {
7338     char_u	*str;
7339     char_u	buf[NUMBUFLEN];
7340 
7341     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7342 	return;
7343 
7344     str = tv_get_string_buf(&argvars[0], buf);
7345     do_perleval(str, rettv);
7346 }
7347 #endif
7348 
7349 /*
7350  * "prevnonblank()" function
7351  */
7352     static void
f_prevnonblank(typval_T * argvars,typval_T * rettv)7353 f_prevnonblank(typval_T *argvars, typval_T *rettv)
7354 {
7355     linenr_T	lnum;
7356 
7357     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
7358 	return;
7359 
7360     lnum = tv_get_lnum(argvars);
7361     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7362 	lnum = 0;
7363     else
7364 	while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7365 	    --lnum;
7366     rettv->vval.v_number = lnum;
7367 }
7368 
7369 // This dummy va_list is here because:
7370 // - passing a NULL pointer doesn't work when va_list isn't a pointer
7371 // - locally in the function results in a "used before set" warning
7372 // - using va_start() to initialize it gives "function with fixed args" error
7373 static va_list	ap;
7374 
7375 /*
7376  * "printf()" function
7377  */
7378     static void
f_printf(typval_T * argvars,typval_T * rettv)7379 f_printf(typval_T *argvars, typval_T *rettv)
7380 {
7381     char_u	buf[NUMBUFLEN];
7382     int		len;
7383     char_u	*s;
7384     int		saved_did_emsg = did_emsg;
7385     char	*fmt;
7386 
7387     rettv->v_type = VAR_STRING;
7388     rettv->vval.v_string = NULL;
7389 
7390     if (in_vim9script() && check_for_string_or_number_arg(argvars, 0) == FAIL)
7391 	return;
7392 
7393     // Get the required length, allocate the buffer and do it for real.
7394     did_emsg = FALSE;
7395     fmt = (char *)tv_get_string_buf(&argvars[0], buf);
7396     len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
7397     if (!did_emsg)
7398     {
7399 	s = alloc(len + 1);
7400 	if (s != NULL)
7401 	{
7402 	    rettv->vval.v_string = s;
7403 	    (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7404 							      ap, argvars + 1);
7405 	}
7406     }
7407     did_emsg |= saved_did_emsg;
7408 }
7409 
7410 /*
7411  * "pum_getpos()" function
7412  */
7413     static void
f_pum_getpos(typval_T * argvars UNUSED,typval_T * rettv UNUSED)7414 f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7415 {
7416     if (rettv_dict_alloc(rettv) != OK)
7417 	return;
7418     pum_set_event_info(rettv->vval.v_dict);
7419 }
7420 
7421 /*
7422  * "pumvisible()" function
7423  */
7424     static void
f_pumvisible(typval_T * argvars UNUSED,typval_T * rettv UNUSED)7425 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7426 {
7427     if (pum_visible())
7428 	rettv->vval.v_number = 1;
7429 }
7430 
7431 #ifdef FEAT_PYTHON3
7432 /*
7433  * "py3eval()" function
7434  */
7435     static void
f_py3eval(typval_T * argvars,typval_T * rettv)7436 f_py3eval(typval_T *argvars, typval_T *rettv)
7437 {
7438     char_u	*str;
7439     char_u	buf[NUMBUFLEN];
7440 
7441     if (check_restricted() || check_secure())
7442 	return;
7443 
7444     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7445 	return;
7446 
7447     if (p_pyx == 0)
7448 	p_pyx = 3;
7449 
7450     str = tv_get_string_buf(&argvars[0], buf);
7451     do_py3eval(str, rettv);
7452 }
7453 #endif
7454 
7455 #ifdef FEAT_PYTHON
7456 /*
7457  * "pyeval()" function
7458  */
7459     static void
f_pyeval(typval_T * argvars,typval_T * rettv)7460 f_pyeval(typval_T *argvars, typval_T *rettv)
7461 {
7462     char_u	*str;
7463     char_u	buf[NUMBUFLEN];
7464 
7465     if (check_restricted() || check_secure())
7466 	return;
7467 
7468     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7469 	return;
7470 
7471     if (p_pyx == 0)
7472 	p_pyx = 2;
7473 
7474     str = tv_get_string_buf(&argvars[0], buf);
7475     do_pyeval(str, rettv);
7476 }
7477 #endif
7478 
7479 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7480 /*
7481  * "pyxeval()" function
7482  */
7483     static void
f_pyxeval(typval_T * argvars,typval_T * rettv)7484 f_pyxeval(typval_T *argvars, typval_T *rettv)
7485 {
7486     if (check_restricted() || check_secure())
7487 	return;
7488 
7489     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7490 	return;
7491 
7492 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7493     init_pyxversion();
7494     if (p_pyx == 2)
7495 	f_pyeval(argvars, rettv);
7496     else
7497 	f_py3eval(argvars, rettv);
7498 # elif defined(FEAT_PYTHON)
7499     f_pyeval(argvars, rettv);
7500 # elif defined(FEAT_PYTHON3)
7501     f_py3eval(argvars, rettv);
7502 # endif
7503 }
7504 #endif
7505 
7506 static UINT32_T srand_seed_for_testing = 0;
7507 static int	srand_seed_for_testing_is_used = FALSE;
7508 
7509     static void
f_test_srand_seed(typval_T * argvars,typval_T * rettv UNUSED)7510 f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
7511 {
7512     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
7513 	return;
7514 
7515     if (argvars[0].v_type == VAR_UNKNOWN)
7516 	srand_seed_for_testing_is_used = FALSE;
7517     else
7518     {
7519 	srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
7520 	srand_seed_for_testing_is_used = TRUE;
7521     }
7522 }
7523 
7524     static void
init_srand(UINT32_T * x)7525 init_srand(UINT32_T *x)
7526 {
7527 #ifndef MSWIN
7528     static int dev_urandom_state = NOTDONE;  // FAIL or OK once tried
7529 #endif
7530 
7531     if (srand_seed_for_testing_is_used)
7532     {
7533 	*x = srand_seed_for_testing;
7534 	return;
7535     }
7536 #ifndef MSWIN
7537     if (dev_urandom_state != FAIL)
7538     {
7539 	int  fd = open("/dev/urandom", O_RDONLY);
7540 	struct {
7541 	    union {
7542 		UINT32_T number;
7543 		char     bytes[sizeof(UINT32_T)];
7544 	    } contents;
7545 	} buf;
7546 
7547 	// Attempt reading /dev/urandom.
7548 	if (fd == -1)
7549 	    dev_urandom_state = FAIL;
7550 	else
7551 	{
7552 	    buf.contents.number = 0;
7553 	    if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
7554 							   != sizeof(UINT32_T))
7555 		dev_urandom_state = FAIL;
7556 	    else
7557 	    {
7558 		dev_urandom_state = OK;
7559 		*x = buf.contents.number;
7560 	    }
7561 	    close(fd);
7562 	}
7563     }
7564     if (dev_urandom_state != OK)
7565 	// Reading /dev/urandom doesn't work, fall back to time().
7566 #endif
7567 	*x = vim_time();
7568 }
7569 
7570 #define ROTL(x, k) ((x << k) | (x >> (32 - k)))
7571 #define SPLITMIX32(x, z) ( \
7572     z = (x += 0x9e3779b9), \
7573     z = (z ^ (z >> 16)) * 0x85ebca6b, \
7574     z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7575     z ^ (z >> 16) \
7576     )
7577 #define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
7578     result = ROTL(y * 5, 7) * 9; \
7579     t = y << 9; \
7580     z ^= x; \
7581     w ^= y; \
7582     y ^= z, x ^= w; \
7583     z ^= t; \
7584     w = ROTL(w, 11);
7585 
7586 /*
7587  * "rand()" function
7588  */
7589     static void
f_rand(typval_T * argvars,typval_T * rettv)7590 f_rand(typval_T *argvars, typval_T *rettv)
7591 {
7592     list_T	*l = NULL;
7593     static UINT32_T	gx, gy, gz, gw;
7594     static int	initialized = FALSE;
7595     listitem_T	*lx, *ly, *lz, *lw;
7596     UINT32_T	x = 0, y, z, w, t, result;
7597 
7598     if (in_vim9script() && check_for_opt_list_arg(argvars, 0) == FAIL)
7599 	return;
7600 
7601     if (argvars[0].v_type == VAR_UNKNOWN)
7602     {
7603 	// When no argument is given use the global seed list.
7604 	if (initialized == FALSE)
7605 	{
7606 	    // Initialize the global seed list.
7607 	    init_srand(&x);
7608 
7609 	    gx = SPLITMIX32(x, z);
7610 	    gy = SPLITMIX32(x, z);
7611 	    gz = SPLITMIX32(x, z);
7612 	    gw = SPLITMIX32(x, z);
7613 	    initialized = TRUE;
7614 	}
7615 
7616 	SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
7617     }
7618     else if (argvars[0].v_type == VAR_LIST)
7619     {
7620 	l = argvars[0].vval.v_list;
7621 	if (l == NULL || list_len(l) != 4)
7622 	    goto theend;
7623 
7624 	lx = list_find(l, 0L);
7625 	ly = list_find(l, 1L);
7626 	lz = list_find(l, 2L);
7627 	lw = list_find(l, 3L);
7628 	if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
7629 	if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
7630 	if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
7631 	if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
7632 	x = (UINT32_T)lx->li_tv.vval.v_number;
7633 	y = (UINT32_T)ly->li_tv.vval.v_number;
7634 	z = (UINT32_T)lz->li_tv.vval.v_number;
7635 	w = (UINT32_T)lw->li_tv.vval.v_number;
7636 
7637 	SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
7638 
7639 	lx->li_tv.vval.v_number = (varnumber_T)x;
7640 	ly->li_tv.vval.v_number = (varnumber_T)y;
7641 	lz->li_tv.vval.v_number = (varnumber_T)z;
7642 	lw->li_tv.vval.v_number = (varnumber_T)w;
7643     }
7644     else
7645 	goto theend;
7646 
7647     rettv->v_type = VAR_NUMBER;
7648     rettv->vval.v_number = (varnumber_T)result;
7649     return;
7650 
7651 theend:
7652     semsg(_(e_invarg2), tv_get_string(&argvars[0]));
7653     rettv->v_type = VAR_NUMBER;
7654     rettv->vval.v_number = -1;
7655 }
7656 
7657 /*
7658  * "srand()" function
7659  */
7660     static void
f_srand(typval_T * argvars,typval_T * rettv)7661 f_srand(typval_T *argvars, typval_T *rettv)
7662 {
7663     UINT32_T x = 0, z;
7664 
7665     if (rettv_list_alloc(rettv) == FAIL)
7666 	return;
7667 
7668     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
7669 	return;
7670 
7671     if (argvars[0].v_type == VAR_UNKNOWN)
7672     {
7673 	init_srand(&x);
7674     }
7675     else
7676     {
7677 	int	    error = FALSE;
7678 
7679 	x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
7680 	if (error)
7681 	    return;
7682     }
7683 
7684     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7685     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7686     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7687     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7688 }
7689 
7690 #undef ROTL
7691 #undef SPLITMIX32
7692 #undef SHUFFLE_XOSHIRO128STARSTAR
7693 
7694 /*
7695  * "range()" function
7696  */
7697     static void
f_range(typval_T * argvars,typval_T * rettv)7698 f_range(typval_T *argvars, typval_T *rettv)
7699 {
7700     varnumber_T	start;
7701     varnumber_T	end;
7702     varnumber_T	stride = 1;
7703     int		error = FALSE;
7704 
7705     if (in_vim9script()
7706 	    && (check_for_number_arg(argvars, 0) == FAIL
7707 		|| check_for_opt_number_arg(argvars, 1) == FAIL
7708 		|| (argvars[1].v_type != VAR_UNKNOWN
7709 		    && check_for_opt_number_arg(argvars, 2) == FAIL)))
7710 	return;
7711 
7712     start = tv_get_number_chk(&argvars[0], &error);
7713     if (argvars[1].v_type == VAR_UNKNOWN)
7714     {
7715 	end = start - 1;
7716 	start = 0;
7717     }
7718     else
7719     {
7720 	end = tv_get_number_chk(&argvars[1], &error);
7721 	if (argvars[2].v_type != VAR_UNKNOWN)
7722 	    stride = tv_get_number_chk(&argvars[2], &error);
7723     }
7724 
7725     if (error)
7726 	return;		// type error; errmsg already given
7727     if (stride == 0)
7728 	emsg(_("E726: Stride is zero"));
7729     else if (stride > 0 ? end + 1 < start : end - 1 > start)
7730 	emsg(_("E727: Start past end"));
7731     else if (rettv_list_alloc(rettv) == OK)
7732     {
7733 	list_T *list = rettv->vval.v_list;
7734 
7735 	// Create a non-materialized list.  This is much more efficient and
7736 	// works with ":for".  If used otherwise CHECK_LIST_MATERIALIZE() must
7737 	// be called.
7738 	list->lv_first = &range_list_item;
7739 	list->lv_u.nonmat.lv_start = start;
7740 	list->lv_u.nonmat.lv_end = end;
7741 	list->lv_u.nonmat.lv_stride = stride;
7742 	list->lv_len = (end - start) / stride + 1;
7743     }
7744 }
7745 
7746 /*
7747  * Materialize "list".
7748  * Do not call directly, use CHECK_LIST_MATERIALIZE()
7749  */
7750     void
range_list_materialize(list_T * list)7751 range_list_materialize(list_T *list)
7752 {
7753     varnumber_T start = list->lv_u.nonmat.lv_start;
7754     varnumber_T end = list->lv_u.nonmat.lv_end;
7755     int	    stride = list->lv_u.nonmat.lv_stride;
7756     varnumber_T i;
7757 
7758     list->lv_first = NULL;
7759     list->lv_u.mat.lv_last = NULL;
7760     list->lv_len = 0;
7761     list->lv_u.mat.lv_idx_item = NULL;
7762     for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7763 	if (list_append_number(list, (varnumber_T)i) == FAIL)
7764 	    break;
7765 }
7766 
7767 /*
7768  * "getreginfo()" function
7769  */
7770     static void
f_getreginfo(typval_T * argvars,typval_T * rettv)7771 f_getreginfo(typval_T *argvars, typval_T *rettv)
7772 {
7773     char_u	*strregname;
7774     int		regname;
7775     char_u	buf[NUMBUFLEN + 2];
7776     long	reglen = 0;
7777     dict_T	*dict;
7778     list_T	*list;
7779 
7780     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
7781 	return;
7782 
7783     if (argvars[0].v_type != VAR_UNKNOWN)
7784     {
7785 	strregname = tv_get_string_chk(&argvars[0]);
7786 	if (strregname == NULL)
7787 	    return;
7788 	if (in_vim9script() && STRLEN(strregname) > 1)
7789 	{
7790 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
7791 	    return;
7792 	}
7793     }
7794     else
7795 	strregname = get_vim_var_str(VV_REG);
7796 
7797     regname = (strregname == NULL ? '"' : *strregname);
7798     if (regname == 0 || regname == '@')
7799 	regname = '"';
7800 
7801     if (rettv_dict_alloc(rettv) == FAIL)
7802 	return;
7803     dict = rettv->vval.v_dict;
7804 
7805     list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
7806     if (list == NULL)
7807 	return;
7808     (void)dict_add_list(dict, "regcontents", list);
7809 
7810     buf[0] = NUL;
7811     buf[1] = NUL;
7812     switch (get_reg_type(regname, &reglen))
7813     {
7814 	case MLINE: buf[0] = 'V'; break;
7815 	case MCHAR: buf[0] = 'v'; break;
7816 	case MBLOCK:
7817 		    vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
7818 			    reglen + 1);
7819 		    break;
7820     }
7821     (void)dict_add_string(dict, (char *)"regtype", buf);
7822 
7823     buf[0] = get_register_name(get_unname_register());
7824     buf[1] = NUL;
7825     if (regname == '"')
7826 	(void)dict_add_string(dict, (char *)"points_to", buf);
7827     else
7828     {
7829 	dictitem_T	*item = dictitem_alloc((char_u *)"isunnamed");
7830 
7831 	if (item != NULL)
7832 	{
7833 	    item->di_tv.v_type = VAR_SPECIAL;
7834 	    item->di_tv.vval.v_number = regname == buf[0]
7835 						      ? VVAL_TRUE : VVAL_FALSE;
7836 	    (void)dict_add(dict, item);
7837 	}
7838     }
7839 }
7840 
7841     static void
return_register(int regname,typval_T * rettv)7842 return_register(int regname, typval_T *rettv)
7843 {
7844     char_u buf[2] = {0, 0};
7845 
7846     buf[0] = (char_u)regname;
7847     rettv->v_type = VAR_STRING;
7848     rettv->vval.v_string = vim_strsave(buf);
7849 }
7850 
7851 /*
7852  * "reg_executing()" function
7853  */
7854     static void
f_reg_executing(typval_T * argvars UNUSED,typval_T * rettv)7855 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
7856 {
7857     return_register(reg_executing, rettv);
7858 }
7859 
7860 /*
7861  * "reg_recording()" function
7862  */
7863     static void
f_reg_recording(typval_T * argvars UNUSED,typval_T * rettv)7864 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
7865 {
7866     return_register(reg_recording, rettv);
7867 }
7868 
7869 /*
7870  * "rename({from}, {to})" function
7871  */
7872     static void
f_rename(typval_T * argvars,typval_T * rettv)7873 f_rename(typval_T *argvars, typval_T *rettv)
7874 {
7875     char_u	buf[NUMBUFLEN];
7876 
7877     rettv->vval.v_number = -1;
7878     if (check_restricted() || check_secure())
7879 	return;
7880 
7881     if (in_vim9script()
7882 	    && (check_for_string_arg(argvars, 0) == FAIL
7883 		|| check_for_string_arg(argvars, 1) == FAIL))
7884 	return;
7885 
7886     rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7887 				      tv_get_string_buf(&argvars[1], buf));
7888 }
7889 
7890 /*
7891  * "repeat()" function
7892  */
7893     static void
f_repeat(typval_T * argvars,typval_T * rettv)7894 f_repeat(typval_T *argvars, typval_T *rettv)
7895 {
7896     char_u	*p;
7897     int		n;
7898     int		slen;
7899     int		len;
7900     char_u	*r;
7901     int		i;
7902 
7903     if (in_vim9script()
7904 	    && (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
7905 		|| check_for_number_arg(argvars, 1) == FAIL))
7906 	return;
7907 
7908     n = (int)tv_get_number(&argvars[1]);
7909     if (argvars[0].v_type == VAR_LIST)
7910     {
7911 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7912 	    while (n-- > 0)
7913 		if (list_extend(rettv->vval.v_list,
7914 					argvars[0].vval.v_list, NULL) == FAIL)
7915 		    break;
7916     }
7917     else
7918     {
7919 	p = tv_get_string(&argvars[0]);
7920 	rettv->v_type = VAR_STRING;
7921 	rettv->vval.v_string = NULL;
7922 
7923 	slen = (int)STRLEN(p);
7924 	len = slen * n;
7925 	if (len <= 0)
7926 	    return;
7927 
7928 	r = alloc(len + 1);
7929 	if (r != NULL)
7930 	{
7931 	    for (i = 0; i < n; i++)
7932 		mch_memmove(r + i * slen, p, (size_t)slen);
7933 	    r[len] = NUL;
7934 	}
7935 
7936 	rettv->vval.v_string = r;
7937     }
7938 }
7939 
7940 #define SP_NOMOVE	0x01	    // don't move cursor
7941 #define SP_REPEAT	0x02	    // repeat to find outer pair
7942 #define SP_RETCOUNT	0x04	    // return matchcount
7943 #define SP_SETPCMARK	0x08	    // set previous context mark
7944 #define SP_START	0x10	    // accept match at start position
7945 #define SP_SUBPAT	0x20	    // return nr of matching sub-pattern
7946 #define SP_END		0x40	    // leave cursor at end of match
7947 #define SP_COLUMN	0x80	    // start at cursor column
7948 
7949 /*
7950  * Get flags for a search function.
7951  * Possibly sets "p_ws".
7952  * Returns BACKWARD, FORWARD or zero (for an error).
7953  */
7954     static int
get_search_arg(typval_T * varp,int * flagsp)7955 get_search_arg(typval_T *varp, int *flagsp)
7956 {
7957     int		dir = FORWARD;
7958     char_u	*flags;
7959     char_u	nbuf[NUMBUFLEN];
7960     int		mask;
7961 
7962     if (varp->v_type != VAR_UNKNOWN)
7963     {
7964 	flags = tv_get_string_buf_chk(varp, nbuf);
7965 	if (flags == NULL)
7966 	    return 0;		// type error; errmsg already given
7967 	while (*flags != NUL)
7968 	{
7969 	    switch (*flags)
7970 	    {
7971 		case 'b': dir = BACKWARD; break;
7972 		case 'w': p_ws = TRUE; break;
7973 		case 'W': p_ws = FALSE; break;
7974 		default:  mask = 0;
7975 			  if (flagsp != NULL)
7976 			     switch (*flags)
7977 			     {
7978 				 case 'c': mask = SP_START; break;
7979 				 case 'e': mask = SP_END; break;
7980 				 case 'm': mask = SP_RETCOUNT; break;
7981 				 case 'n': mask = SP_NOMOVE; break;
7982 				 case 'p': mask = SP_SUBPAT; break;
7983 				 case 'r': mask = SP_REPEAT; break;
7984 				 case 's': mask = SP_SETPCMARK; break;
7985 				 case 'z': mask = SP_COLUMN; break;
7986 			     }
7987 			  if (mask == 0)
7988 			  {
7989 			      semsg(_(e_invarg2), flags);
7990 			      dir = 0;
7991 			  }
7992 			  else
7993 			      *flagsp |= mask;
7994 	    }
7995 	    if (dir == 0)
7996 		break;
7997 	    ++flags;
7998 	}
7999     }
8000     return dir;
8001 }
8002 
8003 /*
8004  * Shared by search() and searchpos() functions.
8005  */
8006     static int
search_cmn(typval_T * argvars,pos_T * match_pos,int * flagsp)8007 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8008 {
8009     int		flags;
8010     char_u	*pat;
8011     pos_T	pos;
8012     pos_T	save_cursor;
8013     int		save_p_ws = p_ws;
8014     int		dir;
8015     int		retval = 0;	// default: FAIL
8016     long	lnum_stop = 0;
8017 #ifdef FEAT_RELTIME
8018     proftime_T	tm;
8019     long	time_limit = 0;
8020 #endif
8021     int		options = SEARCH_KEEP;
8022     int		subpatnum;
8023     searchit_arg_T sia;
8024     int		use_skip = FALSE;
8025     pos_T	firstpos;
8026 
8027     if (in_vim9script()
8028 	    && (check_for_string_arg(argvars, 0) == FAIL
8029 		|| check_for_opt_string_arg(argvars, 1) == FAIL
8030 		|| (argvars[1].v_type != VAR_UNKNOWN
8031 		    && (check_for_opt_number_arg(argvars, 2) == FAIL
8032 			|| (argvars[2].v_type != VAR_UNKNOWN
8033 			    && check_for_opt_number_arg(argvars, 3) == FAIL)))))
8034 	goto theend;
8035 
8036     pat = tv_get_string(&argvars[0]);
8037     dir = get_search_arg(&argvars[1], flagsp);	// may set p_ws
8038     if (dir == 0)
8039 	goto theend;
8040     flags = *flagsp;
8041     if (flags & SP_START)
8042 	options |= SEARCH_START;
8043     if (flags & SP_END)
8044 	options |= SEARCH_END;
8045     if (flags & SP_COLUMN)
8046 	options |= SEARCH_COL;
8047 
8048     // Optional arguments: line number to stop searching, timeout and skip.
8049     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8050     {
8051 	lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
8052 	if (lnum_stop < 0)
8053 	    goto theend;
8054 	if (argvars[3].v_type != VAR_UNKNOWN)
8055 	{
8056 #ifdef FEAT_RELTIME
8057 	    time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
8058 	    if (time_limit < 0)
8059 		goto theend;
8060 #endif
8061 	    use_skip = eval_expr_valid_arg(&argvars[4]);
8062 	}
8063     }
8064 
8065 #ifdef FEAT_RELTIME
8066     // Set the time limit, if there is one.
8067     profile_setlimit(time_limit, &tm);
8068 #endif
8069 
8070     /*
8071      * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8072      * Check to make sure only those flags are set.
8073      * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8074      * flags cannot be set. Check for that condition also.
8075      */
8076     if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8077 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8078     {
8079 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
8080 	goto theend;
8081     }
8082 
8083     pos = save_cursor = curwin->w_cursor;
8084     CLEAR_FIELD(firstpos);
8085     CLEAR_FIELD(sia);
8086     sia.sa_stop_lnum = (linenr_T)lnum_stop;
8087 #ifdef FEAT_RELTIME
8088     sia.sa_tm = &tm;
8089 #endif
8090 
8091     // Repeat until {skip} returns FALSE.
8092     for (;;)
8093     {
8094 	subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
8095 						     options, RE_SEARCH, &sia);
8096 	// finding the first match again means there is no match where {skip}
8097 	// evaluates to zero.
8098 	if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
8099 	    subpatnum = FAIL;
8100 
8101 	if (subpatnum == FAIL || !use_skip)
8102 	    // didn't find it or no skip argument
8103 	    break;
8104 	firstpos = pos;
8105 
8106 	// If the skip expression matches, ignore this match.
8107 	{
8108 	    int	    do_skip;
8109 	    int	    err;
8110 	    pos_T   save_pos = curwin->w_cursor;
8111 
8112 	    curwin->w_cursor = pos;
8113 	    err = FALSE;
8114 	    do_skip = eval_expr_to_bool(&argvars[4], &err);
8115 	    curwin->w_cursor = save_pos;
8116 	    if (err)
8117 	    {
8118 		// Evaluating {skip} caused an error, break here.
8119 		subpatnum = FAIL;
8120 		break;
8121 	    }
8122 	    if (!do_skip)
8123 		break;
8124 	}
8125     }
8126 
8127     if (subpatnum != FAIL)
8128     {
8129 	if (flags & SP_SUBPAT)
8130 	    retval = subpatnum;
8131 	else
8132 	    retval = pos.lnum;
8133 	if (flags & SP_SETPCMARK)
8134 	    setpcmark();
8135 	curwin->w_cursor = pos;
8136 	if (match_pos != NULL)
8137 	{
8138 	    // Store the match cursor position
8139 	    match_pos->lnum = pos.lnum;
8140 	    match_pos->col = pos.col + 1;
8141 	}
8142 	// "/$" will put the cursor after the end of the line, may need to
8143 	// correct that here
8144 	check_cursor();
8145     }
8146 
8147     // If 'n' flag is used: restore cursor position.
8148     if (flags & SP_NOMOVE)
8149 	curwin->w_cursor = save_cursor;
8150     else
8151 	curwin->w_set_curswant = TRUE;
8152 theend:
8153     p_ws = save_p_ws;
8154 
8155     return retval;
8156 }
8157 
8158 #ifdef FEAT_RUBY
8159 /*
8160  * "rubyeval()" function
8161  */
8162     static void
f_rubyeval(typval_T * argvars,typval_T * rettv)8163 f_rubyeval(typval_T *argvars, typval_T *rettv)
8164 {
8165     char_u	*str;
8166     char_u	buf[NUMBUFLEN];
8167 
8168     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
8169 	return;
8170 
8171     str = tv_get_string_buf(&argvars[0], buf);
8172     do_rubyeval(str, rettv);
8173 }
8174 #endif
8175 
8176 /*
8177  * "screenattr()" function
8178  */
8179     static void
f_screenattr(typval_T * argvars,typval_T * rettv)8180 f_screenattr(typval_T *argvars, typval_T *rettv)
8181 {
8182     int		row;
8183     int		col;
8184     int		c;
8185 
8186     if (in_vim9script()
8187 	    && (check_for_number_arg(argvars, 0) == FAIL
8188 		|| check_for_number_arg(argvars, 1) == FAIL))
8189 	return;
8190 
8191     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8192     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8193     if (row < 0 || row >= screen_Rows
8194 	    || col < 0 || col >= screen_Columns)
8195 	c = -1;
8196     else
8197 	c = ScreenAttrs[LineOffset[row] + col];
8198     rettv->vval.v_number = c;
8199 }
8200 
8201 /*
8202  * "screenchar()" function
8203  */
8204     static void
f_screenchar(typval_T * argvars,typval_T * rettv)8205 f_screenchar(typval_T *argvars, typval_T *rettv)
8206 {
8207     int		row;
8208     int		col;
8209     int		off;
8210     int		c;
8211 
8212     if (in_vim9script()
8213 	    && (check_for_number_arg(argvars, 0) == FAIL
8214 		|| check_for_number_arg(argvars, 1) == FAIL))
8215 	return;
8216 
8217     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8218     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8219     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8220 	c = -1;
8221     else
8222     {
8223 	off = LineOffset[row] + col;
8224 	if (enc_utf8 && ScreenLinesUC[off] != 0)
8225 	    c = ScreenLinesUC[off];
8226 	else
8227 	    c = ScreenLines[off];
8228     }
8229     rettv->vval.v_number = c;
8230 }
8231 
8232 /*
8233  * "screenchars()" function
8234  */
8235     static void
f_screenchars(typval_T * argvars,typval_T * rettv)8236 f_screenchars(typval_T *argvars, typval_T *rettv)
8237 {
8238     int		row;
8239     int		col;
8240     int		off;
8241     int		c;
8242     int		i;
8243 
8244     if (rettv_list_alloc(rettv) == FAIL)
8245 	return;
8246 
8247     if (in_vim9script()
8248 	    && (check_for_number_arg(argvars, 0) == FAIL
8249 		|| check_for_number_arg(argvars, 1) == FAIL))
8250 	return;
8251 
8252     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8253     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8254     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8255 	return;
8256 
8257     off = LineOffset[row] + col;
8258     if (enc_utf8 && ScreenLinesUC[off] != 0)
8259 	c = ScreenLinesUC[off];
8260     else
8261 	c = ScreenLines[off];
8262     list_append_number(rettv->vval.v_list, (varnumber_T)c);
8263 
8264     if (enc_utf8)
8265 
8266 	for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
8267 	    list_append_number(rettv->vval.v_list,
8268 				       (varnumber_T)ScreenLinesC[i][off]);
8269 }
8270 
8271 /*
8272  * "screencol()" function
8273  *
8274  * First column is 1 to be consistent with virtcol().
8275  */
8276     static void
f_screencol(typval_T * argvars UNUSED,typval_T * rettv)8277 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8278 {
8279     rettv->vval.v_number = screen_screencol() + 1;
8280 }
8281 
8282 /*
8283  * "screenrow()" function
8284  */
8285     static void
f_screenrow(typval_T * argvars UNUSED,typval_T * rettv)8286 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8287 {
8288     rettv->vval.v_number = screen_screenrow() + 1;
8289 }
8290 
8291 /*
8292  * "screenstring()" function
8293  */
8294     static void
f_screenstring(typval_T * argvars,typval_T * rettv)8295 f_screenstring(typval_T *argvars, typval_T *rettv)
8296 {
8297     int		row;
8298     int		col;
8299     int		off;
8300     int		c;
8301     int		i;
8302     char_u	buf[MB_MAXBYTES + 1];
8303     int		buflen = 0;
8304 
8305     rettv->vval.v_string = NULL;
8306     rettv->v_type = VAR_STRING;
8307 
8308     if (in_vim9script()
8309 	    && (check_for_number_arg(argvars, 0) == FAIL
8310 		|| check_for_number_arg(argvars, 1) == FAIL))
8311 	return;
8312 
8313     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8314     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8315     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8316 	return;
8317 
8318     off = LineOffset[row] + col;
8319     if (enc_utf8 && ScreenLinesUC[off] != 0)
8320 	c = ScreenLinesUC[off];
8321     else
8322 	c = ScreenLines[off];
8323     buflen += mb_char2bytes(c, buf);
8324 
8325     if (enc_utf8 && ScreenLinesUC[off] != 0)
8326 	for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
8327 	    buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
8328 
8329     buf[buflen] = NUL;
8330     rettv->vval.v_string = vim_strsave(buf);
8331 }
8332 
8333 /*
8334  * "search()" function
8335  */
8336     static void
f_search(typval_T * argvars,typval_T * rettv)8337 f_search(typval_T *argvars, typval_T *rettv)
8338 {
8339     int		flags = 0;
8340 
8341     rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
8342 }
8343 
8344 /*
8345  * "searchdecl()" function
8346  */
8347     static void
f_searchdecl(typval_T * argvars,typval_T * rettv)8348 f_searchdecl(typval_T *argvars, typval_T *rettv)
8349 {
8350     int		locally = TRUE;
8351     int		thisblock = FALSE;
8352     int		error = FALSE;
8353     char_u	*name;
8354 
8355     rettv->vval.v_number = 1;	// default: FAIL
8356 
8357     if (in_vim9script()
8358 	    && (check_for_string_arg(argvars, 0) == FAIL
8359 		|| check_for_opt_bool_arg(argvars, 1) == FAIL
8360 		|| (argvars[1].v_type != VAR_UNKNOWN
8361 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
8362 	return;
8363 
8364     name = tv_get_string_chk(&argvars[0]);
8365     if (argvars[1].v_type != VAR_UNKNOWN)
8366     {
8367 	locally = !(int)tv_get_bool_chk(&argvars[1], &error);
8368 	if (!error && argvars[2].v_type != VAR_UNKNOWN)
8369 	    thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
8370     }
8371     if (!error && name != NULL)
8372 	rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
8373 				     locally, thisblock, SEARCH_KEEP) == FAIL;
8374 }
8375 
8376 /*
8377  * Used by searchpair() and searchpairpos()
8378  */
8379     static int
searchpair_cmn(typval_T * argvars,pos_T * match_pos)8380 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
8381 {
8382     char_u	*spat, *mpat, *epat;
8383     typval_T	*skip;
8384     int		save_p_ws = p_ws;
8385     int		dir;
8386     int		flags = 0;
8387     char_u	nbuf1[NUMBUFLEN];
8388     char_u	nbuf2[NUMBUFLEN];
8389     int		retval = 0;		// default: FAIL
8390     long	lnum_stop = 0;
8391     long	time_limit = 0;
8392 
8393     if (in_vim9script()
8394 	    && (check_for_string_arg(argvars, 0) == FAIL
8395 		|| check_for_string_arg(argvars, 1) == FAIL
8396 		|| check_for_string_arg(argvars, 2) == FAIL
8397 		|| check_for_opt_string_arg(argvars, 3) == FAIL
8398 		|| (argvars[3].v_type != VAR_UNKNOWN
8399 		    && argvars[4].v_type != VAR_UNKNOWN
8400 		    && (check_for_opt_number_arg(argvars, 5) == FAIL
8401 			|| (argvars[5].v_type != VAR_UNKNOWN
8402 			    && check_for_opt_number_arg(argvars, 6) == FAIL)))))
8403 	goto theend;
8404 
8405     // Get the three pattern arguments: start, middle, end. Will result in an
8406     // error if not a valid argument.
8407     spat = tv_get_string_chk(&argvars[0]);
8408     mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
8409     epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
8410     if (spat == NULL || mpat == NULL || epat == NULL)
8411 	goto theend;	    // type error
8412 
8413     // Handle the optional fourth argument: flags
8414     dir = get_search_arg(&argvars[3], &flags); // may set p_ws
8415     if (dir == 0)
8416 	goto theend;
8417 
8418     // Don't accept SP_END or SP_SUBPAT.
8419     // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
8420     if ((flags & (SP_END | SP_SUBPAT)) != 0
8421 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8422     {
8423 	semsg(_(e_invarg2), tv_get_string(&argvars[3]));
8424 	goto theend;
8425     }
8426 
8427     // Using 'r' implies 'W', otherwise it doesn't work.
8428     if (flags & SP_REPEAT)
8429 	p_ws = FALSE;
8430 
8431     // Optional fifth argument: skip expression
8432     if (argvars[3].v_type == VAR_UNKNOWN
8433 	    || argvars[4].v_type == VAR_UNKNOWN)
8434 	skip = NULL;
8435     else
8436     {
8437 	// Type is checked later.
8438 	skip = &argvars[4];
8439 
8440 	if (argvars[5].v_type != VAR_UNKNOWN)
8441 	{
8442 	    lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
8443 	    if (lnum_stop < 0)
8444 	    {
8445 		semsg(_(e_invarg2), tv_get_string(&argvars[5]));
8446 		goto theend;
8447 	    }
8448 #ifdef FEAT_RELTIME
8449 	    if (argvars[6].v_type != VAR_UNKNOWN)
8450 	    {
8451 		time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
8452 		if (time_limit < 0)
8453 		{
8454 		    semsg(_(e_invarg2), tv_get_string(&argvars[6]));
8455 		    goto theend;
8456 		}
8457 	    }
8458 #endif
8459 	}
8460     }
8461 
8462     retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
8463 					    match_pos, lnum_stop, time_limit);
8464 
8465 theend:
8466     p_ws = save_p_ws;
8467 
8468     return retval;
8469 }
8470 
8471 /*
8472  * "searchpair()" function
8473  */
8474     static void
f_searchpair(typval_T * argvars,typval_T * rettv)8475 f_searchpair(typval_T *argvars, typval_T *rettv)
8476 {
8477     rettv->vval.v_number = searchpair_cmn(argvars, NULL);
8478 }
8479 
8480 /*
8481  * "searchpairpos()" function
8482  */
8483     static void
f_searchpairpos(typval_T * argvars,typval_T * rettv)8484 f_searchpairpos(typval_T *argvars, typval_T *rettv)
8485 {
8486     pos_T	match_pos;
8487     int		lnum = 0;
8488     int		col = 0;
8489 
8490     if (rettv_list_alloc(rettv) == FAIL)
8491 	return;
8492 
8493     if (searchpair_cmn(argvars, &match_pos) > 0)
8494     {
8495 	lnum = match_pos.lnum;
8496 	col = match_pos.col;
8497     }
8498 
8499     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8500     list_append_number(rettv->vval.v_list, (varnumber_T)col);
8501 }
8502 
8503 /*
8504  * Search for a start/middle/end thing.
8505  * Used by searchpair(), see its documentation for the details.
8506  * Returns 0 or -1 for no match,
8507  */
8508     long
do_searchpair(char_u * spat,char_u * mpat,char_u * epat,int dir,typval_T * skip,int flags,pos_T * match_pos,linenr_T lnum_stop,long time_limit UNUSED)8509 do_searchpair(
8510     char_u	*spat,	    // start pattern
8511     char_u	*mpat,	    // middle pattern
8512     char_u	*epat,	    // end pattern
8513     int		dir,	    // BACKWARD or FORWARD
8514     typval_T	*skip,	    // skip expression
8515     int		flags,	    // SP_SETPCMARK and other SP_ values
8516     pos_T	*match_pos,
8517     linenr_T	lnum_stop,  // stop at this line if not zero
8518     long	time_limit UNUSED) // stop after this many msec
8519 {
8520     char_u	*save_cpo;
8521     char_u	*pat, *pat2 = NULL, *pat3 = NULL;
8522     long	retval = 0;
8523     pos_T	pos;
8524     pos_T	firstpos;
8525     pos_T	foundpos;
8526     pos_T	save_cursor;
8527     pos_T	save_pos;
8528     int		n;
8529     int		r;
8530     int		nest = 1;
8531     int		use_skip = FALSE;
8532     int		err;
8533     int		options = SEARCH_KEEP;
8534 #ifdef FEAT_RELTIME
8535     proftime_T	tm;
8536 #endif
8537 
8538     // Make 'cpoptions' empty, the 'l' flag should not be used here.
8539     save_cpo = p_cpo;
8540     p_cpo = empty_option;
8541 
8542 #ifdef FEAT_RELTIME
8543     // Set the time limit, if there is one.
8544     profile_setlimit(time_limit, &tm);
8545 #endif
8546 
8547     // Make two search patterns: start/end (pat2, for in nested pairs) and
8548     // start/middle/end (pat3, for the top pair).
8549     pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
8550     pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
8551     if (pat2 == NULL || pat3 == NULL)
8552 	goto theend;
8553     sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
8554     if (*mpat == NUL)
8555 	STRCPY(pat3, pat2);
8556     else
8557 	sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
8558 							    spat, epat, mpat);
8559     if (flags & SP_START)
8560 	options |= SEARCH_START;
8561 
8562     if (skip != NULL)
8563 	use_skip = eval_expr_valid_arg(skip);
8564 
8565     save_cursor = curwin->w_cursor;
8566     pos = curwin->w_cursor;
8567     CLEAR_POS(&firstpos);
8568     CLEAR_POS(&foundpos);
8569     pat = pat3;
8570     for (;;)
8571     {
8572 	searchit_arg_T sia;
8573 
8574 	CLEAR_FIELD(sia);
8575 	sia.sa_stop_lnum = lnum_stop;
8576 #ifdef FEAT_RELTIME
8577 	sia.sa_tm = &tm;
8578 #endif
8579 	n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
8580 						     options, RE_SEARCH, &sia);
8581 	if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
8582 	    // didn't find it or found the first match again: FAIL
8583 	    break;
8584 
8585 	if (firstpos.lnum == 0)
8586 	    firstpos = pos;
8587 	if (EQUAL_POS(pos, foundpos))
8588 	{
8589 	    // Found the same position again.  Can happen with a pattern that
8590 	    // has "\zs" at the end and searching backwards.  Advance one
8591 	    // character and try again.
8592 	    if (dir == BACKWARD)
8593 		decl(&pos);
8594 	    else
8595 		incl(&pos);
8596 	}
8597 	foundpos = pos;
8598 
8599 	// clear the start flag to avoid getting stuck here
8600 	options &= ~SEARCH_START;
8601 
8602 	// If the skip pattern matches, ignore this match.
8603 	if (use_skip)
8604 	{
8605 	    save_pos = curwin->w_cursor;
8606 	    curwin->w_cursor = pos;
8607 	    err = FALSE;
8608 	    r = eval_expr_to_bool(skip, &err);
8609 	    curwin->w_cursor = save_pos;
8610 	    if (err)
8611 	    {
8612 		// Evaluating {skip} caused an error, break here.
8613 		curwin->w_cursor = save_cursor;
8614 		retval = -1;
8615 		break;
8616 	    }
8617 	    if (r)
8618 		continue;
8619 	}
8620 
8621 	if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
8622 	{
8623 	    // Found end when searching backwards or start when searching
8624 	    // forward: nested pair.
8625 	    ++nest;
8626 	    pat = pat2;		// nested, don't search for middle
8627 	}
8628 	else
8629 	{
8630 	    // Found end when searching forward or start when searching
8631 	    // backward: end of (nested) pair; or found middle in outer pair.
8632 	    if (--nest == 1)
8633 		pat = pat3;	// outer level, search for middle
8634 	}
8635 
8636 	if (nest == 0)
8637 	{
8638 	    // Found the match: return matchcount or line number.
8639 	    if (flags & SP_RETCOUNT)
8640 		++retval;
8641 	    else
8642 		retval = pos.lnum;
8643 	    if (flags & SP_SETPCMARK)
8644 		setpcmark();
8645 	    curwin->w_cursor = pos;
8646 	    if (!(flags & SP_REPEAT))
8647 		break;
8648 	    nest = 1;	    // search for next unmatched
8649 	}
8650     }
8651 
8652     if (match_pos != NULL)
8653     {
8654 	// Store the match cursor position
8655 	match_pos->lnum = curwin->w_cursor.lnum;
8656 	match_pos->col = curwin->w_cursor.col + 1;
8657     }
8658 
8659     // If 'n' flag is used or search failed: restore cursor position.
8660     if ((flags & SP_NOMOVE) || retval == 0)
8661 	curwin->w_cursor = save_cursor;
8662 
8663 theend:
8664     vim_free(pat2);
8665     vim_free(pat3);
8666     if (p_cpo == empty_option)
8667 	p_cpo = save_cpo;
8668     else
8669     {
8670 	// Darn, evaluating the {skip} expression changed the value.
8671 	// If it's still empty it was changed and restored, need to restore in
8672 	// the complicated way.
8673 	if (*p_cpo == NUL)
8674 	    set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
8675 	free_string_option(save_cpo);
8676     }
8677 
8678     return retval;
8679 }
8680 
8681 /*
8682  * "searchpos()" function
8683  */
8684     static void
f_searchpos(typval_T * argvars,typval_T * rettv)8685 f_searchpos(typval_T *argvars, typval_T *rettv)
8686 {
8687     pos_T	match_pos;
8688     int		lnum = 0;
8689     int		col = 0;
8690     int		n;
8691     int		flags = 0;
8692 
8693     if (rettv_list_alloc(rettv) == FAIL)
8694 	return;
8695 
8696     n = search_cmn(argvars, &match_pos, &flags);
8697     if (n > 0)
8698     {
8699 	lnum = match_pos.lnum;
8700 	col = match_pos.col;
8701     }
8702 
8703     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8704     list_append_number(rettv->vval.v_list, (varnumber_T)col);
8705     if (flags & SP_SUBPAT)
8706 	list_append_number(rettv->vval.v_list, (varnumber_T)n);
8707 }
8708 
8709 /*
8710  * Set the cursor or mark position.
8711  * If 'charpos' is TRUE, then use the column number as a character offset.
8712  * Otherwise use the column number as a byte offset.
8713  */
8714     static void
set_position(typval_T * argvars,typval_T * rettv,int charpos)8715 set_position(typval_T *argvars, typval_T *rettv, int charpos)
8716 {
8717     pos_T	pos;
8718     int		fnum;
8719     char_u	*name;
8720     colnr_T	curswant = -1;
8721 
8722     rettv->vval.v_number = -1;
8723 
8724     if (in_vim9script()
8725 	    && (check_for_string_arg(argvars, 0) == FAIL
8726 		|| check_for_list_arg(argvars, 1) == FAIL))
8727 	return;
8728 
8729     name = tv_get_string_chk(argvars);
8730     if (name != NULL)
8731     {
8732 	if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK)
8733 	{
8734 	    if (pos.col != MAXCOL && --pos.col < 0)
8735 		pos.col = 0;
8736 	    if ((name[0] == '.' && name[1] == NUL))
8737 	    {
8738 		// set cursor; "fnum" is ignored
8739 		curwin->w_cursor = pos;
8740 		if (curswant >= 0)
8741 		{
8742 		    curwin->w_curswant = curswant - 1;
8743 		    curwin->w_set_curswant = FALSE;
8744 		}
8745 		check_cursor();
8746 		rettv->vval.v_number = 0;
8747 	    }
8748 	    else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
8749 	    {
8750 		// set mark
8751 		if (setmark_pos(name[1], &pos, fnum) == OK)
8752 		    rettv->vval.v_number = 0;
8753 	    }
8754 	    else
8755 		emsg(_(e_invarg));
8756 	}
8757     }
8758 }
8759 /*
8760  * "setcharpos()" function
8761  */
8762     static void
f_setcharpos(typval_T * argvars,typval_T * rettv)8763 f_setcharpos(typval_T *argvars, typval_T *rettv)
8764 {
8765     set_position(argvars, rettv, TRUE);
8766 }
8767 
8768     static void
f_setcharsearch(typval_T * argvars,typval_T * rettv UNUSED)8769 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
8770 {
8771     dict_T	*d;
8772     dictitem_T	*di;
8773     char_u	*csearch;
8774 
8775     if (in_vim9script() && check_for_dict_arg(argvars, 0) == FAIL)
8776 	return;
8777 
8778     if (argvars[0].v_type != VAR_DICT)
8779     {
8780 	emsg(_(e_dictreq));
8781 	return;
8782     }
8783 
8784     if ((d = argvars[0].vval.v_dict) != NULL)
8785     {
8786 	csearch = dict_get_string(d, (char_u *)"char", FALSE);
8787 	if (csearch != NULL)
8788 	{
8789 	    if (enc_utf8)
8790 	    {
8791 		int pcc[MAX_MCO];
8792 		int c = utfc_ptr2char(csearch, pcc);
8793 
8794 		set_last_csearch(c, csearch, utfc_ptr2len(csearch));
8795 	    }
8796 	    else
8797 		set_last_csearch(PTR2CHAR(csearch),
8798 						csearch, mb_ptr2len(csearch));
8799 	}
8800 
8801 	di = dict_find(d, (char_u *)"forward", -1);
8802 	if (di != NULL)
8803 	    set_csearch_direction((int)tv_get_number(&di->di_tv)
8804 							? FORWARD : BACKWARD);
8805 
8806 	di = dict_find(d, (char_u *)"until", -1);
8807 	if (di != NULL)
8808 	    set_csearch_until(!!tv_get_number(&di->di_tv));
8809     }
8810 }
8811 
8812 /*
8813  * "setcursorcharpos" function
8814  */
8815     static void
f_setcursorcharpos(typval_T * argvars,typval_T * rettv)8816 f_setcursorcharpos(typval_T *argvars, typval_T *rettv)
8817 {
8818     set_cursorpos(argvars, rettv, TRUE);
8819 }
8820 
8821 /*
8822  * "setenv()" function
8823  */
8824     static void
f_setenv(typval_T * argvars,typval_T * rettv UNUSED)8825 f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
8826 {
8827     char_u   namebuf[NUMBUFLEN];
8828     char_u   valbuf[NUMBUFLEN];
8829     char_u  *name;
8830 
8831     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
8832 	return;
8833 
8834     name = tv_get_string_buf(&argvars[0], namebuf);
8835     if (argvars[1].v_type == VAR_SPECIAL
8836 				      && argvars[1].vval.v_number == VVAL_NULL)
8837 	vim_unsetenv(name);
8838     else
8839 	vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
8840 }
8841 
8842 /*
8843  * "setfperm({fname}, {mode})" function
8844  */
8845     static void
f_setfperm(typval_T * argvars,typval_T * rettv)8846 f_setfperm(typval_T *argvars, typval_T *rettv)
8847 {
8848     char_u	*fname;
8849     char_u	modebuf[NUMBUFLEN];
8850     char_u	*mode_str;
8851     int		i;
8852     int		mask;
8853     int		mode = 0;
8854 
8855     rettv->vval.v_number = 0;
8856 
8857     if (in_vim9script()
8858 	    && (check_for_string_arg(argvars, 0) == FAIL
8859 		|| check_for_string_arg(argvars, 1) == FAIL))
8860 	return;
8861 
8862     fname = tv_get_string_chk(&argvars[0]);
8863     if (fname == NULL)
8864 	return;
8865     mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
8866     if (mode_str == NULL)
8867 	return;
8868     if (STRLEN(mode_str) != 9)
8869     {
8870 	semsg(_(e_invarg2), mode_str);
8871 	return;
8872     }
8873 
8874     mask = 1;
8875     for (i = 8; i >= 0; --i)
8876     {
8877 	if (mode_str[i] != '-')
8878 	    mode |= mask;
8879 	mask = mask << 1;
8880     }
8881     rettv->vval.v_number = mch_setperm(fname, mode) == OK;
8882 }
8883 
8884 /*
8885  * "setpos()" function
8886  */
8887     static void
f_setpos(typval_T * argvars,typval_T * rettv)8888 f_setpos(typval_T *argvars, typval_T *rettv)
8889 {
8890     set_position(argvars, rettv, FALSE);
8891 }
8892 
8893 /*
8894  * Translate a register type string to the yank type and block length
8895  */
8896     static int
get_yank_type(char_u ** pp,char_u * yank_type,long * block_len)8897 get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
8898 {
8899     char_u *stropt = *pp;
8900     switch (*stropt)
8901     {
8902 	case 'v': case 'c':	// character-wise selection
8903 	    *yank_type = MCHAR;
8904 	    break;
8905 	case 'V': case 'l':	// line-wise selection
8906 	    *yank_type = MLINE;
8907 	    break;
8908 	case 'b': case Ctrl_V:	// block-wise selection
8909 	    *yank_type = MBLOCK;
8910 	    if (VIM_ISDIGIT(stropt[1]))
8911 	    {
8912 		++stropt;
8913 		*block_len = getdigits(&stropt) - 1;
8914 		--stropt;
8915 	    }
8916 	    break;
8917 	default:
8918 	    return FAIL;
8919     }
8920     *pp = stropt;
8921     return OK;
8922 }
8923 
8924 /*
8925  * "setreg()" function
8926  */
8927     static void
f_setreg(typval_T * argvars,typval_T * rettv)8928 f_setreg(typval_T *argvars, typval_T *rettv)
8929 {
8930     int		regname;
8931     char_u	*strregname;
8932     char_u	*stropt;
8933     char_u	*strval;
8934     int		append;
8935     char_u	yank_type;
8936     long	block_len;
8937     typval_T	*regcontents;
8938     int		pointreg;
8939 
8940     if (in_vim9script()
8941 	    && (check_for_string_arg(argvars, 0) == FAIL
8942 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
8943 	return;
8944 
8945     pointreg = 0;
8946     regcontents = NULL;
8947     block_len = -1;
8948     yank_type = MAUTO;
8949     append = FALSE;
8950 
8951     strregname = tv_get_string_chk(argvars);
8952     rettv->vval.v_number = 1;		// FAIL is default
8953 
8954     if (strregname == NULL)
8955 	return;		// type error; errmsg already given
8956     if (in_vim9script() && STRLEN(strregname) > 1)
8957     {
8958 	semsg(_(e_register_name_must_be_one_char_str), strregname);
8959 	return;
8960     }
8961     regname = *strregname;
8962     if (regname == 0 || regname == '@')
8963 	regname = '"';
8964 
8965     if (argvars[1].v_type == VAR_DICT)
8966     {
8967 	dict_T	    *d = argvars[1].vval.v_dict;
8968 	dictitem_T  *di;
8969 
8970 	if (d == NULL || d->dv_hashtab.ht_used == 0)
8971 	{
8972 	    // Empty dict, clear the register (like setreg(0, []))
8973 	    char_u *lstval[2] = {NULL, NULL};
8974 	    write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
8975 	    return;
8976 	}
8977 
8978 	di = dict_find(d, (char_u *)"regcontents", -1);
8979 	if (di != NULL)
8980 	    regcontents = &di->di_tv;
8981 
8982 	stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
8983 	if (stropt != NULL)
8984 	{
8985 	    int ret = get_yank_type(&stropt, &yank_type, &block_len);
8986 
8987 	    if (ret == FAIL || *++stropt != NUL)
8988 	    {
8989 		semsg(_(e_invargval), "value");
8990 		return;
8991 	    }
8992 	}
8993 
8994 	if (regname == '"')
8995 	{
8996 	    stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
8997 	    if (stropt != NULL)
8998 	    {
8999 		pointreg = *stropt;
9000 		regname = pointreg;
9001 	    }
9002 	}
9003 	else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
9004 	    pointreg = regname;
9005     }
9006     else
9007 	regcontents = &argvars[1];
9008 
9009     if (argvars[2].v_type != VAR_UNKNOWN)
9010     {
9011 	if (yank_type != MAUTO)
9012 	{
9013 	    semsg(_(e_toomanyarg), "setreg");
9014 	    return;
9015 	}
9016 
9017 	stropt = tv_get_string_chk(&argvars[2]);
9018 	if (stropt == NULL)
9019 	    return;		// type error
9020 	for (; *stropt != NUL; ++stropt)
9021 	    switch (*stropt)
9022 	    {
9023 		case 'a': case 'A':	// append
9024 		    append = TRUE;
9025 		    break;
9026 		default:
9027 		    get_yank_type(&stropt, &yank_type, &block_len);
9028 	    }
9029     }
9030 
9031     if (regcontents && regcontents->v_type == VAR_LIST)
9032     {
9033 	char_u		**lstval;
9034 	char_u		**allocval;
9035 	char_u		buf[NUMBUFLEN];
9036 	char_u		**curval;
9037 	char_u		**curallocval;
9038 	list_T		*ll = regcontents->vval.v_list;
9039 	listitem_T	*li;
9040 	int		len;
9041 
9042 	// If the list is NULL handle like an empty list.
9043 	len = ll == NULL ? 0 : ll->lv_len;
9044 
9045 	// First half: use for pointers to result lines; second half: use for
9046 	// pointers to allocated copies.
9047 	lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
9048 	if (lstval == NULL)
9049 	    return;
9050 	curval = lstval;
9051 	allocval = lstval + len + 2;
9052 	curallocval = allocval;
9053 
9054 	if (ll != NULL)
9055 	{
9056 	    CHECK_LIST_MATERIALIZE(ll);
9057 	    FOR_ALL_LIST_ITEMS(ll, li)
9058 	    {
9059 		strval = tv_get_string_buf_chk(&li->li_tv, buf);
9060 		if (strval == NULL)
9061 		    goto free_lstval;
9062 		if (strval == buf)
9063 		{
9064 		    // Need to make a copy, next tv_get_string_buf_chk() will
9065 		    // overwrite the string.
9066 		    strval = vim_strsave(buf);
9067 		    if (strval == NULL)
9068 			goto free_lstval;
9069 		    *curallocval++ = strval;
9070 		}
9071 		*curval++ = strval;
9072 	    }
9073 	}
9074 	*curval++ = NULL;
9075 
9076 	write_reg_contents_lst(regname, lstval, -1,
9077 						append, yank_type, block_len);
9078 free_lstval:
9079 	while (curallocval > allocval)
9080 	    vim_free(*--curallocval);
9081 	vim_free(lstval);
9082     }
9083     else if (regcontents)
9084     {
9085 	strval = tv_get_string_chk(regcontents);
9086 	if (strval == NULL)
9087 	    return;
9088 	write_reg_contents_ex(regname, strval, -1,
9089 						append, yank_type, block_len);
9090     }
9091     if (pointreg != 0)
9092 	get_yank_register(pointreg, TRUE);
9093 
9094     rettv->vval.v_number = 0;
9095 }
9096 
9097 /*
9098  * "settagstack()" function
9099  */
9100     static void
f_settagstack(typval_T * argvars,typval_T * rettv)9101 f_settagstack(typval_T *argvars, typval_T *rettv)
9102 {
9103     static char *e_invact2 = N_("E962: Invalid action: '%s'");
9104     win_T	*wp;
9105     dict_T	*d;
9106     int		action = 'r';
9107 
9108     rettv->vval.v_number = -1;
9109 
9110     if (in_vim9script()
9111 	    && (check_for_number_arg(argvars, 0) == FAIL
9112 		|| check_for_dict_arg(argvars, 1) == FAIL
9113 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
9114 	return;
9115 
9116     // first argument: window number or id
9117     wp = find_win_by_nr_or_id(&argvars[0]);
9118     if (wp == NULL)
9119 	return;
9120 
9121     // second argument: dict with items to set in the tag stack
9122     if (argvars[1].v_type != VAR_DICT)
9123     {
9124 	emsg(_(e_dictreq));
9125 	return;
9126     }
9127     d = argvars[1].vval.v_dict;
9128     if (d == NULL)
9129 	return;
9130 
9131     // third argument: action - 'a' for append and 'r' for replace.
9132     // default is to replace the stack.
9133     if (argvars[2].v_type == VAR_UNKNOWN)
9134 	action = 'r';
9135     else if (argvars[2].v_type == VAR_STRING)
9136     {
9137 	char_u	*actstr;
9138 	actstr = tv_get_string_chk(&argvars[2]);
9139 	if (actstr == NULL)
9140 	    return;
9141 	if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
9142 		&& actstr[1] == NUL)
9143 	    action = *actstr;
9144 	else
9145 	{
9146 	    semsg(_(e_invact2), actstr);
9147 	    return;
9148 	}
9149     }
9150     else
9151     {
9152 	emsg(_(e_stringreq));
9153 	return;
9154     }
9155 
9156     if (set_tagstack(wp, d, action) == OK)
9157 	rettv->vval.v_number = 0;
9158 }
9159 
9160 #ifdef FEAT_CRYPT
9161 /*
9162  * "sha256({string})" function
9163  */
9164     static void
f_sha256(typval_T * argvars,typval_T * rettv)9165 f_sha256(typval_T *argvars, typval_T *rettv)
9166 {
9167     char_u	*p;
9168 
9169     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9170 	return;
9171 
9172     p = tv_get_string(&argvars[0]);
9173     rettv->vval.v_string = vim_strsave(
9174 				    sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9175     rettv->v_type = VAR_STRING;
9176 }
9177 #endif // FEAT_CRYPT
9178 
9179 /*
9180  * "shellescape({string})" function
9181  */
9182     static void
f_shellescape(typval_T * argvars,typval_T * rettv)9183 f_shellescape(typval_T *argvars, typval_T *rettv)
9184 {
9185     int do_special;
9186 
9187     if (in_vim9script()
9188 	    && (check_for_string_arg(argvars, 0) == FAIL
9189 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
9190 	return;
9191 
9192     do_special = non_zero_arg(&argvars[1]);
9193     rettv->vval.v_string = vim_strsave_shellescape(
9194 			   tv_get_string(&argvars[0]), do_special, do_special);
9195     rettv->v_type = VAR_STRING;
9196 }
9197 
9198 /*
9199  * shiftwidth() function
9200  */
9201     static void
f_shiftwidth(typval_T * argvars UNUSED,typval_T * rettv)9202 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9203 {
9204     rettv->vval.v_number = 0;
9205 
9206     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
9207 	return;
9208 
9209     if (argvars[0].v_type != VAR_UNKNOWN)
9210     {
9211 	long	col;
9212 
9213 	col = (long)tv_get_number_chk(argvars, NULL);
9214 	if (col < 0)
9215 	    return;	// type error; errmsg already given
9216 #ifdef FEAT_VARTABS
9217 	rettv->vval.v_number = get_sw_value_col(curbuf, col);
9218 	return;
9219 #endif
9220     }
9221 
9222     rettv->vval.v_number = get_sw_value(curbuf);
9223 }
9224 
9225 /*
9226  * "soundfold({word})" function
9227  */
9228     static void
f_soundfold(typval_T * argvars,typval_T * rettv)9229 f_soundfold(typval_T *argvars, typval_T *rettv)
9230 {
9231     char_u	*s;
9232 
9233     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9234 	return;
9235 
9236     rettv->v_type = VAR_STRING;
9237     s = tv_get_string(&argvars[0]);
9238 #ifdef FEAT_SPELL
9239     rettv->vval.v_string = eval_soundfold(s);
9240 #else
9241     rettv->vval.v_string = vim_strsave(s);
9242 #endif
9243 }
9244 
9245 /*
9246  * "spellbadword()" function
9247  */
9248     static void
f_spellbadword(typval_T * argvars UNUSED,typval_T * rettv)9249 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
9250 {
9251     char_u	*word = (char_u *)"";
9252     hlf_T	attr = HLF_COUNT;
9253     int		len = 0;
9254 #ifdef FEAT_SPELL
9255     int		wo_spell_save = curwin->w_p_spell;
9256 
9257     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
9258 	return;
9259 
9260     if (!curwin->w_p_spell)
9261     {
9262 	did_set_spelllang(curwin);
9263 	curwin->w_p_spell = TRUE;
9264     }
9265 
9266     if (*curwin->w_s->b_p_spl == NUL)
9267     {
9268 	emsg(_(e_no_spell));
9269 	curwin->w_p_spell = wo_spell_save;
9270 	return;
9271     }
9272 #endif
9273 
9274     if (rettv_list_alloc(rettv) == FAIL)
9275     {
9276 #ifdef FEAT_SPELL
9277 	curwin->w_p_spell = wo_spell_save;
9278 #endif
9279 	return;
9280     }
9281 
9282 #ifdef FEAT_SPELL
9283     if (argvars[0].v_type == VAR_UNKNOWN)
9284     {
9285 	// Find the start and length of the badly spelled word.
9286 	len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
9287 	if (len != 0)
9288 	{
9289 	    word = ml_get_cursor();
9290 	    curwin->w_set_curswant = TRUE;
9291 	}
9292     }
9293     else if (*curbuf->b_s.b_p_spl != NUL)
9294     {
9295 	char_u	*str = tv_get_string_chk(&argvars[0]);
9296 	int	capcol = -1;
9297 
9298 	if (str != NULL)
9299 	{
9300 	    // Check the argument for spelling.
9301 	    while (*str != NUL)
9302 	    {
9303 		len = spell_check(curwin, str, &attr, &capcol, FALSE);
9304 		if (attr != HLF_COUNT)
9305 		{
9306 		    word = str;
9307 		    break;
9308 		}
9309 		str += len;
9310 		capcol -= len;
9311 		len = 0;
9312 	    }
9313 	}
9314     }
9315     curwin->w_p_spell = wo_spell_save;
9316 #endif
9317 
9318     list_append_string(rettv->vval.v_list, word, len);
9319     list_append_string(rettv->vval.v_list, (char_u *)(
9320 			attr == HLF_SPB ? "bad" :
9321 			attr == HLF_SPR ? "rare" :
9322 			attr == HLF_SPL ? "local" :
9323 			attr == HLF_SPC ? "caps" :
9324 			""), -1);
9325 }
9326 
9327 /*
9328  * "spellsuggest()" function
9329  */
9330     static void
f_spellsuggest(typval_T * argvars UNUSED,typval_T * rettv)9331 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
9332 {
9333 #ifdef FEAT_SPELL
9334     char_u	*str;
9335     int		typeerr = FALSE;
9336     int		maxcount;
9337     garray_T	ga;
9338     int		i;
9339     listitem_T	*li;
9340     int		need_capital = FALSE;
9341     int		wo_spell_save = curwin->w_p_spell;
9342 
9343     if (in_vim9script()
9344 	    && (check_for_string_arg(argvars, 0) == FAIL
9345 		|| check_for_opt_number_arg(argvars, 1) == FAIL
9346 		|| (argvars[1].v_type != VAR_UNKNOWN
9347 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
9348 	return;
9349 
9350     if (!curwin->w_p_spell)
9351     {
9352 	did_set_spelllang(curwin);
9353 	curwin->w_p_spell = TRUE;
9354     }
9355 
9356     if (*curwin->w_s->b_p_spl == NUL)
9357     {
9358 	emsg(_(e_no_spell));
9359 	curwin->w_p_spell = wo_spell_save;
9360 	return;
9361     }
9362 #endif
9363 
9364     if (rettv_list_alloc(rettv) == FAIL)
9365     {
9366 #ifdef FEAT_SPELL
9367 	curwin->w_p_spell = wo_spell_save;
9368 #endif
9369 	return;
9370     }
9371 
9372 #ifdef FEAT_SPELL
9373     if (*curwin->w_s->b_p_spl != NUL)
9374     {
9375 	str = tv_get_string(&argvars[0]);
9376 	if (argvars[1].v_type != VAR_UNKNOWN)
9377 	{
9378 	    maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
9379 	    if (maxcount <= 0)
9380 		return;
9381 	    if (argvars[2].v_type != VAR_UNKNOWN)
9382 	    {
9383 		need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
9384 		if (typeerr)
9385 		    return;
9386 	    }
9387 	}
9388 	else
9389 	    maxcount = 25;
9390 
9391 	spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
9392 
9393 	for (i = 0; i < ga.ga_len; ++i)
9394 	{
9395 	    str = ((char_u **)ga.ga_data)[i];
9396 
9397 	    li = listitem_alloc();
9398 	    if (li == NULL)
9399 		vim_free(str);
9400 	    else
9401 	    {
9402 		li->li_tv.v_type = VAR_STRING;
9403 		li->li_tv.v_lock = 0;
9404 		li->li_tv.vval.v_string = str;
9405 		list_append(rettv->vval.v_list, li);
9406 	    }
9407 	}
9408 	ga_clear(&ga);
9409     }
9410     curwin->w_p_spell = wo_spell_save;
9411 #endif
9412 }
9413 
9414     static void
f_split(typval_T * argvars,typval_T * rettv)9415 f_split(typval_T *argvars, typval_T *rettv)
9416 {
9417     char_u	*str;
9418     char_u	*end;
9419     char_u	*pat = NULL;
9420     regmatch_T	regmatch;
9421     char_u	patbuf[NUMBUFLEN];
9422     char_u	*save_cpo;
9423     int		match;
9424     colnr_T	col = 0;
9425     int		keepempty = FALSE;
9426     int		typeerr = FALSE;
9427 
9428     if (in_vim9script()
9429 	    && (check_for_string_arg(argvars, 0) == FAIL
9430 		|| check_for_opt_string_arg(argvars, 1) == FAIL
9431 		|| (argvars[1].v_type != VAR_UNKNOWN
9432 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
9433 	return;
9434 
9435     // Make 'cpoptions' empty, the 'l' flag should not be used here.
9436     save_cpo = p_cpo;
9437     p_cpo = empty_option;
9438 
9439     str = tv_get_string(&argvars[0]);
9440     if (argvars[1].v_type != VAR_UNKNOWN)
9441     {
9442 	pat = tv_get_string_buf_chk(&argvars[1], patbuf);
9443 	if (pat == NULL)
9444 	    typeerr = TRUE;
9445 	if (argvars[2].v_type != VAR_UNKNOWN)
9446 	    keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
9447     }
9448     if (pat == NULL || *pat == NUL)
9449 	pat = (char_u *)"[\\x01- ]\\+";
9450 
9451     if (rettv_list_alloc(rettv) == FAIL)
9452 	goto theend;
9453     if (typeerr)
9454 	goto theend;
9455 
9456     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
9457     if (regmatch.regprog != NULL)
9458     {
9459 	regmatch.rm_ic = FALSE;
9460 	while (*str != NUL || keepempty)
9461 	{
9462 	    if (*str == NUL)
9463 		match = FALSE;	// empty item at the end
9464 	    else
9465 		match = vim_regexec_nl(&regmatch, str, col);
9466 	    if (match)
9467 		end = regmatch.startp[0];
9468 	    else
9469 		end = str + STRLEN(str);
9470 	    if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
9471 			   && *str != NUL && match && end < regmatch.endp[0]))
9472 	    {
9473 		if (list_append_string(rettv->vval.v_list, str,
9474 						    (int)(end - str)) == FAIL)
9475 		    break;
9476 	    }
9477 	    if (!match)
9478 		break;
9479 	    // Advance to just after the match.
9480 	    if (regmatch.endp[0] > str)
9481 		col = 0;
9482 	    else
9483 		// Don't get stuck at the same match.
9484 		col = (*mb_ptr2len)(regmatch.endp[0]);
9485 	    str = regmatch.endp[0];
9486 	}
9487 
9488 	vim_regfree(regmatch.regprog);
9489     }
9490 
9491 theend:
9492     p_cpo = save_cpo;
9493 }
9494 
9495 /*
9496  * "submatch()" function
9497  */
9498     static void
f_submatch(typval_T * argvars,typval_T * rettv)9499 f_submatch(typval_T *argvars, typval_T *rettv)
9500 {
9501     int		error = FALSE;
9502     int		no;
9503     int		retList = 0;
9504 
9505     if (in_vim9script()
9506 	    && (check_for_number_arg(argvars, 0) == FAIL
9507 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
9508 	return;
9509 
9510     no = (int)tv_get_number_chk(&argvars[0], &error);
9511     if (error)
9512 	return;
9513     if (no < 0 || no >= NSUBEXP)
9514     {
9515 	semsg(_("E935: invalid submatch number: %d"), no);
9516 	return;
9517     }
9518     if (argvars[1].v_type != VAR_UNKNOWN)
9519 	retList = (int)tv_get_bool_chk(&argvars[1], &error);
9520     if (error)
9521 	return;
9522 
9523     if (retList == 0)
9524     {
9525 	rettv->v_type = VAR_STRING;
9526 	rettv->vval.v_string = reg_submatch(no);
9527     }
9528     else
9529     {
9530 	rettv->v_type = VAR_LIST;
9531 	rettv->vval.v_list = reg_submatch_list(no);
9532     }
9533 }
9534 
9535 /*
9536  * "substitute()" function
9537  */
9538     static void
f_substitute(typval_T * argvars,typval_T * rettv)9539 f_substitute(typval_T *argvars, typval_T *rettv)
9540 {
9541     char_u	patbuf[NUMBUFLEN];
9542     char_u	subbuf[NUMBUFLEN];
9543     char_u	flagsbuf[NUMBUFLEN];
9544     char_u	*str;
9545     char_u	*pat;
9546     char_u	*sub = NULL;
9547     typval_T	*expr = NULL;
9548     char_u	*flg;
9549 
9550     if (in_vim9script()
9551 	    && (check_for_string_arg(argvars, 0) == FAIL
9552 		|| check_for_string_arg(argvars, 1) == FAIL
9553 		|| check_for_string_arg(argvars, 3) == FAIL))
9554 	return;
9555 
9556     str = tv_get_string_chk(&argvars[0]);
9557     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
9558     flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
9559 
9560     if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
9561 	expr = &argvars[2];
9562     else
9563 	sub = tv_get_string_buf_chk(&argvars[2], subbuf);
9564 
9565     rettv->v_type = VAR_STRING;
9566     if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
9567 								|| flg == NULL)
9568 	rettv->vval.v_string = NULL;
9569     else
9570 	rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
9571 }
9572 
9573 /*
9574  * "swapinfo(swap_filename)" function
9575  */
9576     static void
f_swapinfo(typval_T * argvars,typval_T * rettv)9577 f_swapinfo(typval_T *argvars, typval_T *rettv)
9578 {
9579     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9580 	return;
9581 
9582     if (rettv_dict_alloc(rettv) == OK)
9583 	get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
9584 }
9585 
9586 /*
9587  * "swapname(expr)" function
9588  */
9589     static void
f_swapname(typval_T * argvars,typval_T * rettv)9590 f_swapname(typval_T *argvars, typval_T *rettv)
9591 {
9592     buf_T	*buf;
9593 
9594     rettv->v_type = VAR_STRING;
9595 
9596     if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
9597 	return;
9598 
9599     buf = tv_get_buf(&argvars[0], FALSE);
9600     if (buf == NULL || buf->b_ml.ml_mfp == NULL
9601 					|| buf->b_ml.ml_mfp->mf_fname == NULL)
9602 	rettv->vval.v_string = NULL;
9603     else
9604 	rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9605 }
9606 
9607 /*
9608  * "synID(lnum, col, trans)" function
9609  */
9610     static void
f_synID(typval_T * argvars UNUSED,typval_T * rettv)9611 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9612 {
9613     int		id = 0;
9614 #ifdef FEAT_SYN_HL
9615     linenr_T	lnum;
9616     colnr_T	col;
9617     int		trans;
9618     int		transerr = FALSE;
9619 
9620     if (in_vim9script()
9621 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9622 		|| check_for_number_arg(argvars, 1) == FAIL
9623 		|| check_for_bool_arg(argvars, 2) == FAIL))
9624 	return;
9625 
9626     lnum = tv_get_lnum(argvars);		// -1 on type error
9627     col = (linenr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9628     trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
9629 
9630     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9631 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9632 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9633 #endif
9634 
9635     rettv->vval.v_number = id;
9636 }
9637 
9638 /*
9639  * "synIDattr(id, what [, mode])" function
9640  */
9641     static void
f_synIDattr(typval_T * argvars UNUSED,typval_T * rettv)9642 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9643 {
9644     char_u	*p = NULL;
9645 #ifdef FEAT_SYN_HL
9646     int		id;
9647     char_u	*what;
9648     char_u	*mode;
9649     char_u	modebuf[NUMBUFLEN];
9650     int		modec;
9651 
9652     if (in_vim9script()
9653 	    && (check_for_number_arg(argvars, 0) == FAIL
9654 		|| check_for_string_arg(argvars, 1) == FAIL
9655 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
9656 	return;
9657 
9658     id = (int)tv_get_number(&argvars[0]);
9659     what = tv_get_string(&argvars[1]);
9660     if (argvars[2].v_type != VAR_UNKNOWN)
9661     {
9662 	mode = tv_get_string_buf(&argvars[2], modebuf);
9663 	modec = TOLOWER_ASC(mode[0]);
9664 	if (modec != 't' && modec != 'c' && modec != 'g')
9665 	    modec = 0;	// replace invalid with current
9666     }
9667     else
9668     {
9669 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9670 	if (USE_24BIT)
9671 	    modec = 'g';
9672 	else
9673 #endif
9674 	    if (t_colors > 1)
9675 		modec = 'c';
9676 	    else
9677 		modec = 't';
9678     }
9679 
9680     switch (TOLOWER_ASC(what[0]))
9681     {
9682 	case 'b':
9683 		if (TOLOWER_ASC(what[1]) == 'g')	// bg[#]
9684 		    p = highlight_color(id, what, modec);
9685 		else					// bold
9686 		    p = highlight_has_attr(id, HL_BOLD, modec);
9687 		break;
9688 
9689 	case 'f':					// fg[#] or font
9690 		p = highlight_color(id, what, modec);
9691 		break;
9692 
9693 	case 'i':
9694 		if (TOLOWER_ASC(what[1]) == 'n')	// inverse
9695 		    p = highlight_has_attr(id, HL_INVERSE, modec);
9696 		else					// italic
9697 		    p = highlight_has_attr(id, HL_ITALIC, modec);
9698 		break;
9699 
9700 	case 'n':					// name
9701 		p = get_highlight_name_ext(NULL, id - 1, FALSE);
9702 		break;
9703 
9704 	case 'r':					// reverse
9705 		p = highlight_has_attr(id, HL_INVERSE, modec);
9706 		break;
9707 
9708 	case 's':
9709 		if (TOLOWER_ASC(what[1]) == 'p')	// sp[#]
9710 		    p = highlight_color(id, what, modec);
9711 							// strikeout
9712 		else if (TOLOWER_ASC(what[1]) == 't' &&
9713 			TOLOWER_ASC(what[2]) == 'r')
9714 		    p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
9715 		else					// standout
9716 		    p = highlight_has_attr(id, HL_STANDOUT, modec);
9717 		break;
9718 
9719 	case 'u':
9720 		if (TOLOWER_ASC(what[1]) == 'l')	// ul
9721 		    p = highlight_color(id, what, modec);
9722 		else if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
9723 							// underline
9724 		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
9725 		else
9726 							// undercurl
9727 		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
9728 		break;
9729     }
9730 
9731     if (p != NULL)
9732 	p = vim_strsave(p);
9733 #endif
9734     rettv->v_type = VAR_STRING;
9735     rettv->vval.v_string = p;
9736 }
9737 
9738 /*
9739  * "synIDtrans(id)" function
9740  */
9741     static void
f_synIDtrans(typval_T * argvars UNUSED,typval_T * rettv)9742 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9743 {
9744     int		id;
9745 
9746 #ifdef FEAT_SYN_HL
9747     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
9748 	return;
9749 
9750     id = (int)tv_get_number(&argvars[0]);
9751 
9752     if (id > 0)
9753 	id = syn_get_final_id(id);
9754     else
9755 #endif
9756 	id = 0;
9757 
9758     rettv->vval.v_number = id;
9759 }
9760 
9761 /*
9762  * "synconcealed(lnum, col)" function
9763  */
9764     static void
f_synconcealed(typval_T * argvars UNUSED,typval_T * rettv)9765 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9766 {
9767 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9768     linenr_T	lnum;
9769     colnr_T	col;
9770     int		syntax_flags = 0;
9771     int		cchar;
9772     int		matchid = 0;
9773     char_u	str[NUMBUFLEN];
9774 #endif
9775 
9776     rettv_list_set(rettv, NULL);
9777 
9778     if (in_vim9script()
9779 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9780 		|| check_for_number_arg(argvars, 1) == FAIL))
9781 	return;
9782 
9783 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9784     lnum = tv_get_lnum(argvars);		// -1 on type error
9785     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9786 
9787     CLEAR_FIELD(str);
9788 
9789     if (rettv_list_alloc(rettv) != FAIL)
9790     {
9791 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9792 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9793 	    && curwin->w_p_cole > 0)
9794 	{
9795 	    (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9796 	    syntax_flags = get_syntax_info(&matchid);
9797 
9798 	    // get the conceal character
9799 	    if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9800 	    {
9801 		cchar = syn_get_sub_char();
9802 		if (cchar == NUL && curwin->w_p_cole == 1)
9803 		    cchar = (curwin->w_lcs_chars.conceal == NUL) ? ' '
9804 					: curwin->w_lcs_chars.conceal;
9805 		if (cchar != NUL)
9806 		{
9807 		    if (has_mbyte)
9808 			(*mb_char2bytes)(cchar, str);
9809 		    else
9810 			str[0] = cchar;
9811 		}
9812 	    }
9813 	}
9814 
9815 	list_append_number(rettv->vval.v_list,
9816 					    (syntax_flags & HL_CONCEAL) != 0);
9817 	// -1 to auto-determine strlen
9818 	list_append_string(rettv->vval.v_list, str, -1);
9819 	list_append_number(rettv->vval.v_list, matchid);
9820     }
9821 #endif
9822 }
9823 
9824 /*
9825  * "synstack(lnum, col)" function
9826  */
9827     static void
f_synstack(typval_T * argvars UNUSED,typval_T * rettv)9828 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9829 {
9830 #ifdef FEAT_SYN_HL
9831     linenr_T	lnum;
9832     colnr_T	col;
9833     int		i;
9834     int		id;
9835 #endif
9836 
9837     rettv_list_set(rettv, NULL);
9838 
9839     if (in_vim9script()
9840 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9841 		|| check_for_number_arg(argvars, 1) == FAIL))
9842 	return;
9843 
9844 #ifdef FEAT_SYN_HL
9845     lnum = tv_get_lnum(argvars);		// -1 on type error
9846     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9847 
9848     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9849 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9850 	    && rettv_list_alloc(rettv) != FAIL)
9851     {
9852 	(void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9853 	for (i = 0; ; ++i)
9854 	{
9855 	    id = syn_get_stack_item(i);
9856 	    if (id < 0)
9857 		break;
9858 	    if (list_append_number(rettv->vval.v_list, id) == FAIL)
9859 		break;
9860 	}
9861     }
9862 #endif
9863 }
9864 
9865 /*
9866  * "tabpagebuflist()" function
9867  */
9868     static void
f_tabpagebuflist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)9869 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9870 {
9871     tabpage_T	*tp;
9872     win_T	*wp = NULL;
9873 
9874     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
9875 	return;
9876 
9877     if (argvars[0].v_type == VAR_UNKNOWN)
9878 	wp = firstwin;
9879     else
9880     {
9881 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
9882 	if (tp != NULL)
9883 	    wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9884     }
9885     if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9886     {
9887 	for (; wp != NULL; wp = wp->w_next)
9888 	    if (list_append_number(rettv->vval.v_list,
9889 						wp->w_buffer->b_fnum) == FAIL)
9890 		break;
9891     }
9892 }
9893 
9894 /*
9895  * "tagfiles()" function
9896  */
9897     static void
f_tagfiles(typval_T * argvars UNUSED,typval_T * rettv)9898 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9899 {
9900     char_u	*fname;
9901     tagname_T	tn;
9902     int		first;
9903 
9904     if (rettv_list_alloc(rettv) == FAIL)
9905 	return;
9906     fname = alloc(MAXPATHL);
9907     if (fname == NULL)
9908 	return;
9909 
9910     for (first = TRUE; ; first = FALSE)
9911 	if (get_tagfname(&tn, first, fname) == FAIL
9912 		|| list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9913 	    break;
9914     tagname_free(&tn);
9915     vim_free(fname);
9916 }
9917 
9918 /*
9919  * "taglist()" function
9920  */
9921     static void
f_taglist(typval_T * argvars,typval_T * rettv)9922 f_taglist(typval_T *argvars, typval_T *rettv)
9923 {
9924     char_u  *fname = NULL;
9925     char_u  *tag_pattern;
9926 
9927     if (in_vim9script()
9928 	    && (check_for_string_arg(argvars, 0) == FAIL
9929 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
9930 	return;
9931 
9932     tag_pattern = tv_get_string(&argvars[0]);
9933 
9934     rettv->vval.v_number = FALSE;
9935     if (*tag_pattern == NUL)
9936 	return;
9937 
9938     if (argvars[1].v_type != VAR_UNKNOWN)
9939 	fname = tv_get_string(&argvars[1]);
9940     if (rettv_list_alloc(rettv) == OK)
9941 	(void)get_tags(rettv->vval.v_list, tag_pattern, fname);
9942 }
9943 
9944 /*
9945  * "type(expr)" function
9946  */
9947     static void
f_type(typval_T * argvars,typval_T * rettv)9948 f_type(typval_T *argvars, typval_T *rettv)
9949 {
9950     int n = -1;
9951 
9952     switch (argvars[0].v_type)
9953     {
9954 	case VAR_NUMBER:  n = VAR_TYPE_NUMBER; break;
9955 	case VAR_STRING:  n = VAR_TYPE_STRING; break;
9956 	case VAR_PARTIAL:
9957 	case VAR_FUNC:    n = VAR_TYPE_FUNC; break;
9958 	case VAR_LIST:    n = VAR_TYPE_LIST; break;
9959 	case VAR_DICT:    n = VAR_TYPE_DICT; break;
9960 	case VAR_FLOAT:   n = VAR_TYPE_FLOAT; break;
9961 	case VAR_BOOL:	  n = VAR_TYPE_BOOL; break;
9962 	case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
9963 	case VAR_JOB:     n = VAR_TYPE_JOB; break;
9964 	case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
9965 	case VAR_BLOB:    n = VAR_TYPE_BLOB; break;
9966 	case VAR_INSTR:   n = VAR_TYPE_INSTR; break;
9967 	case VAR_UNKNOWN:
9968 	case VAR_ANY:
9969 	case VAR_VOID:
9970 	     internal_error_no_abort("f_type(UNKNOWN)");
9971 	     n = -1;
9972 	     break;
9973     }
9974     rettv->vval.v_number = n;
9975 }
9976 
9977 /*
9978  * "virtcol(string)" function
9979  */
9980     static void
f_virtcol(typval_T * argvars,typval_T * rettv)9981 f_virtcol(typval_T *argvars, typval_T *rettv)
9982 {
9983     colnr_T	vcol = 0;
9984     pos_T	*fp;
9985     int		fnum = curbuf->b_fnum;
9986     int		len;
9987 
9988     if (in_vim9script()
9989 	    && check_for_string_or_list_arg(argvars, 0) == FAIL)
9990 	return;
9991 
9992     fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
9993     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9994 						    && fnum == curbuf->b_fnum)
9995     {
9996 	// Limit the column to a valid value, getvvcol() doesn't check.
9997 	if (fp->col < 0)
9998 	    fp->col = 0;
9999 	else
10000 	{
10001 	    len = (int)STRLEN(ml_get(fp->lnum));
10002 	    if (fp->col > len)
10003 		fp->col = len;
10004 	}
10005 	getvvcol(curwin, fp, NULL, NULL, &vcol);
10006 	++vcol;
10007     }
10008 
10009     rettv->vval.v_number = vcol;
10010 }
10011 
10012 /*
10013  * "visualmode()" function
10014  */
10015     static void
f_visualmode(typval_T * argvars,typval_T * rettv)10016 f_visualmode(typval_T *argvars, typval_T *rettv)
10017 {
10018     char_u	str[2];
10019 
10020     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
10021 	return;
10022 
10023     rettv->v_type = VAR_STRING;
10024     str[0] = curbuf->b_visual_mode_eval;
10025     str[1] = NUL;
10026     rettv->vval.v_string = vim_strsave(str);
10027 
10028     // A non-zero number or non-empty string argument: reset mode.
10029     if (non_zero_arg(&argvars[0]))
10030 	curbuf->b_visual_mode_eval = NUL;
10031 }
10032 
10033 /*
10034  * "wildmenumode()" function
10035  */
10036     static void
f_wildmenumode(typval_T * argvars UNUSED,typval_T * rettv UNUSED)10037 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10038 {
10039 #ifdef FEAT_WILDMENU
10040     if (wild_menu_showing)
10041 	rettv->vval.v_number = 1;
10042 #endif
10043 }
10044 
10045 /*
10046  * "windowsversion()" function
10047  */
10048     static void
f_windowsversion(typval_T * argvars UNUSED,typval_T * rettv UNUSED)10049 f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10050 {
10051     rettv->v_type = VAR_STRING;
10052     rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
10053 }
10054 
10055 /*
10056  * "wordcount()" function
10057  */
10058     static void
f_wordcount(typval_T * argvars UNUSED,typval_T * rettv)10059 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
10060 {
10061     if (rettv_dict_alloc(rettv) == FAIL)
10062 	return;
10063     cursor_pos_info(rettv->vval.v_dict);
10064 }
10065 
10066 /*
10067  * "xor(expr, expr)" function
10068  */
10069     static void
f_xor(typval_T * argvars,typval_T * rettv)10070 f_xor(typval_T *argvars, typval_T *rettv)
10071 {
10072     if (in_vim9script()
10073 	    && (check_for_number_arg(argvars, 0) == FAIL
10074 		|| check_for_number_arg(argvars, 1) == FAIL))
10075 	return;
10076 
10077     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
10078 					^ tv_get_number_chk(&argvars[1], NULL);
10079 }
10080 
10081 #endif // FEAT_EVAL
10082