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