xref: /vim-8.2.3635/src/evalfunc.c (revision d1a8d658)
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 = trans_function_name(&name, &is_global, FALSE,
3959 	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF,
3960 							     NULL, NULL, NULL);
3961 	if (*name != NUL)
3962 	    s = NULL;
3963     }
3964 
3965     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3966 					 || (is_funcref && trans_name == NULL))
3967 	semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
3968     // Don't check an autoload name for existence here.
3969     else if (trans_name != NULL && (is_funcref
3970 			 ? find_func(trans_name, is_global, NULL) == NULL
3971 			 : !translated_function_exists(trans_name, is_global)))
3972 	semsg(_("E700: Unknown function: %s"), s);
3973     else
3974     {
3975 	int	dict_idx = 0;
3976 	int	arg_idx = 0;
3977 	list_T	*list = NULL;
3978 
3979 	if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3980 	{
3981 	    char	sid_buf[25];
3982 	    int		off = *s == 's' ? 2 : 5;
3983 
3984 	    // Expand s: and <SID> into <SNR>nr_, so that the function can
3985 	    // also be called from another script. Using trans_function_name()
3986 	    // would also work, but some plugins depend on the name being
3987 	    // printable text.
3988 	    sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
3989 	    name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
3990 	    if (name != NULL)
3991 	    {
3992 		STRCPY(name, sid_buf);
3993 		STRCAT(name, s + off);
3994 	    }
3995 	}
3996 	else
3997 	    name = vim_strsave(s);
3998 
3999 	if (argvars[1].v_type != VAR_UNKNOWN)
4000 	{
4001 	    if (argvars[2].v_type != VAR_UNKNOWN)
4002 	    {
4003 		// function(name, [args], dict)
4004 		arg_idx = 1;
4005 		dict_idx = 2;
4006 	    }
4007 	    else if (argvars[1].v_type == VAR_DICT)
4008 		// function(name, dict)
4009 		dict_idx = 1;
4010 	    else
4011 		// function(name, [args])
4012 		arg_idx = 1;
4013 	    if (dict_idx > 0)
4014 	    {
4015 		if (argvars[dict_idx].v_type != VAR_DICT)
4016 		{
4017 		    emsg(_("E922: expected a dict"));
4018 		    vim_free(name);
4019 		    goto theend;
4020 		}
4021 		if (argvars[dict_idx].vval.v_dict == NULL)
4022 		    dict_idx = 0;
4023 	    }
4024 	    if (arg_idx > 0)
4025 	    {
4026 		if (argvars[arg_idx].v_type != VAR_LIST)
4027 		{
4028 		    emsg(_("E923: Second argument of function() must be a list or a dict"));
4029 		    vim_free(name);
4030 		    goto theend;
4031 		}
4032 		list = argvars[arg_idx].vval.v_list;
4033 		if (list == NULL || list->lv_len == 0)
4034 		    arg_idx = 0;
4035 		else if (list->lv_len > MAX_FUNC_ARGS)
4036 		{
4037 		    emsg_funcname((char *)e_toomanyarg, s);
4038 		    vim_free(name);
4039 		    goto theend;
4040 		}
4041 	    }
4042 	}
4043 	if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
4044 	{
4045 	    partial_T	*pt = ALLOC_CLEAR_ONE(partial_T);
4046 
4047 	    // result is a VAR_PARTIAL
4048 	    if (pt == NULL)
4049 		vim_free(name);
4050 	    else
4051 	    {
4052 		if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4053 		{
4054 		    listitem_T	*li;
4055 		    int		i = 0;
4056 		    int		arg_len = 0;
4057 		    int		lv_len = 0;
4058 
4059 		    if (arg_pt != NULL)
4060 			arg_len = arg_pt->pt_argc;
4061 		    if (list != NULL)
4062 			lv_len = list->lv_len;
4063 		    pt->pt_argc = arg_len + lv_len;
4064 		    pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
4065 		    if (pt->pt_argv == NULL)
4066 		    {
4067 			vim_free(pt);
4068 			vim_free(name);
4069 			goto theend;
4070 		    }
4071 		    for (i = 0; i < arg_len; i++)
4072 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4073 		    if (lv_len > 0)
4074 		    {
4075 			CHECK_LIST_MATERIALIZE(list);
4076 			FOR_ALL_LIST_ITEMS(list, li)
4077 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
4078 		    }
4079 		}
4080 
4081 		// For "function(dict.func, [], dict)" and "func" is a partial
4082 		// use "dict".  That is backwards compatible.
4083 		if (dict_idx > 0)
4084 		{
4085 		    // The dict is bound explicitly, pt_auto is FALSE.
4086 		    pt->pt_dict = argvars[dict_idx].vval.v_dict;
4087 		    ++pt->pt_dict->dv_refcount;
4088 		}
4089 		else if (arg_pt != NULL)
4090 		{
4091 		    // If the dict was bound automatically the result is also
4092 		    // bound automatically.
4093 		    pt->pt_dict = arg_pt->pt_dict;
4094 		    pt->pt_auto = arg_pt->pt_auto;
4095 		    if (pt->pt_dict != NULL)
4096 			++pt->pt_dict->dv_refcount;
4097 		}
4098 
4099 		pt->pt_refcount = 1;
4100 		if (arg_pt != NULL && arg_pt->pt_func != NULL)
4101 		{
4102 		    pt->pt_func = arg_pt->pt_func;
4103 		    func_ptr_ref(pt->pt_func);
4104 		    vim_free(name);
4105 		}
4106 		else if (is_funcref)
4107 		{
4108 		    pt->pt_func = find_func(trans_name, is_global, NULL);
4109 		    func_ptr_ref(pt->pt_func);
4110 		    vim_free(name);
4111 		}
4112 		else
4113 		{
4114 		    pt->pt_name = name;
4115 		    func_ref(name);
4116 		}
4117 	    }
4118 	    rettv->v_type = VAR_PARTIAL;
4119 	    rettv->vval.v_partial = pt;
4120 	}
4121 	else
4122 	{
4123 	    // result is a VAR_FUNC
4124 	    rettv->v_type = VAR_FUNC;
4125 	    rettv->vval.v_string = name;
4126 	    func_ref(name);
4127 	}
4128     }
4129 theend:
4130     vim_free(trans_name);
4131 }
4132 
4133 /*
4134  * "funcref()" function
4135  */
4136     static void
f_funcref(typval_T * argvars,typval_T * rettv)4137 f_funcref(typval_T *argvars, typval_T *rettv)
4138 {
4139     common_function(argvars, rettv, TRUE);
4140 }
4141 
4142     static type_T *
ret_f_function(int argcount,type_T ** argtypes)4143 ret_f_function(int argcount, type_T **argtypes)
4144 {
4145     if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
4146 	return &t_func_any;
4147     // Need to check the type at runtime, the function may be defined later.
4148     return &t_func_unknown;
4149 }
4150 
4151 /*
4152  * "function()" function
4153  */
4154     static void
f_function(typval_T * argvars,typval_T * rettv)4155 f_function(typval_T *argvars, typval_T *rettv)
4156 {
4157     common_function(argvars, rettv, FALSE);
4158 }
4159 
4160 /*
4161  * "garbagecollect()" function
4162  */
4163     static void
f_garbagecollect(typval_T * argvars,typval_T * rettv UNUSED)4164 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4165 {
4166     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
4167 	return;
4168 
4169     // This is postponed until we are back at the toplevel, because we may be
4170     // using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]".
4171     want_garbage_collect = TRUE;
4172 
4173     if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
4174 	garbage_collect_at_exit = TRUE;
4175 }
4176 
4177 /*
4178  * "get()" function
4179  */
4180     static void
f_get(typval_T * argvars,typval_T * rettv)4181 f_get(typval_T *argvars, typval_T *rettv)
4182 {
4183     listitem_T	*li;
4184     list_T	*l;
4185     dictitem_T	*di;
4186     dict_T	*d;
4187     typval_T	*tv = NULL;
4188     int		what_is_dict = FALSE;
4189 
4190     if (argvars[0].v_type == VAR_BLOB)
4191     {
4192 	int error = FALSE;
4193 	int idx = tv_get_number_chk(&argvars[1], &error);
4194 
4195 	if (!error)
4196 	{
4197 	    rettv->v_type = VAR_NUMBER;
4198 	    if (idx < 0)
4199 		idx = blob_len(argvars[0].vval.v_blob) + idx;
4200 	    if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4201 		rettv->vval.v_number = -1;
4202 	    else
4203 	    {
4204 		rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
4205 		tv = rettv;
4206 	    }
4207 	}
4208     }
4209     else if (argvars[0].v_type == VAR_LIST)
4210     {
4211 	if ((l = argvars[0].vval.v_list) != NULL)
4212 	{
4213 	    int		error = FALSE;
4214 
4215 	    li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
4216 	    if (!error && li != NULL)
4217 		tv = &li->li_tv;
4218 	}
4219     }
4220     else if (argvars[0].v_type == VAR_DICT)
4221     {
4222 	if ((d = argvars[0].vval.v_dict) != NULL)
4223 	{
4224 	    di = dict_find(d, tv_get_string(&argvars[1]), -1);
4225 	    if (di != NULL)
4226 		tv = &di->di_tv;
4227 	}
4228     }
4229     else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4230     {
4231 	partial_T	*pt;
4232 	partial_T	fref_pt;
4233 
4234 	if (argvars[0].v_type == VAR_PARTIAL)
4235 	    pt = argvars[0].vval.v_partial;
4236 	else
4237 	{
4238 	    CLEAR_FIELD(fref_pt);
4239 	    fref_pt.pt_name = argvars[0].vval.v_string;
4240 	    pt = &fref_pt;
4241 	}
4242 
4243 	if (pt != NULL)
4244 	{
4245 	    char_u *what = tv_get_string(&argvars[1]);
4246 	    char_u *n;
4247 
4248 	    if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4249 	    {
4250 		rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
4251 		n = partial_name(pt);
4252 		if (n == NULL)
4253 		    rettv->vval.v_string = NULL;
4254 		else
4255 		{
4256 		    rettv->vval.v_string = vim_strsave(n);
4257 		    if (rettv->v_type == VAR_FUNC)
4258 			func_ref(rettv->vval.v_string);
4259 		}
4260 	    }
4261 	    else if (STRCMP(what, "dict") == 0)
4262 	    {
4263 		what_is_dict = TRUE;
4264 		if (pt->pt_dict != NULL)
4265 		    rettv_dict_set(rettv, pt->pt_dict);
4266 	    }
4267 	    else if (STRCMP(what, "args") == 0)
4268 	    {
4269 		rettv->v_type = VAR_LIST;
4270 		if (rettv_list_alloc(rettv) == OK)
4271 		{
4272 		    int i;
4273 
4274 		    for (i = 0; i < pt->pt_argc; ++i)
4275 			list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4276 		}
4277 	    }
4278 	    else
4279 		semsg(_(e_invarg2), what);
4280 
4281 	    // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4282 	    // third argument
4283 	    if (!what_is_dict)
4284 		return;
4285 	}
4286     }
4287     else
4288 	semsg(_(e_listdictblobarg), "get()");
4289 
4290     if (tv == NULL)
4291     {
4292 	if (argvars[2].v_type != VAR_UNKNOWN)
4293 	    copy_tv(&argvars[2], rettv);
4294     }
4295     else
4296 	copy_tv(tv, rettv);
4297 }
4298 
4299 /*
4300  * "getchangelist()" function
4301  */
4302     static void
f_getchangelist(typval_T * argvars,typval_T * rettv)4303 f_getchangelist(typval_T *argvars, typval_T *rettv)
4304 {
4305 #ifdef FEAT_JUMPLIST
4306     buf_T	*buf;
4307     int		i;
4308     list_T	*l;
4309     dict_T	*d;
4310 #endif
4311 
4312     if (rettv_list_alloc(rettv) != OK)
4313 	return;
4314 
4315     if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL)
4316 	return;
4317 
4318 #ifdef FEAT_JUMPLIST
4319     if (argvars[0].v_type == VAR_UNKNOWN)
4320 	buf = curbuf;
4321     else
4322 	buf = tv_get_buf_from_arg(&argvars[0]);
4323     if (buf == NULL)
4324 	return;
4325 
4326     l = list_alloc();
4327     if (l == NULL)
4328 	return;
4329 
4330     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4331 	return;
4332     /*
4333      * The current window change list index tracks only the position in the
4334      * current buffer change list. For other buffers, use the change list
4335      * length as the current index.
4336      */
4337     list_append_number(rettv->vval.v_list,
4338 	    (varnumber_T)((buf == curwin->w_buffer)
4339 		? curwin->w_changelistidx : buf->b_changelistlen));
4340 
4341     for (i = 0; i < buf->b_changelistlen; ++i)
4342     {
4343 	if (buf->b_changelist[i].lnum == 0)
4344 	    continue;
4345 	if ((d = dict_alloc()) == NULL)
4346 	    return;
4347 	if (list_append_dict(l, d) == FAIL)
4348 	    return;
4349 	dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4350 	dict_add_number(d, "col", (long)buf->b_changelist[i].col);
4351 	dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
4352     }
4353 #endif
4354 }
4355 
4356     static void
getpos_both(typval_T * argvars,typval_T * rettv,int getcurpos,int charcol)4357 getpos_both(
4358     typval_T	*argvars,
4359     typval_T	*rettv,
4360     int		getcurpos,
4361     int		charcol)
4362 {
4363     pos_T	*fp = NULL;
4364     pos_T	pos;
4365     win_T	*wp = curwin;
4366     list_T	*l;
4367     int		fnum = -1;
4368 
4369     if (rettv_list_alloc(rettv) == OK)
4370     {
4371 	l = rettv->vval.v_list;
4372 	if (getcurpos)
4373 	{
4374 	    if (argvars[0].v_type != VAR_UNKNOWN)
4375 	    {
4376 		wp = find_win_by_nr_or_id(&argvars[0]);
4377 		if (wp != NULL)
4378 		    fp = &wp->w_cursor;
4379 	    }
4380 	    else
4381 		fp = &curwin->w_cursor;
4382 	    if (fp != NULL && charcol)
4383 	    {
4384 		pos = *fp;
4385 		pos.col =
4386 		    buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col);
4387 		fp = &pos;
4388 	    }
4389 	}
4390 	else
4391 	    fp = var2fpos(&argvars[0], TRUE, &fnum, charcol);
4392 	if (fnum != -1)
4393 	    list_append_number(l, (varnumber_T)fnum);
4394 	else
4395 	    list_append_number(l, (varnumber_T)0);
4396 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4397 							    : (varnumber_T)0);
4398 	list_append_number(l, (fp != NULL)
4399 		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4400 							    : (varnumber_T)0);
4401 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
4402 							      (varnumber_T)0);
4403 	if (getcurpos)
4404 	{
4405 	    int	    save_set_curswant = curwin->w_set_curswant;
4406 	    colnr_T save_curswant = curwin->w_curswant;
4407 	    colnr_T save_virtcol = curwin->w_virtcol;
4408 
4409 	    if (wp == curwin)
4410 		update_curswant();
4411 	    list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
4412 		    ?  (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
4413 
4414 	    // Do not change "curswant", as it is unexpected that a get
4415 	    // function has a side effect.
4416 	    if (wp == curwin && save_set_curswant)
4417 	    {
4418 		curwin->w_set_curswant = save_set_curswant;
4419 		curwin->w_curswant = save_curswant;
4420 		curwin->w_virtcol = save_virtcol;
4421 		curwin->w_valid &= ~VALID_VIRTCOL;
4422 	    }
4423 	}
4424     }
4425     else
4426 	rettv->vval.v_number = FALSE;
4427 }
4428 
4429 /*
4430  * "getcharpos()" function
4431  */
4432     static void
f_getcharpos(typval_T * argvars UNUSED,typval_T * rettv)4433 f_getcharpos(typval_T *argvars UNUSED, typval_T *rettv)
4434 {
4435     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4436 	return;
4437 
4438     getpos_both(argvars, rettv, FALSE, TRUE);
4439 }
4440 
4441 /*
4442  * "getcharsearch()" function
4443  */
4444     static void
f_getcharsearch(typval_T * argvars UNUSED,typval_T * rettv)4445 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4446 {
4447     if (rettv_dict_alloc(rettv) != FAIL)
4448     {
4449 	dict_T *dict = rettv->vval.v_dict;
4450 
4451 	dict_add_string(dict, "char", last_csearch());
4452 	dict_add_number(dict, "forward", last_csearch_forward());
4453 	dict_add_number(dict, "until", last_csearch_until());
4454     }
4455 }
4456 
4457 /*
4458  * "getenv()" function
4459  */
4460     static void
f_getenv(typval_T * argvars,typval_T * rettv)4461 f_getenv(typval_T *argvars, typval_T *rettv)
4462 {
4463     int	    mustfree = FALSE;
4464     char_u  *p;
4465 
4466     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4467 	return;
4468 
4469     p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4470     if (p == NULL)
4471     {
4472 	rettv->v_type = VAR_SPECIAL;
4473 	rettv->vval.v_number = VVAL_NULL;
4474 	return;
4475     }
4476     if (!mustfree)
4477 	p = vim_strsave(p);
4478     rettv->vval.v_string = p;
4479     rettv->v_type = VAR_STRING;
4480 }
4481 
4482 /*
4483  * "getfontname()" function
4484  */
4485     static void
f_getfontname(typval_T * argvars UNUSED,typval_T * rettv)4486 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4487 {
4488     rettv->v_type = VAR_STRING;
4489     rettv->vval.v_string = NULL;
4490 
4491     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
4492 	return;
4493 
4494 #ifdef FEAT_GUI
4495     if (gui.in_use)
4496     {
4497 	GuiFont font;
4498 	char_u	*name = NULL;
4499 
4500 	if (argvars[0].v_type == VAR_UNKNOWN)
4501 	{
4502 	    // Get the "Normal" font.  Either the name saved by
4503 	    // hl_set_font_name() or from the font ID.
4504 	    font = gui.norm_font;
4505 	    name = hl_get_font_name();
4506 	}
4507 	else
4508 	{
4509 	    name = tv_get_string(&argvars[0]);
4510 	    if (STRCMP(name, "*") == 0)	    // don't use font dialog
4511 		return;
4512 	    font = gui_mch_get_font(name, FALSE);
4513 	    if (font == NOFONT)
4514 		return;	    // Invalid font name, return empty string.
4515 	}
4516 	rettv->vval.v_string = gui_mch_get_fontname(font, name);
4517 	if (argvars[0].v_type != VAR_UNKNOWN)
4518 	    gui_mch_free_font(font);
4519     }
4520 #endif
4521 }
4522 
4523 /*
4524  * "getjumplist()" function
4525  */
4526     static void
f_getjumplist(typval_T * argvars,typval_T * rettv)4527 f_getjumplist(typval_T *argvars, typval_T *rettv)
4528 {
4529 #ifdef FEAT_JUMPLIST
4530     win_T	*wp;
4531     int		i;
4532     list_T	*l;
4533     dict_T	*d;
4534 #endif
4535 
4536     if (rettv_list_alloc(rettv) != OK)
4537 	return;
4538 
4539     if (in_vim9script()
4540 	    && (check_for_opt_number_arg(argvars, 0) == FAIL
4541 		|| (argvars[0].v_type != VAR_UNKNOWN
4542 		    && check_for_opt_number_arg(argvars, 1) == FAIL)))
4543 	return;
4544 
4545 #ifdef FEAT_JUMPLIST
4546     wp = find_tabwin(&argvars[0], &argvars[1], NULL);
4547     if (wp == NULL)
4548 	return;
4549 
4550     cleanup_jumplist(wp, TRUE);
4551 
4552     l = list_alloc();
4553     if (l == NULL)
4554 	return;
4555 
4556     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4557 	return;
4558     list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4559 
4560     for (i = 0; i < wp->w_jumplistlen; ++i)
4561     {
4562 	if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4563 	    continue;
4564 	if ((d = dict_alloc()) == NULL)
4565 	    return;
4566 	if (list_append_dict(l, d) == FAIL)
4567 	    return;
4568 	dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4569 	dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
4570 	dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
4571 	dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
4572 	if (wp->w_jumplist[i].fname != NULL)
4573 	    dict_add_string(d, "filename", wp->w_jumplist[i].fname);
4574     }
4575 #endif
4576 }
4577 
4578 /*
4579  * "getpid()" function
4580  */
4581     static void
f_getpid(typval_T * argvars UNUSED,typval_T * rettv)4582 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4583 {
4584     rettv->vval.v_number = mch_get_pid();
4585 }
4586 
4587 /*
4588  * "getcurpos()" function
4589  */
4590     static void
f_getcurpos(typval_T * argvars,typval_T * rettv)4591 f_getcurpos(typval_T *argvars, typval_T *rettv)
4592 {
4593     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4594 	return;
4595 
4596     getpos_both(argvars, rettv, TRUE, FALSE);
4597 }
4598 
4599     static void
f_getcursorcharpos(typval_T * argvars,typval_T * rettv)4600 f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
4601 {
4602     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4603 	return;
4604 
4605     getpos_both(argvars, rettv, TRUE, TRUE);
4606 }
4607 
4608 /*
4609  * "getpos(string)" function
4610  */
4611     static void
f_getpos(typval_T * argvars,typval_T * rettv)4612 f_getpos(typval_T *argvars, typval_T *rettv)
4613 {
4614     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4615 	return;
4616 
4617     getpos_both(argvars, rettv, FALSE, FALSE);
4618 }
4619 
4620 /*
4621  * "getreg()" function
4622  */
4623     static void
f_getreg(typval_T * argvars,typval_T * rettv)4624 f_getreg(typval_T *argvars, typval_T *rettv)
4625 {
4626     char_u	*strregname;
4627     int		regname;
4628     int		arg2 = FALSE;
4629     int		return_list = FALSE;
4630     int		error = FALSE;
4631 
4632     if (in_vim9script()
4633 	    && (check_for_opt_string_arg(argvars, 0) == FAIL
4634 		|| (argvars[0].v_type != VAR_UNKNOWN
4635 		    && (check_for_opt_bool_arg(argvars, 1) == FAIL
4636 			|| (argvars[1].v_type != VAR_UNKNOWN
4637 			    && check_for_opt_bool_arg(argvars, 2) == FAIL)))))
4638 	return;
4639 
4640     if (argvars[0].v_type != VAR_UNKNOWN)
4641     {
4642 	strregname = tv_get_string_chk(&argvars[0]);
4643 	if (strregname == NULL)
4644 	    error = TRUE;
4645 	else if (in_vim9script() && STRLEN(strregname) > 1)
4646 	{
4647 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
4648 	    error = TRUE;
4649 	}
4650 	if (argvars[1].v_type != VAR_UNKNOWN)
4651 	{
4652 	    arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
4653 	    if (!error && argvars[2].v_type != VAR_UNKNOWN)
4654 		return_list = (int)tv_get_bool_chk(&argvars[2], &error);
4655 	}
4656     }
4657     else
4658 	strregname = get_vim_var_str(VV_REG);
4659 
4660     if (error)
4661 	return;
4662 
4663     regname = (strregname == NULL ? '"' : *strregname);
4664     if (regname == 0)
4665 	regname = '"';
4666 
4667     if (return_list)
4668     {
4669 	rettv->v_type = VAR_LIST;
4670 	rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4671 				      (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4672 	if (rettv->vval.v_list == NULL)
4673 	    (void)rettv_list_alloc(rettv);
4674 	else
4675 	    ++rettv->vval.v_list->lv_refcount;
4676     }
4677     else
4678     {
4679 	rettv->v_type = VAR_STRING;
4680 	rettv->vval.v_string = get_reg_contents(regname,
4681 						    arg2 ? GREG_EXPR_SRC : 0);
4682     }
4683 }
4684 
4685 /*
4686  * "getregtype()" function
4687  */
4688     static void
f_getregtype(typval_T * argvars,typval_T * rettv)4689 f_getregtype(typval_T *argvars, typval_T *rettv)
4690 {
4691     char_u	*strregname;
4692     int		regname;
4693     char_u	buf[NUMBUFLEN + 2];
4694     long	reglen = 0;
4695 
4696     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
4697 	return;
4698 
4699     if (argvars[0].v_type != VAR_UNKNOWN)
4700     {
4701 	strregname = tv_get_string_chk(&argvars[0]);
4702 	if (strregname != NULL && in_vim9script() && STRLEN(strregname) > 1)
4703 	{
4704 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
4705 	    strregname = NULL;
4706 	}
4707 	if (strregname == NULL)	    // type error; errmsg already given
4708 	{
4709 	    rettv->v_type = VAR_STRING;
4710 	    rettv->vval.v_string = NULL;
4711 	    return;
4712 	}
4713     }
4714     else
4715 	// Default to v:register
4716 	strregname = get_vim_var_str(VV_REG);
4717 
4718     regname = (strregname == NULL ? '"' : *strregname);
4719     if (regname == 0)
4720 	regname = '"';
4721 
4722     buf[0] = NUL;
4723     buf[1] = NUL;
4724     switch (get_reg_type(regname, &reglen))
4725     {
4726 	case MLINE: buf[0] = 'V'; break;
4727 	case MCHAR: buf[0] = 'v'; break;
4728 	case MBLOCK:
4729 		buf[0] = Ctrl_V;
4730 		sprintf((char *)buf + 1, "%ld", reglen + 1);
4731 		break;
4732     }
4733     rettv->v_type = VAR_STRING;
4734     rettv->vval.v_string = vim_strsave(buf);
4735 }
4736 
4737 /*
4738  * "gettagstack()" function
4739  */
4740     static void
f_gettagstack(typval_T * argvars,typval_T * rettv)4741 f_gettagstack(typval_T *argvars, typval_T *rettv)
4742 {
4743     win_T	*wp = curwin;			// default is current window
4744 
4745     if (rettv_dict_alloc(rettv) != OK)
4746 	return;
4747 
4748     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
4749 	return;
4750 
4751     if (argvars[0].v_type != VAR_UNKNOWN)
4752     {
4753 	wp = find_win_by_nr_or_id(&argvars[0]);
4754 	if (wp == NULL)
4755 	    return;
4756     }
4757 
4758     get_tagstack(wp, rettv->vval.v_dict);
4759 }
4760 
4761 /*
4762  * "gettext()" function
4763  */
4764     static void
f_gettext(typval_T * argvars,typval_T * rettv)4765 f_gettext(typval_T *argvars, typval_T *rettv)
4766 {
4767     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
4768 	return;
4769 
4770     if (argvars[0].v_type != VAR_STRING
4771 	    || argvars[0].vval.v_string == NULL
4772 	    || *argvars[0].vval.v_string == NUL)
4773     {
4774 	semsg(_(e_invarg2), tv_get_string(&argvars[0]));
4775     }
4776     else
4777     {
4778 	rettv->v_type = VAR_STRING;
4779 	rettv->vval.v_string = vim_strsave(
4780 					(char_u *)_(argvars[0].vval.v_string));
4781     }
4782 }
4783 
4784 // for VIM_VERSION_ defines
4785 #include "version.h"
4786 
4787 /*
4788  * "has()" function
4789  */
4790     void
f_has(typval_T * argvars,typval_T * rettv)4791 f_has(typval_T *argvars, typval_T *rettv)
4792 {
4793     int		i;
4794     char_u	*name;
4795     int		x = FALSE;
4796     int		n = FALSE;
4797     typedef struct {
4798 	char *name;
4799 	short present;
4800     } has_item_T;
4801     static has_item_T has_list[] =
4802     {
4803 	{"amiga",
4804 #ifdef AMIGA
4805 		1
4806 #else
4807 		0
4808 #endif
4809 		},
4810 	{"arp",
4811 #if defined(AMIGA) && defined(FEAT_ARP)
4812 		1
4813 #else
4814 		0
4815 #endif
4816 		},
4817 	{"haiku",
4818 #ifdef __HAIKU__
4819 		1
4820 #else
4821 		0
4822 #endif
4823 		},
4824 	{"bsd",
4825 #if defined(BSD) && !defined(MACOS_X)
4826 		1
4827 #else
4828 		0
4829 #endif
4830 		},
4831 	{"hpux",
4832 #ifdef hpux
4833 		1
4834 #else
4835 		0
4836 #endif
4837 		},
4838 	{"linux",
4839 #ifdef __linux__
4840 		1
4841 #else
4842 		0
4843 #endif
4844 		},
4845 	{"mac",		// Mac OS X (and, once, Mac OS Classic)
4846 #ifdef MACOS_X
4847 		1
4848 #else
4849 		0
4850 #endif
4851 		},
4852 	{"osx",		// Mac OS X
4853 #ifdef MACOS_X
4854 		1
4855 #else
4856 		0
4857 #endif
4858 		},
4859 	{"macunix",	// Mac OS X, with the darwin feature
4860 #if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4861 		1
4862 #else
4863 		0
4864 #endif
4865 		},
4866 	{"osxdarwin",	// synonym for macunix
4867 #if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4868 		1
4869 #else
4870 		0
4871 #endif
4872 		},
4873 	{"qnx",
4874 #ifdef __QNX__
4875 		1
4876 #else
4877 		0
4878 #endif
4879 		},
4880 	{"sun",
4881 #ifdef SUN_SYSTEM
4882 		1
4883 #else
4884 		0
4885 #endif
4886 		},
4887 	{"unix",
4888 #ifdef UNIX
4889 		1
4890 #else
4891 		0
4892 #endif
4893 		},
4894 	{"vms",
4895 #ifdef VMS
4896 		1
4897 #else
4898 		0
4899 #endif
4900 		},
4901 	{"win32",
4902 #ifdef MSWIN
4903 		1
4904 #else
4905 		0
4906 #endif
4907 		},
4908 	{"win32unix",
4909 #if defined(UNIX) && defined(__CYGWIN__)
4910 		1
4911 #else
4912 		0
4913 #endif
4914 		},
4915 	{"win64",
4916 #ifdef _WIN64
4917 		1
4918 #else
4919 		0
4920 #endif
4921 		},
4922 	{"ebcdic",
4923 #ifdef EBCDIC
4924 		1
4925 #else
4926 		0
4927 #endif
4928 		},
4929 	{"fname_case",
4930 #ifndef CASE_INSENSITIVE_FILENAME
4931 		1
4932 #else
4933 		0
4934 #endif
4935 		},
4936 	{"acl",
4937 #ifdef HAVE_ACL
4938 		1
4939 #else
4940 		0
4941 #endif
4942 		},
4943 	{"arabic",
4944 #ifdef FEAT_ARABIC
4945 		1
4946 #else
4947 		0
4948 #endif
4949 		},
4950 	{"autocmd", 1},
4951 	{"autochdir",
4952 #ifdef FEAT_AUTOCHDIR
4953 		1
4954 #else
4955 		0
4956 #endif
4957 		},
4958 	{"autoservername",
4959 #ifdef FEAT_AUTOSERVERNAME
4960 		1
4961 #else
4962 		0
4963 #endif
4964 		},
4965 	{"balloon_eval",
4966 #ifdef FEAT_BEVAL_GUI
4967 		1
4968 #else
4969 		0
4970 #endif
4971 		},
4972 	{"balloon_multiline",
4973 #if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
4974 			// MS-Windows requires runtime check, see below
4975 		1
4976 #else
4977 		0
4978 #endif
4979 		},
4980 	{"balloon_eval_term",
4981 #ifdef FEAT_BEVAL_TERM
4982 		1
4983 #else
4984 		0
4985 #endif
4986 		},
4987 	{"builtin_terms",
4988 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
4989 		1
4990 #else
4991 		0
4992 #endif
4993 		},
4994 	{"all_builtin_terms",
4995 #if defined(ALL_BUILTIN_TCAPS)
4996 		1
4997 #else
4998 		0
4999 #endif
5000 		},
5001 	{"browsefilter",
5002 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5003 	|| defined(FEAT_GUI_MSWIN) \
5004 	|| defined(FEAT_GUI_MOTIF))
5005 		1
5006 #else
5007 		0
5008 #endif
5009 		},
5010 	{"byte_offset",
5011 #ifdef FEAT_BYTEOFF
5012 		1
5013 #else
5014 		0
5015 #endif
5016 		},
5017 	{"channel",
5018 #ifdef FEAT_JOB_CHANNEL
5019 		1
5020 #else
5021 		0
5022 #endif
5023 		},
5024 	{"cindent",
5025 #ifdef FEAT_CINDENT
5026 		1
5027 #else
5028 		0
5029 #endif
5030 		},
5031 	{"clientserver",
5032 #ifdef FEAT_CLIENTSERVER
5033 		1
5034 #else
5035 		0
5036 #endif
5037 		},
5038 	{"clipboard",
5039 #ifdef FEAT_CLIPBOARD
5040 		1
5041 #else
5042 		0
5043 #endif
5044 		},
5045 	{"cmdline_compl", 1},
5046 	{"cmdline_hist", 1},
5047 	{"cmdwin",
5048 #ifdef FEAT_CMDWIN
5049 		1
5050 #else
5051 		0
5052 #endif
5053 		},
5054 	{"comments", 1},
5055 	{"conceal",
5056 #ifdef FEAT_CONCEAL
5057 		1
5058 #else
5059 		0
5060 #endif
5061 		},
5062 	{"cryptv",
5063 #ifdef FEAT_CRYPT
5064 		1
5065 #else
5066 		0
5067 #endif
5068 		},
5069 	{"crypt-blowfish",
5070 #ifdef FEAT_CRYPT
5071 		1
5072 #else
5073 		0
5074 #endif
5075 		},
5076 	{"crypt-blowfish2",
5077 #ifdef FEAT_CRYPT
5078 		1
5079 #else
5080 		0
5081 #endif
5082 		},
5083 	{"cscope",
5084 #ifdef FEAT_CSCOPE
5085 		1
5086 #else
5087 		0
5088 #endif
5089 		},
5090 	{"cursorbind", 1},
5091 	{"cursorshape",
5092 #ifdef CURSOR_SHAPE
5093 		1
5094 #else
5095 		0
5096 #endif
5097 		},
5098 	{"debug",
5099 #ifdef DEBUG
5100 		1
5101 #else
5102 		0
5103 #endif
5104 		},
5105 	{"dialog_con",
5106 #ifdef FEAT_CON_DIALOG
5107 		1
5108 #else
5109 		0
5110 #endif
5111 		},
5112 	{"dialog_gui",
5113 #ifdef FEAT_GUI_DIALOG
5114 		1
5115 #else
5116 		0
5117 #endif
5118 		},
5119 	{"diff",
5120 #ifdef FEAT_DIFF
5121 		1
5122 #else
5123 		0
5124 #endif
5125 		},
5126 	{"digraphs",
5127 #ifdef FEAT_DIGRAPHS
5128 		1
5129 #else
5130 		0
5131 #endif
5132 		},
5133 	{"directx",
5134 #ifdef FEAT_DIRECTX
5135 		1
5136 #else
5137 		0
5138 #endif
5139 		},
5140 	{"dnd",
5141 #ifdef FEAT_DND
5142 		1
5143 #else
5144 		0
5145 #endif
5146 		},
5147 	{"drop_file",
5148 #ifdef HAVE_DROP_FILE
5149 		1
5150 #else
5151 		0
5152 #endif
5153 		},
5154 	{"emacs_tags",
5155 #ifdef FEAT_EMACS_TAGS
5156 		1
5157 #else
5158 		0
5159 #endif
5160 		},
5161 	{"eval", 1},		// always present, of course!
5162 	{"ex_extra", 1},	// graduated feature
5163 	{"extra_search",
5164 #ifdef FEAT_SEARCH_EXTRA
5165 		1
5166 #else
5167 		0
5168 #endif
5169 		},
5170 	{"file_in_path",
5171 #ifdef FEAT_SEARCHPATH
5172 		1
5173 #else
5174 		0
5175 #endif
5176 		},
5177 	{"filterpipe",
5178 #if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
5179 		1
5180 #else
5181 		0
5182 #endif
5183 		},
5184 	{"find_in_path",
5185 #ifdef FEAT_FIND_ID
5186 		1
5187 #else
5188 		0
5189 #endif
5190 		},
5191 	{"float",
5192 #ifdef FEAT_FLOAT
5193 		1
5194 #else
5195 		0
5196 #endif
5197 		},
5198 	{"folding",
5199 #ifdef FEAT_FOLDING
5200 		1
5201 #else
5202 		0
5203 #endif
5204 		},
5205 	{"footer",
5206 #ifdef FEAT_FOOTER
5207 		1
5208 #else
5209 		0
5210 #endif
5211 		},
5212 	{"fork",
5213 #if !defined(USE_SYSTEM) && defined(UNIX)
5214 		1
5215 #else
5216 		0
5217 #endif
5218 		},
5219 	{"gettext",
5220 #ifdef FEAT_GETTEXT
5221 		1
5222 #else
5223 		0
5224 #endif
5225 		},
5226 	{"gui",
5227 #ifdef FEAT_GUI
5228 		1
5229 #else
5230 		0
5231 #endif
5232 		},
5233 	{"gui_neXtaw",
5234 #if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
5235 		1
5236 #else
5237 		0
5238 #endif
5239 		},
5240 	{"gui_athena",
5241 #if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
5242 		1
5243 #else
5244 		0
5245 #endif
5246 		},
5247 	{"gui_gtk",
5248 #ifdef FEAT_GUI_GTK
5249 		1
5250 #else
5251 		0
5252 #endif
5253 		},
5254 	{"gui_gtk2",
5255 #if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
5256 		1
5257 #else
5258 		0
5259 #endif
5260 		},
5261 	{"gui_gtk3",
5262 #if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
5263 		1
5264 #else
5265 		0
5266 #endif
5267 		},
5268 	{"gui_gnome",
5269 #ifdef FEAT_GUI_GNOME
5270 		1
5271 #else
5272 		0
5273 #endif
5274 		},
5275 	{"gui_haiku",
5276 #ifdef FEAT_GUI_HAIKU
5277 		1
5278 #else
5279 		0
5280 #endif
5281 		},
5282 	{"gui_mac", 0},
5283 	{"gui_motif",
5284 #ifdef FEAT_GUI_MOTIF
5285 		1
5286 #else
5287 		0
5288 #endif
5289 		},
5290 	{"gui_photon",
5291 #ifdef FEAT_GUI_PHOTON
5292 		1
5293 #else
5294 		0
5295 #endif
5296 		},
5297 	{"gui_win32",
5298 #ifdef FEAT_GUI_MSWIN
5299 		1
5300 #else
5301 		0
5302 #endif
5303 		},
5304 	{"iconv",
5305 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5306 		1
5307 #else
5308 		0
5309 #endif
5310 		},
5311 	{"insert_expand", 1},
5312 	{"ipv6",
5313 #ifdef FEAT_IPV6
5314 		1
5315 #else
5316 		0
5317 #endif
5318 	},
5319 	{"job",
5320 #ifdef FEAT_JOB_CHANNEL
5321 		1
5322 #else
5323 		0
5324 #endif
5325 		},
5326 	{"jumplist",
5327 #ifdef FEAT_JUMPLIST
5328 		1
5329 #else
5330 		0
5331 #endif
5332 		},
5333 	{"keymap",
5334 #ifdef FEAT_KEYMAP
5335 		1
5336 #else
5337 		0
5338 #endif
5339 		},
5340 	{"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
5341 	{"langmap",
5342 #ifdef FEAT_LANGMAP
5343 		1
5344 #else
5345 		0
5346 #endif
5347 		},
5348 	{"libcall",
5349 #ifdef FEAT_LIBCALL
5350 		1
5351 #else
5352 		0
5353 #endif
5354 		},
5355 	{"linebreak",
5356 #ifdef FEAT_LINEBREAK
5357 		1
5358 #else
5359 		0
5360 #endif
5361 		},
5362 	{"lispindent",
5363 #ifdef FEAT_LISP
5364 		1
5365 #else
5366 		0
5367 #endif
5368 		},
5369 	{"listcmds", 1},
5370 	{"localmap", 1},
5371 	{"lua",
5372 #if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
5373 		1
5374 #else
5375 		0
5376 #endif
5377 		},
5378 	{"menu",
5379 #ifdef FEAT_MENU
5380 		1
5381 #else
5382 		0
5383 #endif
5384 		},
5385 	{"mksession",
5386 #ifdef FEAT_SESSION
5387 		1
5388 #else
5389 		0
5390 #endif
5391 		},
5392 	{"modify_fname", 1},
5393 	{"mouse", 1},
5394 	{"mouseshape",
5395 #ifdef FEAT_MOUSESHAPE
5396 		1
5397 #else
5398 		0
5399 #endif
5400 		},
5401 	{"mouse_dec",
5402 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
5403 		1
5404 #else
5405 		0
5406 #endif
5407 		},
5408 	{"mouse_gpm",
5409 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
5410 		1
5411 #else
5412 		0
5413 #endif
5414 		},
5415 	{"mouse_jsbterm",
5416 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
5417 		1
5418 #else
5419 		0
5420 #endif
5421 		},
5422 	{"mouse_netterm",
5423 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
5424 		1
5425 #else
5426 		0
5427 #endif
5428 		},
5429 	{"mouse_pterm",
5430 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
5431 		1
5432 #else
5433 		0
5434 #endif
5435 		},
5436 	{"mouse_sgr",
5437 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5438 		1
5439 #else
5440 		0
5441 #endif
5442 		},
5443 	{"mouse_sysmouse",
5444 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
5445 		1
5446 #else
5447 		0
5448 #endif
5449 		},
5450 	{"mouse_urxvt",
5451 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
5452 		1
5453 #else
5454 		0
5455 #endif
5456 		},
5457 	{"mouse_xterm",
5458 #if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5459 		1
5460 #else
5461 		0
5462 #endif
5463 		},
5464 	{"multi_byte", 1},
5465 	{"multi_byte_ime",
5466 #ifdef FEAT_MBYTE_IME
5467 		1
5468 #else
5469 		0
5470 #endif
5471 		},
5472 	{"multi_lang",
5473 #ifdef FEAT_MULTI_LANG
5474 		1
5475 #else
5476 		0
5477 #endif
5478 		},
5479 	{"mzscheme",
5480 #if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
5481 		1
5482 #else
5483 		0
5484 #endif
5485 		},
5486 	{"nanotime",
5487 #ifdef ST_MTIM_NSEC
5488 		1
5489 #else
5490 		0
5491 #endif
5492 	},
5493 	{"num64", 1},
5494 	{"ole",
5495 #ifdef FEAT_OLE
5496 		1
5497 #else
5498 		0
5499 #endif
5500 		},
5501 	{"packages",
5502 #ifdef FEAT_EVAL
5503 		1
5504 #else
5505 		0
5506 #endif
5507 		},
5508 	{"path_extra",
5509 #ifdef FEAT_PATH_EXTRA
5510 		1
5511 #else
5512 		0
5513 #endif
5514 		},
5515 	{"perl",
5516 #if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
5517 		1
5518 #else
5519 		0
5520 #endif
5521 		},
5522 	{"persistent_undo",
5523 #ifdef FEAT_PERSISTENT_UNDO
5524 		1
5525 #else
5526 		0
5527 #endif
5528 		},
5529 	{"python_compiled",
5530 #if defined(FEAT_PYTHON)
5531 		1
5532 #else
5533 		0
5534 #endif
5535 		},
5536 	{"python_dynamic",
5537 #if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
5538 		1
5539 #else
5540 		0
5541 #endif
5542 		},
5543 	{"python",
5544 #if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
5545 		1
5546 #else
5547 		0
5548 #endif
5549 		},
5550 	{"pythonx",
5551 #if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
5552 	|| (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
5553 		1
5554 #else
5555 		0
5556 #endif
5557 		},
5558 	{"python3_compiled",
5559 #if defined(FEAT_PYTHON3)
5560 		1
5561 #else
5562 		0
5563 #endif
5564 		},
5565 	{"python3_dynamic",
5566 #if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
5567 		1
5568 #else
5569 		0
5570 #endif
5571 		},
5572 	{"python3",
5573 #if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
5574 		1
5575 #else
5576 		0
5577 #endif
5578 		},
5579 	{"popupwin",
5580 #ifdef FEAT_PROP_POPUP
5581 		1
5582 #else
5583 		0
5584 #endif
5585 		},
5586 	{"postscript",
5587 #ifdef FEAT_POSTSCRIPT
5588 		1
5589 #else
5590 		0
5591 #endif
5592 		},
5593 	{"printer",
5594 #ifdef FEAT_PRINTER
5595 		1
5596 #else
5597 		0
5598 #endif
5599 		},
5600 	{"profile",
5601 #ifdef FEAT_PROFILE
5602 		1
5603 #else
5604 		0
5605 #endif
5606 		},
5607 	{"reltime",
5608 #ifdef FEAT_RELTIME
5609 		1
5610 #else
5611 		0
5612 #endif
5613 		},
5614 	{"quickfix",
5615 #ifdef FEAT_QUICKFIX
5616 		1
5617 #else
5618 		0
5619 #endif
5620 		},
5621 	{"rightleft",
5622 #ifdef FEAT_RIGHTLEFT
5623 		1
5624 #else
5625 		0
5626 #endif
5627 		},
5628 	{"ruby",
5629 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5630 		1
5631 #else
5632 		0
5633 #endif
5634 		},
5635 	{"scrollbind", 1},
5636 	{"showcmd",
5637 #ifdef FEAT_CMDL_INFO
5638 		1
5639 #else
5640 		0
5641 #endif
5642 		},
5643 	{"cmdline_info",
5644 #ifdef FEAT_CMDL_INFO
5645 		1
5646 #else
5647 		0
5648 #endif
5649 		},
5650 	{"signs",
5651 #ifdef FEAT_SIGNS
5652 		1
5653 #else
5654 		0
5655 #endif
5656 		},
5657 	{"smartindent",
5658 #ifdef FEAT_SMARTINDENT
5659 		1
5660 #else
5661 		0
5662 #endif
5663 		},
5664 	{"startuptime",
5665 #ifdef STARTUPTIME
5666 		1
5667 #else
5668 		0
5669 #endif
5670 		},
5671 	{"statusline",
5672 #ifdef FEAT_STL_OPT
5673 		1
5674 #else
5675 		0
5676 #endif
5677 		},
5678 	{"netbeans_intg",
5679 #ifdef FEAT_NETBEANS_INTG
5680 		1
5681 #else
5682 		0
5683 #endif
5684 		},
5685 	{"sodium",
5686 #ifdef FEAT_SODIUM
5687 		1
5688 #else
5689 		0
5690 #endif
5691 		},
5692 	{"sound",
5693 #ifdef FEAT_SOUND
5694 		1
5695 #else
5696 		0
5697 #endif
5698 		},
5699 	{"spell",
5700 #ifdef FEAT_SPELL
5701 		1
5702 #else
5703 		0
5704 #endif
5705 		},
5706 	{"syntax",
5707 #ifdef FEAT_SYN_HL
5708 		1
5709 #else
5710 		0
5711 #endif
5712 		},
5713 	{"system",
5714 #if defined(USE_SYSTEM) || !defined(UNIX)
5715 		1
5716 #else
5717 		0
5718 #endif
5719 		},
5720 	{"tag_binary",
5721 #ifdef FEAT_TAG_BINS
5722 		1
5723 #else
5724 		0
5725 #endif
5726 		},
5727 	{"tcl",
5728 #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
5729 		1
5730 #else
5731 		0
5732 #endif
5733 		},
5734 	{"termguicolors",
5735 #ifdef FEAT_TERMGUICOLORS
5736 		1
5737 #else
5738 		0
5739 #endif
5740 		},
5741 	{"terminal",
5742 #if defined(FEAT_TERMINAL) && !defined(MSWIN)
5743 		1
5744 #else
5745 		0
5746 #endif
5747 		},
5748 	{"terminfo",
5749 #ifdef TERMINFO
5750 		1
5751 #else
5752 		0
5753 #endif
5754 		},
5755 	{"termresponse",
5756 #ifdef FEAT_TERMRESPONSE
5757 		1
5758 #else
5759 		0
5760 #endif
5761 		},
5762 	{"textobjects",
5763 #ifdef FEAT_TEXTOBJ
5764 		1
5765 #else
5766 		0
5767 #endif
5768 		},
5769 	{"textprop",
5770 #ifdef FEAT_PROP_POPUP
5771 		1
5772 #else
5773 		0
5774 #endif
5775 		},
5776 	{"tgetent",
5777 #ifdef HAVE_TGETENT
5778 		1
5779 #else
5780 		0
5781 #endif
5782 		},
5783 	{"timers",
5784 #ifdef FEAT_TIMERS
5785 		1
5786 #else
5787 		0
5788 #endif
5789 		},
5790 	{"title",
5791 #ifdef FEAT_TITLE
5792 		1
5793 #else
5794 		0
5795 #endif
5796 		},
5797 	{"toolbar",
5798 #ifdef FEAT_TOOLBAR
5799 		1
5800 #else
5801 		0
5802 #endif
5803 		},
5804 	{"unnamedplus",
5805 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5806 		1
5807 #else
5808 		0
5809 #endif
5810 		},
5811 	{"user-commands", 1},    // was accidentally included in 5.4
5812 	{"user_commands", 1},
5813 	{"vartabs",
5814 #ifdef FEAT_VARTABS
5815 		1
5816 #else
5817 		0
5818 #endif
5819 		},
5820 	{"vertsplit", 1},
5821 	{"viminfo",
5822 #ifdef FEAT_VIMINFO
5823 		1
5824 #else
5825 		0
5826 #endif
5827 		},
5828 	{"vimscript-1", 1},
5829 	{"vimscript-2", 1},
5830 	{"vimscript-3", 1},
5831 	{"vimscript-4", 1},
5832 	{"virtualedit", 1},
5833 	{"visual", 1},
5834 	{"visualextra", 1},
5835 	{"vreplace", 1},
5836 	{"vtp",
5837 #ifdef FEAT_VTP
5838 		1
5839 #else
5840 		0
5841 #endif
5842 		},
5843 	{"wildignore",
5844 #ifdef FEAT_WILDIGN
5845 		1
5846 #else
5847 		0
5848 #endif
5849 		},
5850 	{"wildmenu",
5851 #ifdef FEAT_WILDMENU
5852 		1
5853 #else
5854 		0
5855 #endif
5856 		},
5857 	{"windows", 1},
5858 	{"winaltkeys",
5859 #ifdef FEAT_WAK
5860 		1
5861 #else
5862 		0
5863 #endif
5864 		},
5865 	{"writebackup",
5866 #ifdef FEAT_WRITEBACKUP
5867 		1
5868 #else
5869 		0
5870 #endif
5871 		},
5872 	{"xim",
5873 #ifdef FEAT_XIM
5874 		1
5875 #else
5876 		0
5877 #endif
5878 		},
5879 	{"xfontset",
5880 #ifdef FEAT_XFONTSET
5881 		1
5882 #else
5883 		0
5884 #endif
5885 		},
5886 	{"xpm",
5887 #if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
5888 		1
5889 #else
5890 		0
5891 #endif
5892 		},
5893 	{"xpm_w32",	// for backward compatibility
5894 #ifdef FEAT_XPM_W32
5895 		1
5896 #else
5897 		0
5898 #endif
5899 		},
5900 	{"xsmp",
5901 #ifdef USE_XSMP
5902 		1
5903 #else
5904 		0
5905 #endif
5906 		},
5907 	{"xsmp_interact",
5908 #ifdef USE_XSMP_INTERACT
5909 		1
5910 #else
5911 		0
5912 #endif
5913 		},
5914 	{"xterm_clipboard",
5915 #ifdef FEAT_XCLIPBOARD
5916 		1
5917 #else
5918 		0
5919 #endif
5920 		},
5921 	{"xterm_save",
5922 #ifdef FEAT_XTERM_SAVE
5923 		1
5924 #else
5925 		0
5926 #endif
5927 		},
5928 	{"X11",
5929 #if defined(UNIX) && defined(FEAT_X11)
5930 		1
5931 #else
5932 		0
5933 #endif
5934 		},
5935 	{NULL, 0}
5936     };
5937 
5938     if (in_vim9script()
5939 	    && (check_for_string_arg(argvars, 0) == FAIL
5940 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
5941 	return;
5942 
5943     name = tv_get_string(&argvars[0]);
5944     for (i = 0; has_list[i].name != NULL; ++i)
5945 	if (STRICMP(name, has_list[i].name) == 0)
5946 	{
5947 	    x = TRUE;
5948 	    n = has_list[i].present;
5949 	    break;
5950 	}
5951 
5952     // features also in has_list[] but sometimes enabled at runtime
5953     if (x == TRUE && n == FALSE)
5954     {
5955 	if (0)
5956 	{
5957 	    // intentionally empty
5958 	}
5959 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
5960 	else if (STRICMP(name, "balloon_multiline") == 0)
5961 	    n = multiline_balloon_available();
5962 #endif
5963 #ifdef VIMDLL
5964 	else if (STRICMP(name, "filterpipe") == 0)
5965 	    n = gui.in_use || gui.starting;
5966 #endif
5967 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5968 	else if (STRICMP(name, "iconv") == 0)
5969 	    n = iconv_enabled(FALSE);
5970 #endif
5971 #ifdef DYNAMIC_LUA
5972 	else if (STRICMP(name, "lua") == 0)
5973 	    n = lua_enabled(FALSE);
5974 #endif
5975 #ifdef DYNAMIC_MZSCHEME
5976 	else if (STRICMP(name, "mzscheme") == 0)
5977 	    n = mzscheme_enabled(FALSE);
5978 #endif
5979 #ifdef DYNAMIC_PERL
5980 	else if (STRICMP(name, "perl") == 0)
5981 	    n = perl_enabled(FALSE);
5982 #endif
5983 #ifdef DYNAMIC_PYTHON
5984 	else if (STRICMP(name, "python") == 0)
5985 	    n = python_enabled(FALSE);
5986 #endif
5987 #ifdef DYNAMIC_PYTHON3
5988 	else if (STRICMP(name, "python3") == 0)
5989 	    n = python3_enabled(FALSE);
5990 #endif
5991 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5992 	else if (STRICMP(name, "pythonx") == 0)
5993 	{
5994 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5995 	    if (p_pyx == 0)
5996 		n = python3_enabled(FALSE) || python_enabled(FALSE);
5997 	    else if (p_pyx == 3)
5998 		n = python3_enabled(FALSE);
5999 	    else if (p_pyx == 2)
6000 		n = python_enabled(FALSE);
6001 # elif defined(DYNAMIC_PYTHON)
6002 	    n = python_enabled(FALSE);
6003 # elif defined(DYNAMIC_PYTHON3)
6004 	    n = python3_enabled(FALSE);
6005 # endif
6006 	}
6007 #endif
6008 #ifdef DYNAMIC_RUBY
6009 	else if (STRICMP(name, "ruby") == 0)
6010 	    n = ruby_enabled(FALSE);
6011 #endif
6012 #ifdef DYNAMIC_TCL
6013 	else if (STRICMP(name, "tcl") == 0)
6014 	    n = tcl_enabled(FALSE);
6015 #endif
6016 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6017 	else if (STRICMP(name, "terminal") == 0)
6018 	    n = terminal_enabled();
6019 #endif
6020     }
6021 
6022     // features not in has_list[]
6023     if (x == FALSE)
6024     {
6025 	if (STRNICMP(name, "patch", 5) == 0)
6026 	{
6027 	    x = TRUE;
6028 	    if (name[5] == '-'
6029 		    && STRLEN(name) >= 11
6030 		    && vim_isdigit(name[6])
6031 		    && vim_isdigit(name[8])
6032 		    && vim_isdigit(name[10]))
6033 	    {
6034 		int major = atoi((char *)name + 6);
6035 		int minor = atoi((char *)name + 8);
6036 
6037 		// Expect "patch-9.9.01234".
6038 		n = (major < VIM_VERSION_MAJOR
6039 		     || (major == VIM_VERSION_MAJOR
6040 			 && (minor < VIM_VERSION_MINOR
6041 			     || (minor == VIM_VERSION_MINOR
6042 				 && has_patch(atoi((char *)name + 10))))));
6043 	    }
6044 	    else
6045 		n = has_patch(atoi((char *)name + 5));
6046 	}
6047 	else if (STRICMP(name, "vim_starting") == 0)
6048 	{
6049 	    x = TRUE;
6050 	    n = (starting != 0);
6051 	}
6052 	else if (STRICMP(name, "ttyin") == 0)
6053 	{
6054 	    x = TRUE;
6055 	    n = mch_input_isatty();
6056 	}
6057 	else if (STRICMP(name, "ttyout") == 0)
6058 	{
6059 	    x = TRUE;
6060 	    n = stdout_isatty;
6061 	}
6062 	else if (STRICMP(name, "multi_byte_encoding") == 0)
6063 	{
6064 	    x = TRUE;
6065 	    n = has_mbyte;
6066 	}
6067 	else if (STRICMP(name, "gui_running") == 0)
6068 	{
6069 	    x = TRUE;
6070 #ifdef FEAT_GUI
6071 	    n = (gui.in_use || gui.starting);
6072 #endif
6073 	}
6074 	else if (STRICMP(name, "browse") == 0)
6075 	{
6076 	    x = TRUE;
6077 #if defined(FEAT_GUI) && defined(FEAT_BROWSE)
6078 	    n = gui.in_use;	// gui_mch_browse() works when GUI is running
6079 #endif
6080 	}
6081 	else if (STRICMP(name, "syntax_items") == 0)
6082 	{
6083 	    x = TRUE;
6084 #ifdef FEAT_SYN_HL
6085 	    n = syntax_present(curwin);
6086 #endif
6087 	}
6088 	else if (STRICMP(name, "vcon") == 0)
6089 	{
6090 	    x = TRUE;
6091 #ifdef FEAT_VTP
6092 	    n = is_term_win32() && has_vtp_working();
6093 #endif
6094 	}
6095 	else if (STRICMP(name, "netbeans_enabled") == 0)
6096 	{
6097 	    x = TRUE;
6098 #ifdef FEAT_NETBEANS_INTG
6099 	    n = netbeans_active();
6100 #endif
6101 	}
6102 	else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6103 	{
6104 	    x = TRUE;
6105 #ifdef FEAT_MOUSE_GPM
6106 	    n = gpm_enabled();
6107 #endif
6108 	}
6109 	else if (STRICMP(name, "conpty") == 0)
6110 	{
6111 	    x = TRUE;
6112 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6113 	    n = use_conpty();
6114 #endif
6115 	}
6116 	else if (STRICMP(name, "clipboard_working") == 0)
6117 	{
6118 	    x = TRUE;
6119 #ifdef FEAT_CLIPBOARD
6120 	    n = clip_star.available;
6121 #endif
6122 	}
6123     }
6124 
6125     if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
6126 	// return whether feature could ever be enabled
6127 	rettv->vval.v_number = x;
6128     else
6129 	// return whether feature is enabled
6130 	rettv->vval.v_number = n;
6131 }
6132 
6133 /*
6134  * Return TRUE if "feature" can change later.
6135  * Also when checking for the feature has side effects, such as loading a DLL.
6136  */
6137     int
dynamic_feature(char_u * feature)6138 dynamic_feature(char_u *feature)
6139 {
6140     return (feature == NULL
6141 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
6142 	    || STRICMP(feature, "balloon_multiline") == 0
6143 #endif
6144 #if defined(FEAT_GUI) && defined(FEAT_BROWSE)
6145 	    || (STRICMP(feature, "browse") == 0 && !gui.in_use)
6146 #endif
6147 #ifdef VIMDLL
6148 	    || STRICMP(feature, "filterpipe") == 0
6149 #endif
6150 #if defined(FEAT_GUI) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL)
6151 	    // this can only change on Unix where the ":gui" command could be
6152 	    // used.
6153 	    || (STRICMP(feature, "gui_running") == 0 && !gui.in_use)
6154 #endif
6155 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6156 	    || STRICMP(feature, "iconv") == 0
6157 #endif
6158 #ifdef DYNAMIC_LUA
6159 	    || STRICMP(feature, "lua") == 0
6160 #endif
6161 #ifdef FEAT_MOUSE_GPM
6162 	    || (STRICMP(feature, "mouse_gpm_enabled") == 0 && !gpm_enabled())
6163 #endif
6164 #ifdef DYNAMIC_MZSCHEME
6165 	    || STRICMP(feature, "mzscheme") == 0
6166 #endif
6167 #ifdef FEAT_NETBEANS_INTG
6168 	    || STRICMP(feature, "netbeans_enabled") == 0
6169 #endif
6170 #ifdef DYNAMIC_PERL
6171 	    || STRICMP(feature, "perl") == 0
6172 #endif
6173 #ifdef DYNAMIC_PYTHON
6174 	    || STRICMP(feature, "python") == 0
6175 #endif
6176 #ifdef DYNAMIC_PYTHON3
6177 	    || STRICMP(feature, "python3") == 0
6178 #endif
6179 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6180 	    || STRICMP(feature, "pythonx") == 0
6181 #endif
6182 #ifdef DYNAMIC_RUBY
6183 	    || STRICMP(feature, "ruby") == 0
6184 #endif
6185 #ifdef FEAT_SYN_HL
6186 	    || STRICMP(feature, "syntax_items") == 0
6187 #endif
6188 #ifdef DYNAMIC_TCL
6189 	    || STRICMP(feature, "tcl") == 0
6190 #endif
6191 	    // once "starting" is zero it will stay that way
6192 	    || (STRICMP(feature, "vim_starting") == 0 && starting != 0)
6193 	    || STRICMP(feature, "multi_byte_encoding") == 0
6194 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6195 	    || STRICMP(feature, "conpty") == 0
6196 #endif
6197 	    );
6198 }
6199 
6200 /*
6201  * "haslocaldir()" function
6202  */
6203     static void
f_haslocaldir(typval_T * argvars,typval_T * rettv)6204 f_haslocaldir(typval_T *argvars, typval_T *rettv)
6205 {
6206     tabpage_T	*tp = NULL;
6207     win_T	*wp = NULL;
6208 
6209     if (in_vim9script()
6210 	    && (check_for_opt_number_arg(argvars, 0) == FAIL
6211 		|| (argvars[0].v_type != VAR_UNKNOWN
6212 		    && check_for_opt_number_arg(argvars, 1) == FAIL)))
6213 	return;
6214 
6215     wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6216 
6217     // Check for window-local and tab-local directories
6218     if (wp != NULL && wp->w_localdir != NULL)
6219 	rettv->vval.v_number = 1;
6220     else if (tp != NULL && tp->tp_localdir != NULL)
6221 	rettv->vval.v_number = 2;
6222     else
6223 	rettv->vval.v_number = 0;
6224 }
6225 
6226 /*
6227  * "hasmapto()" function
6228  */
6229     static void
f_hasmapto(typval_T * argvars,typval_T * rettv)6230 f_hasmapto(typval_T *argvars, typval_T *rettv)
6231 {
6232     char_u	*name;
6233     char_u	*mode;
6234     char_u	buf[NUMBUFLEN];
6235     int		abbr = FALSE;
6236 
6237     if (in_vim9script()
6238 	    && (check_for_string_arg(argvars, 0) == FAIL
6239 		|| check_for_opt_string_arg(argvars, 1) == FAIL
6240 		|| (argvars[1].v_type != VAR_UNKNOWN
6241 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
6242 	return;
6243 
6244     name = tv_get_string(&argvars[0]);
6245     if (argvars[1].v_type == VAR_UNKNOWN)
6246 	mode = (char_u *)"nvo";
6247     else
6248     {
6249 	mode = tv_get_string_buf(&argvars[1], buf);
6250 	if (argvars[2].v_type != VAR_UNKNOWN)
6251 	    abbr = (int)tv_get_bool(&argvars[2]);
6252     }
6253 
6254     if (map_to_exists(name, mode, abbr))
6255 	rettv->vval.v_number = TRUE;
6256     else
6257 	rettv->vval.v_number = FALSE;
6258 }
6259 
6260 /*
6261  * "highlightID(name)" function
6262  */
6263     static void
f_hlID(typval_T * argvars,typval_T * rettv)6264 f_hlID(typval_T *argvars, typval_T *rettv)
6265 {
6266     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6267 	return;
6268 
6269     rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
6270 }
6271 
6272 /*
6273  * "highlight_exists()" function
6274  */
6275     static void
f_hlexists(typval_T * argvars,typval_T * rettv)6276 f_hlexists(typval_T *argvars, typval_T *rettv)
6277 {
6278     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6279 	return;
6280 
6281     rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
6282 }
6283 
6284 /*
6285  * "hostname()" function
6286  */
6287     static void
f_hostname(typval_T * argvars UNUSED,typval_T * rettv)6288 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6289 {
6290     char_u hostname[256];
6291 
6292     mch_get_host_name(hostname, 256);
6293     rettv->v_type = VAR_STRING;
6294     rettv->vval.v_string = vim_strsave(hostname);
6295 }
6296 
6297 /*
6298  * "index()" function
6299  */
6300     static void
f_index(typval_T * argvars,typval_T * rettv)6301 f_index(typval_T *argvars, typval_T *rettv)
6302 {
6303     list_T	*l;
6304     listitem_T	*item;
6305     blob_T	*b;
6306     long	idx = 0;
6307     int		ic = FALSE;
6308     int		error = FALSE;
6309 
6310     rettv->vval.v_number = -1;
6311 
6312     if (in_vim9script()
6313 	    && (check_for_list_or_blob_arg(argvars, 0) == FAIL
6314 		|| (argvars[0].v_type == VAR_BLOB
6315 		    && check_for_number_arg(argvars, 1) == FAIL)
6316 		|| check_for_opt_number_arg(argvars, 2) == FAIL
6317 		|| (argvars[2].v_type != VAR_UNKNOWN
6318 		    && check_for_opt_bool_arg(argvars, 3) == FAIL)))
6319 	return;
6320 
6321     if (argvars[0].v_type == VAR_BLOB)
6322     {
6323 	typval_T	tv;
6324 	int		start = 0;
6325 
6326 	if (argvars[2].v_type != VAR_UNKNOWN)
6327 	{
6328 	    start = tv_get_number_chk(&argvars[2], &error);
6329 	    if (error)
6330 		return;
6331 	}
6332 	b = argvars[0].vval.v_blob;
6333 	if (b == NULL)
6334 	    return;
6335 	if (start < 0)
6336 	{
6337 	    start = blob_len(b) + start;
6338 	    if (start < 0)
6339 		start = 0;
6340 	}
6341 
6342 	for (idx = start; idx < blob_len(b); ++idx)
6343 	{
6344 	    tv.v_type = VAR_NUMBER;
6345 	    tv.vval.v_number = blob_get(b, idx);
6346 	    if (tv_equal(&tv, &argvars[1], ic, FALSE))
6347 	    {
6348 		rettv->vval.v_number = idx;
6349 		return;
6350 	    }
6351 	}
6352 	return;
6353     }
6354     else if (argvars[0].v_type != VAR_LIST)
6355     {
6356 	emsg(_(e_listblobreq));
6357 	return;
6358     }
6359 
6360     l = argvars[0].vval.v_list;
6361     if (l != NULL)
6362     {
6363 	CHECK_LIST_MATERIALIZE(l);
6364 	item = l->lv_first;
6365 	if (argvars[2].v_type != VAR_UNKNOWN)
6366 	{
6367 	    // Start at specified item.  Use the cached index that list_find()
6368 	    // sets, so that a negative number also works.
6369 	    item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
6370 	    idx = l->lv_u.mat.lv_idx;
6371 	    if (argvars[3].v_type != VAR_UNKNOWN)
6372 		ic = (int)tv_get_bool_chk(&argvars[3], &error);
6373 	    if (error)
6374 		item = NULL;
6375 	}
6376 
6377 	for ( ; item != NULL; item = item->li_next, ++idx)
6378 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6379 	    {
6380 		rettv->vval.v_number = idx;
6381 		break;
6382 	    }
6383     }
6384 }
6385 
6386 static int inputsecret_flag = 0;
6387 
6388 /*
6389  * "input()" function
6390  *     Also handles inputsecret() when inputsecret is set.
6391  */
6392     static void
f_input(typval_T * argvars,typval_T * rettv)6393 f_input(typval_T *argvars, typval_T *rettv)
6394 {
6395     get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6396 }
6397 
6398 /*
6399  * "inputdialog()" function
6400  */
6401     static void
f_inputdialog(typval_T * argvars,typval_T * rettv)6402 f_inputdialog(typval_T *argvars, typval_T *rettv)
6403 {
6404 #if defined(FEAT_GUI_TEXTDIALOG)
6405     // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
6406     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6407     {
6408 	char_u	*message;
6409 	char_u	buf[NUMBUFLEN];
6410 	char_u	*defstr = (char_u *)"";
6411 
6412 	if (in_vim9script()
6413 		&& (check_for_string_arg(argvars, 0) == FAIL
6414 		    || check_for_opt_string_arg(argvars, 1) == FAIL
6415 		    || (argvars[1].v_type != VAR_UNKNOWN
6416 			&& check_for_opt_string_arg(argvars, 2) == FAIL)))
6417 	    return;
6418 
6419 	message = tv_get_string_chk(&argvars[0]);
6420 	if (argvars[1].v_type != VAR_UNKNOWN
6421 		&& (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
6422 	    vim_strncpy(IObuff, defstr, IOSIZE - 1);
6423 	else
6424 	    IObuff[0] = NUL;
6425 	if (message != NULL && defstr != NULL
6426 		&& do_dialog(VIM_QUESTION, NULL, message,
6427 			  (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6428 	    rettv->vval.v_string = vim_strsave(IObuff);
6429 	else
6430 	{
6431 	    if (message != NULL && defstr != NULL
6432 					&& argvars[1].v_type != VAR_UNKNOWN
6433 					&& argvars[2].v_type != VAR_UNKNOWN)
6434 		rettv->vval.v_string = vim_strsave(
6435 				      tv_get_string_buf(&argvars[2], buf));
6436 	    else
6437 		rettv->vval.v_string = NULL;
6438 	}
6439 	rettv->v_type = VAR_STRING;
6440     }
6441     else
6442 #endif
6443 	get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6444 }
6445 
6446 /*
6447  * "inputlist()" function
6448  */
6449     static void
f_inputlist(typval_T * argvars,typval_T * rettv)6450 f_inputlist(typval_T *argvars, typval_T *rettv)
6451 {
6452     list_T	*l;
6453     listitem_T	*li;
6454     int		selected;
6455     int		mouse_used;
6456 
6457 #ifdef NO_CONSOLE_INPUT
6458     // While starting up, there is no place to enter text. When running tests
6459     // with --not-a-term we assume feedkeys() will be used.
6460     if (no_console_input() && !is_not_a_term())
6461 	return;
6462 #endif
6463     if (in_vim9script() && check_for_list_arg(argvars, 0) == FAIL)
6464 	return;
6465 
6466     if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6467     {
6468 	semsg(_(e_listarg), "inputlist()");
6469 	return;
6470     }
6471 
6472     msg_start();
6473     msg_row = Rows - 1;	// for when 'cmdheight' > 1
6474     lines_left = Rows;	// avoid more prompt
6475     msg_scroll = TRUE;
6476     msg_clr_eos();
6477 
6478     l = argvars[0].vval.v_list;
6479     CHECK_LIST_MATERIALIZE(l);
6480     FOR_ALL_LIST_ITEMS(l, li)
6481     {
6482 	msg_puts((char *)tv_get_string(&li->li_tv));
6483 	msg_putchar('\n');
6484     }
6485 
6486     // Ask for choice.
6487     selected = prompt_for_number(&mouse_used);
6488     if (mouse_used)
6489 	selected -= lines_left;
6490 
6491     rettv->vval.v_number = selected;
6492 }
6493 
6494 static garray_T	    ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6495 
6496 /*
6497  * "inputrestore()" function
6498  */
6499     static void
f_inputrestore(typval_T * argvars UNUSED,typval_T * rettv)6500 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6501 {
6502     if (ga_userinput.ga_len > 0)
6503     {
6504 	--ga_userinput.ga_len;
6505 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6506 						  + ga_userinput.ga_len, TRUE);
6507 	// default return is zero == OK
6508     }
6509     else if (p_verbose > 1)
6510     {
6511 	verb_msg(_("called inputrestore() more often than inputsave()"));
6512 	rettv->vval.v_number = 1; // Failed
6513     }
6514 }
6515 
6516 /*
6517  * "inputsave()" function
6518  */
6519     static void
f_inputsave(typval_T * argvars UNUSED,typval_T * rettv)6520 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6521 {
6522     // Add an entry to the stack of typeahead storage.
6523     if (ga_grow(&ga_userinput, 1) == OK)
6524     {
6525 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
6526 						       + ga_userinput.ga_len);
6527 	++ga_userinput.ga_len;
6528 	// default return is zero == OK
6529     }
6530     else
6531 	rettv->vval.v_number = 1; // Failed
6532 }
6533 
6534 /*
6535  * "inputsecret()" function
6536  */
6537     static void
f_inputsecret(typval_T * argvars,typval_T * rettv)6538 f_inputsecret(typval_T *argvars, typval_T *rettv)
6539 {
6540     if (in_vim9script()
6541 	    && (check_for_string_arg(argvars, 0) == FAIL
6542 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
6543 	return;
6544 
6545     ++cmdline_star;
6546     ++inputsecret_flag;
6547     f_input(argvars, rettv);
6548     --cmdline_star;
6549     --inputsecret_flag;
6550 }
6551 
6552 /*
6553  * "interrupt()" function
6554  */
6555     static void
f_interrupt(typval_T * argvars UNUSED,typval_T * rettv UNUSED)6556 f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6557 {
6558     got_int = TRUE;
6559 }
6560 
6561 /*
6562  * "invert(expr)" function
6563  */
6564     static void
f_invert(typval_T * argvars,typval_T * rettv)6565 f_invert(typval_T *argvars, typval_T *rettv)
6566 {
6567     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
6568 	return;
6569 
6570     rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
6571 }
6572 
6573 /*
6574  * "islocked()" function
6575  */
6576     static void
f_islocked(typval_T * argvars,typval_T * rettv)6577 f_islocked(typval_T *argvars, typval_T *rettv)
6578 {
6579     lval_T	lv;
6580     char_u	*end;
6581     dictitem_T	*di;
6582 
6583     rettv->vval.v_number = -1;
6584 
6585     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6586 	return;
6587 
6588     end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6589 			     GLV_NO_AUTOLOAD | GLV_READ_ONLY | GLV_NO_DECL,
6590 			     FNE_CHECK_START);
6591     if (end != NULL && lv.ll_name != NULL)
6592     {
6593 	if (*end != NUL)
6594 	{
6595 	    semsg(_(lv.ll_name == lv.ll_name_end
6596 					   ? e_invarg2 : e_trailing_arg), end);
6597 	}
6598 	else
6599 	{
6600 	    if (lv.ll_tv == NULL)
6601 	    {
6602 		di = find_var(lv.ll_name, NULL, TRUE);
6603 		if (di != NULL)
6604 		{
6605 		    // Consider a variable locked when:
6606 		    // 1. the variable itself is locked
6607 		    // 2. the value of the variable is locked.
6608 		    // 3. the List or Dict value is locked.
6609 		    rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6610 						   || tv_islocked(&di->di_tv));
6611 		}
6612 	    }
6613 	    else if (lv.ll_range)
6614 		emsg(_("E786: Range not allowed"));
6615 	    else if (lv.ll_newkey != NULL)
6616 		semsg(_(e_dictkey), lv.ll_newkey);
6617 	    else if (lv.ll_list != NULL)
6618 		// List item.
6619 		rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6620 	    else
6621 		// Dictionary item.
6622 		rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6623 	}
6624     }
6625 
6626     clear_lval(&lv);
6627 }
6628 
6629 /*
6630  * "last_buffer_nr()" function.
6631  */
6632     static void
f_last_buffer_nr(typval_T * argvars UNUSED,typval_T * rettv)6633 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6634 {
6635     int		n = 0;
6636     buf_T	*buf;
6637 
6638     FOR_ALL_BUFFERS(buf)
6639 	if (n < buf->b_fnum)
6640 	    n = buf->b_fnum;
6641 
6642     rettv->vval.v_number = n;
6643 }
6644 
6645 /*
6646  * "len()" function
6647  */
6648     static void
f_len(typval_T * argvars,typval_T * rettv)6649 f_len(typval_T *argvars, typval_T *rettv)
6650 {
6651     switch (argvars[0].v_type)
6652     {
6653 	case VAR_STRING:
6654 	case VAR_NUMBER:
6655 	    rettv->vval.v_number = (varnumber_T)STRLEN(
6656 					       tv_get_string(&argvars[0]));
6657 	    break;
6658 	case VAR_BLOB:
6659 	    rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6660 	    break;
6661 	case VAR_LIST:
6662 	    rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6663 	    break;
6664 	case VAR_DICT:
6665 	    rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6666 	    break;
6667 	case VAR_UNKNOWN:
6668 	case VAR_ANY:
6669 	case VAR_VOID:
6670 	case VAR_BOOL:
6671 	case VAR_SPECIAL:
6672 	case VAR_FLOAT:
6673 	case VAR_FUNC:
6674 	case VAR_PARTIAL:
6675 	case VAR_JOB:
6676 	case VAR_CHANNEL:
6677 	case VAR_INSTR:
6678 	    emsg(_("E701: Invalid type for len()"));
6679 	    break;
6680     }
6681 }
6682 
6683     static void
libcall_common(typval_T * argvars UNUSED,typval_T * rettv,int type)6684 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
6685 {
6686 #ifdef FEAT_LIBCALL
6687     char_u		*string_in;
6688     char_u		**string_result;
6689     int			nr_result;
6690 #endif
6691 
6692     rettv->v_type = type;
6693     if (type != VAR_NUMBER)
6694 	rettv->vval.v_string = NULL;
6695 
6696     if (check_restricted() || check_secure())
6697 	return;
6698 
6699     if (in_vim9script()
6700 	    && (check_for_string_arg(argvars, 0) == FAIL
6701 		|| check_for_string_arg(argvars, 1) == FAIL
6702 		|| check_for_string_or_number_arg(argvars, 2) == FAIL))
6703 	return;
6704 
6705 #ifdef FEAT_LIBCALL
6706     // The first two args must be strings, otherwise it's meaningless
6707     if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6708     {
6709 	string_in = NULL;
6710 	if (argvars[2].v_type == VAR_STRING)
6711 	    string_in = argvars[2].vval.v_string;
6712 	if (type == VAR_NUMBER)
6713 	{
6714 	    string_result = NULL;
6715 	}
6716 	else
6717 	{
6718 	    rettv->vval.v_string = NULL;
6719 	    string_result = &rettv->vval.v_string;
6720 	}
6721 	if (mch_libcall(argvars[0].vval.v_string,
6722 			     argvars[1].vval.v_string,
6723 			     string_in,
6724 			     argvars[2].vval.v_number,
6725 			     string_result,
6726 			     &nr_result) == OK
6727 		&& type == VAR_NUMBER)
6728 	    rettv->vval.v_number = nr_result;
6729     }
6730 #endif
6731 }
6732 
6733 /*
6734  * "libcall()" function
6735  */
6736     static void
f_libcall(typval_T * argvars,typval_T * rettv)6737 f_libcall(typval_T *argvars, typval_T *rettv)
6738 {
6739     libcall_common(argvars, rettv, VAR_STRING);
6740 }
6741 
6742 /*
6743  * "libcallnr()" function
6744  */
6745     static void
f_libcallnr(typval_T * argvars,typval_T * rettv)6746 f_libcallnr(typval_T *argvars, typval_T *rettv)
6747 {
6748     libcall_common(argvars, rettv, VAR_NUMBER);
6749 }
6750 
6751 /*
6752  * "line(string, [winid])" function
6753  */
6754     static void
f_line(typval_T * argvars,typval_T * rettv)6755 f_line(typval_T *argvars, typval_T *rettv)
6756 {
6757     linenr_T	lnum = 0;
6758     pos_T	*fp = NULL;
6759     int		fnum;
6760     int		id;
6761     tabpage_T	*tp;
6762     win_T	*wp;
6763     win_T	*save_curwin;
6764     tabpage_T	*save_curtab;
6765 
6766     if (in_vim9script()
6767 	    && (check_for_string_arg(argvars, 0) == FAIL
6768 		|| check_for_opt_number_arg(argvars, 1) == FAIL))
6769 	return;
6770 
6771     if (argvars[1].v_type != VAR_UNKNOWN)
6772     {
6773 	// use window specified in the second argument
6774 	id = (int)tv_get_number(&argvars[1]);
6775 	wp = win_id2wp_tp(id, &tp);
6776 	if (wp != NULL && tp != NULL)
6777 	{
6778 	    if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
6779 									 == OK)
6780 	    {
6781 		check_cursor();
6782 		fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
6783 	    }
6784 	    restore_win_noblock(save_curwin, save_curtab, TRUE);
6785 	}
6786     }
6787     else
6788 	// use current window
6789 	fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
6790 
6791     if (fp != NULL)
6792 	lnum = fp->lnum;
6793     rettv->vval.v_number = lnum;
6794 }
6795 
6796 /*
6797  * "line2byte(lnum)" function
6798  */
6799     static void
f_line2byte(typval_T * argvars UNUSED,typval_T * rettv)6800 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6801 {
6802 #ifndef FEAT_BYTEOFF
6803     rettv->vval.v_number = -1;
6804 #else
6805     linenr_T	lnum;
6806 
6807     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
6808 	return;
6809 
6810     lnum = tv_get_lnum(argvars);
6811     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6812 	rettv->vval.v_number = -1;
6813     else
6814 	rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6815     if (rettv->vval.v_number >= 0)
6816 	++rettv->vval.v_number;
6817 #endif
6818 }
6819 
6820 #ifdef FEAT_LUA
6821 /*
6822  * "luaeval()" function
6823  */
6824     static void
f_luaeval(typval_T * argvars,typval_T * rettv)6825 f_luaeval(typval_T *argvars, typval_T *rettv)
6826 {
6827     char_u	*str;
6828     char_u	buf[NUMBUFLEN];
6829 
6830     if (check_restricted() || check_secure())
6831 	return;
6832 
6833     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
6834 	return;
6835 
6836     str = tv_get_string_buf(&argvars[0], buf);
6837     do_luaeval(str, argvars + 1, rettv);
6838 }
6839 #endif
6840 
6841 typedef enum
6842 {
6843     MATCH_END,	    // matchend()
6844     MATCH_MATCH,    // match()
6845     MATCH_STR,	    // matchstr()
6846     MATCH_LIST,	    // matchlist()
6847     MATCH_POS	    // matchstrpos()
6848 } matchtype_T;
6849 
6850     static void
find_some_match(typval_T * argvars,typval_T * rettv,matchtype_T type)6851 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
6852 {
6853     char_u	*str = NULL;
6854     long	len = 0;
6855     char_u	*expr = NULL;
6856     char_u	*pat;
6857     regmatch_T	regmatch;
6858     char_u	patbuf[NUMBUFLEN];
6859     char_u	strbuf[NUMBUFLEN];
6860     char_u	*save_cpo;
6861     long	start = 0;
6862     long	nth = 1;
6863     colnr_T	startcol = 0;
6864     int		match = 0;
6865     list_T	*l = NULL;
6866     listitem_T	*li = NULL;
6867     long	idx = 0;
6868     char_u	*tofree = NULL;
6869 
6870     // Make 'cpoptions' empty, the 'l' flag should not be used here.
6871     save_cpo = p_cpo;
6872     p_cpo = empty_option;
6873 
6874     rettv->vval.v_number = -1;
6875     if (type == MATCH_LIST || type == MATCH_POS)
6876     {
6877 	// type MATCH_LIST: return empty list when there are no matches.
6878 	// type MATCH_POS: return ["", -1, -1, -1]
6879 	if (rettv_list_alloc(rettv) == FAIL)
6880 	    goto theend;
6881 	if (type == MATCH_POS
6882 		&& (list_append_string(rettv->vval.v_list,
6883 					    (char_u *)"", 0) == FAIL
6884 		    || list_append_number(rettv->vval.v_list,
6885 					    (varnumber_T)-1) == FAIL
6886 		    || list_append_number(rettv->vval.v_list,
6887 					    (varnumber_T)-1) == FAIL
6888 		    || list_append_number(rettv->vval.v_list,
6889 					    (varnumber_T)-1) == FAIL))
6890 	{
6891 		list_free(rettv->vval.v_list);
6892 		rettv->vval.v_list = NULL;
6893 		goto theend;
6894 	}
6895     }
6896     else if (type == MATCH_STR)
6897     {
6898 	rettv->v_type = VAR_STRING;
6899 	rettv->vval.v_string = NULL;
6900     }
6901 
6902     if (in_vim9script()
6903 	    && (check_for_string_or_list_arg(argvars, 0) == FAIL
6904 		|| check_for_string_arg(argvars, 1) == FAIL
6905 		|| check_for_opt_number_arg(argvars, 2) == FAIL
6906 		|| (argvars[2].v_type != VAR_UNKNOWN
6907 		    && check_for_opt_number_arg(argvars, 3) == FAIL)))
6908 	goto theend;
6909 
6910     if (argvars[0].v_type == VAR_LIST)
6911     {
6912 	if ((l = argvars[0].vval.v_list) == NULL)
6913 	    goto theend;
6914 	CHECK_LIST_MATERIALIZE(l);
6915 	li = l->lv_first;
6916     }
6917     else
6918     {
6919 	expr = str = tv_get_string(&argvars[0]);
6920 	len = (long)STRLEN(str);
6921     }
6922 
6923     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
6924     if (pat == NULL)
6925 	goto theend;
6926 
6927     if (argvars[2].v_type != VAR_UNKNOWN)
6928     {
6929 	int	    error = FALSE;
6930 
6931 	start = (long)tv_get_number_chk(&argvars[2], &error);
6932 	if (error)
6933 	    goto theend;
6934 	if (l != NULL)
6935 	{
6936 	    li = list_find(l, start);
6937 	    if (li == NULL)
6938 		goto theend;
6939 	    idx = l->lv_u.mat.lv_idx;	// use the cached index
6940 	}
6941 	else
6942 	{
6943 	    if (start < 0)
6944 		start = 0;
6945 	    if (start > len)
6946 		goto theend;
6947 	    // When "count" argument is there ignore matches before "start",
6948 	    // otherwise skip part of the string.  Differs when pattern is "^"
6949 	    // or "\<".
6950 	    if (argvars[3].v_type != VAR_UNKNOWN)
6951 		startcol = start;
6952 	    else
6953 	    {
6954 		str += start;
6955 		len -= start;
6956 	    }
6957 	}
6958 
6959 	if (argvars[3].v_type != VAR_UNKNOWN)
6960 	    nth = (long)tv_get_number_chk(&argvars[3], &error);
6961 	if (error)
6962 	    goto theend;
6963     }
6964 
6965     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6966     if (regmatch.regprog != NULL)
6967     {
6968 	regmatch.rm_ic = p_ic;
6969 
6970 	for (;;)
6971 	{
6972 	    if (l != NULL)
6973 	    {
6974 		if (li == NULL)
6975 		{
6976 		    match = FALSE;
6977 		    break;
6978 		}
6979 		vim_free(tofree);
6980 		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6981 		if (str == NULL)
6982 		    break;
6983 	    }
6984 
6985 	    match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6986 
6987 	    if (match && --nth <= 0)
6988 		break;
6989 	    if (l == NULL && !match)
6990 		break;
6991 
6992 	    // Advance to just after the match.
6993 	    if (l != NULL)
6994 	    {
6995 		li = li->li_next;
6996 		++idx;
6997 	    }
6998 	    else
6999 	    {
7000 		startcol = (colnr_T)(regmatch.startp[0]
7001 				    + (*mb_ptr2len)(regmatch.startp[0]) - str);
7002 		if (startcol > (colnr_T)len
7003 				      || str + startcol <= regmatch.startp[0])
7004 		{
7005 		    match = FALSE;
7006 		    break;
7007 		}
7008 	    }
7009 	}
7010 
7011 	if (match)
7012 	{
7013 	    if (type == MATCH_POS)
7014 	    {
7015 		listitem_T *li1 = rettv->vval.v_list->lv_first;
7016 		listitem_T *li2 = li1->li_next;
7017 		listitem_T *li3 = li2->li_next;
7018 		listitem_T *li4 = li3->li_next;
7019 
7020 		vim_free(li1->li_tv.vval.v_string);
7021 		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7022 					regmatch.endp[0] - regmatch.startp[0]);
7023 		li3->li_tv.vval.v_number =
7024 				      (varnumber_T)(regmatch.startp[0] - expr);
7025 		li4->li_tv.vval.v_number =
7026 					(varnumber_T)(regmatch.endp[0] - expr);
7027 		if (l != NULL)
7028 		    li2->li_tv.vval.v_number = (varnumber_T)idx;
7029 	    }
7030 	    else if (type == MATCH_LIST)
7031 	    {
7032 		int i;
7033 
7034 		// return list with matched string and submatches
7035 		for (i = 0; i < NSUBEXP; ++i)
7036 		{
7037 		    if (regmatch.endp[i] == NULL)
7038 		    {
7039 			if (list_append_string(rettv->vval.v_list,
7040 						     (char_u *)"", 0) == FAIL)
7041 			    break;
7042 		    }
7043 		    else if (list_append_string(rettv->vval.v_list,
7044 				regmatch.startp[i],
7045 				(int)(regmatch.endp[i] - regmatch.startp[i]))
7046 			    == FAIL)
7047 			break;
7048 		}
7049 	    }
7050 	    else if (type == MATCH_STR)
7051 	    {
7052 		// return matched string
7053 		if (l != NULL)
7054 		    copy_tv(&li->li_tv, rettv);
7055 		else
7056 		    rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7057 					regmatch.endp[0] - regmatch.startp[0]);
7058 	    }
7059 	    else if (l != NULL)
7060 		rettv->vval.v_number = idx;
7061 	    else
7062 	    {
7063 		if (type != MATCH_END)
7064 		    rettv->vval.v_number =
7065 				      (varnumber_T)(regmatch.startp[0] - str);
7066 		else
7067 		    rettv->vval.v_number =
7068 					(varnumber_T)(regmatch.endp[0] - str);
7069 		rettv->vval.v_number += (varnumber_T)(str - expr);
7070 	    }
7071 	}
7072 	vim_regfree(regmatch.regprog);
7073     }
7074 
7075 theend:
7076     if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
7077 	// matchstrpos() without a list: drop the second item.
7078 	listitem_remove(rettv->vval.v_list,
7079 				       rettv->vval.v_list->lv_first->li_next);
7080     vim_free(tofree);
7081     p_cpo = save_cpo;
7082 }
7083 
7084 /*
7085  * "match()" function
7086  */
7087     static void
f_match(typval_T * argvars,typval_T * rettv)7088 f_match(typval_T *argvars, typval_T *rettv)
7089 {
7090     find_some_match(argvars, rettv, MATCH_MATCH);
7091 }
7092 
7093 /*
7094  * "matchend()" function
7095  */
7096     static void
f_matchend(typval_T * argvars,typval_T * rettv)7097 f_matchend(typval_T *argvars, typval_T *rettv)
7098 {
7099     find_some_match(argvars, rettv, MATCH_END);
7100 }
7101 
7102 /*
7103  * "matchlist()" function
7104  */
7105     static void
f_matchlist(typval_T * argvars,typval_T * rettv)7106 f_matchlist(typval_T *argvars, typval_T *rettv)
7107 {
7108     find_some_match(argvars, rettv, MATCH_LIST);
7109 }
7110 
7111 /*
7112  * "matchstr()" function
7113  */
7114     static void
f_matchstr(typval_T * argvars,typval_T * rettv)7115 f_matchstr(typval_T *argvars, typval_T *rettv)
7116 {
7117     find_some_match(argvars, rettv, MATCH_STR);
7118 }
7119 
7120 /*
7121  * "matchstrpos()" function
7122  */
7123     static void
f_matchstrpos(typval_T * argvars,typval_T * rettv)7124 f_matchstrpos(typval_T *argvars, typval_T *rettv)
7125 {
7126     find_some_match(argvars, rettv, MATCH_POS);
7127 }
7128 
7129     static void
max_min(typval_T * argvars,typval_T * rettv,int domax)7130 max_min(typval_T *argvars, typval_T *rettv, int domax)
7131 {
7132     varnumber_T	n = 0;
7133     varnumber_T	i;
7134     int		error = FALSE;
7135 
7136     if (in_vim9script() && check_for_list_or_dict_arg(argvars, 0) == FAIL)
7137 	return;
7138 
7139     if (argvars[0].v_type == VAR_LIST)
7140     {
7141 	list_T		*l;
7142 	listitem_T	*li;
7143 
7144 	l = argvars[0].vval.v_list;
7145 	if (l != NULL && l->lv_len > 0)
7146 	{
7147 	    if (l->lv_first == &range_list_item)
7148 	    {
7149 		if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
7150 		    n = l->lv_u.nonmat.lv_start;
7151 		else
7152 		    n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
7153 						    * l->lv_u.nonmat.lv_stride;
7154 	    }
7155 	    else
7156 	    {
7157 		li = l->lv_first;
7158 		if (li != NULL)
7159 		{
7160 		    n = tv_get_number_chk(&li->li_tv, &error);
7161 		    if (error)
7162 			return; // type error; errmsg already given
7163 		    for (;;)
7164 		    {
7165 			li = li->li_next;
7166 			if (li == NULL)
7167 			    break;
7168 			i = tv_get_number_chk(&li->li_tv, &error);
7169 			if (error)
7170 			    return; // type error; errmsg already given
7171 			if (domax ? i > n : i < n)
7172 			    n = i;
7173 		    }
7174 		}
7175 	    }
7176 	}
7177     }
7178     else if (argvars[0].v_type == VAR_DICT)
7179     {
7180 	dict_T		*d;
7181 	int		first = TRUE;
7182 	hashitem_T	*hi;
7183 	int		todo;
7184 
7185 	d = argvars[0].vval.v_dict;
7186 	if (d != NULL)
7187 	{
7188 	    todo = (int)d->dv_hashtab.ht_used;
7189 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7190 	    {
7191 		if (!HASHITEM_EMPTY(hi))
7192 		{
7193 		    --todo;
7194 		    i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
7195 		    if (error)
7196 			return; // type error; errmsg already given
7197 		    if (first)
7198 		    {
7199 			n = i;
7200 			first = FALSE;
7201 		    }
7202 		    else if (domax ? i > n : i < n)
7203 			n = i;
7204 		}
7205 	    }
7206 	}
7207     }
7208     else
7209 	semsg(_(e_listdictarg), domax ? "max()" : "min()");
7210 
7211     rettv->vval.v_number = n;
7212 }
7213 
7214 /*
7215  * "max()" function
7216  */
7217     static void
f_max(typval_T * argvars,typval_T * rettv)7218 f_max(typval_T *argvars, typval_T *rettv)
7219 {
7220     max_min(argvars, rettv, TRUE);
7221 }
7222 
7223 /*
7224  * "min()" function
7225  */
7226     static void
f_min(typval_T * argvars,typval_T * rettv)7227 f_min(typval_T *argvars, typval_T *rettv)
7228 {
7229     max_min(argvars, rettv, FALSE);
7230 }
7231 
7232 #if defined(FEAT_MZSCHEME) || defined(PROTO)
7233 /*
7234  * "mzeval()" function
7235  */
7236     static void
f_mzeval(typval_T * argvars,typval_T * rettv)7237 f_mzeval(typval_T *argvars, typval_T *rettv)
7238 {
7239     char_u	*str;
7240     char_u	buf[NUMBUFLEN];
7241 
7242     if (check_restricted() || check_secure())
7243 	return;
7244 
7245     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7246 	return;
7247 
7248     str = tv_get_string_buf(&argvars[0], buf);
7249     do_mzeval(str, rettv);
7250 }
7251 
7252     void
mzscheme_call_vim(char_u * name,typval_T * args,typval_T * rettv)7253 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7254 {
7255     typval_T argvars[3];
7256 
7257     argvars[0].v_type = VAR_STRING;
7258     argvars[0].vval.v_string = name;
7259     copy_tv(args, &argvars[1]);
7260     argvars[2].v_type = VAR_UNKNOWN;
7261     f_call(argvars, rettv);
7262     clear_tv(&argvars[1]);
7263 }
7264 #endif
7265 
7266 /*
7267  * "nextnonblank()" function
7268  */
7269     static void
f_nextnonblank(typval_T * argvars,typval_T * rettv)7270 f_nextnonblank(typval_T *argvars, typval_T *rettv)
7271 {
7272     linenr_T	lnum;
7273 
7274     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
7275 	return;
7276 
7277     for (lnum = tv_get_lnum(argvars); ; ++lnum)
7278     {
7279 	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7280 	{
7281 	    lnum = 0;
7282 	    break;
7283 	}
7284 	if (*skipwhite(ml_get(lnum)) != NUL)
7285 	    break;
7286     }
7287     rettv->vval.v_number = lnum;
7288 }
7289 
7290 /*
7291  * "nr2char()" function
7292  */
7293     static void
f_nr2char(typval_T * argvars,typval_T * rettv)7294 f_nr2char(typval_T *argvars, typval_T *rettv)
7295 {
7296     char_u	buf[NUMBUFLEN];
7297 
7298     if (in_vim9script()
7299 	    && (check_for_number_arg(argvars, 0) == FAIL
7300 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
7301 	return;
7302 
7303     if (has_mbyte)
7304     {
7305 	int	utf8 = 0;
7306 
7307 	if (argvars[1].v_type != VAR_UNKNOWN)
7308 	    utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
7309 	if (utf8)
7310 	    buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
7311 	else
7312 	    buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
7313     }
7314     else
7315     {
7316 	buf[0] = (char_u)tv_get_number(&argvars[0]);
7317 	buf[1] = NUL;
7318     }
7319     rettv->v_type = VAR_STRING;
7320     rettv->vval.v_string = vim_strsave(buf);
7321 }
7322 
7323 /*
7324  * "or(expr, expr)" function
7325  */
7326     static void
f_or(typval_T * argvars,typval_T * rettv)7327 f_or(typval_T *argvars, typval_T *rettv)
7328 {
7329     if (in_vim9script()
7330 	    && (check_for_number_arg(argvars, 0) == FAIL
7331 		|| check_for_number_arg(argvars, 1) == FAIL))
7332 	return;
7333 
7334     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7335 					| tv_get_number_chk(&argvars[1], NULL);
7336 }
7337 
7338 #ifdef FEAT_PERL
7339 /*
7340  * "perleval()" function
7341  */
7342     static void
f_perleval(typval_T * argvars,typval_T * rettv)7343 f_perleval(typval_T *argvars, typval_T *rettv)
7344 {
7345     char_u	*str;
7346     char_u	buf[NUMBUFLEN];
7347 
7348     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7349 	return;
7350 
7351     str = tv_get_string_buf(&argvars[0], buf);
7352     do_perleval(str, rettv);
7353 }
7354 #endif
7355 
7356 /*
7357  * "prevnonblank()" function
7358  */
7359     static void
f_prevnonblank(typval_T * argvars,typval_T * rettv)7360 f_prevnonblank(typval_T *argvars, typval_T *rettv)
7361 {
7362     linenr_T	lnum;
7363 
7364     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
7365 	return;
7366 
7367     lnum = tv_get_lnum(argvars);
7368     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7369 	lnum = 0;
7370     else
7371 	while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7372 	    --lnum;
7373     rettv->vval.v_number = lnum;
7374 }
7375 
7376 // This dummy va_list is here because:
7377 // - passing a NULL pointer doesn't work when va_list isn't a pointer
7378 // - locally in the function results in a "used before set" warning
7379 // - using va_start() to initialize it gives "function with fixed args" error
7380 static va_list	ap;
7381 
7382 /*
7383  * "printf()" function
7384  */
7385     static void
f_printf(typval_T * argvars,typval_T * rettv)7386 f_printf(typval_T *argvars, typval_T *rettv)
7387 {
7388     char_u	buf[NUMBUFLEN];
7389     int		len;
7390     char_u	*s;
7391     int		saved_did_emsg = did_emsg;
7392     char	*fmt;
7393 
7394     rettv->v_type = VAR_STRING;
7395     rettv->vval.v_string = NULL;
7396 
7397     if (in_vim9script() && check_for_string_or_number_arg(argvars, 0) == FAIL)
7398 	return;
7399 
7400     // Get the required length, allocate the buffer and do it for real.
7401     did_emsg = FALSE;
7402     fmt = (char *)tv_get_string_buf(&argvars[0], buf);
7403     len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
7404     if (!did_emsg)
7405     {
7406 	s = alloc(len + 1);
7407 	if (s != NULL)
7408 	{
7409 	    rettv->vval.v_string = s;
7410 	    (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7411 							      ap, argvars + 1);
7412 	}
7413     }
7414     did_emsg |= saved_did_emsg;
7415 }
7416 
7417 /*
7418  * "pum_getpos()" function
7419  */
7420     static void
f_pum_getpos(typval_T * argvars UNUSED,typval_T * rettv UNUSED)7421 f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7422 {
7423     if (rettv_dict_alloc(rettv) != OK)
7424 	return;
7425     pum_set_event_info(rettv->vval.v_dict);
7426 }
7427 
7428 /*
7429  * "pumvisible()" function
7430  */
7431     static void
f_pumvisible(typval_T * argvars UNUSED,typval_T * rettv UNUSED)7432 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7433 {
7434     if (pum_visible())
7435 	rettv->vval.v_number = 1;
7436 }
7437 
7438 #ifdef FEAT_PYTHON3
7439 /*
7440  * "py3eval()" function
7441  */
7442     static void
f_py3eval(typval_T * argvars,typval_T * rettv)7443 f_py3eval(typval_T *argvars, typval_T *rettv)
7444 {
7445     char_u	*str;
7446     char_u	buf[NUMBUFLEN];
7447 
7448     if (check_restricted() || check_secure())
7449 	return;
7450 
7451     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7452 	return;
7453 
7454     if (p_pyx == 0)
7455 	p_pyx = 3;
7456 
7457     str = tv_get_string_buf(&argvars[0], buf);
7458     do_py3eval(str, rettv);
7459 }
7460 #endif
7461 
7462 #ifdef FEAT_PYTHON
7463 /*
7464  * "pyeval()" function
7465  */
7466     static void
f_pyeval(typval_T * argvars,typval_T * rettv)7467 f_pyeval(typval_T *argvars, typval_T *rettv)
7468 {
7469     char_u	*str;
7470     char_u	buf[NUMBUFLEN];
7471 
7472     if (check_restricted() || check_secure())
7473 	return;
7474 
7475     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7476 	return;
7477 
7478     if (p_pyx == 0)
7479 	p_pyx = 2;
7480 
7481     str = tv_get_string_buf(&argvars[0], buf);
7482     do_pyeval(str, rettv);
7483 }
7484 #endif
7485 
7486 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7487 /*
7488  * "pyxeval()" function
7489  */
7490     static void
f_pyxeval(typval_T * argvars,typval_T * rettv)7491 f_pyxeval(typval_T *argvars, typval_T *rettv)
7492 {
7493     if (check_restricted() || check_secure())
7494 	return;
7495 
7496     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
7497 	return;
7498 
7499 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7500     init_pyxversion();
7501     if (p_pyx == 2)
7502 	f_pyeval(argvars, rettv);
7503     else
7504 	f_py3eval(argvars, rettv);
7505 # elif defined(FEAT_PYTHON)
7506     f_pyeval(argvars, rettv);
7507 # elif defined(FEAT_PYTHON3)
7508     f_py3eval(argvars, rettv);
7509 # endif
7510 }
7511 #endif
7512 
7513 static UINT32_T srand_seed_for_testing = 0;
7514 static int	srand_seed_for_testing_is_used = FALSE;
7515 
7516     static void
f_test_srand_seed(typval_T * argvars,typval_T * rettv UNUSED)7517 f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
7518 {
7519     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
7520 	return;
7521 
7522     if (argvars[0].v_type == VAR_UNKNOWN)
7523 	srand_seed_for_testing_is_used = FALSE;
7524     else
7525     {
7526 	srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
7527 	srand_seed_for_testing_is_used = TRUE;
7528     }
7529 }
7530 
7531     static void
init_srand(UINT32_T * x)7532 init_srand(UINT32_T *x)
7533 {
7534 #ifndef MSWIN
7535     static int dev_urandom_state = NOTDONE;  // FAIL or OK once tried
7536 #endif
7537 
7538     if (srand_seed_for_testing_is_used)
7539     {
7540 	*x = srand_seed_for_testing;
7541 	return;
7542     }
7543 #ifndef MSWIN
7544     if (dev_urandom_state != FAIL)
7545     {
7546 	int  fd = open("/dev/urandom", O_RDONLY);
7547 	struct {
7548 	    union {
7549 		UINT32_T number;
7550 		char     bytes[sizeof(UINT32_T)];
7551 	    } contents;
7552 	} buf;
7553 
7554 	// Attempt reading /dev/urandom.
7555 	if (fd == -1)
7556 	    dev_urandom_state = FAIL;
7557 	else
7558 	{
7559 	    buf.contents.number = 0;
7560 	    if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
7561 							   != sizeof(UINT32_T))
7562 		dev_urandom_state = FAIL;
7563 	    else
7564 	    {
7565 		dev_urandom_state = OK;
7566 		*x = buf.contents.number;
7567 	    }
7568 	    close(fd);
7569 	}
7570     }
7571     if (dev_urandom_state != OK)
7572 	// Reading /dev/urandom doesn't work, fall back to time().
7573 #endif
7574 	*x = vim_time();
7575 }
7576 
7577 #define ROTL(x, k) ((x << k) | (x >> (32 - k)))
7578 #define SPLITMIX32(x, z) ( \
7579     z = (x += 0x9e3779b9), \
7580     z = (z ^ (z >> 16)) * 0x85ebca6b, \
7581     z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7582     z ^ (z >> 16) \
7583     )
7584 #define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
7585     result = ROTL(y * 5, 7) * 9; \
7586     t = y << 9; \
7587     z ^= x; \
7588     w ^= y; \
7589     y ^= z, x ^= w; \
7590     z ^= t; \
7591     w = ROTL(w, 11);
7592 
7593 /*
7594  * "rand()" function
7595  */
7596     static void
f_rand(typval_T * argvars,typval_T * rettv)7597 f_rand(typval_T *argvars, typval_T *rettv)
7598 {
7599     list_T	*l = NULL;
7600     static UINT32_T	gx, gy, gz, gw;
7601     static int	initialized = FALSE;
7602     listitem_T	*lx, *ly, *lz, *lw;
7603     UINT32_T	x = 0, y, z, w, t, result;
7604 
7605     if (in_vim9script() && check_for_opt_list_arg(argvars, 0) == FAIL)
7606 	return;
7607 
7608     if (argvars[0].v_type == VAR_UNKNOWN)
7609     {
7610 	// When no argument is given use the global seed list.
7611 	if (initialized == FALSE)
7612 	{
7613 	    // Initialize the global seed list.
7614 	    init_srand(&x);
7615 
7616 	    gx = SPLITMIX32(x, z);
7617 	    gy = SPLITMIX32(x, z);
7618 	    gz = SPLITMIX32(x, z);
7619 	    gw = SPLITMIX32(x, z);
7620 	    initialized = TRUE;
7621 	}
7622 
7623 	SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
7624     }
7625     else if (argvars[0].v_type == VAR_LIST)
7626     {
7627 	l = argvars[0].vval.v_list;
7628 	if (l == NULL || list_len(l) != 4)
7629 	    goto theend;
7630 
7631 	lx = list_find(l, 0L);
7632 	ly = list_find(l, 1L);
7633 	lz = list_find(l, 2L);
7634 	lw = list_find(l, 3L);
7635 	if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
7636 	if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
7637 	if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
7638 	if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
7639 	x = (UINT32_T)lx->li_tv.vval.v_number;
7640 	y = (UINT32_T)ly->li_tv.vval.v_number;
7641 	z = (UINT32_T)lz->li_tv.vval.v_number;
7642 	w = (UINT32_T)lw->li_tv.vval.v_number;
7643 
7644 	SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
7645 
7646 	lx->li_tv.vval.v_number = (varnumber_T)x;
7647 	ly->li_tv.vval.v_number = (varnumber_T)y;
7648 	lz->li_tv.vval.v_number = (varnumber_T)z;
7649 	lw->li_tv.vval.v_number = (varnumber_T)w;
7650     }
7651     else
7652 	goto theend;
7653 
7654     rettv->v_type = VAR_NUMBER;
7655     rettv->vval.v_number = (varnumber_T)result;
7656     return;
7657 
7658 theend:
7659     semsg(_(e_invarg2), tv_get_string(&argvars[0]));
7660     rettv->v_type = VAR_NUMBER;
7661     rettv->vval.v_number = -1;
7662 }
7663 
7664 /*
7665  * "srand()" function
7666  */
7667     static void
f_srand(typval_T * argvars,typval_T * rettv)7668 f_srand(typval_T *argvars, typval_T *rettv)
7669 {
7670     UINT32_T x = 0, z;
7671 
7672     if (rettv_list_alloc(rettv) == FAIL)
7673 	return;
7674 
7675     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
7676 	return;
7677 
7678     if (argvars[0].v_type == VAR_UNKNOWN)
7679     {
7680 	init_srand(&x);
7681     }
7682     else
7683     {
7684 	int	    error = FALSE;
7685 
7686 	x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
7687 	if (error)
7688 	    return;
7689     }
7690 
7691     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7692     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7693     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7694     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7695 }
7696 
7697 #undef ROTL
7698 #undef SPLITMIX32
7699 #undef SHUFFLE_XOSHIRO128STARSTAR
7700 
7701 /*
7702  * "range()" function
7703  */
7704     static void
f_range(typval_T * argvars,typval_T * rettv)7705 f_range(typval_T *argvars, typval_T *rettv)
7706 {
7707     varnumber_T	start;
7708     varnumber_T	end;
7709     varnumber_T	stride = 1;
7710     int		error = FALSE;
7711 
7712     if (in_vim9script()
7713 	    && (check_for_number_arg(argvars, 0) == FAIL
7714 		|| check_for_opt_number_arg(argvars, 1) == FAIL
7715 		|| (argvars[1].v_type != VAR_UNKNOWN
7716 		    && check_for_opt_number_arg(argvars, 2) == FAIL)))
7717 	return;
7718 
7719     start = tv_get_number_chk(&argvars[0], &error);
7720     if (argvars[1].v_type == VAR_UNKNOWN)
7721     {
7722 	end = start - 1;
7723 	start = 0;
7724     }
7725     else
7726     {
7727 	end = tv_get_number_chk(&argvars[1], &error);
7728 	if (argvars[2].v_type != VAR_UNKNOWN)
7729 	    stride = tv_get_number_chk(&argvars[2], &error);
7730     }
7731 
7732     if (error)
7733 	return;		// type error; errmsg already given
7734     if (stride == 0)
7735 	emsg(_("E726: Stride is zero"));
7736     else if (stride > 0 ? end + 1 < start : end - 1 > start)
7737 	emsg(_("E727: Start past end"));
7738     else if (rettv_list_alloc(rettv) == OK)
7739     {
7740 	list_T *list = rettv->vval.v_list;
7741 
7742 	// Create a non-materialized list.  This is much more efficient and
7743 	// works with ":for".  If used otherwise CHECK_LIST_MATERIALIZE() must
7744 	// be called.
7745 	list->lv_first = &range_list_item;
7746 	list->lv_u.nonmat.lv_start = start;
7747 	list->lv_u.nonmat.lv_end = end;
7748 	list->lv_u.nonmat.lv_stride = stride;
7749 	list->lv_len = (end - start) / stride + 1;
7750     }
7751 }
7752 
7753 /*
7754  * Materialize "list".
7755  * Do not call directly, use CHECK_LIST_MATERIALIZE()
7756  */
7757     void
range_list_materialize(list_T * list)7758 range_list_materialize(list_T *list)
7759 {
7760     varnumber_T start = list->lv_u.nonmat.lv_start;
7761     varnumber_T end = list->lv_u.nonmat.lv_end;
7762     int	    stride = list->lv_u.nonmat.lv_stride;
7763     varnumber_T i;
7764 
7765     list->lv_first = NULL;
7766     list->lv_u.mat.lv_last = NULL;
7767     list->lv_len = 0;
7768     list->lv_u.mat.lv_idx_item = NULL;
7769     for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7770 	if (list_append_number(list, (varnumber_T)i) == FAIL)
7771 	    break;
7772 }
7773 
7774 /*
7775  * "getreginfo()" function
7776  */
7777     static void
f_getreginfo(typval_T * argvars,typval_T * rettv)7778 f_getreginfo(typval_T *argvars, typval_T *rettv)
7779 {
7780     char_u	*strregname;
7781     int		regname;
7782     char_u	buf[NUMBUFLEN + 2];
7783     long	reglen = 0;
7784     dict_T	*dict;
7785     list_T	*list;
7786 
7787     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
7788 	return;
7789 
7790     if (argvars[0].v_type != VAR_UNKNOWN)
7791     {
7792 	strregname = tv_get_string_chk(&argvars[0]);
7793 	if (strregname == NULL)
7794 	    return;
7795 	if (in_vim9script() && STRLEN(strregname) > 1)
7796 	{
7797 	    semsg(_(e_register_name_must_be_one_char_str), strregname);
7798 	    return;
7799 	}
7800     }
7801     else
7802 	strregname = get_vim_var_str(VV_REG);
7803 
7804     regname = (strregname == NULL ? '"' : *strregname);
7805     if (regname == 0 || regname == '@')
7806 	regname = '"';
7807 
7808     if (rettv_dict_alloc(rettv) == FAIL)
7809 	return;
7810     dict = rettv->vval.v_dict;
7811 
7812     list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
7813     if (list == NULL)
7814 	return;
7815     (void)dict_add_list(dict, "regcontents", list);
7816 
7817     buf[0] = NUL;
7818     buf[1] = NUL;
7819     switch (get_reg_type(regname, &reglen))
7820     {
7821 	case MLINE: buf[0] = 'V'; break;
7822 	case MCHAR: buf[0] = 'v'; break;
7823 	case MBLOCK:
7824 		    vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
7825 			    reglen + 1);
7826 		    break;
7827     }
7828     (void)dict_add_string(dict, (char *)"regtype", buf);
7829 
7830     buf[0] = get_register_name(get_unname_register());
7831     buf[1] = NUL;
7832     if (regname == '"')
7833 	(void)dict_add_string(dict, (char *)"points_to", buf);
7834     else
7835     {
7836 	dictitem_T	*item = dictitem_alloc((char_u *)"isunnamed");
7837 
7838 	if (item != NULL)
7839 	{
7840 	    item->di_tv.v_type = VAR_SPECIAL;
7841 	    item->di_tv.vval.v_number = regname == buf[0]
7842 						      ? VVAL_TRUE : VVAL_FALSE;
7843 	    (void)dict_add(dict, item);
7844 	}
7845     }
7846 }
7847 
7848     static void
return_register(int regname,typval_T * rettv)7849 return_register(int regname, typval_T *rettv)
7850 {
7851     char_u buf[2] = {0, 0};
7852 
7853     buf[0] = (char_u)regname;
7854     rettv->v_type = VAR_STRING;
7855     rettv->vval.v_string = vim_strsave(buf);
7856 }
7857 
7858 /*
7859  * "reg_executing()" function
7860  */
7861     static void
f_reg_executing(typval_T * argvars UNUSED,typval_T * rettv)7862 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
7863 {
7864     return_register(reg_executing, rettv);
7865 }
7866 
7867 /*
7868  * "reg_recording()" function
7869  */
7870     static void
f_reg_recording(typval_T * argvars UNUSED,typval_T * rettv)7871 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
7872 {
7873     return_register(reg_recording, rettv);
7874 }
7875 
7876 /*
7877  * "rename({from}, {to})" function
7878  */
7879     static void
f_rename(typval_T * argvars,typval_T * rettv)7880 f_rename(typval_T *argvars, typval_T *rettv)
7881 {
7882     char_u	buf[NUMBUFLEN];
7883 
7884     rettv->vval.v_number = -1;
7885     if (check_restricted() || check_secure())
7886 	return;
7887 
7888     if (in_vim9script()
7889 	    && (check_for_string_arg(argvars, 0) == FAIL
7890 		|| check_for_string_arg(argvars, 1) == FAIL))
7891 	return;
7892 
7893     rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7894 				      tv_get_string_buf(&argvars[1], buf));
7895 }
7896 
7897 /*
7898  * "repeat()" function
7899  */
7900     static void
f_repeat(typval_T * argvars,typval_T * rettv)7901 f_repeat(typval_T *argvars, typval_T *rettv)
7902 {
7903     char_u	*p;
7904     int		n;
7905     int		slen;
7906     int		len;
7907     char_u	*r;
7908     int		i;
7909 
7910     if (in_vim9script()
7911 	    && (check_for_string_or_number_or_list_arg(argvars, 0) == FAIL
7912 		|| check_for_number_arg(argvars, 1) == FAIL))
7913 	return;
7914 
7915     n = (int)tv_get_number(&argvars[1]);
7916     if (argvars[0].v_type == VAR_LIST)
7917     {
7918 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7919 	    while (n-- > 0)
7920 		if (list_extend(rettv->vval.v_list,
7921 					argvars[0].vval.v_list, NULL) == FAIL)
7922 		    break;
7923     }
7924     else
7925     {
7926 	p = tv_get_string(&argvars[0]);
7927 	rettv->v_type = VAR_STRING;
7928 	rettv->vval.v_string = NULL;
7929 
7930 	slen = (int)STRLEN(p);
7931 	len = slen * n;
7932 	if (len <= 0)
7933 	    return;
7934 
7935 	r = alloc(len + 1);
7936 	if (r != NULL)
7937 	{
7938 	    for (i = 0; i < n; i++)
7939 		mch_memmove(r + i * slen, p, (size_t)slen);
7940 	    r[len] = NUL;
7941 	}
7942 
7943 	rettv->vval.v_string = r;
7944     }
7945 }
7946 
7947 #define SP_NOMOVE	0x01	    // don't move cursor
7948 #define SP_REPEAT	0x02	    // repeat to find outer pair
7949 #define SP_RETCOUNT	0x04	    // return matchcount
7950 #define SP_SETPCMARK	0x08	    // set previous context mark
7951 #define SP_START	0x10	    // accept match at start position
7952 #define SP_SUBPAT	0x20	    // return nr of matching sub-pattern
7953 #define SP_END		0x40	    // leave cursor at end of match
7954 #define SP_COLUMN	0x80	    // start at cursor column
7955 
7956 /*
7957  * Get flags for a search function.
7958  * Possibly sets "p_ws".
7959  * Returns BACKWARD, FORWARD or zero (for an error).
7960  */
7961     static int
get_search_arg(typval_T * varp,int * flagsp)7962 get_search_arg(typval_T *varp, int *flagsp)
7963 {
7964     int		dir = FORWARD;
7965     char_u	*flags;
7966     char_u	nbuf[NUMBUFLEN];
7967     int		mask;
7968 
7969     if (varp->v_type != VAR_UNKNOWN)
7970     {
7971 	flags = tv_get_string_buf_chk(varp, nbuf);
7972 	if (flags == NULL)
7973 	    return 0;		// type error; errmsg already given
7974 	while (*flags != NUL)
7975 	{
7976 	    switch (*flags)
7977 	    {
7978 		case 'b': dir = BACKWARD; break;
7979 		case 'w': p_ws = TRUE; break;
7980 		case 'W': p_ws = FALSE; break;
7981 		default:  mask = 0;
7982 			  if (flagsp != NULL)
7983 			     switch (*flags)
7984 			     {
7985 				 case 'c': mask = SP_START; break;
7986 				 case 'e': mask = SP_END; break;
7987 				 case 'm': mask = SP_RETCOUNT; break;
7988 				 case 'n': mask = SP_NOMOVE; break;
7989 				 case 'p': mask = SP_SUBPAT; break;
7990 				 case 'r': mask = SP_REPEAT; break;
7991 				 case 's': mask = SP_SETPCMARK; break;
7992 				 case 'z': mask = SP_COLUMN; break;
7993 			     }
7994 			  if (mask == 0)
7995 			  {
7996 			      semsg(_(e_invarg2), flags);
7997 			      dir = 0;
7998 			  }
7999 			  else
8000 			      *flagsp |= mask;
8001 	    }
8002 	    if (dir == 0)
8003 		break;
8004 	    ++flags;
8005 	}
8006     }
8007     return dir;
8008 }
8009 
8010 /*
8011  * Shared by search() and searchpos() functions.
8012  */
8013     static int
search_cmn(typval_T * argvars,pos_T * match_pos,int * flagsp)8014 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8015 {
8016     int		flags;
8017     char_u	*pat;
8018     pos_T	pos;
8019     pos_T	save_cursor;
8020     int		save_p_ws = p_ws;
8021     int		dir;
8022     int		retval = 0;	// default: FAIL
8023     long	lnum_stop = 0;
8024 #ifdef FEAT_RELTIME
8025     proftime_T	tm;
8026     long	time_limit = 0;
8027 #endif
8028     int		options = SEARCH_KEEP;
8029     int		subpatnum;
8030     searchit_arg_T sia;
8031     int		use_skip = FALSE;
8032     pos_T	firstpos;
8033 
8034     if (in_vim9script()
8035 	    && (check_for_string_arg(argvars, 0) == FAIL
8036 		|| check_for_opt_string_arg(argvars, 1) == FAIL
8037 		|| (argvars[1].v_type != VAR_UNKNOWN
8038 		    && (check_for_opt_number_arg(argvars, 2) == FAIL
8039 			|| (argvars[2].v_type != VAR_UNKNOWN
8040 			    && check_for_opt_number_arg(argvars, 3) == FAIL)))))
8041 	goto theend;
8042 
8043     pat = tv_get_string(&argvars[0]);
8044     dir = get_search_arg(&argvars[1], flagsp);	// may set p_ws
8045     if (dir == 0)
8046 	goto theend;
8047     flags = *flagsp;
8048     if (flags & SP_START)
8049 	options |= SEARCH_START;
8050     if (flags & SP_END)
8051 	options |= SEARCH_END;
8052     if (flags & SP_COLUMN)
8053 	options |= SEARCH_COL;
8054 
8055     // Optional arguments: line number to stop searching, timeout and skip.
8056     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8057     {
8058 	lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
8059 	if (lnum_stop < 0)
8060 	    goto theend;
8061 	if (argvars[3].v_type != VAR_UNKNOWN)
8062 	{
8063 #ifdef FEAT_RELTIME
8064 	    time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
8065 	    if (time_limit < 0)
8066 		goto theend;
8067 #endif
8068 	    use_skip = eval_expr_valid_arg(&argvars[4]);
8069 	}
8070     }
8071 
8072 #ifdef FEAT_RELTIME
8073     // Set the time limit, if there is one.
8074     profile_setlimit(time_limit, &tm);
8075 #endif
8076 
8077     /*
8078      * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8079      * Check to make sure only those flags are set.
8080      * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8081      * flags cannot be set. Check for that condition also.
8082      */
8083     if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8084 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8085     {
8086 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
8087 	goto theend;
8088     }
8089 
8090     pos = save_cursor = curwin->w_cursor;
8091     CLEAR_FIELD(firstpos);
8092     CLEAR_FIELD(sia);
8093     sia.sa_stop_lnum = (linenr_T)lnum_stop;
8094 #ifdef FEAT_RELTIME
8095     sia.sa_tm = &tm;
8096 #endif
8097 
8098     // Repeat until {skip} returns FALSE.
8099     for (;;)
8100     {
8101 	subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
8102 						     options, RE_SEARCH, &sia);
8103 	// finding the first match again means there is no match where {skip}
8104 	// evaluates to zero.
8105 	if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
8106 	    subpatnum = FAIL;
8107 
8108 	if (subpatnum == FAIL || !use_skip)
8109 	    // didn't find it or no skip argument
8110 	    break;
8111 	firstpos = pos;
8112 
8113 	// If the skip expression matches, ignore this match.
8114 	{
8115 	    int	    do_skip;
8116 	    int	    err;
8117 	    pos_T   save_pos = curwin->w_cursor;
8118 
8119 	    curwin->w_cursor = pos;
8120 	    err = FALSE;
8121 	    do_skip = eval_expr_to_bool(&argvars[4], &err);
8122 	    curwin->w_cursor = save_pos;
8123 	    if (err)
8124 	    {
8125 		// Evaluating {skip} caused an error, break here.
8126 		subpatnum = FAIL;
8127 		break;
8128 	    }
8129 	    if (!do_skip)
8130 		break;
8131 	}
8132     }
8133 
8134     if (subpatnum != FAIL)
8135     {
8136 	if (flags & SP_SUBPAT)
8137 	    retval = subpatnum;
8138 	else
8139 	    retval = pos.lnum;
8140 	if (flags & SP_SETPCMARK)
8141 	    setpcmark();
8142 	curwin->w_cursor = pos;
8143 	if (match_pos != NULL)
8144 	{
8145 	    // Store the match cursor position
8146 	    match_pos->lnum = pos.lnum;
8147 	    match_pos->col = pos.col + 1;
8148 	}
8149 	// "/$" will put the cursor after the end of the line, may need to
8150 	// correct that here
8151 	check_cursor();
8152     }
8153 
8154     // If 'n' flag is used: restore cursor position.
8155     if (flags & SP_NOMOVE)
8156 	curwin->w_cursor = save_cursor;
8157     else
8158 	curwin->w_set_curswant = TRUE;
8159 theend:
8160     p_ws = save_p_ws;
8161 
8162     return retval;
8163 }
8164 
8165 #ifdef FEAT_RUBY
8166 /*
8167  * "rubyeval()" function
8168  */
8169     static void
f_rubyeval(typval_T * argvars,typval_T * rettv)8170 f_rubyeval(typval_T *argvars, typval_T *rettv)
8171 {
8172     char_u	*str;
8173     char_u	buf[NUMBUFLEN];
8174 
8175     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
8176 	return;
8177 
8178     str = tv_get_string_buf(&argvars[0], buf);
8179     do_rubyeval(str, rettv);
8180 }
8181 #endif
8182 
8183 /*
8184  * "screenattr()" function
8185  */
8186     static void
f_screenattr(typval_T * argvars,typval_T * rettv)8187 f_screenattr(typval_T *argvars, typval_T *rettv)
8188 {
8189     int		row;
8190     int		col;
8191     int		c;
8192 
8193     if (in_vim9script()
8194 	    && (check_for_number_arg(argvars, 0) == FAIL
8195 		|| check_for_number_arg(argvars, 1) == FAIL))
8196 	return;
8197 
8198     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8199     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8200     if (row < 0 || row >= screen_Rows
8201 	    || col < 0 || col >= screen_Columns)
8202 	c = -1;
8203     else
8204 	c = ScreenAttrs[LineOffset[row] + col];
8205     rettv->vval.v_number = c;
8206 }
8207 
8208 /*
8209  * "screenchar()" function
8210  */
8211     static void
f_screenchar(typval_T * argvars,typval_T * rettv)8212 f_screenchar(typval_T *argvars, typval_T *rettv)
8213 {
8214     int		row;
8215     int		col;
8216     int		off;
8217     int		c;
8218 
8219     if (in_vim9script()
8220 	    && (check_for_number_arg(argvars, 0) == FAIL
8221 		|| check_for_number_arg(argvars, 1) == FAIL))
8222 	return;
8223 
8224     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8225     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8226     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8227 	c = -1;
8228     else
8229     {
8230 	off = LineOffset[row] + col;
8231 	if (enc_utf8 && ScreenLinesUC[off] != 0)
8232 	    c = ScreenLinesUC[off];
8233 	else
8234 	    c = ScreenLines[off];
8235     }
8236     rettv->vval.v_number = c;
8237 }
8238 
8239 /*
8240  * "screenchars()" function
8241  */
8242     static void
f_screenchars(typval_T * argvars,typval_T * rettv)8243 f_screenchars(typval_T *argvars, typval_T *rettv)
8244 {
8245     int		row;
8246     int		col;
8247     int		off;
8248     int		c;
8249     int		i;
8250 
8251     if (rettv_list_alloc(rettv) == FAIL)
8252 	return;
8253 
8254     if (in_vim9script()
8255 	    && (check_for_number_arg(argvars, 0) == FAIL
8256 		|| check_for_number_arg(argvars, 1) == FAIL))
8257 	return;
8258 
8259     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8260     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8261     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8262 	return;
8263 
8264     off = LineOffset[row] + col;
8265     if (enc_utf8 && ScreenLinesUC[off] != 0)
8266 	c = ScreenLinesUC[off];
8267     else
8268 	c = ScreenLines[off];
8269     list_append_number(rettv->vval.v_list, (varnumber_T)c);
8270 
8271     if (enc_utf8)
8272 
8273 	for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
8274 	    list_append_number(rettv->vval.v_list,
8275 				       (varnumber_T)ScreenLinesC[i][off]);
8276 }
8277 
8278 /*
8279  * "screencol()" function
8280  *
8281  * First column is 1 to be consistent with virtcol().
8282  */
8283     static void
f_screencol(typval_T * argvars UNUSED,typval_T * rettv)8284 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8285 {
8286     rettv->vval.v_number = screen_screencol() + 1;
8287 }
8288 
8289 /*
8290  * "screenrow()" function
8291  */
8292     static void
f_screenrow(typval_T * argvars UNUSED,typval_T * rettv)8293 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8294 {
8295     rettv->vval.v_number = screen_screenrow() + 1;
8296 }
8297 
8298 /*
8299  * "screenstring()" function
8300  */
8301     static void
f_screenstring(typval_T * argvars,typval_T * rettv)8302 f_screenstring(typval_T *argvars, typval_T *rettv)
8303 {
8304     int		row;
8305     int		col;
8306     int		off;
8307     int		c;
8308     int		i;
8309     char_u	buf[MB_MAXBYTES + 1];
8310     int		buflen = 0;
8311 
8312     rettv->vval.v_string = NULL;
8313     rettv->v_type = VAR_STRING;
8314 
8315     if (in_vim9script()
8316 	    && (check_for_number_arg(argvars, 0) == FAIL
8317 		|| check_for_number_arg(argvars, 1) == FAIL))
8318 	return;
8319 
8320     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8321     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8322     if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8323 	return;
8324 
8325     off = LineOffset[row] + col;
8326     if (enc_utf8 && ScreenLinesUC[off] != 0)
8327 	c = ScreenLinesUC[off];
8328     else
8329 	c = ScreenLines[off];
8330     buflen += mb_char2bytes(c, buf);
8331 
8332     if (enc_utf8 && ScreenLinesUC[off] != 0)
8333 	for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
8334 	    buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
8335 
8336     buf[buflen] = NUL;
8337     rettv->vval.v_string = vim_strsave(buf);
8338 }
8339 
8340 /*
8341  * "search()" function
8342  */
8343     static void
f_search(typval_T * argvars,typval_T * rettv)8344 f_search(typval_T *argvars, typval_T *rettv)
8345 {
8346     int		flags = 0;
8347 
8348     rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
8349 }
8350 
8351 /*
8352  * "searchdecl()" function
8353  */
8354     static void
f_searchdecl(typval_T * argvars,typval_T * rettv)8355 f_searchdecl(typval_T *argvars, typval_T *rettv)
8356 {
8357     int		locally = TRUE;
8358     int		thisblock = FALSE;
8359     int		error = FALSE;
8360     char_u	*name;
8361 
8362     rettv->vval.v_number = 1;	// default: FAIL
8363 
8364     if (in_vim9script()
8365 	    && (check_for_string_arg(argvars, 0) == FAIL
8366 		|| check_for_opt_bool_arg(argvars, 1) == FAIL
8367 		|| (argvars[1].v_type != VAR_UNKNOWN
8368 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
8369 	return;
8370 
8371     name = tv_get_string_chk(&argvars[0]);
8372     if (argvars[1].v_type != VAR_UNKNOWN)
8373     {
8374 	locally = !(int)tv_get_bool_chk(&argvars[1], &error);
8375 	if (!error && argvars[2].v_type != VAR_UNKNOWN)
8376 	    thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
8377     }
8378     if (!error && name != NULL)
8379 	rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
8380 				     locally, thisblock, SEARCH_KEEP) == FAIL;
8381 }
8382 
8383 /*
8384  * Used by searchpair() and searchpairpos()
8385  */
8386     static int
searchpair_cmn(typval_T * argvars,pos_T * match_pos)8387 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
8388 {
8389     char_u	*spat, *mpat, *epat;
8390     typval_T	*skip;
8391     int		save_p_ws = p_ws;
8392     int		dir;
8393     int		flags = 0;
8394     char_u	nbuf1[NUMBUFLEN];
8395     char_u	nbuf2[NUMBUFLEN];
8396     int		retval = 0;		// default: FAIL
8397     long	lnum_stop = 0;
8398     long	time_limit = 0;
8399 
8400     if (in_vim9script()
8401 	    && (check_for_string_arg(argvars, 0) == FAIL
8402 		|| check_for_string_arg(argvars, 1) == FAIL
8403 		|| check_for_string_arg(argvars, 2) == FAIL
8404 		|| check_for_opt_string_arg(argvars, 3) == FAIL
8405 		|| (argvars[3].v_type != VAR_UNKNOWN
8406 		    && argvars[4].v_type != VAR_UNKNOWN
8407 		    && (check_for_opt_number_arg(argvars, 5) == FAIL
8408 			|| (argvars[5].v_type != VAR_UNKNOWN
8409 			    && check_for_opt_number_arg(argvars, 6) == FAIL)))))
8410 	goto theend;
8411 
8412     // Get the three pattern arguments: start, middle, end. Will result in an
8413     // error if not a valid argument.
8414     spat = tv_get_string_chk(&argvars[0]);
8415     mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
8416     epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
8417     if (spat == NULL || mpat == NULL || epat == NULL)
8418 	goto theend;	    // type error
8419 
8420     // Handle the optional fourth argument: flags
8421     dir = get_search_arg(&argvars[3], &flags); // may set p_ws
8422     if (dir == 0)
8423 	goto theend;
8424 
8425     // Don't accept SP_END or SP_SUBPAT.
8426     // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
8427     if ((flags & (SP_END | SP_SUBPAT)) != 0
8428 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8429     {
8430 	semsg(_(e_invarg2), tv_get_string(&argvars[3]));
8431 	goto theend;
8432     }
8433 
8434     // Using 'r' implies 'W', otherwise it doesn't work.
8435     if (flags & SP_REPEAT)
8436 	p_ws = FALSE;
8437 
8438     // Optional fifth argument: skip expression
8439     if (argvars[3].v_type == VAR_UNKNOWN
8440 	    || argvars[4].v_type == VAR_UNKNOWN)
8441 	skip = NULL;
8442     else
8443     {
8444 	// Type is checked later.
8445 	skip = &argvars[4];
8446 
8447 	if (argvars[5].v_type != VAR_UNKNOWN)
8448 	{
8449 	    lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
8450 	    if (lnum_stop < 0)
8451 	    {
8452 		semsg(_(e_invarg2), tv_get_string(&argvars[5]));
8453 		goto theend;
8454 	    }
8455 #ifdef FEAT_RELTIME
8456 	    if (argvars[6].v_type != VAR_UNKNOWN)
8457 	    {
8458 		time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
8459 		if (time_limit < 0)
8460 		{
8461 		    semsg(_(e_invarg2), tv_get_string(&argvars[6]));
8462 		    goto theend;
8463 		}
8464 	    }
8465 #endif
8466 	}
8467     }
8468 
8469     retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
8470 					    match_pos, lnum_stop, time_limit);
8471 
8472 theend:
8473     p_ws = save_p_ws;
8474 
8475     return retval;
8476 }
8477 
8478 /*
8479  * "searchpair()" function
8480  */
8481     static void
f_searchpair(typval_T * argvars,typval_T * rettv)8482 f_searchpair(typval_T *argvars, typval_T *rettv)
8483 {
8484     rettv->vval.v_number = searchpair_cmn(argvars, NULL);
8485 }
8486 
8487 /*
8488  * "searchpairpos()" function
8489  */
8490     static void
f_searchpairpos(typval_T * argvars,typval_T * rettv)8491 f_searchpairpos(typval_T *argvars, typval_T *rettv)
8492 {
8493     pos_T	match_pos;
8494     int		lnum = 0;
8495     int		col = 0;
8496 
8497     if (rettv_list_alloc(rettv) == FAIL)
8498 	return;
8499 
8500     if (searchpair_cmn(argvars, &match_pos) > 0)
8501     {
8502 	lnum = match_pos.lnum;
8503 	col = match_pos.col;
8504     }
8505 
8506     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8507     list_append_number(rettv->vval.v_list, (varnumber_T)col);
8508 }
8509 
8510 /*
8511  * Search for a start/middle/end thing.
8512  * Used by searchpair(), see its documentation for the details.
8513  * Returns 0 or -1 for no match,
8514  */
8515     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)8516 do_searchpair(
8517     char_u	*spat,	    // start pattern
8518     char_u	*mpat,	    // middle pattern
8519     char_u	*epat,	    // end pattern
8520     int		dir,	    // BACKWARD or FORWARD
8521     typval_T	*skip,	    // skip expression
8522     int		flags,	    // SP_SETPCMARK and other SP_ values
8523     pos_T	*match_pos,
8524     linenr_T	lnum_stop,  // stop at this line if not zero
8525     long	time_limit UNUSED) // stop after this many msec
8526 {
8527     char_u	*save_cpo;
8528     char_u	*pat, *pat2 = NULL, *pat3 = NULL;
8529     long	retval = 0;
8530     pos_T	pos;
8531     pos_T	firstpos;
8532     pos_T	foundpos;
8533     pos_T	save_cursor;
8534     pos_T	save_pos;
8535     int		n;
8536     int		r;
8537     int		nest = 1;
8538     int		use_skip = FALSE;
8539     int		err;
8540     int		options = SEARCH_KEEP;
8541 #ifdef FEAT_RELTIME
8542     proftime_T	tm;
8543 #endif
8544 
8545     // Make 'cpoptions' empty, the 'l' flag should not be used here.
8546     save_cpo = p_cpo;
8547     p_cpo = empty_option;
8548 
8549 #ifdef FEAT_RELTIME
8550     // Set the time limit, if there is one.
8551     profile_setlimit(time_limit, &tm);
8552 #endif
8553 
8554     // Make two search patterns: start/end (pat2, for in nested pairs) and
8555     // start/middle/end (pat3, for the top pair).
8556     pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
8557     pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
8558     if (pat2 == NULL || pat3 == NULL)
8559 	goto theend;
8560     sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
8561     if (*mpat == NUL)
8562 	STRCPY(pat3, pat2);
8563     else
8564 	sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
8565 							    spat, epat, mpat);
8566     if (flags & SP_START)
8567 	options |= SEARCH_START;
8568 
8569     if (skip != NULL)
8570 	use_skip = eval_expr_valid_arg(skip);
8571 
8572     save_cursor = curwin->w_cursor;
8573     pos = curwin->w_cursor;
8574     CLEAR_POS(&firstpos);
8575     CLEAR_POS(&foundpos);
8576     pat = pat3;
8577     for (;;)
8578     {
8579 	searchit_arg_T sia;
8580 
8581 	CLEAR_FIELD(sia);
8582 	sia.sa_stop_lnum = lnum_stop;
8583 #ifdef FEAT_RELTIME
8584 	sia.sa_tm = &tm;
8585 #endif
8586 	n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
8587 						     options, RE_SEARCH, &sia);
8588 	if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
8589 	    // didn't find it or found the first match again: FAIL
8590 	    break;
8591 
8592 	if (firstpos.lnum == 0)
8593 	    firstpos = pos;
8594 	if (EQUAL_POS(pos, foundpos))
8595 	{
8596 	    // Found the same position again.  Can happen with a pattern that
8597 	    // has "\zs" at the end and searching backwards.  Advance one
8598 	    // character and try again.
8599 	    if (dir == BACKWARD)
8600 		decl(&pos);
8601 	    else
8602 		incl(&pos);
8603 	}
8604 	foundpos = pos;
8605 
8606 	// clear the start flag to avoid getting stuck here
8607 	options &= ~SEARCH_START;
8608 
8609 	// If the skip pattern matches, ignore this match.
8610 	if (use_skip)
8611 	{
8612 	    save_pos = curwin->w_cursor;
8613 	    curwin->w_cursor = pos;
8614 	    err = FALSE;
8615 	    r = eval_expr_to_bool(skip, &err);
8616 	    curwin->w_cursor = save_pos;
8617 	    if (err)
8618 	    {
8619 		// Evaluating {skip} caused an error, break here.
8620 		curwin->w_cursor = save_cursor;
8621 		retval = -1;
8622 		break;
8623 	    }
8624 	    if (r)
8625 		continue;
8626 	}
8627 
8628 	if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
8629 	{
8630 	    // Found end when searching backwards or start when searching
8631 	    // forward: nested pair.
8632 	    ++nest;
8633 	    pat = pat2;		// nested, don't search for middle
8634 	}
8635 	else
8636 	{
8637 	    // Found end when searching forward or start when searching
8638 	    // backward: end of (nested) pair; or found middle in outer pair.
8639 	    if (--nest == 1)
8640 		pat = pat3;	// outer level, search for middle
8641 	}
8642 
8643 	if (nest == 0)
8644 	{
8645 	    // Found the match: return matchcount or line number.
8646 	    if (flags & SP_RETCOUNT)
8647 		++retval;
8648 	    else
8649 		retval = pos.lnum;
8650 	    if (flags & SP_SETPCMARK)
8651 		setpcmark();
8652 	    curwin->w_cursor = pos;
8653 	    if (!(flags & SP_REPEAT))
8654 		break;
8655 	    nest = 1;	    // search for next unmatched
8656 	}
8657     }
8658 
8659     if (match_pos != NULL)
8660     {
8661 	// Store the match cursor position
8662 	match_pos->lnum = curwin->w_cursor.lnum;
8663 	match_pos->col = curwin->w_cursor.col + 1;
8664     }
8665 
8666     // If 'n' flag is used or search failed: restore cursor position.
8667     if ((flags & SP_NOMOVE) || retval == 0)
8668 	curwin->w_cursor = save_cursor;
8669 
8670 theend:
8671     vim_free(pat2);
8672     vim_free(pat3);
8673     if (p_cpo == empty_option)
8674 	p_cpo = save_cpo;
8675     else
8676     {
8677 	// Darn, evaluating the {skip} expression changed the value.
8678 	// If it's still empty it was changed and restored, need to restore in
8679 	// the complicated way.
8680 	if (*p_cpo == NUL)
8681 	    set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
8682 	free_string_option(save_cpo);
8683     }
8684 
8685     return retval;
8686 }
8687 
8688 /*
8689  * "searchpos()" function
8690  */
8691     static void
f_searchpos(typval_T * argvars,typval_T * rettv)8692 f_searchpos(typval_T *argvars, typval_T *rettv)
8693 {
8694     pos_T	match_pos;
8695     int		lnum = 0;
8696     int		col = 0;
8697     int		n;
8698     int		flags = 0;
8699 
8700     if (rettv_list_alloc(rettv) == FAIL)
8701 	return;
8702 
8703     n = search_cmn(argvars, &match_pos, &flags);
8704     if (n > 0)
8705     {
8706 	lnum = match_pos.lnum;
8707 	col = match_pos.col;
8708     }
8709 
8710     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8711     list_append_number(rettv->vval.v_list, (varnumber_T)col);
8712     if (flags & SP_SUBPAT)
8713 	list_append_number(rettv->vval.v_list, (varnumber_T)n);
8714 }
8715 
8716 /*
8717  * Set the cursor or mark position.
8718  * If 'charpos' is TRUE, then use the column number as a character offset.
8719  * Otherwise use the column number as a byte offset.
8720  */
8721     static void
set_position(typval_T * argvars,typval_T * rettv,int charpos)8722 set_position(typval_T *argvars, typval_T *rettv, int charpos)
8723 {
8724     pos_T	pos;
8725     int		fnum;
8726     char_u	*name;
8727     colnr_T	curswant = -1;
8728 
8729     rettv->vval.v_number = -1;
8730 
8731     if (in_vim9script()
8732 	    && (check_for_string_arg(argvars, 0) == FAIL
8733 		|| check_for_list_arg(argvars, 1) == FAIL))
8734 	return;
8735 
8736     name = tv_get_string_chk(argvars);
8737     if (name != NULL)
8738     {
8739 	if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK)
8740 	{
8741 	    if (pos.col != MAXCOL && --pos.col < 0)
8742 		pos.col = 0;
8743 	    if ((name[0] == '.' && name[1] == NUL))
8744 	    {
8745 		// set cursor; "fnum" is ignored
8746 		curwin->w_cursor = pos;
8747 		if (curswant >= 0)
8748 		{
8749 		    curwin->w_curswant = curswant - 1;
8750 		    curwin->w_set_curswant = FALSE;
8751 		}
8752 		check_cursor();
8753 		rettv->vval.v_number = 0;
8754 	    }
8755 	    else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
8756 	    {
8757 		// set mark
8758 		if (setmark_pos(name[1], &pos, fnum) == OK)
8759 		    rettv->vval.v_number = 0;
8760 	    }
8761 	    else
8762 		emsg(_(e_invarg));
8763 	}
8764     }
8765 }
8766 /*
8767  * "setcharpos()" function
8768  */
8769     static void
f_setcharpos(typval_T * argvars,typval_T * rettv)8770 f_setcharpos(typval_T *argvars, typval_T *rettv)
8771 {
8772     set_position(argvars, rettv, TRUE);
8773 }
8774 
8775     static void
f_setcharsearch(typval_T * argvars,typval_T * rettv UNUSED)8776 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
8777 {
8778     dict_T	*d;
8779     dictitem_T	*di;
8780     char_u	*csearch;
8781 
8782     if (in_vim9script() && check_for_dict_arg(argvars, 0) == FAIL)
8783 	return;
8784 
8785     if (argvars[0].v_type != VAR_DICT)
8786     {
8787 	emsg(_(e_dictreq));
8788 	return;
8789     }
8790 
8791     if ((d = argvars[0].vval.v_dict) != NULL)
8792     {
8793 	csearch = dict_get_string(d, (char_u *)"char", FALSE);
8794 	if (csearch != NULL)
8795 	{
8796 	    if (enc_utf8)
8797 	    {
8798 		int pcc[MAX_MCO];
8799 		int c = utfc_ptr2char(csearch, pcc);
8800 
8801 		set_last_csearch(c, csearch, utfc_ptr2len(csearch));
8802 	    }
8803 	    else
8804 		set_last_csearch(PTR2CHAR(csearch),
8805 						csearch, mb_ptr2len(csearch));
8806 	}
8807 
8808 	di = dict_find(d, (char_u *)"forward", -1);
8809 	if (di != NULL)
8810 	    set_csearch_direction((int)tv_get_number(&di->di_tv)
8811 							? FORWARD : BACKWARD);
8812 
8813 	di = dict_find(d, (char_u *)"until", -1);
8814 	if (di != NULL)
8815 	    set_csearch_until(!!tv_get_number(&di->di_tv));
8816     }
8817 }
8818 
8819 /*
8820  * "setcursorcharpos" function
8821  */
8822     static void
f_setcursorcharpos(typval_T * argvars,typval_T * rettv)8823 f_setcursorcharpos(typval_T *argvars, typval_T *rettv)
8824 {
8825     set_cursorpos(argvars, rettv, TRUE);
8826 }
8827 
8828 /*
8829  * "setenv()" function
8830  */
8831     static void
f_setenv(typval_T * argvars,typval_T * rettv UNUSED)8832 f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
8833 {
8834     char_u   namebuf[NUMBUFLEN];
8835     char_u   valbuf[NUMBUFLEN];
8836     char_u  *name;
8837 
8838     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
8839 	return;
8840 
8841     name = tv_get_string_buf(&argvars[0], namebuf);
8842     if (argvars[1].v_type == VAR_SPECIAL
8843 				      && argvars[1].vval.v_number == VVAL_NULL)
8844 	vim_unsetenv(name);
8845     else
8846 	vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
8847 }
8848 
8849 /*
8850  * "setfperm({fname}, {mode})" function
8851  */
8852     static void
f_setfperm(typval_T * argvars,typval_T * rettv)8853 f_setfperm(typval_T *argvars, typval_T *rettv)
8854 {
8855     char_u	*fname;
8856     char_u	modebuf[NUMBUFLEN];
8857     char_u	*mode_str;
8858     int		i;
8859     int		mask;
8860     int		mode = 0;
8861 
8862     rettv->vval.v_number = 0;
8863 
8864     if (in_vim9script()
8865 	    && (check_for_string_arg(argvars, 0) == FAIL
8866 		|| check_for_string_arg(argvars, 1) == FAIL))
8867 	return;
8868 
8869     fname = tv_get_string_chk(&argvars[0]);
8870     if (fname == NULL)
8871 	return;
8872     mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
8873     if (mode_str == NULL)
8874 	return;
8875     if (STRLEN(mode_str) != 9)
8876     {
8877 	semsg(_(e_invarg2), mode_str);
8878 	return;
8879     }
8880 
8881     mask = 1;
8882     for (i = 8; i >= 0; --i)
8883     {
8884 	if (mode_str[i] != '-')
8885 	    mode |= mask;
8886 	mask = mask << 1;
8887     }
8888     rettv->vval.v_number = mch_setperm(fname, mode) == OK;
8889 }
8890 
8891 /*
8892  * "setpos()" function
8893  */
8894     static void
f_setpos(typval_T * argvars,typval_T * rettv)8895 f_setpos(typval_T *argvars, typval_T *rettv)
8896 {
8897     set_position(argvars, rettv, FALSE);
8898 }
8899 
8900 /*
8901  * Translate a register type string to the yank type and block length
8902  */
8903     static int
get_yank_type(char_u ** pp,char_u * yank_type,long * block_len)8904 get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
8905 {
8906     char_u *stropt = *pp;
8907     switch (*stropt)
8908     {
8909 	case 'v': case 'c':	// character-wise selection
8910 	    *yank_type = MCHAR;
8911 	    break;
8912 	case 'V': case 'l':	// line-wise selection
8913 	    *yank_type = MLINE;
8914 	    break;
8915 	case 'b': case Ctrl_V:	// block-wise selection
8916 	    *yank_type = MBLOCK;
8917 	    if (VIM_ISDIGIT(stropt[1]))
8918 	    {
8919 		++stropt;
8920 		*block_len = getdigits(&stropt) - 1;
8921 		--stropt;
8922 	    }
8923 	    break;
8924 	default:
8925 	    return FAIL;
8926     }
8927     *pp = stropt;
8928     return OK;
8929 }
8930 
8931 /*
8932  * "setreg()" function
8933  */
8934     static void
f_setreg(typval_T * argvars,typval_T * rettv)8935 f_setreg(typval_T *argvars, typval_T *rettv)
8936 {
8937     int		regname;
8938     char_u	*strregname;
8939     char_u	*stropt;
8940     char_u	*strval;
8941     int		append;
8942     char_u	yank_type;
8943     long	block_len;
8944     typval_T	*regcontents;
8945     int		pointreg;
8946 
8947     if (in_vim9script()
8948 	    && (check_for_string_arg(argvars, 0) == FAIL
8949 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
8950 	return;
8951 
8952     pointreg = 0;
8953     regcontents = NULL;
8954     block_len = -1;
8955     yank_type = MAUTO;
8956     append = FALSE;
8957 
8958     strregname = tv_get_string_chk(argvars);
8959     rettv->vval.v_number = 1;		// FAIL is default
8960 
8961     if (strregname == NULL)
8962 	return;		// type error; errmsg already given
8963     if (in_vim9script() && STRLEN(strregname) > 1)
8964     {
8965 	semsg(_(e_register_name_must_be_one_char_str), strregname);
8966 	return;
8967     }
8968     regname = *strregname;
8969     if (regname == 0 || regname == '@')
8970 	regname = '"';
8971 
8972     if (argvars[1].v_type == VAR_DICT)
8973     {
8974 	dict_T	    *d = argvars[1].vval.v_dict;
8975 	dictitem_T  *di;
8976 
8977 	if (d == NULL || d->dv_hashtab.ht_used == 0)
8978 	{
8979 	    // Empty dict, clear the register (like setreg(0, []))
8980 	    char_u *lstval[2] = {NULL, NULL};
8981 	    write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
8982 	    return;
8983 	}
8984 
8985 	di = dict_find(d, (char_u *)"regcontents", -1);
8986 	if (di != NULL)
8987 	    regcontents = &di->di_tv;
8988 
8989 	stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
8990 	if (stropt != NULL)
8991 	{
8992 	    int ret = get_yank_type(&stropt, &yank_type, &block_len);
8993 
8994 	    if (ret == FAIL || *++stropt != NUL)
8995 	    {
8996 		semsg(_(e_invargval), "value");
8997 		return;
8998 	    }
8999 	}
9000 
9001 	if (regname == '"')
9002 	{
9003 	    stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
9004 	    if (stropt != NULL)
9005 	    {
9006 		pointreg = *stropt;
9007 		regname = pointreg;
9008 	    }
9009 	}
9010 	else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
9011 	    pointreg = regname;
9012     }
9013     else
9014 	regcontents = &argvars[1];
9015 
9016     if (argvars[2].v_type != VAR_UNKNOWN)
9017     {
9018 	if (yank_type != MAUTO)
9019 	{
9020 	    semsg(_(e_toomanyarg), "setreg");
9021 	    return;
9022 	}
9023 
9024 	stropt = tv_get_string_chk(&argvars[2]);
9025 	if (stropt == NULL)
9026 	    return;		// type error
9027 	for (; *stropt != NUL; ++stropt)
9028 	    switch (*stropt)
9029 	    {
9030 		case 'a': case 'A':	// append
9031 		    append = TRUE;
9032 		    break;
9033 		default:
9034 		    get_yank_type(&stropt, &yank_type, &block_len);
9035 	    }
9036     }
9037 
9038     if (regcontents && regcontents->v_type == VAR_LIST)
9039     {
9040 	char_u		**lstval;
9041 	char_u		**allocval;
9042 	char_u		buf[NUMBUFLEN];
9043 	char_u		**curval;
9044 	char_u		**curallocval;
9045 	list_T		*ll = regcontents->vval.v_list;
9046 	listitem_T	*li;
9047 	int		len;
9048 
9049 	// If the list is NULL handle like an empty list.
9050 	len = ll == NULL ? 0 : ll->lv_len;
9051 
9052 	// First half: use for pointers to result lines; second half: use for
9053 	// pointers to allocated copies.
9054 	lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
9055 	if (lstval == NULL)
9056 	    return;
9057 	curval = lstval;
9058 	allocval = lstval + len + 2;
9059 	curallocval = allocval;
9060 
9061 	if (ll != NULL)
9062 	{
9063 	    CHECK_LIST_MATERIALIZE(ll);
9064 	    FOR_ALL_LIST_ITEMS(ll, li)
9065 	    {
9066 		strval = tv_get_string_buf_chk(&li->li_tv, buf);
9067 		if (strval == NULL)
9068 		    goto free_lstval;
9069 		if (strval == buf)
9070 		{
9071 		    // Need to make a copy, next tv_get_string_buf_chk() will
9072 		    // overwrite the string.
9073 		    strval = vim_strsave(buf);
9074 		    if (strval == NULL)
9075 			goto free_lstval;
9076 		    *curallocval++ = strval;
9077 		}
9078 		*curval++ = strval;
9079 	    }
9080 	}
9081 	*curval++ = NULL;
9082 
9083 	write_reg_contents_lst(regname, lstval, -1,
9084 						append, yank_type, block_len);
9085 free_lstval:
9086 	while (curallocval > allocval)
9087 	    vim_free(*--curallocval);
9088 	vim_free(lstval);
9089     }
9090     else if (regcontents)
9091     {
9092 	strval = tv_get_string_chk(regcontents);
9093 	if (strval == NULL)
9094 	    return;
9095 	write_reg_contents_ex(regname, strval, -1,
9096 						append, yank_type, block_len);
9097     }
9098     if (pointreg != 0)
9099 	get_yank_register(pointreg, TRUE);
9100 
9101     rettv->vval.v_number = 0;
9102 }
9103 
9104 /*
9105  * "settagstack()" function
9106  */
9107     static void
f_settagstack(typval_T * argvars,typval_T * rettv)9108 f_settagstack(typval_T *argvars, typval_T *rettv)
9109 {
9110     static char *e_invact2 = N_("E962: Invalid action: '%s'");
9111     win_T	*wp;
9112     dict_T	*d;
9113     int		action = 'r';
9114 
9115     rettv->vval.v_number = -1;
9116 
9117     if (in_vim9script()
9118 	    && (check_for_number_arg(argvars, 0) == FAIL
9119 		|| check_for_dict_arg(argvars, 1) == FAIL
9120 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
9121 	return;
9122 
9123     // first argument: window number or id
9124     wp = find_win_by_nr_or_id(&argvars[0]);
9125     if (wp == NULL)
9126 	return;
9127 
9128     // second argument: dict with items to set in the tag stack
9129     if (argvars[1].v_type != VAR_DICT)
9130     {
9131 	emsg(_(e_dictreq));
9132 	return;
9133     }
9134     d = argvars[1].vval.v_dict;
9135     if (d == NULL)
9136 	return;
9137 
9138     // third argument: action - 'a' for append and 'r' for replace.
9139     // default is to replace the stack.
9140     if (argvars[2].v_type == VAR_UNKNOWN)
9141 	action = 'r';
9142     else if (argvars[2].v_type == VAR_STRING)
9143     {
9144 	char_u	*actstr;
9145 	actstr = tv_get_string_chk(&argvars[2]);
9146 	if (actstr == NULL)
9147 	    return;
9148 	if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
9149 		&& actstr[1] == NUL)
9150 	    action = *actstr;
9151 	else
9152 	{
9153 	    semsg(_(e_invact2), actstr);
9154 	    return;
9155 	}
9156     }
9157     else
9158     {
9159 	emsg(_(e_stringreq));
9160 	return;
9161     }
9162 
9163     if (set_tagstack(wp, d, action) == OK)
9164 	rettv->vval.v_number = 0;
9165 }
9166 
9167 #ifdef FEAT_CRYPT
9168 /*
9169  * "sha256({string})" function
9170  */
9171     static void
f_sha256(typval_T * argvars,typval_T * rettv)9172 f_sha256(typval_T *argvars, typval_T *rettv)
9173 {
9174     char_u	*p;
9175 
9176     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9177 	return;
9178 
9179     p = tv_get_string(&argvars[0]);
9180     rettv->vval.v_string = vim_strsave(
9181 				    sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9182     rettv->v_type = VAR_STRING;
9183 }
9184 #endif // FEAT_CRYPT
9185 
9186 /*
9187  * "shellescape({string})" function
9188  */
9189     static void
f_shellescape(typval_T * argvars,typval_T * rettv)9190 f_shellescape(typval_T *argvars, typval_T *rettv)
9191 {
9192     int do_special;
9193 
9194     if (in_vim9script()
9195 	    && (check_for_string_arg(argvars, 0) == FAIL
9196 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
9197 	return;
9198 
9199     do_special = non_zero_arg(&argvars[1]);
9200     rettv->vval.v_string = vim_strsave_shellescape(
9201 			   tv_get_string(&argvars[0]), do_special, do_special);
9202     rettv->v_type = VAR_STRING;
9203 }
9204 
9205 /*
9206  * shiftwidth() function
9207  */
9208     static void
f_shiftwidth(typval_T * argvars UNUSED,typval_T * rettv)9209 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9210 {
9211     rettv->vval.v_number = 0;
9212 
9213     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
9214 	return;
9215 
9216     if (argvars[0].v_type != VAR_UNKNOWN)
9217     {
9218 	long	col;
9219 
9220 	col = (long)tv_get_number_chk(argvars, NULL);
9221 	if (col < 0)
9222 	    return;	// type error; errmsg already given
9223 #ifdef FEAT_VARTABS
9224 	rettv->vval.v_number = get_sw_value_col(curbuf, col);
9225 	return;
9226 #endif
9227     }
9228 
9229     rettv->vval.v_number = get_sw_value(curbuf);
9230 }
9231 
9232 /*
9233  * "soundfold({word})" function
9234  */
9235     static void
f_soundfold(typval_T * argvars,typval_T * rettv)9236 f_soundfold(typval_T *argvars, typval_T *rettv)
9237 {
9238     char_u	*s;
9239 
9240     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9241 	return;
9242 
9243     rettv->v_type = VAR_STRING;
9244     s = tv_get_string(&argvars[0]);
9245 #ifdef FEAT_SPELL
9246     rettv->vval.v_string = eval_soundfold(s);
9247 #else
9248     rettv->vval.v_string = vim_strsave(s);
9249 #endif
9250 }
9251 
9252 /*
9253  * "spellbadword()" function
9254  */
9255     static void
f_spellbadword(typval_T * argvars UNUSED,typval_T * rettv)9256 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
9257 {
9258     char_u	*word = (char_u *)"";
9259     hlf_T	attr = HLF_COUNT;
9260     int		len = 0;
9261 #ifdef FEAT_SPELL
9262     int		wo_spell_save = curwin->w_p_spell;
9263 
9264     if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
9265 	return;
9266 
9267     if (!curwin->w_p_spell)
9268     {
9269 	did_set_spelllang(curwin);
9270 	curwin->w_p_spell = TRUE;
9271     }
9272 
9273     if (*curwin->w_s->b_p_spl == NUL)
9274     {
9275 	emsg(_(e_no_spell));
9276 	curwin->w_p_spell = wo_spell_save;
9277 	return;
9278     }
9279 #endif
9280 
9281     if (rettv_list_alloc(rettv) == FAIL)
9282     {
9283 #ifdef FEAT_SPELL
9284 	curwin->w_p_spell = wo_spell_save;
9285 #endif
9286 	return;
9287     }
9288 
9289 #ifdef FEAT_SPELL
9290     if (argvars[0].v_type == VAR_UNKNOWN)
9291     {
9292 	// Find the start and length of the badly spelled word.
9293 	len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
9294 	if (len != 0)
9295 	{
9296 	    word = ml_get_cursor();
9297 	    curwin->w_set_curswant = TRUE;
9298 	}
9299     }
9300     else if (*curbuf->b_s.b_p_spl != NUL)
9301     {
9302 	char_u	*str = tv_get_string_chk(&argvars[0]);
9303 	int	capcol = -1;
9304 
9305 	if (str != NULL)
9306 	{
9307 	    // Check the argument for spelling.
9308 	    while (*str != NUL)
9309 	    {
9310 		len = spell_check(curwin, str, &attr, &capcol, FALSE);
9311 		if (attr != HLF_COUNT)
9312 		{
9313 		    word = str;
9314 		    break;
9315 		}
9316 		str += len;
9317 		capcol -= len;
9318 		len = 0;
9319 	    }
9320 	}
9321     }
9322     curwin->w_p_spell = wo_spell_save;
9323 #endif
9324 
9325     list_append_string(rettv->vval.v_list, word, len);
9326     list_append_string(rettv->vval.v_list, (char_u *)(
9327 			attr == HLF_SPB ? "bad" :
9328 			attr == HLF_SPR ? "rare" :
9329 			attr == HLF_SPL ? "local" :
9330 			attr == HLF_SPC ? "caps" :
9331 			""), -1);
9332 }
9333 
9334 /*
9335  * "spellsuggest()" function
9336  */
9337     static void
f_spellsuggest(typval_T * argvars UNUSED,typval_T * rettv)9338 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
9339 {
9340 #ifdef FEAT_SPELL
9341     char_u	*str;
9342     int		typeerr = FALSE;
9343     int		maxcount;
9344     garray_T	ga;
9345     int		i;
9346     listitem_T	*li;
9347     int		need_capital = FALSE;
9348     int		wo_spell_save = curwin->w_p_spell;
9349 
9350     if (in_vim9script()
9351 	    && (check_for_string_arg(argvars, 0) == FAIL
9352 		|| check_for_opt_number_arg(argvars, 1) == FAIL
9353 		|| (argvars[1].v_type != VAR_UNKNOWN
9354 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
9355 	return;
9356 
9357     if (!curwin->w_p_spell)
9358     {
9359 	did_set_spelllang(curwin);
9360 	curwin->w_p_spell = TRUE;
9361     }
9362 
9363     if (*curwin->w_s->b_p_spl == NUL)
9364     {
9365 	emsg(_(e_no_spell));
9366 	curwin->w_p_spell = wo_spell_save;
9367 	return;
9368     }
9369 #endif
9370 
9371     if (rettv_list_alloc(rettv) == FAIL)
9372     {
9373 #ifdef FEAT_SPELL
9374 	curwin->w_p_spell = wo_spell_save;
9375 #endif
9376 	return;
9377     }
9378 
9379 #ifdef FEAT_SPELL
9380     if (*curwin->w_s->b_p_spl != NUL)
9381     {
9382 	str = tv_get_string(&argvars[0]);
9383 	if (argvars[1].v_type != VAR_UNKNOWN)
9384 	{
9385 	    maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
9386 	    if (maxcount <= 0)
9387 		return;
9388 	    if (argvars[2].v_type != VAR_UNKNOWN)
9389 	    {
9390 		need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
9391 		if (typeerr)
9392 		    return;
9393 	    }
9394 	}
9395 	else
9396 	    maxcount = 25;
9397 
9398 	spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
9399 
9400 	for (i = 0; i < ga.ga_len; ++i)
9401 	{
9402 	    str = ((char_u **)ga.ga_data)[i];
9403 
9404 	    li = listitem_alloc();
9405 	    if (li == NULL)
9406 		vim_free(str);
9407 	    else
9408 	    {
9409 		li->li_tv.v_type = VAR_STRING;
9410 		li->li_tv.v_lock = 0;
9411 		li->li_tv.vval.v_string = str;
9412 		list_append(rettv->vval.v_list, li);
9413 	    }
9414 	}
9415 	ga_clear(&ga);
9416     }
9417     curwin->w_p_spell = wo_spell_save;
9418 #endif
9419 }
9420 
9421     static void
f_split(typval_T * argvars,typval_T * rettv)9422 f_split(typval_T *argvars, typval_T *rettv)
9423 {
9424     char_u	*str;
9425     char_u	*end;
9426     char_u	*pat = NULL;
9427     regmatch_T	regmatch;
9428     char_u	patbuf[NUMBUFLEN];
9429     char_u	*save_cpo;
9430     int		match;
9431     colnr_T	col = 0;
9432     int		keepempty = FALSE;
9433     int		typeerr = FALSE;
9434 
9435     if (in_vim9script()
9436 	    && (check_for_string_arg(argvars, 0) == FAIL
9437 		|| check_for_opt_string_arg(argvars, 1) == FAIL
9438 		|| (argvars[1].v_type != VAR_UNKNOWN
9439 		    && check_for_opt_bool_arg(argvars, 2) == FAIL)))
9440 	return;
9441 
9442     // Make 'cpoptions' empty, the 'l' flag should not be used here.
9443     save_cpo = p_cpo;
9444     p_cpo = empty_option;
9445 
9446     str = tv_get_string(&argvars[0]);
9447     if (argvars[1].v_type != VAR_UNKNOWN)
9448     {
9449 	pat = tv_get_string_buf_chk(&argvars[1], patbuf);
9450 	if (pat == NULL)
9451 	    typeerr = TRUE;
9452 	if (argvars[2].v_type != VAR_UNKNOWN)
9453 	    keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
9454     }
9455     if (pat == NULL || *pat == NUL)
9456 	pat = (char_u *)"[\\x01- ]\\+";
9457 
9458     if (rettv_list_alloc(rettv) == FAIL)
9459 	goto theend;
9460     if (typeerr)
9461 	goto theend;
9462 
9463     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
9464     if (regmatch.regprog != NULL)
9465     {
9466 	regmatch.rm_ic = FALSE;
9467 	while (*str != NUL || keepempty)
9468 	{
9469 	    if (*str == NUL)
9470 		match = FALSE;	// empty item at the end
9471 	    else
9472 		match = vim_regexec_nl(&regmatch, str, col);
9473 	    if (match)
9474 		end = regmatch.startp[0];
9475 	    else
9476 		end = str + STRLEN(str);
9477 	    if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
9478 			   && *str != NUL && match && end < regmatch.endp[0]))
9479 	    {
9480 		if (list_append_string(rettv->vval.v_list, str,
9481 						    (int)(end - str)) == FAIL)
9482 		    break;
9483 	    }
9484 	    if (!match)
9485 		break;
9486 	    // Advance to just after the match.
9487 	    if (regmatch.endp[0] > str)
9488 		col = 0;
9489 	    else
9490 		// Don't get stuck at the same match.
9491 		col = (*mb_ptr2len)(regmatch.endp[0]);
9492 	    str = regmatch.endp[0];
9493 	}
9494 
9495 	vim_regfree(regmatch.regprog);
9496     }
9497 
9498 theend:
9499     p_cpo = save_cpo;
9500 }
9501 
9502 /*
9503  * "submatch()" function
9504  */
9505     static void
f_submatch(typval_T * argvars,typval_T * rettv)9506 f_submatch(typval_T *argvars, typval_T *rettv)
9507 {
9508     int		error = FALSE;
9509     int		no;
9510     int		retList = 0;
9511 
9512     if (in_vim9script()
9513 	    && (check_for_number_arg(argvars, 0) == FAIL
9514 		|| check_for_opt_bool_arg(argvars, 1) == FAIL))
9515 	return;
9516 
9517     no = (int)tv_get_number_chk(&argvars[0], &error);
9518     if (error)
9519 	return;
9520     if (no < 0 || no >= NSUBEXP)
9521     {
9522 	semsg(_("E935: invalid submatch number: %d"), no);
9523 	return;
9524     }
9525     if (argvars[1].v_type != VAR_UNKNOWN)
9526 	retList = (int)tv_get_bool_chk(&argvars[1], &error);
9527     if (error)
9528 	return;
9529 
9530     if (retList == 0)
9531     {
9532 	rettv->v_type = VAR_STRING;
9533 	rettv->vval.v_string = reg_submatch(no);
9534     }
9535     else
9536     {
9537 	rettv->v_type = VAR_LIST;
9538 	rettv->vval.v_list = reg_submatch_list(no);
9539     }
9540 }
9541 
9542 /*
9543  * "substitute()" function
9544  */
9545     static void
f_substitute(typval_T * argvars,typval_T * rettv)9546 f_substitute(typval_T *argvars, typval_T *rettv)
9547 {
9548     char_u	patbuf[NUMBUFLEN];
9549     char_u	subbuf[NUMBUFLEN];
9550     char_u	flagsbuf[NUMBUFLEN];
9551     char_u	*str;
9552     char_u	*pat;
9553     char_u	*sub = NULL;
9554     typval_T	*expr = NULL;
9555     char_u	*flg;
9556 
9557     if (in_vim9script()
9558 	    && (check_for_string_arg(argvars, 0) == FAIL
9559 		|| check_for_string_arg(argvars, 1) == FAIL
9560 		|| check_for_string_arg(argvars, 3) == FAIL))
9561 	return;
9562 
9563     str = tv_get_string_chk(&argvars[0]);
9564     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
9565     flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
9566 
9567     if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
9568 	expr = &argvars[2];
9569     else
9570 	sub = tv_get_string_buf_chk(&argvars[2], subbuf);
9571 
9572     rettv->v_type = VAR_STRING;
9573     if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
9574 								|| flg == NULL)
9575 	rettv->vval.v_string = NULL;
9576     else
9577 	rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
9578 }
9579 
9580 /*
9581  * "swapinfo(swap_filename)" function
9582  */
9583     static void
f_swapinfo(typval_T * argvars,typval_T * rettv)9584 f_swapinfo(typval_T *argvars, typval_T *rettv)
9585 {
9586     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
9587 	return;
9588 
9589     if (rettv_dict_alloc(rettv) == OK)
9590 	get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
9591 }
9592 
9593 /*
9594  * "swapname(expr)" function
9595  */
9596     static void
f_swapname(typval_T * argvars,typval_T * rettv)9597 f_swapname(typval_T *argvars, typval_T *rettv)
9598 {
9599     buf_T	*buf;
9600 
9601     rettv->v_type = VAR_STRING;
9602 
9603     if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
9604 	return;
9605 
9606     buf = tv_get_buf(&argvars[0], FALSE);
9607     if (buf == NULL || buf->b_ml.ml_mfp == NULL
9608 					|| buf->b_ml.ml_mfp->mf_fname == NULL)
9609 	rettv->vval.v_string = NULL;
9610     else
9611 	rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9612 }
9613 
9614 /*
9615  * "synID(lnum, col, trans)" function
9616  */
9617     static void
f_synID(typval_T * argvars UNUSED,typval_T * rettv)9618 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9619 {
9620     int		id = 0;
9621 #ifdef FEAT_SYN_HL
9622     linenr_T	lnum;
9623     colnr_T	col;
9624     int		trans;
9625     int		transerr = FALSE;
9626 
9627     if (in_vim9script()
9628 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9629 		|| check_for_number_arg(argvars, 1) == FAIL
9630 		|| check_for_bool_arg(argvars, 2) == FAIL))
9631 	return;
9632 
9633     lnum = tv_get_lnum(argvars);		// -1 on type error
9634     col = (linenr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9635     trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
9636 
9637     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9638 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9639 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9640 #endif
9641 
9642     rettv->vval.v_number = id;
9643 }
9644 
9645 /*
9646  * "synIDattr(id, what [, mode])" function
9647  */
9648     static void
f_synIDattr(typval_T * argvars UNUSED,typval_T * rettv)9649 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9650 {
9651     char_u	*p = NULL;
9652 #ifdef FEAT_SYN_HL
9653     int		id;
9654     char_u	*what;
9655     char_u	*mode;
9656     char_u	modebuf[NUMBUFLEN];
9657     int		modec;
9658 
9659     if (in_vim9script()
9660 	    && (check_for_number_arg(argvars, 0) == FAIL
9661 		|| check_for_string_arg(argvars, 1) == FAIL
9662 		|| check_for_opt_string_arg(argvars, 2) == FAIL))
9663 	return;
9664 
9665     id = (int)tv_get_number(&argvars[0]);
9666     what = tv_get_string(&argvars[1]);
9667     if (argvars[2].v_type != VAR_UNKNOWN)
9668     {
9669 	mode = tv_get_string_buf(&argvars[2], modebuf);
9670 	modec = TOLOWER_ASC(mode[0]);
9671 	if (modec != 't' && modec != 'c' && modec != 'g')
9672 	    modec = 0;	// replace invalid with current
9673     }
9674     else
9675     {
9676 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9677 	if (USE_24BIT)
9678 	    modec = 'g';
9679 	else
9680 #endif
9681 	    if (t_colors > 1)
9682 		modec = 'c';
9683 	    else
9684 		modec = 't';
9685     }
9686 
9687     switch (TOLOWER_ASC(what[0]))
9688     {
9689 	case 'b':
9690 		if (TOLOWER_ASC(what[1]) == 'g')	// bg[#]
9691 		    p = highlight_color(id, what, modec);
9692 		else					// bold
9693 		    p = highlight_has_attr(id, HL_BOLD, modec);
9694 		break;
9695 
9696 	case 'f':					// fg[#] or font
9697 		p = highlight_color(id, what, modec);
9698 		break;
9699 
9700 	case 'i':
9701 		if (TOLOWER_ASC(what[1]) == 'n')	// inverse
9702 		    p = highlight_has_attr(id, HL_INVERSE, modec);
9703 		else					// italic
9704 		    p = highlight_has_attr(id, HL_ITALIC, modec);
9705 		break;
9706 
9707 	case 'n':					// name
9708 		p = get_highlight_name_ext(NULL, id - 1, FALSE);
9709 		break;
9710 
9711 	case 'r':					// reverse
9712 		p = highlight_has_attr(id, HL_INVERSE, modec);
9713 		break;
9714 
9715 	case 's':
9716 		if (TOLOWER_ASC(what[1]) == 'p')	// sp[#]
9717 		    p = highlight_color(id, what, modec);
9718 							// strikeout
9719 		else if (TOLOWER_ASC(what[1]) == 't' &&
9720 			TOLOWER_ASC(what[2]) == 'r')
9721 		    p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
9722 		else					// standout
9723 		    p = highlight_has_attr(id, HL_STANDOUT, modec);
9724 		break;
9725 
9726 	case 'u':
9727 		if (TOLOWER_ASC(what[1]) == 'l')	// ul
9728 		    p = highlight_color(id, what, modec);
9729 		else if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
9730 							// underline
9731 		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
9732 		else
9733 							// undercurl
9734 		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
9735 		break;
9736     }
9737 
9738     if (p != NULL)
9739 	p = vim_strsave(p);
9740 #endif
9741     rettv->v_type = VAR_STRING;
9742     rettv->vval.v_string = p;
9743 }
9744 
9745 /*
9746  * "synIDtrans(id)" function
9747  */
9748     static void
f_synIDtrans(typval_T * argvars UNUSED,typval_T * rettv)9749 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9750 {
9751     int		id;
9752 
9753 #ifdef FEAT_SYN_HL
9754     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
9755 	return;
9756 
9757     id = (int)tv_get_number(&argvars[0]);
9758 
9759     if (id > 0)
9760 	id = syn_get_final_id(id);
9761     else
9762 #endif
9763 	id = 0;
9764 
9765     rettv->vval.v_number = id;
9766 }
9767 
9768 /*
9769  * "synconcealed(lnum, col)" function
9770  */
9771     static void
f_synconcealed(typval_T * argvars UNUSED,typval_T * rettv)9772 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9773 {
9774 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9775     linenr_T	lnum;
9776     colnr_T	col;
9777     int		syntax_flags = 0;
9778     int		cchar;
9779     int		matchid = 0;
9780     char_u	str[NUMBUFLEN];
9781 #endif
9782 
9783     rettv_list_set(rettv, NULL);
9784 
9785     if (in_vim9script()
9786 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9787 		|| check_for_number_arg(argvars, 1) == FAIL))
9788 	return;
9789 
9790 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9791     lnum = tv_get_lnum(argvars);		// -1 on type error
9792     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9793 
9794     CLEAR_FIELD(str);
9795 
9796     if (rettv_list_alloc(rettv) != FAIL)
9797     {
9798 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9799 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9800 	    && curwin->w_p_cole > 0)
9801 	{
9802 	    (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9803 	    syntax_flags = get_syntax_info(&matchid);
9804 
9805 	    // get the conceal character
9806 	    if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9807 	    {
9808 		cchar = syn_get_sub_char();
9809 		if (cchar == NUL && curwin->w_p_cole == 1)
9810 		    cchar = (curwin->w_lcs_chars.conceal == NUL) ? ' '
9811 					: curwin->w_lcs_chars.conceal;
9812 		if (cchar != NUL)
9813 		{
9814 		    if (has_mbyte)
9815 			(*mb_char2bytes)(cchar, str);
9816 		    else
9817 			str[0] = cchar;
9818 		}
9819 	    }
9820 	}
9821 
9822 	list_append_number(rettv->vval.v_list,
9823 					    (syntax_flags & HL_CONCEAL) != 0);
9824 	// -1 to auto-determine strlen
9825 	list_append_string(rettv->vval.v_list, str, -1);
9826 	list_append_number(rettv->vval.v_list, matchid);
9827     }
9828 #endif
9829 }
9830 
9831 /*
9832  * "synstack(lnum, col)" function
9833  */
9834     static void
f_synstack(typval_T * argvars UNUSED,typval_T * rettv)9835 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9836 {
9837 #ifdef FEAT_SYN_HL
9838     linenr_T	lnum;
9839     colnr_T	col;
9840     int		i;
9841     int		id;
9842 #endif
9843 
9844     rettv_list_set(rettv, NULL);
9845 
9846     if (in_vim9script()
9847 	    && (check_for_lnum_arg(argvars, 0) == FAIL
9848 		|| check_for_number_arg(argvars, 1) == FAIL))
9849 	return;
9850 
9851 #ifdef FEAT_SYN_HL
9852     lnum = tv_get_lnum(argvars);		// -1 on type error
9853     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	// -1 on type error
9854 
9855     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9856 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9857 	    && rettv_list_alloc(rettv) != FAIL)
9858     {
9859 	(void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9860 	for (i = 0; ; ++i)
9861 	{
9862 	    id = syn_get_stack_item(i);
9863 	    if (id < 0)
9864 		break;
9865 	    if (list_append_number(rettv->vval.v_list, id) == FAIL)
9866 		break;
9867 	}
9868     }
9869 #endif
9870 }
9871 
9872 /*
9873  * "tabpagebuflist()" function
9874  */
9875     static void
f_tabpagebuflist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)9876 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9877 {
9878     tabpage_T	*tp;
9879     win_T	*wp = NULL;
9880 
9881     if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
9882 	return;
9883 
9884     if (argvars[0].v_type == VAR_UNKNOWN)
9885 	wp = firstwin;
9886     else
9887     {
9888 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
9889 	if (tp != NULL)
9890 	    wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9891     }
9892     if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9893     {
9894 	for (; wp != NULL; wp = wp->w_next)
9895 	    if (list_append_number(rettv->vval.v_list,
9896 						wp->w_buffer->b_fnum) == FAIL)
9897 		break;
9898     }
9899 }
9900 
9901 /*
9902  * "tagfiles()" function
9903  */
9904     static void
f_tagfiles(typval_T * argvars UNUSED,typval_T * rettv)9905 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9906 {
9907     char_u	*fname;
9908     tagname_T	tn;
9909     int		first;
9910 
9911     if (rettv_list_alloc(rettv) == FAIL)
9912 	return;
9913     fname = alloc(MAXPATHL);
9914     if (fname == NULL)
9915 	return;
9916 
9917     for (first = TRUE; ; first = FALSE)
9918 	if (get_tagfname(&tn, first, fname) == FAIL
9919 		|| list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9920 	    break;
9921     tagname_free(&tn);
9922     vim_free(fname);
9923 }
9924 
9925 /*
9926  * "taglist()" function
9927  */
9928     static void
f_taglist(typval_T * argvars,typval_T * rettv)9929 f_taglist(typval_T *argvars, typval_T *rettv)
9930 {
9931     char_u  *fname = NULL;
9932     char_u  *tag_pattern;
9933 
9934     if (in_vim9script()
9935 	    && (check_for_string_arg(argvars, 0) == FAIL
9936 		|| check_for_opt_string_arg(argvars, 1) == FAIL))
9937 	return;
9938 
9939     tag_pattern = tv_get_string(&argvars[0]);
9940 
9941     rettv->vval.v_number = FALSE;
9942     if (*tag_pattern == NUL)
9943 	return;
9944 
9945     if (argvars[1].v_type != VAR_UNKNOWN)
9946 	fname = tv_get_string(&argvars[1]);
9947     if (rettv_list_alloc(rettv) == OK)
9948 	(void)get_tags(rettv->vval.v_list, tag_pattern, fname);
9949 }
9950 
9951 /*
9952  * "type(expr)" function
9953  */
9954     static void
f_type(typval_T * argvars,typval_T * rettv)9955 f_type(typval_T *argvars, typval_T *rettv)
9956 {
9957     int n = -1;
9958 
9959     switch (argvars[0].v_type)
9960     {
9961 	case VAR_NUMBER:  n = VAR_TYPE_NUMBER; break;
9962 	case VAR_STRING:  n = VAR_TYPE_STRING; break;
9963 	case VAR_PARTIAL:
9964 	case VAR_FUNC:    n = VAR_TYPE_FUNC; break;
9965 	case VAR_LIST:    n = VAR_TYPE_LIST; break;
9966 	case VAR_DICT:    n = VAR_TYPE_DICT; break;
9967 	case VAR_FLOAT:   n = VAR_TYPE_FLOAT; break;
9968 	case VAR_BOOL:	  n = VAR_TYPE_BOOL; break;
9969 	case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
9970 	case VAR_JOB:     n = VAR_TYPE_JOB; break;
9971 	case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
9972 	case VAR_BLOB:    n = VAR_TYPE_BLOB; break;
9973 	case VAR_INSTR:   n = VAR_TYPE_INSTR; break;
9974 	case VAR_UNKNOWN:
9975 	case VAR_ANY:
9976 	case VAR_VOID:
9977 	     internal_error_no_abort("f_type(UNKNOWN)");
9978 	     n = -1;
9979 	     break;
9980     }
9981     rettv->vval.v_number = n;
9982 }
9983 
9984 /*
9985  * "virtcol(string)" function
9986  */
9987     static void
f_virtcol(typval_T * argvars,typval_T * rettv)9988 f_virtcol(typval_T *argvars, typval_T *rettv)
9989 {
9990     colnr_T	vcol = 0;
9991     pos_T	*fp;
9992     int		fnum = curbuf->b_fnum;
9993     int		len;
9994 
9995     if (in_vim9script()
9996 	    && check_for_string_or_list_arg(argvars, 0) == FAIL)
9997 	return;
9998 
9999     fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
10000     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
10001 						    && fnum == curbuf->b_fnum)
10002     {
10003 	// Limit the column to a valid value, getvvcol() doesn't check.
10004 	if (fp->col < 0)
10005 	    fp->col = 0;
10006 	else
10007 	{
10008 	    len = (int)STRLEN(ml_get(fp->lnum));
10009 	    if (fp->col > len)
10010 		fp->col = len;
10011 	}
10012 	getvvcol(curwin, fp, NULL, NULL, &vcol);
10013 	++vcol;
10014     }
10015 
10016     rettv->vval.v_number = vcol;
10017 }
10018 
10019 /*
10020  * "visualmode()" function
10021  */
10022     static void
f_visualmode(typval_T * argvars,typval_T * rettv)10023 f_visualmode(typval_T *argvars, typval_T *rettv)
10024 {
10025     char_u	str[2];
10026 
10027     if (in_vim9script() && check_for_opt_bool_arg(argvars, 0) == FAIL)
10028 	return;
10029 
10030     rettv->v_type = VAR_STRING;
10031     str[0] = curbuf->b_visual_mode_eval;
10032     str[1] = NUL;
10033     rettv->vval.v_string = vim_strsave(str);
10034 
10035     // A non-zero number or non-empty string argument: reset mode.
10036     if (non_zero_arg(&argvars[0]))
10037 	curbuf->b_visual_mode_eval = NUL;
10038 }
10039 
10040 /*
10041  * "wildmenumode()" function
10042  */
10043     static void
f_wildmenumode(typval_T * argvars UNUSED,typval_T * rettv UNUSED)10044 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10045 {
10046 #ifdef FEAT_WILDMENU
10047     if (wild_menu_showing)
10048 	rettv->vval.v_number = 1;
10049 #endif
10050 }
10051 
10052 /*
10053  * "windowsversion()" function
10054  */
10055     static void
f_windowsversion(typval_T * argvars UNUSED,typval_T * rettv UNUSED)10056 f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10057 {
10058     rettv->v_type = VAR_STRING;
10059     rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
10060 }
10061 
10062 /*
10063  * "wordcount()" function
10064  */
10065     static void
f_wordcount(typval_T * argvars UNUSED,typval_T * rettv)10066 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
10067 {
10068     if (rettv_dict_alloc(rettv) == FAIL)
10069 	return;
10070     cursor_pos_info(rettv->vval.v_dict);
10071 }
10072 
10073 /*
10074  * "xor(expr, expr)" function
10075  */
10076     static void
f_xor(typval_T * argvars,typval_T * rettv)10077 f_xor(typval_T *argvars, typval_T *rettv)
10078 {
10079     if (in_vim9script()
10080 	    && (check_for_number_arg(argvars, 0) == FAIL
10081 		|| check_for_number_arg(argvars, 1) == FAIL))
10082 	return;
10083 
10084     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
10085 					^ tv_get_number_chk(&argvars[1], NULL);
10086 }
10087 
10088 #endif // FEAT_EVAL
10089