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, ®len))
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(®match, 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, ®len))
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(®match, 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