xref: /vim-8.2.3635/src/evalfunc.c (revision e46736b2)
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 AMIGA
20 # include <time.h>	/* for strftime() */
21 #endif
22 
23 #ifdef VMS
24 # include <float.h>
25 #endif
26 
27 #ifdef MACOS_X
28 # include <time.h>	/* for time_t */
29 #endif
30 
31 static char *e_listarg = N_("E686: Argument of %s must be a List");
32 static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
33 static char *e_stringreq = N_("E928: String required");
34 
35 #ifdef FEAT_FLOAT
36 static void f_abs(typval_T *argvars, typval_T *rettv);
37 static void f_acos(typval_T *argvars, typval_T *rettv);
38 #endif
39 static void f_add(typval_T *argvars, typval_T *rettv);
40 static void f_and(typval_T *argvars, typval_T *rettv);
41 static void f_append(typval_T *argvars, typval_T *rettv);
42 static void f_appendbufline(typval_T *argvars, typval_T *rettv);
43 static void f_argc(typval_T *argvars, typval_T *rettv);
44 static void f_argidx(typval_T *argvars, typval_T *rettv);
45 static void f_arglistid(typval_T *argvars, typval_T *rettv);
46 static void f_argv(typval_T *argvars, typval_T *rettv);
47 static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
48 static void f_assert_equal(typval_T *argvars, typval_T *rettv);
49 static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
50 static void f_assert_exception(typval_T *argvars, typval_T *rettv);
51 static void f_assert_fails(typval_T *argvars, typval_T *rettv);
52 static void f_assert_false(typval_T *argvars, typval_T *rettv);
53 static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
54 static void f_assert_match(typval_T *argvars, typval_T *rettv);
55 static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
56 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
57 static void f_assert_report(typval_T *argvars, typval_T *rettv);
58 static void f_assert_true(typval_T *argvars, typval_T *rettv);
59 #ifdef FEAT_FLOAT
60 static void f_asin(typval_T *argvars, typval_T *rettv);
61 static void f_atan(typval_T *argvars, typval_T *rettv);
62 static void f_atan2(typval_T *argvars, typval_T *rettv);
63 #endif
64 #ifdef FEAT_BEVAL
65 static void f_balloon_show(typval_T *argvars, typval_T *rettv);
66 # if defined(FEAT_BEVAL_TERM)
67 static void f_balloon_split(typval_T *argvars, typval_T *rettv);
68 # endif
69 #endif
70 static void f_browse(typval_T *argvars, typval_T *rettv);
71 static void f_browsedir(typval_T *argvars, typval_T *rettv);
72 static void f_bufexists(typval_T *argvars, typval_T *rettv);
73 static void f_buflisted(typval_T *argvars, typval_T *rettv);
74 static void f_bufloaded(typval_T *argvars, typval_T *rettv);
75 static void f_bufname(typval_T *argvars, typval_T *rettv);
76 static void f_bufnr(typval_T *argvars, typval_T *rettv);
77 static void f_bufwinid(typval_T *argvars, typval_T *rettv);
78 static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
79 static void f_byte2line(typval_T *argvars, typval_T *rettv);
80 static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
81 static void f_byteidx(typval_T *argvars, typval_T *rettv);
82 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
83 static void f_call(typval_T *argvars, typval_T *rettv);
84 #ifdef FEAT_FLOAT
85 static void f_ceil(typval_T *argvars, typval_T *rettv);
86 #endif
87 #ifdef FEAT_JOB_CHANNEL
88 static void f_ch_canread(typval_T *argvars, typval_T *rettv);
89 static void f_ch_close(typval_T *argvars, typval_T *rettv);
90 static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
91 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
92 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
93 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
94 static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
95 static void f_ch_info(typval_T *argvars, typval_T *rettv);
96 static void f_ch_log(typval_T *argvars, typval_T *rettv);
97 static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
98 static void f_ch_open(typval_T *argvars, typval_T *rettv);
99 static void f_ch_read(typval_T *argvars, typval_T *rettv);
100 static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
101 static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
102 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
103 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
104 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
105 static void f_ch_status(typval_T *argvars, typval_T *rettv);
106 #endif
107 static void f_changenr(typval_T *argvars, typval_T *rettv);
108 static void f_char2nr(typval_T *argvars, typval_T *rettv);
109 static void f_cindent(typval_T *argvars, typval_T *rettv);
110 static void f_clearmatches(typval_T *argvars, typval_T *rettv);
111 static void f_col(typval_T *argvars, typval_T *rettv);
112 #if defined(FEAT_INS_EXPAND)
113 static void f_complete(typval_T *argvars, typval_T *rettv);
114 static void f_complete_add(typval_T *argvars, typval_T *rettv);
115 static void f_complete_check(typval_T *argvars, typval_T *rettv);
116 static void f_complete_info(typval_T *argvars, typval_T *rettv);
117 #endif
118 static void f_confirm(typval_T *argvars, typval_T *rettv);
119 static void f_copy(typval_T *argvars, typval_T *rettv);
120 #ifdef FEAT_FLOAT
121 static void f_cos(typval_T *argvars, typval_T *rettv);
122 static void f_cosh(typval_T *argvars, typval_T *rettv);
123 #endif
124 static void f_count(typval_T *argvars, typval_T *rettv);
125 static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
126 static void f_cursor(typval_T *argsvars, typval_T *rettv);
127 #ifdef MSWIN
128 static void f_debugbreak(typval_T *argvars, typval_T *rettv);
129 #endif
130 static void f_deepcopy(typval_T *argvars, typval_T *rettv);
131 static void f_delete(typval_T *argvars, typval_T *rettv);
132 static void f_deletebufline(typval_T *argvars, typval_T *rettv);
133 static void f_did_filetype(typval_T *argvars, typval_T *rettv);
134 static void f_diff_filler(typval_T *argvars, typval_T *rettv);
135 static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
136 static void f_empty(typval_T *argvars, typval_T *rettv);
137 static void f_escape(typval_T *argvars, typval_T *rettv);
138 static void f_eval(typval_T *argvars, typval_T *rettv);
139 static void f_eventhandler(typval_T *argvars, typval_T *rettv);
140 static void f_executable(typval_T *argvars, typval_T *rettv);
141 static void f_execute(typval_T *argvars, typval_T *rettv);
142 static void f_exepath(typval_T *argvars, typval_T *rettv);
143 static void f_exists(typval_T *argvars, typval_T *rettv);
144 #ifdef FEAT_FLOAT
145 static void f_exp(typval_T *argvars, typval_T *rettv);
146 #endif
147 static void f_expand(typval_T *argvars, typval_T *rettv);
148 static void f_extend(typval_T *argvars, typval_T *rettv);
149 static void f_feedkeys(typval_T *argvars, typval_T *rettv);
150 static void f_filereadable(typval_T *argvars, typval_T *rettv);
151 static void f_filewritable(typval_T *argvars, typval_T *rettv);
152 static void f_filter(typval_T *argvars, typval_T *rettv);
153 static void f_finddir(typval_T *argvars, typval_T *rettv);
154 static void f_findfile(typval_T *argvars, typval_T *rettv);
155 #ifdef FEAT_FLOAT
156 static void f_float2nr(typval_T *argvars, typval_T *rettv);
157 static void f_floor(typval_T *argvars, typval_T *rettv);
158 static void f_fmod(typval_T *argvars, typval_T *rettv);
159 #endif
160 static void f_fnameescape(typval_T *argvars, typval_T *rettv);
161 static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
162 static void f_foldclosed(typval_T *argvars, typval_T *rettv);
163 static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
164 static void f_foldlevel(typval_T *argvars, typval_T *rettv);
165 static void f_foldtext(typval_T *argvars, typval_T *rettv);
166 static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
167 static void f_foreground(typval_T *argvars, typval_T *rettv);
168 static void f_funcref(typval_T *argvars, typval_T *rettv);
169 static void f_function(typval_T *argvars, typval_T *rettv);
170 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
171 static void f_get(typval_T *argvars, typval_T *rettv);
172 static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
173 static void f_getbufline(typval_T *argvars, typval_T *rettv);
174 static void f_getbufvar(typval_T *argvars, typval_T *rettv);
175 static void f_getchangelist(typval_T *argvars, typval_T *rettv);
176 static void f_getchar(typval_T *argvars, typval_T *rettv);
177 static void f_getcharmod(typval_T *argvars, typval_T *rettv);
178 static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
179 static void f_getcmdline(typval_T *argvars, typval_T *rettv);
180 #if defined(FEAT_CMDL_COMPL)
181 static void f_getcompletion(typval_T *argvars, typval_T *rettv);
182 #endif
183 static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
184 static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
185 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
186 static void f_getcwd(typval_T *argvars, typval_T *rettv);
187 static void f_getfontname(typval_T *argvars, typval_T *rettv);
188 static void f_getfperm(typval_T *argvars, typval_T *rettv);
189 static void f_getfsize(typval_T *argvars, typval_T *rettv);
190 static void f_getftime(typval_T *argvars, typval_T *rettv);
191 static void f_getftype(typval_T *argvars, typval_T *rettv);
192 static void f_getjumplist(typval_T *argvars, typval_T *rettv);
193 static void f_getline(typval_T *argvars, typval_T *rettv);
194 static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
195 static void f_getmatches(typval_T *argvars, typval_T *rettv);
196 static void f_getpid(typval_T *argvars, typval_T *rettv);
197 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
198 static void f_getpos(typval_T *argvars, typval_T *rettv);
199 static void f_getqflist(typval_T *argvars, typval_T *rettv);
200 static void f_getreg(typval_T *argvars, typval_T *rettv);
201 static void f_getregtype(typval_T *argvars, typval_T *rettv);
202 static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
203 static void f_gettabvar(typval_T *argvars, typval_T *rettv);
204 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
205 static void f_gettagstack(typval_T *argvars, typval_T *rettv);
206 static void f_getwininfo(typval_T *argvars, typval_T *rettv);
207 static void f_getwinpos(typval_T *argvars, typval_T *rettv);
208 static void f_getwinposx(typval_T *argvars, typval_T *rettv);
209 static void f_getwinposy(typval_T *argvars, typval_T *rettv);
210 static void f_getwinvar(typval_T *argvars, typval_T *rettv);
211 static void f_glob(typval_T *argvars, typval_T *rettv);
212 static void f_globpath(typval_T *argvars, typval_T *rettv);
213 static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
214 static void f_has(typval_T *argvars, typval_T *rettv);
215 static void f_has_key(typval_T *argvars, typval_T *rettv);
216 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
217 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
218 static void f_histadd(typval_T *argvars, typval_T *rettv);
219 static void f_histdel(typval_T *argvars, typval_T *rettv);
220 static void f_histget(typval_T *argvars, typval_T *rettv);
221 static void f_histnr(typval_T *argvars, typval_T *rettv);
222 static void f_hlID(typval_T *argvars, typval_T *rettv);
223 static void f_hlexists(typval_T *argvars, typval_T *rettv);
224 static void f_hostname(typval_T *argvars, typval_T *rettv);
225 static void f_iconv(typval_T *argvars, typval_T *rettv);
226 static void f_indent(typval_T *argvars, typval_T *rettv);
227 static void f_index(typval_T *argvars, typval_T *rettv);
228 static void f_input(typval_T *argvars, typval_T *rettv);
229 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
230 static void f_inputlist(typval_T *argvars, typval_T *rettv);
231 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
232 static void f_inputsave(typval_T *argvars, typval_T *rettv);
233 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
234 static void f_insert(typval_T *argvars, typval_T *rettv);
235 static void f_invert(typval_T *argvars, typval_T *rettv);
236 static void f_isdirectory(typval_T *argvars, typval_T *rettv);
237 static void f_islocked(typval_T *argvars, typval_T *rettv);
238 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
239 static void f_isnan(typval_T *argvars, typval_T *rettv);
240 #endif
241 static void f_items(typval_T *argvars, typval_T *rettv);
242 #ifdef FEAT_JOB_CHANNEL
243 static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
244 static void f_job_info(typval_T *argvars, typval_T *rettv);
245 static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
246 static void f_job_start(typval_T *argvars, typval_T *rettv);
247 static void f_job_stop(typval_T *argvars, typval_T *rettv);
248 static void f_job_status(typval_T *argvars, typval_T *rettv);
249 #endif
250 static void f_join(typval_T *argvars, typval_T *rettv);
251 static void f_js_decode(typval_T *argvars, typval_T *rettv);
252 static void f_js_encode(typval_T *argvars, typval_T *rettv);
253 static void f_json_decode(typval_T *argvars, typval_T *rettv);
254 static void f_json_encode(typval_T *argvars, typval_T *rettv);
255 static void f_keys(typval_T *argvars, typval_T *rettv);
256 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
257 static void f_len(typval_T *argvars, typval_T *rettv);
258 static void f_libcall(typval_T *argvars, typval_T *rettv);
259 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
260 static void f_line(typval_T *argvars, typval_T *rettv);
261 static void f_line2byte(typval_T *argvars, typval_T *rettv);
262 static void f_lispindent(typval_T *argvars, typval_T *rettv);
263 static void f_localtime(typval_T *argvars, typval_T *rettv);
264 #ifdef FEAT_FLOAT
265 static void f_log(typval_T *argvars, typval_T *rettv);
266 static void f_log10(typval_T *argvars, typval_T *rettv);
267 #endif
268 #ifdef FEAT_LUA
269 static void f_luaeval(typval_T *argvars, typval_T *rettv);
270 #endif
271 static void f_map(typval_T *argvars, typval_T *rettv);
272 static void f_maparg(typval_T *argvars, typval_T *rettv);
273 static void f_mapcheck(typval_T *argvars, typval_T *rettv);
274 static void f_match(typval_T *argvars, typval_T *rettv);
275 static void f_matchadd(typval_T *argvars, typval_T *rettv);
276 static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
277 static void f_matcharg(typval_T *argvars, typval_T *rettv);
278 static void f_matchdelete(typval_T *argvars, typval_T *rettv);
279 static void f_matchend(typval_T *argvars, typval_T *rettv);
280 static void f_matchlist(typval_T *argvars, typval_T *rettv);
281 static void f_matchstr(typval_T *argvars, typval_T *rettv);
282 static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
283 static void f_max(typval_T *argvars, typval_T *rettv);
284 static void f_min(typval_T *argvars, typval_T *rettv);
285 #ifdef vim_mkdir
286 static void f_mkdir(typval_T *argvars, typval_T *rettv);
287 #endif
288 static void f_mode(typval_T *argvars, typval_T *rettv);
289 #ifdef FEAT_MZSCHEME
290 static void f_mzeval(typval_T *argvars, typval_T *rettv);
291 #endif
292 static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
293 static void f_nr2char(typval_T *argvars, typval_T *rettv);
294 static void f_or(typval_T *argvars, typval_T *rettv);
295 static void f_pathshorten(typval_T *argvars, typval_T *rettv);
296 #ifdef FEAT_PERL
297 static void f_perleval(typval_T *argvars, typval_T *rettv);
298 #endif
299 #ifdef FEAT_FLOAT
300 static void f_pow(typval_T *argvars, typval_T *rettv);
301 #endif
302 static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
303 static void f_printf(typval_T *argvars, typval_T *rettv);
304 #ifdef FEAT_JOB_CHANNEL
305 static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
306 static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
307 static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
308 #endif
309 static void f_pumvisible(typval_T *argvars, typval_T *rettv);
310 #ifdef FEAT_PYTHON3
311 static void f_py3eval(typval_T *argvars, typval_T *rettv);
312 #endif
313 #ifdef FEAT_PYTHON
314 static void f_pyeval(typval_T *argvars, typval_T *rettv);
315 #endif
316 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
317 static void f_pyxeval(typval_T *argvars, typval_T *rettv);
318 #endif
319 static void f_range(typval_T *argvars, typval_T *rettv);
320 static void f_readfile(typval_T *argvars, typval_T *rettv);
321 static void f_reg_executing(typval_T *argvars, typval_T *rettv);
322 static void f_reg_recording(typval_T *argvars, typval_T *rettv);
323 static void f_reltime(typval_T *argvars, typval_T *rettv);
324 #ifdef FEAT_FLOAT
325 static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
326 #endif
327 static void f_reltimestr(typval_T *argvars, typval_T *rettv);
328 static void f_remote_expr(typval_T *argvars, typval_T *rettv);
329 static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
330 static void f_remote_peek(typval_T *argvars, typval_T *rettv);
331 static void f_remote_read(typval_T *argvars, typval_T *rettv);
332 static void f_remote_send(typval_T *argvars, typval_T *rettv);
333 static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
334 static void f_remove(typval_T *argvars, typval_T *rettv);
335 static void f_rename(typval_T *argvars, typval_T *rettv);
336 static void f_repeat(typval_T *argvars, typval_T *rettv);
337 static void f_resolve(typval_T *argvars, typval_T *rettv);
338 static void f_reverse(typval_T *argvars, typval_T *rettv);
339 #ifdef FEAT_FLOAT
340 static void f_round(typval_T *argvars, typval_T *rettv);
341 #endif
342 #ifdef FEAT_RUBY
343 static void f_rubyeval(typval_T *argvars, typval_T *rettv);
344 #endif
345 static void f_screenattr(typval_T *argvars, typval_T *rettv);
346 static void f_screenchar(typval_T *argvars, typval_T *rettv);
347 static void f_screencol(typval_T *argvars, typval_T *rettv);
348 static void f_screenrow(typval_T *argvars, typval_T *rettv);
349 static void f_search(typval_T *argvars, typval_T *rettv);
350 static void f_searchdecl(typval_T *argvars, typval_T *rettv);
351 static void f_searchpair(typval_T *argvars, typval_T *rettv);
352 static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
353 static void f_searchpos(typval_T *argvars, typval_T *rettv);
354 static void f_server2client(typval_T *argvars, typval_T *rettv);
355 static void f_serverlist(typval_T *argvars, typval_T *rettv);
356 static void f_setbufline(typval_T *argvars, typval_T *rettv);
357 static void f_setbufvar(typval_T *argvars, typval_T *rettv);
358 static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
359 static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
360 static void f_setfperm(typval_T *argvars, typval_T *rettv);
361 static void f_setline(typval_T *argvars, typval_T *rettv);
362 static void f_setloclist(typval_T *argvars, typval_T *rettv);
363 static void f_setmatches(typval_T *argvars, typval_T *rettv);
364 static void f_setpos(typval_T *argvars, typval_T *rettv);
365 static void f_setqflist(typval_T *argvars, typval_T *rettv);
366 static void f_setreg(typval_T *argvars, typval_T *rettv);
367 static void f_settabvar(typval_T *argvars, typval_T *rettv);
368 static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
369 static void f_settagstack(typval_T *argvars, typval_T *rettv);
370 static void f_setwinvar(typval_T *argvars, typval_T *rettv);
371 #ifdef FEAT_CRYPT
372 static void f_sha256(typval_T *argvars, typval_T *rettv);
373 #endif /* FEAT_CRYPT */
374 static void f_shellescape(typval_T *argvars, typval_T *rettv);
375 static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
376 #ifdef FEAT_SIGNS
377 static void f_sign_define(typval_T *argvars, typval_T *rettv);
378 static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
379 static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
380 static void f_sign_jump(typval_T *argvars, typval_T *rettv);
381 static void f_sign_place(typval_T *argvars, typval_T *rettv);
382 static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
383 static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
384 #endif
385 static void f_simplify(typval_T *argvars, typval_T *rettv);
386 #ifdef FEAT_FLOAT
387 static void f_sin(typval_T *argvars, typval_T *rettv);
388 static void f_sinh(typval_T *argvars, typval_T *rettv);
389 #endif
390 static void f_sort(typval_T *argvars, typval_T *rettv);
391 static void f_soundfold(typval_T *argvars, typval_T *rettv);
392 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
393 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
394 static void f_split(typval_T *argvars, typval_T *rettv);
395 #ifdef FEAT_FLOAT
396 static void f_sqrt(typval_T *argvars, typval_T *rettv);
397 static void f_str2float(typval_T *argvars, typval_T *rettv);
398 #endif
399 static void f_str2nr(typval_T *argvars, typval_T *rettv);
400 static void f_strchars(typval_T *argvars, typval_T *rettv);
401 #ifdef HAVE_STRFTIME
402 static void f_strftime(typval_T *argvars, typval_T *rettv);
403 #endif
404 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
405 static void f_stridx(typval_T *argvars, typval_T *rettv);
406 static void f_strlen(typval_T *argvars, typval_T *rettv);
407 static void f_strcharpart(typval_T *argvars, typval_T *rettv);
408 static void f_strpart(typval_T *argvars, typval_T *rettv);
409 static void f_strridx(typval_T *argvars, typval_T *rettv);
410 static void f_strtrans(typval_T *argvars, typval_T *rettv);
411 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
412 static void f_strwidth(typval_T *argvars, typval_T *rettv);
413 static void f_submatch(typval_T *argvars, typval_T *rettv);
414 static void f_substitute(typval_T *argvars, typval_T *rettv);
415 static void f_swapinfo(typval_T *argvars, typval_T *rettv);
416 static void f_swapname(typval_T *argvars, typval_T *rettv);
417 static void f_synID(typval_T *argvars, typval_T *rettv);
418 static void f_synIDattr(typval_T *argvars, typval_T *rettv);
419 static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
420 static void f_synstack(typval_T *argvars, typval_T *rettv);
421 static void f_synconcealed(typval_T *argvars, typval_T *rettv);
422 static void f_system(typval_T *argvars, typval_T *rettv);
423 static void f_systemlist(typval_T *argvars, typval_T *rettv);
424 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
425 static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
426 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
427 static void f_taglist(typval_T *argvars, typval_T *rettv);
428 static void f_tagfiles(typval_T *argvars, typval_T *rettv);
429 static void f_tempname(typval_T *argvars, typval_T *rettv);
430 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
431 static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
432 static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
433 static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
434 static void f_test_override(typval_T *argvars, typval_T *rettv);
435 static void f_test_refcount(typval_T *argvars, typval_T *rettv);
436 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
437 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
438 static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
439 #ifdef FEAT_JOB_CHANNEL
440 static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
441 #endif
442 static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
443 #ifdef FEAT_JOB_CHANNEL
444 static void f_test_null_job(typval_T *argvars, typval_T *rettv);
445 #endif
446 static void f_test_null_list(typval_T *argvars, typval_T *rettv);
447 static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
448 static void f_test_null_string(typval_T *argvars, typval_T *rettv);
449 #ifdef FEAT_GUI
450 static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
451 #endif
452 static void f_test_settime(typval_T *argvars, typval_T *rettv);
453 #ifdef FEAT_FLOAT
454 static void f_tan(typval_T *argvars, typval_T *rettv);
455 static void f_tanh(typval_T *argvars, typval_T *rettv);
456 #endif
457 #ifdef FEAT_TIMERS
458 static void f_timer_info(typval_T *argvars, typval_T *rettv);
459 static void f_timer_pause(typval_T *argvars, typval_T *rettv);
460 static void f_timer_start(typval_T *argvars, typval_T *rettv);
461 static void f_timer_stop(typval_T *argvars, typval_T *rettv);
462 static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
463 #endif
464 static void f_tolower(typval_T *argvars, typval_T *rettv);
465 static void f_toupper(typval_T *argvars, typval_T *rettv);
466 static void f_tr(typval_T *argvars, typval_T *rettv);
467 static void f_trim(typval_T *argvars, typval_T *rettv);
468 #ifdef FEAT_FLOAT
469 static void f_trunc(typval_T *argvars, typval_T *rettv);
470 #endif
471 static void f_type(typval_T *argvars, typval_T *rettv);
472 static void f_undofile(typval_T *argvars, typval_T *rettv);
473 static void f_undotree(typval_T *argvars, typval_T *rettv);
474 static void f_uniq(typval_T *argvars, typval_T *rettv);
475 static void f_values(typval_T *argvars, typval_T *rettv);
476 static void f_virtcol(typval_T *argvars, typval_T *rettv);
477 static void f_visualmode(typval_T *argvars, typval_T *rettv);
478 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
479 static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
480 static void f_win_getid(typval_T *argvars, typval_T *rettv);
481 static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
482 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
483 static void f_win_id2win(typval_T *argvars, typval_T *rettv);
484 static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
485 static void f_winbufnr(typval_T *argvars, typval_T *rettv);
486 static void f_wincol(typval_T *argvars, typval_T *rettv);
487 static void f_winheight(typval_T *argvars, typval_T *rettv);
488 static void f_winlayout(typval_T *argvars, typval_T *rettv);
489 static void f_winline(typval_T *argvars, typval_T *rettv);
490 static void f_winnr(typval_T *argvars, typval_T *rettv);
491 static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
492 static void f_winrestview(typval_T *argvars, typval_T *rettv);
493 static void f_winsaveview(typval_T *argvars, typval_T *rettv);
494 static void f_winwidth(typval_T *argvars, typval_T *rettv);
495 static void f_writefile(typval_T *argvars, typval_T *rettv);
496 static void f_wordcount(typval_T *argvars, typval_T *rettv);
497 static void f_xor(typval_T *argvars, typval_T *rettv);
498 
499 /*
500  * Array with names and number of arguments of all internal functions
501  * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
502  */
503 static struct fst
504 {
505     char	*f_name;	/* function name */
506     char	f_min_argc;	/* minimal number of arguments */
507     char	f_max_argc;	/* maximal number of arguments */
508     void	(*f_func)(typval_T *args, typval_T *rvar);
509 				/* implementation of function */
510 } functions[] =
511 {
512 #ifdef FEAT_FLOAT
513     {"abs",		1, 1, f_abs},
514     {"acos",		1, 1, f_acos},	/* WJMc */
515 #endif
516     {"add",		2, 2, f_add},
517     {"and",		2, 2, f_and},
518     {"append",		2, 2, f_append},
519     {"appendbufline",	3, 3, f_appendbufline},
520     {"argc",		0, 1, f_argc},
521     {"argidx",		0, 0, f_argidx},
522     {"arglistid",	0, 2, f_arglistid},
523     {"argv",		0, 2, f_argv},
524 #ifdef FEAT_FLOAT
525     {"asin",		1, 1, f_asin},	/* WJMc */
526 #endif
527     {"assert_beeps",	1, 2, f_assert_beeps},
528     {"assert_equal",	2, 3, f_assert_equal},
529     {"assert_equalfile", 2, 2, f_assert_equalfile},
530     {"assert_exception", 1, 2, f_assert_exception},
531     {"assert_fails",	1, 3, f_assert_fails},
532     {"assert_false",	1, 2, f_assert_false},
533     {"assert_inrange",	3, 4, f_assert_inrange},
534     {"assert_match",	2, 3, f_assert_match},
535     {"assert_notequal",	2, 3, f_assert_notequal},
536     {"assert_notmatch",	2, 3, f_assert_notmatch},
537     {"assert_report",	1, 1, f_assert_report},
538     {"assert_true",	1, 2, f_assert_true},
539 #ifdef FEAT_FLOAT
540     {"atan",		1, 1, f_atan},
541     {"atan2",		2, 2, f_atan2},
542 #endif
543 #ifdef FEAT_BEVAL
544     {"balloon_show",	1, 1, f_balloon_show},
545 # if defined(FEAT_BEVAL_TERM)
546     {"balloon_split",	1, 1, f_balloon_split},
547 # endif
548 #endif
549     {"browse",		4, 4, f_browse},
550     {"browsedir",	2, 2, f_browsedir},
551     {"bufexists",	1, 1, f_bufexists},
552     {"buffer_exists",	1, 1, f_bufexists},	/* obsolete */
553     {"buffer_name",	1, 1, f_bufname},	/* obsolete */
554     {"buffer_number",	1, 1, f_bufnr},		/* obsolete */
555     {"buflisted",	1, 1, f_buflisted},
556     {"bufloaded",	1, 1, f_bufloaded},
557     {"bufname",		1, 1, f_bufname},
558     {"bufnr",		1, 2, f_bufnr},
559     {"bufwinid",	1, 1, f_bufwinid},
560     {"bufwinnr",	1, 1, f_bufwinnr},
561     {"byte2line",	1, 1, f_byte2line},
562     {"byteidx",		2, 2, f_byteidx},
563     {"byteidxcomp",	2, 2, f_byteidxcomp},
564     {"call",		2, 3, f_call},
565 #ifdef FEAT_FLOAT
566     {"ceil",		1, 1, f_ceil},
567 #endif
568 #ifdef FEAT_JOB_CHANNEL
569     {"ch_canread",	1, 1, f_ch_canread},
570     {"ch_close",	1, 1, f_ch_close},
571     {"ch_close_in",	1, 1, f_ch_close_in},
572     {"ch_evalexpr",	2, 3, f_ch_evalexpr},
573     {"ch_evalraw",	2, 3, f_ch_evalraw},
574     {"ch_getbufnr",	2, 2, f_ch_getbufnr},
575     {"ch_getjob",	1, 1, f_ch_getjob},
576     {"ch_info",		1, 1, f_ch_info},
577     {"ch_log",		1, 2, f_ch_log},
578     {"ch_logfile",	1, 2, f_ch_logfile},
579     {"ch_open",		1, 2, f_ch_open},
580     {"ch_read",		1, 2, f_ch_read},
581     {"ch_readblob",	1, 2, f_ch_readblob},
582     {"ch_readraw",	1, 2, f_ch_readraw},
583     {"ch_sendexpr",	2, 3, f_ch_sendexpr},
584     {"ch_sendraw",	2, 3, f_ch_sendraw},
585     {"ch_setoptions",	2, 2, f_ch_setoptions},
586     {"ch_status",	1, 2, f_ch_status},
587 #endif
588     {"changenr",	0, 0, f_changenr},
589     {"char2nr",		1, 2, f_char2nr},
590     {"cindent",		1, 1, f_cindent},
591     {"clearmatches",	0, 0, f_clearmatches},
592     {"col",		1, 1, f_col},
593 #if defined(FEAT_INS_EXPAND)
594     {"complete",	2, 2, f_complete},
595     {"complete_add",	1, 1, f_complete_add},
596     {"complete_check",	0, 0, f_complete_check},
597     {"complete_info",	0, 1, f_complete_info},
598 #endif
599     {"confirm",		1, 4, f_confirm},
600     {"copy",		1, 1, f_copy},
601 #ifdef FEAT_FLOAT
602     {"cos",		1, 1, f_cos},
603     {"cosh",		1, 1, f_cosh},
604 #endif
605     {"count",		2, 4, f_count},
606     {"cscope_connection",0,3, f_cscope_connection},
607     {"cursor",		1, 3, f_cursor},
608 #ifdef MSWIN
609     {"debugbreak",	1, 1, f_debugbreak},
610 #endif
611     {"deepcopy",	1, 2, f_deepcopy},
612     {"delete",		1, 2, f_delete},
613     {"deletebufline",	2, 3, f_deletebufline},
614     {"did_filetype",	0, 0, f_did_filetype},
615     {"diff_filler",	1, 1, f_diff_filler},
616     {"diff_hlID",	2, 2, f_diff_hlID},
617     {"empty",		1, 1, f_empty},
618     {"escape",		2, 2, f_escape},
619     {"eval",		1, 1, f_eval},
620     {"eventhandler",	0, 0, f_eventhandler},
621     {"executable",	1, 1, f_executable},
622     {"execute",		1, 2, f_execute},
623     {"exepath",		1, 1, f_exepath},
624     {"exists",		1, 1, f_exists},
625 #ifdef FEAT_FLOAT
626     {"exp",		1, 1, f_exp},
627 #endif
628     {"expand",		1, 3, f_expand},
629     {"extend",		2, 3, f_extend},
630     {"feedkeys",	1, 2, f_feedkeys},
631     {"file_readable",	1, 1, f_filereadable},	/* obsolete */
632     {"filereadable",	1, 1, f_filereadable},
633     {"filewritable",	1, 1, f_filewritable},
634     {"filter",		2, 2, f_filter},
635     {"finddir",		1, 3, f_finddir},
636     {"findfile",	1, 3, f_findfile},
637 #ifdef FEAT_FLOAT
638     {"float2nr",	1, 1, f_float2nr},
639     {"floor",		1, 1, f_floor},
640     {"fmod",		2, 2, f_fmod},
641 #endif
642     {"fnameescape",	1, 1, f_fnameescape},
643     {"fnamemodify",	2, 2, f_fnamemodify},
644     {"foldclosed",	1, 1, f_foldclosed},
645     {"foldclosedend",	1, 1, f_foldclosedend},
646     {"foldlevel",	1, 1, f_foldlevel},
647     {"foldtext",	0, 0, f_foldtext},
648     {"foldtextresult",	1, 1, f_foldtextresult},
649     {"foreground",	0, 0, f_foreground},
650     {"funcref",		1, 3, f_funcref},
651     {"function",	1, 3, f_function},
652     {"garbagecollect",	0, 1, f_garbagecollect},
653     {"get",		2, 3, f_get},
654     {"getbufinfo",	0, 1, f_getbufinfo},
655     {"getbufline",	2, 3, f_getbufline},
656     {"getbufvar",	2, 3, f_getbufvar},
657     {"getchangelist",	1, 1, f_getchangelist},
658     {"getchar",		0, 1, f_getchar},
659     {"getcharmod",	0, 0, f_getcharmod},
660     {"getcharsearch",	0, 0, f_getcharsearch},
661     {"getcmdline",	0, 0, f_getcmdline},
662     {"getcmdpos",	0, 0, f_getcmdpos},
663     {"getcmdtype",	0, 0, f_getcmdtype},
664     {"getcmdwintype",	0, 0, f_getcmdwintype},
665 #if defined(FEAT_CMDL_COMPL)
666     {"getcompletion",	2, 3, f_getcompletion},
667 #endif
668     {"getcurpos",	0, 0, f_getcurpos},
669     {"getcwd",		0, 2, f_getcwd},
670     {"getfontname",	0, 1, f_getfontname},
671     {"getfperm",	1, 1, f_getfperm},
672     {"getfsize",	1, 1, f_getfsize},
673     {"getftime",	1, 1, f_getftime},
674     {"getftype",	1, 1, f_getftype},
675     {"getjumplist",	0, 2, f_getjumplist},
676     {"getline",		1, 2, f_getline},
677     {"getloclist",	1, 2, f_getloclist},
678     {"getmatches",	0, 0, f_getmatches},
679     {"getpid",		0, 0, f_getpid},
680     {"getpos",		1, 1, f_getpos},
681     {"getqflist",	0, 1, f_getqflist},
682     {"getreg",		0, 3, f_getreg},
683     {"getregtype",	0, 1, f_getregtype},
684     {"gettabinfo",	0, 1, f_gettabinfo},
685     {"gettabvar",	2, 3, f_gettabvar},
686     {"gettabwinvar",	3, 4, f_gettabwinvar},
687     {"gettagstack",	0, 1, f_gettagstack},
688     {"getwininfo",	0, 1, f_getwininfo},
689     {"getwinpos",	0, 1, f_getwinpos},
690     {"getwinposx",	0, 0, f_getwinposx},
691     {"getwinposy",	0, 0, f_getwinposy},
692     {"getwinvar",	2, 3, f_getwinvar},
693     {"glob",		1, 4, f_glob},
694     {"glob2regpat",	1, 1, f_glob2regpat},
695     {"globpath",	2, 5, f_globpath},
696     {"has",		1, 1, f_has},
697     {"has_key",		2, 2, f_has_key},
698     {"haslocaldir",	0, 2, f_haslocaldir},
699     {"hasmapto",	1, 3, f_hasmapto},
700     {"highlightID",	1, 1, f_hlID},		/* obsolete */
701     {"highlight_exists",1, 1, f_hlexists},	/* obsolete */
702     {"histadd",		2, 2, f_histadd},
703     {"histdel",		1, 2, f_histdel},
704     {"histget",		1, 2, f_histget},
705     {"histnr",		1, 1, f_histnr},
706     {"hlID",		1, 1, f_hlID},
707     {"hlexists",	1, 1, f_hlexists},
708     {"hostname",	0, 0, f_hostname},
709     {"iconv",		3, 3, f_iconv},
710     {"indent",		1, 1, f_indent},
711     {"index",		2, 4, f_index},
712     {"input",		1, 3, f_input},
713     {"inputdialog",	1, 3, f_inputdialog},
714     {"inputlist",	1, 1, f_inputlist},
715     {"inputrestore",	0, 0, f_inputrestore},
716     {"inputsave",	0, 0, f_inputsave},
717     {"inputsecret",	1, 2, f_inputsecret},
718     {"insert",		2, 3, f_insert},
719     {"invert",		1, 1, f_invert},
720     {"isdirectory",	1, 1, f_isdirectory},
721     {"islocked",	1, 1, f_islocked},
722 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
723     {"isnan",		1, 1, f_isnan},
724 #endif
725     {"items",		1, 1, f_items},
726 #ifdef FEAT_JOB_CHANNEL
727     {"job_getchannel",	1, 1, f_job_getchannel},
728     {"job_info",	0, 1, f_job_info},
729     {"job_setoptions",	2, 2, f_job_setoptions},
730     {"job_start",	1, 2, f_job_start},
731     {"job_status",	1, 1, f_job_status},
732     {"job_stop",	1, 2, f_job_stop},
733 #endif
734     {"join",		1, 2, f_join},
735     {"js_decode",	1, 1, f_js_decode},
736     {"js_encode",	1, 1, f_js_encode},
737     {"json_decode",	1, 1, f_json_decode},
738     {"json_encode",	1, 1, f_json_encode},
739     {"keys",		1, 1, f_keys},
740     {"last_buffer_nr",	0, 0, f_last_buffer_nr},/* obsolete */
741     {"len",		1, 1, f_len},
742     {"libcall",		3, 3, f_libcall},
743     {"libcallnr",	3, 3, f_libcallnr},
744     {"line",		1, 1, f_line},
745     {"line2byte",	1, 1, f_line2byte},
746     {"lispindent",	1, 1, f_lispindent},
747     {"localtime",	0, 0, f_localtime},
748 #ifdef FEAT_FLOAT
749     {"log",		1, 1, f_log},
750     {"log10",		1, 1, f_log10},
751 #endif
752 #ifdef FEAT_LUA
753     {"luaeval",		1, 2, f_luaeval},
754 #endif
755     {"map",		2, 2, f_map},
756     {"maparg",		1, 4, f_maparg},
757     {"mapcheck",	1, 3, f_mapcheck},
758     {"match",		2, 4, f_match},
759     {"matchadd",	2, 5, f_matchadd},
760     {"matchaddpos",	2, 5, f_matchaddpos},
761     {"matcharg",	1, 1, f_matcharg},
762     {"matchdelete",	1, 1, f_matchdelete},
763     {"matchend",	2, 4, f_matchend},
764     {"matchlist",	2, 4, f_matchlist},
765     {"matchstr",	2, 4, f_matchstr},
766     {"matchstrpos",	2, 4, f_matchstrpos},
767     {"max",		1, 1, f_max},
768     {"min",		1, 1, f_min},
769 #ifdef vim_mkdir
770     {"mkdir",		1, 3, f_mkdir},
771 #endif
772     {"mode",		0, 1, f_mode},
773 #ifdef FEAT_MZSCHEME
774     {"mzeval",		1, 1, f_mzeval},
775 #endif
776     {"nextnonblank",	1, 1, f_nextnonblank},
777     {"nr2char",		1, 2, f_nr2char},
778     {"or",		2, 2, f_or},
779     {"pathshorten",	1, 1, f_pathshorten},
780 #ifdef FEAT_PERL
781     {"perleval",	1, 1, f_perleval},
782 #endif
783 #ifdef FEAT_FLOAT
784     {"pow",		2, 2, f_pow},
785 #endif
786     {"prevnonblank",	1, 1, f_prevnonblank},
787     {"printf",		1, 19, f_printf},
788 #ifdef FEAT_JOB_CHANNEL
789     {"prompt_setcallback", 2, 2, f_prompt_setcallback},
790     {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
791     {"prompt_setprompt", 2, 2, f_prompt_setprompt},
792 #endif
793 #ifdef FEAT_TEXT_PROP
794     {"prop_add",	3, 3, f_prop_add},
795     {"prop_clear",	1, 3, f_prop_clear},
796     {"prop_list",	1, 2, f_prop_list},
797     {"prop_remove",	1, 3, f_prop_remove},
798     {"prop_type_add",	2, 2, f_prop_type_add},
799     {"prop_type_change", 2, 2, f_prop_type_change},
800     {"prop_type_delete", 1, 2, f_prop_type_delete},
801     {"prop_type_get",	1, 2, f_prop_type_get},
802     {"prop_type_list",	0, 1, f_prop_type_list},
803 #endif
804     {"pumvisible",	0, 0, f_pumvisible},
805 #ifdef FEAT_PYTHON3
806     {"py3eval",		1, 1, f_py3eval},
807 #endif
808 #ifdef FEAT_PYTHON
809     {"pyeval",		1, 1, f_pyeval},
810 #endif
811 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
812     {"pyxeval",		1, 1, f_pyxeval},
813 #endif
814     {"range",		1, 3, f_range},
815     {"readfile",	1, 3, f_readfile},
816     {"reg_executing",	0, 0, f_reg_executing},
817     {"reg_recording",	0, 0, f_reg_recording},
818     {"reltime",		0, 2, f_reltime},
819 #ifdef FEAT_FLOAT
820     {"reltimefloat",	1, 1, f_reltimefloat},
821 #endif
822     {"reltimestr",	1, 1, f_reltimestr},
823     {"remote_expr",	2, 4, f_remote_expr},
824     {"remote_foreground", 1, 1, f_remote_foreground},
825     {"remote_peek",	1, 2, f_remote_peek},
826     {"remote_read",	1, 2, f_remote_read},
827     {"remote_send",	2, 3, f_remote_send},
828     {"remote_startserver", 1, 1, f_remote_startserver},
829     {"remove",		2, 3, f_remove},
830     {"rename",		2, 2, f_rename},
831     {"repeat",		2, 2, f_repeat},
832     {"resolve",		1, 1, f_resolve},
833     {"reverse",		1, 1, f_reverse},
834 #ifdef FEAT_FLOAT
835     {"round",		1, 1, f_round},
836 #endif
837 #ifdef FEAT_RUBY
838     {"rubyeval",	1, 1, f_rubyeval},
839 #endif
840     {"screenattr",	2, 2, f_screenattr},
841     {"screenchar",	2, 2, f_screenchar},
842     {"screencol",	0, 0, f_screencol},
843     {"screenrow",	0, 0, f_screenrow},
844     {"search",		1, 4, f_search},
845     {"searchdecl",	1, 3, f_searchdecl},
846     {"searchpair",	3, 7, f_searchpair},
847     {"searchpairpos",	3, 7, f_searchpairpos},
848     {"searchpos",	1, 4, f_searchpos},
849     {"server2client",	2, 2, f_server2client},
850     {"serverlist",	0, 0, f_serverlist},
851     {"setbufline",	3, 3, f_setbufline},
852     {"setbufvar",	3, 3, f_setbufvar},
853     {"setcharsearch",	1, 1, f_setcharsearch},
854     {"setcmdpos",	1, 1, f_setcmdpos},
855     {"setfperm",	2, 2, f_setfperm},
856     {"setline",		2, 2, f_setline},
857     {"setloclist",	2, 4, f_setloclist},
858     {"setmatches",	1, 1, f_setmatches},
859     {"setpos",		2, 2, f_setpos},
860     {"setqflist",	1, 3, f_setqflist},
861     {"setreg",		2, 3, f_setreg},
862     {"settabvar",	3, 3, f_settabvar},
863     {"settabwinvar",	4, 4, f_settabwinvar},
864     {"settagstack",	2, 3, f_settagstack},
865     {"setwinvar",	3, 3, f_setwinvar},
866 #ifdef FEAT_CRYPT
867     {"sha256",		1, 1, f_sha256},
868 #endif
869     {"shellescape",	1, 2, f_shellescape},
870     {"shiftwidth",	0, 1, f_shiftwidth},
871 #ifdef FEAT_SIGNS
872     {"sign_define",	1, 2, f_sign_define},
873     {"sign_getdefined",	0, 1, f_sign_getdefined},
874     {"sign_getplaced",	0, 2, f_sign_getplaced},
875     {"sign_jump",	3, 3, f_sign_jump},
876     {"sign_place",	4, 5, f_sign_place},
877     {"sign_undefine",	0, 1, f_sign_undefine},
878     {"sign_unplace",	1, 2, f_sign_unplace},
879 #endif
880     {"simplify",	1, 1, f_simplify},
881 #ifdef FEAT_FLOAT
882     {"sin",		1, 1, f_sin},
883     {"sinh",		1, 1, f_sinh},
884 #endif
885     {"sort",		1, 3, f_sort},
886     {"soundfold",	1, 1, f_soundfold},
887     {"spellbadword",	0, 1, f_spellbadword},
888     {"spellsuggest",	1, 3, f_spellsuggest},
889     {"split",		1, 3, f_split},
890 #ifdef FEAT_FLOAT
891     {"sqrt",		1, 1, f_sqrt},
892     {"str2float",	1, 1, f_str2float},
893 #endif
894     {"str2nr",		1, 2, f_str2nr},
895     {"strcharpart",	2, 3, f_strcharpart},
896     {"strchars",	1, 2, f_strchars},
897     {"strdisplaywidth",	1, 2, f_strdisplaywidth},
898 #ifdef HAVE_STRFTIME
899     {"strftime",	1, 2, f_strftime},
900 #endif
901     {"strgetchar",	2, 2, f_strgetchar},
902     {"stridx",		2, 3, f_stridx},
903     {"string",		1, 1, f_string},
904     {"strlen",		1, 1, f_strlen},
905     {"strpart",		2, 3, f_strpart},
906     {"strridx",		2, 3, f_strridx},
907     {"strtrans",	1, 1, f_strtrans},
908     {"strwidth",	1, 1, f_strwidth},
909     {"submatch",	1, 2, f_submatch},
910     {"substitute",	4, 4, f_substitute},
911     {"swapinfo",	1, 1, f_swapinfo},
912     {"swapname",	1, 1, f_swapname},
913     {"synID",		3, 3, f_synID},
914     {"synIDattr",	2, 3, f_synIDattr},
915     {"synIDtrans",	1, 1, f_synIDtrans},
916     {"synconcealed",	2, 2, f_synconcealed},
917     {"synstack",	2, 2, f_synstack},
918     {"system",		1, 2, f_system},
919     {"systemlist",	1, 2, f_systemlist},
920     {"tabpagebuflist",	0, 1, f_tabpagebuflist},
921     {"tabpagenr",	0, 1, f_tabpagenr},
922     {"tabpagewinnr",	1, 2, f_tabpagewinnr},
923     {"tagfiles",	0, 0, f_tagfiles},
924     {"taglist",		1, 2, f_taglist},
925 #ifdef FEAT_FLOAT
926     {"tan",		1, 1, f_tan},
927     {"tanh",		1, 1, f_tanh},
928 #endif
929     {"tempname",	0, 0, f_tempname},
930 #ifdef FEAT_TERMINAL
931     {"term_dumpdiff",	2, 3, f_term_dumpdiff},
932     {"term_dumpload",	1, 2, f_term_dumpload},
933     {"term_dumpwrite",	2, 3, f_term_dumpwrite},
934     {"term_getaltscreen", 1, 1, f_term_getaltscreen},
935 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
936     {"term_getansicolors", 1, 1, f_term_getansicolors},
937 # endif
938     {"term_getattr",	2, 2, f_term_getattr},
939     {"term_getcursor",	1, 1, f_term_getcursor},
940     {"term_getjob",	1, 1, f_term_getjob},
941     {"term_getline",	2, 2, f_term_getline},
942     {"term_getscrolled", 1, 1, f_term_getscrolled},
943     {"term_getsize",	1, 1, f_term_getsize},
944     {"term_getstatus",	1, 1, f_term_getstatus},
945     {"term_gettitle",	1, 1, f_term_gettitle},
946     {"term_gettty",	1, 2, f_term_gettty},
947     {"term_list",	0, 0, f_term_list},
948     {"term_scrape",	2, 2, f_term_scrape},
949     {"term_sendkeys",	2, 2, f_term_sendkeys},
950 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
951     {"term_setansicolors", 2, 2, f_term_setansicolors},
952 # endif
953     {"term_setkill",	2, 2, f_term_setkill},
954     {"term_setrestore",	2, 2, f_term_setrestore},
955     {"term_setsize",	3, 3, f_term_setsize},
956     {"term_start",	1, 2, f_term_start},
957     {"term_wait",	1, 2, f_term_wait},
958 #endif
959     {"test_alloc_fail",	3, 3, f_test_alloc_fail},
960     {"test_autochdir",	0, 0, f_test_autochdir},
961     {"test_feedinput",	1, 1, f_test_feedinput},
962     {"test_garbagecollect_now",	0, 0, f_test_garbagecollect_now},
963     {"test_ignore_error",	1, 1, f_test_ignore_error},
964     {"test_null_blob",	0, 0, f_test_null_blob},
965 #ifdef FEAT_JOB_CHANNEL
966     {"test_null_channel", 0, 0, f_test_null_channel},
967 #endif
968     {"test_null_dict",	0, 0, f_test_null_dict},
969 #ifdef FEAT_JOB_CHANNEL
970     {"test_null_job",	0, 0, f_test_null_job},
971 #endif
972     {"test_null_list",	0, 0, f_test_null_list},
973     {"test_null_partial", 0, 0, f_test_null_partial},
974     {"test_null_string", 0, 0, f_test_null_string},
975     {"test_option_not_set", 1, 1, f_test_option_not_set},
976     {"test_override",	2, 2, f_test_override},
977     {"test_refcount",	1, 1, f_test_refcount},
978 #ifdef FEAT_GUI
979     {"test_scrollbar",	3, 3, f_test_scrollbar},
980 #endif
981     {"test_settime",	1, 1, f_test_settime},
982 #ifdef FEAT_TIMERS
983     {"timer_info",	0, 1, f_timer_info},
984     {"timer_pause",	2, 2, f_timer_pause},
985     {"timer_start",	2, 3, f_timer_start},
986     {"timer_stop",	1, 1, f_timer_stop},
987     {"timer_stopall",	0, 0, f_timer_stopall},
988 #endif
989     {"tolower",		1, 1, f_tolower},
990     {"toupper",		1, 1, f_toupper},
991     {"tr",		3, 3, f_tr},
992     {"trim",		1, 2, f_trim},
993 #ifdef FEAT_FLOAT
994     {"trunc",		1, 1, f_trunc},
995 #endif
996     {"type",		1, 1, f_type},
997     {"undofile",	1, 1, f_undofile},
998     {"undotree",	0, 0, f_undotree},
999     {"uniq",		1, 3, f_uniq},
1000     {"values",		1, 1, f_values},
1001     {"virtcol",		1, 1, f_virtcol},
1002     {"visualmode",	0, 1, f_visualmode},
1003     {"wildmenumode",	0, 0, f_wildmenumode},
1004     {"win_findbuf",	1, 1, f_win_findbuf},
1005     {"win_getid",	0, 2, f_win_getid},
1006     {"win_gotoid",	1, 1, f_win_gotoid},
1007     {"win_id2tabwin",	1, 1, f_win_id2tabwin},
1008     {"win_id2win",	1, 1, f_win_id2win},
1009     {"win_screenpos",	1, 1, f_win_screenpos},
1010     {"winbufnr",	1, 1, f_winbufnr},
1011     {"wincol",		0, 0, f_wincol},
1012     {"winheight",	1, 1, f_winheight},
1013     {"winlayout",	0, 1, f_winlayout},
1014     {"winline",		0, 0, f_winline},
1015     {"winnr",		0, 1, f_winnr},
1016     {"winrestcmd",	0, 0, f_winrestcmd},
1017     {"winrestview",	1, 1, f_winrestview},
1018     {"winsaveview",	0, 0, f_winsaveview},
1019     {"winwidth",	1, 1, f_winwidth},
1020     {"wordcount",	0, 0, f_wordcount},
1021     {"writefile",	2, 3, f_writefile},
1022     {"xor",		2, 2, f_xor},
1023 };
1024 
1025 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1026 
1027 /*
1028  * Function given to ExpandGeneric() to obtain the list of internal
1029  * or user defined function names.
1030  */
1031     char_u *
1032 get_function_name(expand_T *xp, int idx)
1033 {
1034     static int	intidx = -1;
1035     char_u	*name;
1036 
1037     if (idx == 0)
1038 	intidx = -1;
1039     if (intidx < 0)
1040     {
1041 	name = get_user_func_name(xp, idx);
1042 	if (name != NULL)
1043 	    return name;
1044     }
1045     if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1046     {
1047 	STRCPY(IObuff, functions[intidx].f_name);
1048 	STRCAT(IObuff, "(");
1049 	if (functions[intidx].f_max_argc == 0)
1050 	    STRCAT(IObuff, ")");
1051 	return IObuff;
1052     }
1053 
1054     return NULL;
1055 }
1056 
1057 /*
1058  * Function given to ExpandGeneric() to obtain the list of internal or
1059  * user defined variable or function names.
1060  */
1061     char_u *
1062 get_expr_name(expand_T *xp, int idx)
1063 {
1064     static int	intidx = -1;
1065     char_u	*name;
1066 
1067     if (idx == 0)
1068 	intidx = -1;
1069     if (intidx < 0)
1070     {
1071 	name = get_function_name(xp, idx);
1072 	if (name != NULL)
1073 	    return name;
1074     }
1075     return get_user_var_name(xp, ++intidx);
1076 }
1077 
1078 #endif /* FEAT_CMDL_COMPL */
1079 
1080 /*
1081  * Find internal function in table above.
1082  * Return index, or -1 if not found
1083  */
1084     int
1085 find_internal_func(
1086     char_u	*name)		/* name of the function */
1087 {
1088     int		first = 0;
1089     int		last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1090     int		cmp;
1091     int		x;
1092 
1093     /*
1094      * Find the function name in the table. Binary search.
1095      */
1096     while (first <= last)
1097     {
1098 	x = first + ((unsigned)(last - first) >> 1);
1099 	cmp = STRCMP(name, functions[x].f_name);
1100 	if (cmp < 0)
1101 	    last = x - 1;
1102 	else if (cmp > 0)
1103 	    first = x + 1;
1104 	else
1105 	    return x;
1106     }
1107     return -1;
1108 }
1109 
1110     int
1111 call_internal_func(
1112 	char_u	    *name,
1113 	int	    argcount,
1114 	typval_T    *argvars,
1115 	typval_T    *rettv)
1116 {
1117     int i;
1118 
1119     i = find_internal_func(name);
1120     if (i < 0)
1121 	return ERROR_UNKNOWN;
1122     if (argcount < functions[i].f_min_argc)
1123 	return ERROR_TOOFEW;
1124     if (argcount > functions[i].f_max_argc)
1125 	return ERROR_TOOMANY;
1126     argvars[argcount].v_type = VAR_UNKNOWN;
1127     functions[i].f_func(argvars, rettv);
1128     return ERROR_NONE;
1129 }
1130 
1131 /*
1132  * Return TRUE for a non-zero Number and a non-empty String.
1133  */
1134     static int
1135 non_zero_arg(typval_T *argvars)
1136 {
1137     return ((argvars[0].v_type == VAR_NUMBER
1138 		&& argvars[0].vval.v_number != 0)
1139 	    || (argvars[0].v_type == VAR_SPECIAL
1140 		&& argvars[0].vval.v_number == VVAL_TRUE)
1141 	    || (argvars[0].v_type == VAR_STRING
1142 		&& argvars[0].vval.v_string != NULL
1143 		&& *argvars[0].vval.v_string != NUL));
1144 }
1145 
1146 /*
1147  * Get the lnum from the first argument.
1148  * Also accepts ".", "$", etc., but that only works for the current buffer.
1149  * Returns -1 on error.
1150  */
1151     static linenr_T
1152 tv_get_lnum(typval_T *argvars)
1153 {
1154     typval_T	rettv;
1155     linenr_T	lnum;
1156 
1157     lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1158     if (lnum == 0)  /* no valid number, try using line() */
1159     {
1160 	rettv.v_type = VAR_NUMBER;
1161 	f_line(argvars, &rettv);
1162 	lnum = (linenr_T)rettv.vval.v_number;
1163 	clear_tv(&rettv);
1164     }
1165     return lnum;
1166 }
1167 
1168 /*
1169  * Get the lnum from the first argument.
1170  * Also accepts "$", then "buf" is used.
1171  * Returns 0 on error.
1172  */
1173     static linenr_T
1174 tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1175 {
1176     if (argvars[0].v_type == VAR_STRING
1177 	    && argvars[0].vval.v_string != NULL
1178 	    && argvars[0].vval.v_string[0] == '$'
1179 	    && buf != NULL)
1180 	return buf->b_ml.ml_line_count;
1181     return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1182 }
1183 
1184 #ifdef FEAT_FLOAT
1185 /*
1186  * Get the float value of "argvars[0]" into "f".
1187  * Returns FAIL when the argument is not a Number or Float.
1188  */
1189     static int
1190 get_float_arg(typval_T *argvars, float_T *f)
1191 {
1192     if (argvars[0].v_type == VAR_FLOAT)
1193     {
1194 	*f = argvars[0].vval.v_float;
1195 	return OK;
1196     }
1197     if (argvars[0].v_type == VAR_NUMBER)
1198     {
1199 	*f = (float_T)argvars[0].vval.v_number;
1200 	return OK;
1201     }
1202     emsg(_("E808: Number or Float required"));
1203     return FAIL;
1204 }
1205 
1206 /*
1207  * "abs(expr)" function
1208  */
1209     static void
1210 f_abs(typval_T *argvars, typval_T *rettv)
1211 {
1212     if (argvars[0].v_type == VAR_FLOAT)
1213     {
1214 	rettv->v_type = VAR_FLOAT;
1215 	rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1216     }
1217     else
1218     {
1219 	varnumber_T	n;
1220 	int		error = FALSE;
1221 
1222 	n = tv_get_number_chk(&argvars[0], &error);
1223 	if (error)
1224 	    rettv->vval.v_number = -1;
1225 	else if (n > 0)
1226 	    rettv->vval.v_number = n;
1227 	else
1228 	    rettv->vval.v_number = -n;
1229     }
1230 }
1231 
1232 /*
1233  * "acos()" function
1234  */
1235     static void
1236 f_acos(typval_T *argvars, typval_T *rettv)
1237 {
1238     float_T	f = 0.0;
1239 
1240     rettv->v_type = VAR_FLOAT;
1241     if (get_float_arg(argvars, &f) == OK)
1242 	rettv->vval.v_float = acos(f);
1243     else
1244 	rettv->vval.v_float = 0.0;
1245 }
1246 #endif
1247 
1248 /*
1249  * "add(list, item)" function
1250  */
1251     static void
1252 f_add(typval_T *argvars, typval_T *rettv)
1253 {
1254     list_T	*l;
1255     blob_T	*b;
1256 
1257     rettv->vval.v_number = 1; /* Default: Failed */
1258     if (argvars[0].v_type == VAR_LIST)
1259     {
1260 	if ((l = argvars[0].vval.v_list) != NULL
1261 		&& !var_check_lock(l->lv_lock,
1262 					 (char_u *)N_("add() argument"), TRUE)
1263 		&& list_append_tv(l, &argvars[1]) == OK)
1264 	    copy_tv(&argvars[0], rettv);
1265     }
1266     else if (argvars[0].v_type == VAR_BLOB)
1267     {
1268 	if ((b = argvars[0].vval.v_blob) != NULL
1269 		&& !var_check_lock(b->bv_lock,
1270 					 (char_u *)N_("add() argument"), TRUE))
1271 	{
1272 	    int		error = FALSE;
1273 	    varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1274 
1275 	    if (!error)
1276 	    {
1277 		ga_append(&b->bv_ga, (int)n);
1278 		copy_tv(&argvars[0], rettv);
1279 	    }
1280 	}
1281     }
1282     else
1283 	emsg(_(e_listblobreq));
1284 }
1285 
1286 /*
1287  * "and(expr, expr)" function
1288  */
1289     static void
1290 f_and(typval_T *argvars, typval_T *rettv)
1291 {
1292     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1293 					& tv_get_number_chk(&argvars[1], NULL);
1294 }
1295 
1296 /*
1297  * If there is a window for "curbuf", make it the current window.
1298  */
1299     static void
1300 find_win_for_curbuf(void)
1301 {
1302     wininfo_T *wip;
1303 
1304     for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1305     {
1306 	if (wip->wi_win != NULL)
1307 	{
1308 	    curwin = wip->wi_win;
1309 	    break;
1310 	}
1311     }
1312 }
1313 
1314 /*
1315  * Set line or list of lines in buffer "buf".
1316  */
1317     static void
1318 set_buffer_lines(
1319 	buf_T	    *buf,
1320 	linenr_T    lnum_arg,
1321 	int	    append,
1322 	typval_T    *lines,
1323 	typval_T    *rettv)
1324 {
1325     linenr_T    lnum = lnum_arg + (append ? 1 : 0);
1326     char_u	*line = NULL;
1327     list_T	*l = NULL;
1328     listitem_T	*li = NULL;
1329     long	added = 0;
1330     linenr_T	append_lnum;
1331     buf_T	*curbuf_save = NULL;
1332     win_T	*curwin_save = NULL;
1333     int		is_curbuf = buf == curbuf;
1334 
1335     /* When using the current buffer ml_mfp will be set if needed.  Useful when
1336      * setline() is used on startup.  For other buffers the buffer must be
1337      * loaded. */
1338     if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
1339     {
1340 	rettv->vval.v_number = 1;	/* FAIL */
1341 	return;
1342     }
1343 
1344     if (!is_curbuf)
1345     {
1346 	curbuf_save = curbuf;
1347 	curwin_save = curwin;
1348 	curbuf = buf;
1349 	find_win_for_curbuf();
1350     }
1351 
1352     if (append)
1353 	// appendbufline() uses the line number below which we insert
1354 	append_lnum = lnum - 1;
1355     else
1356 	// setbufline() uses the line number above which we insert, we only
1357 	// append if it's below the last line
1358 	append_lnum = curbuf->b_ml.ml_line_count;
1359 
1360     if (lines->v_type == VAR_LIST)
1361     {
1362 	l = lines->vval.v_list;
1363 	li = l->lv_first;
1364     }
1365     else
1366 	line = tv_get_string_chk(lines);
1367 
1368     /* default result is zero == OK */
1369     for (;;)
1370     {
1371 	if (l != NULL)
1372 	{
1373 	    /* list argument, get next string */
1374 	    if (li == NULL)
1375 		break;
1376 	    line = tv_get_string_chk(&li->li_tv);
1377 	    li = li->li_next;
1378 	}
1379 
1380 	rettv->vval.v_number = 1;	/* FAIL */
1381 	if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1382 	    break;
1383 
1384 	/* When coming here from Insert mode, sync undo, so that this can be
1385 	 * undone separately from what was previously inserted. */
1386 	if (u_sync_once == 2)
1387 	{
1388 	    u_sync_once = 1; /* notify that u_sync() was called */
1389 	    u_sync(TRUE);
1390 	}
1391 
1392 	if (!append && lnum <= curbuf->b_ml.ml_line_count)
1393 	{
1394 	    // Existing line, replace it.
1395 	    // Removes any existing text properties.
1396 	    if (u_savesub(lnum) == OK && ml_replace_len(
1397 		      lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
1398 	    {
1399 		changed_bytes(lnum, 0);
1400 		if (is_curbuf && lnum == curwin->w_cursor.lnum)
1401 		    check_cursor_col();
1402 		rettv->vval.v_number = 0;	/* OK */
1403 	    }
1404 	}
1405 	else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1406 	{
1407 	    /* append the line */
1408 	    ++added;
1409 	    if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1410 		rettv->vval.v_number = 0;	/* OK */
1411 	}
1412 
1413 	if (l == NULL)			/* only one string argument */
1414 	    break;
1415 	++lnum;
1416     }
1417 
1418     if (added > 0)
1419     {
1420 	win_T	    *wp;
1421 	tabpage_T   *tp;
1422 
1423 	appended_lines_mark(append_lnum, added);
1424 	FOR_ALL_TAB_WINDOWS(tp, wp)
1425 	    if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1426 		wp->w_cursor.lnum += added;
1427 	check_cursor_col();
1428 
1429 #ifdef FEAT_JOB_CHANNEL
1430 	if (bt_prompt(curbuf) && (State & INSERT))
1431 	    // show the line with the prompt
1432 	    update_topline();
1433 #endif
1434     }
1435 
1436     if (!is_curbuf)
1437     {
1438 	curbuf = curbuf_save;
1439 	curwin = curwin_save;
1440     }
1441 }
1442 
1443 /*
1444  * "append(lnum, string/list)" function
1445  */
1446     static void
1447 f_append(typval_T *argvars, typval_T *rettv)
1448 {
1449     linenr_T	lnum = tv_get_lnum(&argvars[0]);
1450 
1451     set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1452 }
1453 
1454 /*
1455  * "appendbufline(buf, lnum, string/list)" function
1456  */
1457     static void
1458 f_appendbufline(typval_T *argvars, typval_T *rettv)
1459 {
1460     linenr_T	lnum;
1461     buf_T	*buf;
1462 
1463     buf = tv_get_buf(&argvars[0], FALSE);
1464     if (buf == NULL)
1465 	rettv->vval.v_number = 1; /* FAIL */
1466     else
1467     {
1468 	lnum = tv_get_lnum_buf(&argvars[1], buf);
1469 	set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1470     }
1471 }
1472 
1473 /*
1474  * "argc([window id])" function
1475  */
1476     static void
1477 f_argc(typval_T *argvars, typval_T *rettv)
1478 {
1479     win_T	*wp;
1480 
1481     if (argvars[0].v_type == VAR_UNKNOWN)
1482 	// use the current window
1483 	rettv->vval.v_number = ARGCOUNT;
1484     else if (argvars[0].v_type == VAR_NUMBER
1485 					   && tv_get_number(&argvars[0]) == -1)
1486 	// use the global argument list
1487 	rettv->vval.v_number = GARGCOUNT;
1488     else
1489     {
1490 	// use the argument list of the specified window
1491 	wp = find_win_by_nr_or_id(&argvars[0]);
1492 	if (wp != NULL)
1493 	    rettv->vval.v_number = WARGCOUNT(wp);
1494 	else
1495 	    rettv->vval.v_number = -1;
1496     }
1497 }
1498 
1499 /*
1500  * "argidx()" function
1501  */
1502     static void
1503 f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1504 {
1505     rettv->vval.v_number = curwin->w_arg_idx;
1506 }
1507 
1508 /*
1509  * "arglistid()" function
1510  */
1511     static void
1512 f_arglistid(typval_T *argvars, typval_T *rettv)
1513 {
1514     win_T	*wp;
1515 
1516     rettv->vval.v_number = -1;
1517     wp = find_tabwin(&argvars[0], &argvars[1]);
1518     if (wp != NULL)
1519 	rettv->vval.v_number = wp->w_alist->id;
1520 }
1521 
1522 /*
1523  * Get the argument list for a given window
1524  */
1525     static void
1526 get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1527 {
1528     int		idx;
1529 
1530     if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1531 	for (idx = 0; idx < argcount; ++idx)
1532 	    list_append_string(rettv->vval.v_list,
1533 						alist_name(&arglist[idx]), -1);
1534 }
1535 
1536 /*
1537  * "argv(nr)" function
1538  */
1539     static void
1540 f_argv(typval_T *argvars, typval_T *rettv)
1541 {
1542     int		idx;
1543     aentry_T	*arglist = NULL;
1544     int		argcount = -1;
1545 
1546     if (argvars[0].v_type != VAR_UNKNOWN)
1547     {
1548 	if (argvars[1].v_type == VAR_UNKNOWN)
1549 	{
1550 	    arglist = ARGLIST;
1551 	    argcount = ARGCOUNT;
1552 	}
1553 	else if (argvars[1].v_type == VAR_NUMBER
1554 					   && tv_get_number(&argvars[1]) == -1)
1555 	{
1556 	    arglist = GARGLIST;
1557 	    argcount = GARGCOUNT;
1558 	}
1559 	else
1560 	{
1561 	    win_T	*wp = find_win_by_nr_or_id(&argvars[1]);
1562 
1563 	    if (wp != NULL)
1564 	    {
1565 		/* Use the argument list of the specified window */
1566 		arglist = WARGLIST(wp);
1567 		argcount = WARGCOUNT(wp);
1568 	    }
1569 	}
1570 
1571 	rettv->v_type = VAR_STRING;
1572 	rettv->vval.v_string = NULL;
1573 	idx = tv_get_number_chk(&argvars[0], NULL);
1574 	if (arglist != NULL && idx >= 0 && idx < argcount)
1575 	    rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1576 	else if (idx == -1)
1577 	    get_arglist_as_rettv(arglist, argcount, rettv);
1578     }
1579     else
1580 	get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
1581 }
1582 
1583 /*
1584  * "assert_beeps(cmd [, error])" function
1585  */
1586     static void
1587 f_assert_beeps(typval_T *argvars, typval_T *rettv)
1588 {
1589     rettv->vval.v_number = assert_beeps(argvars);
1590 }
1591 
1592 /*
1593  * "assert_equal(expected, actual[, msg])" function
1594  */
1595     static void
1596 f_assert_equal(typval_T *argvars, typval_T *rettv)
1597 {
1598     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
1599 }
1600 
1601 /*
1602  * "assert_equalfile(fname-one, fname-two)" function
1603  */
1604     static void
1605 f_assert_equalfile(typval_T *argvars, typval_T *rettv)
1606 {
1607     rettv->vval.v_number = assert_equalfile(argvars);
1608 }
1609 
1610 /*
1611  * "assert_notequal(expected, actual[, msg])" function
1612  */
1613     static void
1614 f_assert_notequal(typval_T *argvars, typval_T *rettv)
1615 {
1616     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
1617 }
1618 
1619 /*
1620  * "assert_exception(string[, msg])" function
1621  */
1622     static void
1623 f_assert_exception(typval_T *argvars, typval_T *rettv)
1624 {
1625     rettv->vval.v_number = assert_exception(argvars);
1626 }
1627 
1628 /*
1629  * "assert_fails(cmd [, error[, msg]])" function
1630  */
1631     static void
1632 f_assert_fails(typval_T *argvars, typval_T *rettv)
1633 {
1634     rettv->vval.v_number = assert_fails(argvars);
1635 }
1636 
1637 /*
1638  * "assert_false(actual[, msg])" function
1639  */
1640     static void
1641 f_assert_false(typval_T *argvars, typval_T *rettv)
1642 {
1643     rettv->vval.v_number = assert_bool(argvars, FALSE);
1644 }
1645 
1646 /*
1647  * "assert_inrange(lower, upper[, msg])" function
1648  */
1649     static void
1650 f_assert_inrange(typval_T *argvars, typval_T *rettv)
1651 {
1652     rettv->vval.v_number = assert_inrange(argvars);
1653 }
1654 
1655 /*
1656  * "assert_match(pattern, actual[, msg])" function
1657  */
1658     static void
1659 f_assert_match(typval_T *argvars, typval_T *rettv)
1660 {
1661     rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
1662 }
1663 
1664 /*
1665  * "assert_notmatch(pattern, actual[, msg])" function
1666  */
1667     static void
1668 f_assert_notmatch(typval_T *argvars, typval_T *rettv)
1669 {
1670     rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
1671 }
1672 
1673 /*
1674  * "assert_report(msg)" function
1675  */
1676     static void
1677 f_assert_report(typval_T *argvars, typval_T *rettv)
1678 {
1679     rettv->vval.v_number = assert_report(argvars);
1680 }
1681 
1682 /*
1683  * "assert_true(actual[, msg])" function
1684  */
1685     static void
1686 f_assert_true(typval_T *argvars, typval_T *rettv)
1687 {
1688     rettv->vval.v_number = assert_bool(argvars, TRUE);
1689 }
1690 
1691 #ifdef FEAT_FLOAT
1692 /*
1693  * "asin()" function
1694  */
1695     static void
1696 f_asin(typval_T *argvars, typval_T *rettv)
1697 {
1698     float_T	f = 0.0;
1699 
1700     rettv->v_type = VAR_FLOAT;
1701     if (get_float_arg(argvars, &f) == OK)
1702 	rettv->vval.v_float = asin(f);
1703     else
1704 	rettv->vval.v_float = 0.0;
1705 }
1706 
1707 /*
1708  * "atan()" function
1709  */
1710     static void
1711 f_atan(typval_T *argvars, typval_T *rettv)
1712 {
1713     float_T	f = 0.0;
1714 
1715     rettv->v_type = VAR_FLOAT;
1716     if (get_float_arg(argvars, &f) == OK)
1717 	rettv->vval.v_float = atan(f);
1718     else
1719 	rettv->vval.v_float = 0.0;
1720 }
1721 
1722 /*
1723  * "atan2()" function
1724  */
1725     static void
1726 f_atan2(typval_T *argvars, typval_T *rettv)
1727 {
1728     float_T	fx = 0.0, fy = 0.0;
1729 
1730     rettv->v_type = VAR_FLOAT;
1731     if (get_float_arg(argvars, &fx) == OK
1732 				     && get_float_arg(&argvars[1], &fy) == OK)
1733 	rettv->vval.v_float = atan2(fx, fy);
1734     else
1735 	rettv->vval.v_float = 0.0;
1736 }
1737 #endif
1738 
1739 /*
1740  * "balloon_show()" function
1741  */
1742 #ifdef FEAT_BEVAL
1743     static void
1744 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1745 {
1746     if (balloonEval != NULL)
1747     {
1748 	if (argvars[0].v_type == VAR_LIST
1749 # ifdef FEAT_GUI
1750 		&& !gui.in_use
1751 # endif
1752 	   )
1753 	    post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1754 	else
1755 	    post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
1756     }
1757 }
1758 
1759 # if defined(FEAT_BEVAL_TERM)
1760     static void
1761 f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1762 {
1763     if (rettv_list_alloc(rettv) == OK)
1764     {
1765 	char_u *msg = tv_get_string_chk(&argvars[0]);
1766 
1767 	if (msg != NULL)
1768 	{
1769 	    pumitem_T	*array;
1770 	    int		size = split_message(msg, &array);
1771 	    int		i;
1772 
1773 	    /* Skip the first and last item, they are always empty. */
1774 	    for (i = 1; i < size - 1; ++i)
1775 		list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
1776 	    while (size > 0)
1777 		vim_free(array[--size].pum_text);
1778 	    vim_free(array);
1779 	}
1780     }
1781 }
1782 # endif
1783 #endif
1784 
1785 /*
1786  * "browse(save, title, initdir, default)" function
1787  */
1788     static void
1789 f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1790 {
1791 #ifdef FEAT_BROWSE
1792     int		save;
1793     char_u	*title;
1794     char_u	*initdir;
1795     char_u	*defname;
1796     char_u	buf[NUMBUFLEN];
1797     char_u	buf2[NUMBUFLEN];
1798     int		error = FALSE;
1799 
1800     save = (int)tv_get_number_chk(&argvars[0], &error);
1801     title = tv_get_string_chk(&argvars[1]);
1802     initdir = tv_get_string_buf_chk(&argvars[2], buf);
1803     defname = tv_get_string_buf_chk(&argvars[3], buf2);
1804 
1805     if (error || title == NULL || initdir == NULL || defname == NULL)
1806 	rettv->vval.v_string = NULL;
1807     else
1808 	rettv->vval.v_string =
1809 		 do_browse(save ? BROWSE_SAVE : 0,
1810 				 title, defname, NULL, initdir, NULL, curbuf);
1811 #else
1812     rettv->vval.v_string = NULL;
1813 #endif
1814     rettv->v_type = VAR_STRING;
1815 }
1816 
1817 /*
1818  * "browsedir(title, initdir)" function
1819  */
1820     static void
1821 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1822 {
1823 #ifdef FEAT_BROWSE
1824     char_u	*title;
1825     char_u	*initdir;
1826     char_u	buf[NUMBUFLEN];
1827 
1828     title = tv_get_string_chk(&argvars[0]);
1829     initdir = tv_get_string_buf_chk(&argvars[1], buf);
1830 
1831     if (title == NULL || initdir == NULL)
1832 	rettv->vval.v_string = NULL;
1833     else
1834 	rettv->vval.v_string = do_browse(BROWSE_DIR,
1835 				    title, NULL, NULL, initdir, NULL, curbuf);
1836 #else
1837     rettv->vval.v_string = NULL;
1838 #endif
1839     rettv->v_type = VAR_STRING;
1840 }
1841 
1842 /*
1843  * Find a buffer by number or exact name.
1844  */
1845     static buf_T *
1846 find_buffer(typval_T *avar)
1847 {
1848     buf_T	*buf = NULL;
1849 
1850     if (avar->v_type == VAR_NUMBER)
1851 	buf = buflist_findnr((int)avar->vval.v_number);
1852     else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1853     {
1854 	buf = buflist_findname_exp(avar->vval.v_string);
1855 	if (buf == NULL)
1856 	{
1857 	    /* No full path name match, try a match with a URL or a "nofile"
1858 	     * buffer, these don't use the full path. */
1859 	    FOR_ALL_BUFFERS(buf)
1860 		if (buf->b_fname != NULL
1861 			&& (path_with_url(buf->b_fname)
1862 #ifdef FEAT_QUICKFIX
1863 			    || bt_nofile(buf)
1864 #endif
1865 			   )
1866 			&& STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1867 		    break;
1868 	}
1869     }
1870     return buf;
1871 }
1872 
1873 /*
1874  * "bufexists(expr)" function
1875  */
1876     static void
1877 f_bufexists(typval_T *argvars, typval_T *rettv)
1878 {
1879     rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1880 }
1881 
1882 /*
1883  * "buflisted(expr)" function
1884  */
1885     static void
1886 f_buflisted(typval_T *argvars, typval_T *rettv)
1887 {
1888     buf_T	*buf;
1889 
1890     buf = find_buffer(&argvars[0]);
1891     rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1892 }
1893 
1894 /*
1895  * "bufloaded(expr)" function
1896  */
1897     static void
1898 f_bufloaded(typval_T *argvars, typval_T *rettv)
1899 {
1900     buf_T	*buf;
1901 
1902     buf = find_buffer(&argvars[0]);
1903     rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1904 }
1905 
1906     buf_T *
1907 buflist_find_by_name(char_u *name, int curtab_only)
1908 {
1909     int		save_magic;
1910     char_u	*save_cpo;
1911     buf_T	*buf;
1912 
1913     /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1914     save_magic = p_magic;
1915     p_magic = TRUE;
1916     save_cpo = p_cpo;
1917     p_cpo = (char_u *)"";
1918 
1919     buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1920 						    TRUE, FALSE, curtab_only));
1921 
1922     p_magic = save_magic;
1923     p_cpo = save_cpo;
1924     return buf;
1925 }
1926 
1927 /*
1928  * Get buffer by number or pattern.
1929  */
1930     buf_T *
1931 tv_get_buf(typval_T *tv, int curtab_only)
1932 {
1933     char_u	*name = tv->vval.v_string;
1934     buf_T	*buf;
1935 
1936     if (tv->v_type == VAR_NUMBER)
1937 	return buflist_findnr((int)tv->vval.v_number);
1938     if (tv->v_type != VAR_STRING)
1939 	return NULL;
1940     if (name == NULL || *name == NUL)
1941 	return curbuf;
1942     if (name[0] == '$' && name[1] == NUL)
1943 	return lastbuf;
1944 
1945     buf = buflist_find_by_name(name, curtab_only);
1946 
1947     /* If not found, try expanding the name, like done for bufexists(). */
1948     if (buf == NULL)
1949 	buf = find_buffer(tv);
1950 
1951     return buf;
1952 }
1953 
1954 #ifdef FEAT_SIGNS
1955 /*
1956  * Get the buffer from "arg" and give an error and return NULL if it is not
1957  * valid.
1958  */
1959     static buf_T *
1960 get_buf_arg(typval_T *arg)
1961 {
1962     buf_T *buf;
1963 
1964     ++emsg_off;
1965     buf = tv_get_buf(arg, FALSE);
1966     --emsg_off;
1967     if (buf == NULL)
1968 	semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
1969     return buf;
1970 }
1971 #endif
1972 
1973 /*
1974  * "bufname(expr)" function
1975  */
1976     static void
1977 f_bufname(typval_T *argvars, typval_T *rettv)
1978 {
1979     buf_T	*buf;
1980 
1981     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
1982     ++emsg_off;
1983     buf = tv_get_buf(&argvars[0], FALSE);
1984     rettv->v_type = VAR_STRING;
1985     if (buf != NULL && buf->b_fname != NULL)
1986 	rettv->vval.v_string = vim_strsave(buf->b_fname);
1987     else
1988 	rettv->vval.v_string = NULL;
1989     --emsg_off;
1990 }
1991 
1992 /*
1993  * "bufnr(expr)" function
1994  */
1995     static void
1996 f_bufnr(typval_T *argvars, typval_T *rettv)
1997 {
1998     buf_T	*buf;
1999     int		error = FALSE;
2000     char_u	*name;
2001 
2002     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
2003     ++emsg_off;
2004     buf = tv_get_buf(&argvars[0], FALSE);
2005     --emsg_off;
2006 
2007     /* If the buffer isn't found and the second argument is not zero create a
2008      * new buffer. */
2009     if (buf == NULL
2010 	    && argvars[1].v_type != VAR_UNKNOWN
2011 	    && tv_get_number_chk(&argvars[1], &error) != 0
2012 	    && !error
2013 	    && (name = tv_get_string_chk(&argvars[0])) != NULL
2014 	    && !error)
2015 	buf = buflist_new(name, NULL, (linenr_T)1, 0);
2016 
2017     if (buf != NULL)
2018 	rettv->vval.v_number = buf->b_fnum;
2019     else
2020 	rettv->vval.v_number = -1;
2021 }
2022 
2023     static void
2024 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2025 {
2026     win_T	*wp;
2027     int		winnr = 0;
2028     buf_T	*buf;
2029 
2030     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
2031     ++emsg_off;
2032     buf = tv_get_buf(&argvars[0], TRUE);
2033     FOR_ALL_WINDOWS(wp)
2034     {
2035 	++winnr;
2036 	if (wp->w_buffer == buf)
2037 	    break;
2038     }
2039     rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
2040     --emsg_off;
2041 }
2042 
2043 /*
2044  * "bufwinid(nr)" function
2045  */
2046     static void
2047 f_bufwinid(typval_T *argvars, typval_T *rettv)
2048 {
2049     buf_win_common(argvars, rettv, FALSE);
2050 }
2051 
2052 /*
2053  * "bufwinnr(nr)" function
2054  */
2055     static void
2056 f_bufwinnr(typval_T *argvars, typval_T *rettv)
2057 {
2058     buf_win_common(argvars, rettv, TRUE);
2059 }
2060 
2061 /*
2062  * "byte2line(byte)" function
2063  */
2064     static void
2065 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2066 {
2067 #ifndef FEAT_BYTEOFF
2068     rettv->vval.v_number = -1;
2069 #else
2070     long	boff = 0;
2071 
2072     boff = tv_get_number(&argvars[0]) - 1;  /* boff gets -1 on type error */
2073     if (boff < 0)
2074 	rettv->vval.v_number = -1;
2075     else
2076 	rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2077 							  (linenr_T)0, &boff);
2078 #endif
2079 }
2080 
2081     static void
2082 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2083 {
2084     char_u	*t;
2085     char_u	*str;
2086     varnumber_T	idx;
2087 
2088     str = tv_get_string_chk(&argvars[0]);
2089     idx = tv_get_number_chk(&argvars[1], NULL);
2090     rettv->vval.v_number = -1;
2091     if (str == NULL || idx < 0)
2092 	return;
2093 
2094     t = str;
2095     for ( ; idx > 0; idx--)
2096     {
2097 	if (*t == NUL)		/* EOL reached */
2098 	    return;
2099 	if (enc_utf8 && comp)
2100 	    t += utf_ptr2len(t);
2101 	else
2102 	    t += (*mb_ptr2len)(t);
2103     }
2104     rettv->vval.v_number = (varnumber_T)(t - str);
2105 }
2106 
2107 /*
2108  * "byteidx()" function
2109  */
2110     static void
2111 f_byteidx(typval_T *argvars, typval_T *rettv)
2112 {
2113     byteidx(argvars, rettv, FALSE);
2114 }
2115 
2116 /*
2117  * "byteidxcomp()" function
2118  */
2119     static void
2120 f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2121 {
2122     byteidx(argvars, rettv, TRUE);
2123 }
2124 
2125 /*
2126  * "call(func, arglist [, dict])" function
2127  */
2128     static void
2129 f_call(typval_T *argvars, typval_T *rettv)
2130 {
2131     char_u	*func;
2132     partial_T   *partial = NULL;
2133     dict_T	*selfdict = NULL;
2134 
2135     if (argvars[1].v_type != VAR_LIST)
2136     {
2137 	emsg(_(e_listreq));
2138 	return;
2139     }
2140     if (argvars[1].vval.v_list == NULL)
2141 	return;
2142 
2143     if (argvars[0].v_type == VAR_FUNC)
2144 	func = argvars[0].vval.v_string;
2145     else if (argvars[0].v_type == VAR_PARTIAL)
2146     {
2147 	partial = argvars[0].vval.v_partial;
2148 	func = partial_name(partial);
2149     }
2150     else
2151 	func = tv_get_string(&argvars[0]);
2152     if (*func == NUL)
2153 	return;		/* type error or empty name */
2154 
2155     if (argvars[2].v_type != VAR_UNKNOWN)
2156     {
2157 	if (argvars[2].v_type != VAR_DICT)
2158 	{
2159 	    emsg(_(e_dictreq));
2160 	    return;
2161 	}
2162 	selfdict = argvars[2].vval.v_dict;
2163     }
2164 
2165     (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2166 }
2167 
2168 #ifdef FEAT_FLOAT
2169 /*
2170  * "ceil({float})" function
2171  */
2172     static void
2173 f_ceil(typval_T *argvars, typval_T *rettv)
2174 {
2175     float_T	f = 0.0;
2176 
2177     rettv->v_type = VAR_FLOAT;
2178     if (get_float_arg(argvars, &f) == OK)
2179 	rettv->vval.v_float = ceil(f);
2180     else
2181 	rettv->vval.v_float = 0.0;
2182 }
2183 #endif
2184 
2185 #ifdef FEAT_JOB_CHANNEL
2186 /*
2187  * "ch_canread()" function
2188  */
2189     static void
2190 f_ch_canread(typval_T *argvars, typval_T *rettv)
2191 {
2192     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2193 
2194     rettv->vval.v_number = 0;
2195     if (channel != NULL)
2196 	rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2197 			    || channel_has_readahead(channel, PART_OUT)
2198 			    || channel_has_readahead(channel, PART_ERR);
2199 }
2200 
2201 /*
2202  * "ch_close()" function
2203  */
2204     static void
2205 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2206 {
2207     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2208 
2209     if (channel != NULL)
2210     {
2211 	channel_close(channel, FALSE);
2212 	channel_clear(channel);
2213     }
2214 }
2215 
2216 /*
2217  * "ch_close()" function
2218  */
2219     static void
2220 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2221 {
2222     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2223 
2224     if (channel != NULL)
2225 	channel_close_in(channel);
2226 }
2227 
2228 /*
2229  * "ch_getbufnr()" function
2230  */
2231     static void
2232 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2233 {
2234     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2235 
2236     rettv->vval.v_number = -1;
2237     if (channel != NULL)
2238     {
2239 	char_u	*what = tv_get_string(&argvars[1]);
2240 	int	part;
2241 
2242 	if (STRCMP(what, "err") == 0)
2243 	    part = PART_ERR;
2244 	else if (STRCMP(what, "out") == 0)
2245 	    part = PART_OUT;
2246 	else if (STRCMP(what, "in") == 0)
2247 	    part = PART_IN;
2248 	else
2249 	    part = PART_SOCK;
2250 	if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2251 	    rettv->vval.v_number =
2252 			      channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2253     }
2254 }
2255 
2256 /*
2257  * "ch_getjob()" function
2258  */
2259     static void
2260 f_ch_getjob(typval_T *argvars, typval_T *rettv)
2261 {
2262     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2263 
2264     if (channel != NULL)
2265     {
2266 	rettv->v_type = VAR_JOB;
2267 	rettv->vval.v_job = channel->ch_job;
2268 	if (channel->ch_job != NULL)
2269 	    ++channel->ch_job->jv_refcount;
2270     }
2271 }
2272 
2273 /*
2274  * "ch_info()" function
2275  */
2276     static void
2277 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2278 {
2279     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2280 
2281     if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2282 	channel_info(channel, rettv->vval.v_dict);
2283 }
2284 
2285 /*
2286  * "ch_log()" function
2287  */
2288     static void
2289 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2290 {
2291     char_u	*msg = tv_get_string(&argvars[0]);
2292     channel_T	*channel = NULL;
2293 
2294     if (argvars[1].v_type != VAR_UNKNOWN)
2295 	channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2296 
2297     ch_log(channel, "%s", msg);
2298 }
2299 
2300 /*
2301  * "ch_logfile()" function
2302  */
2303     static void
2304 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2305 {
2306     char_u *fname;
2307     char_u *opt = (char_u *)"";
2308     char_u buf[NUMBUFLEN];
2309 
2310     /* Don't open a file in restricted mode. */
2311     if (check_restricted() || check_secure())
2312 	return;
2313     fname = tv_get_string(&argvars[0]);
2314     if (argvars[1].v_type == VAR_STRING)
2315 	opt = tv_get_string_buf(&argvars[1], buf);
2316     ch_logfile(fname, opt);
2317 }
2318 
2319 /*
2320  * "ch_open()" function
2321  */
2322     static void
2323 f_ch_open(typval_T *argvars, typval_T *rettv)
2324 {
2325     rettv->v_type = VAR_CHANNEL;
2326     if (check_restricted() || check_secure())
2327 	return;
2328     rettv->vval.v_channel = channel_open_func(argvars);
2329 }
2330 
2331 /*
2332  * "ch_read()" function
2333  */
2334     static void
2335 f_ch_read(typval_T *argvars, typval_T *rettv)
2336 {
2337     common_channel_read(argvars, rettv, FALSE, FALSE);
2338 }
2339 
2340 /*
2341  * "ch_readblob()" function
2342  */
2343     static void
2344 f_ch_readblob(typval_T *argvars, typval_T *rettv)
2345 {
2346     common_channel_read(argvars, rettv, TRUE, TRUE);
2347 }
2348 
2349 /*
2350  * "ch_readraw()" function
2351  */
2352     static void
2353 f_ch_readraw(typval_T *argvars, typval_T *rettv)
2354 {
2355     common_channel_read(argvars, rettv, TRUE, FALSE);
2356 }
2357 
2358 /*
2359  * "ch_evalexpr()" function
2360  */
2361     static void
2362 f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2363 {
2364     ch_expr_common(argvars, rettv, TRUE);
2365 }
2366 
2367 /*
2368  * "ch_sendexpr()" function
2369  */
2370     static void
2371 f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2372 {
2373     ch_expr_common(argvars, rettv, FALSE);
2374 }
2375 
2376 /*
2377  * "ch_evalraw()" function
2378  */
2379     static void
2380 f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2381 {
2382     ch_raw_common(argvars, rettv, TRUE);
2383 }
2384 
2385 /*
2386  * "ch_sendraw()" function
2387  */
2388     static void
2389 f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2390 {
2391     ch_raw_common(argvars, rettv, FALSE);
2392 }
2393 
2394 /*
2395  * "ch_setoptions()" function
2396  */
2397     static void
2398 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2399 {
2400     channel_T	*channel;
2401     jobopt_T	opt;
2402 
2403     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2404     if (channel == NULL)
2405 	return;
2406     clear_job_options(&opt);
2407     if (get_job_options(&argvars[1], &opt,
2408 			    JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
2409 	channel_set_options(channel, &opt);
2410     free_job_options(&opt);
2411 }
2412 
2413 /*
2414  * "ch_status()" function
2415  */
2416     static void
2417 f_ch_status(typval_T *argvars, typval_T *rettv)
2418 {
2419     channel_T	*channel;
2420     jobopt_T	opt;
2421     int		part = -1;
2422 
2423     /* return an empty string by default */
2424     rettv->v_type = VAR_STRING;
2425     rettv->vval.v_string = NULL;
2426 
2427     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2428 
2429     if (argvars[1].v_type != VAR_UNKNOWN)
2430     {
2431 	clear_job_options(&opt);
2432 	if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
2433 						     && (opt.jo_set & JO_PART))
2434 	    part = opt.jo_part;
2435     }
2436 
2437     rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
2438 }
2439 #endif
2440 
2441 /*
2442  * "changenr()" function
2443  */
2444     static void
2445 f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2446 {
2447     rettv->vval.v_number = curbuf->b_u_seq_cur;
2448 }
2449 
2450 /*
2451  * "char2nr(string)" function
2452  */
2453     static void
2454 f_char2nr(typval_T *argvars, typval_T *rettv)
2455 {
2456     if (has_mbyte)
2457     {
2458 	int	utf8 = 0;
2459 
2460 	if (argvars[1].v_type != VAR_UNKNOWN)
2461 	    utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
2462 
2463 	if (utf8)
2464 	    rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
2465 	else
2466 	    rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
2467     }
2468     else
2469 	rettv->vval.v_number = tv_get_string(&argvars[0])[0];
2470 }
2471 
2472 /*
2473  * "cindent(lnum)" function
2474  */
2475     static void
2476 f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2477 {
2478 #ifdef FEAT_CINDENT
2479     pos_T	pos;
2480     linenr_T	lnum;
2481 
2482     pos = curwin->w_cursor;
2483     lnum = tv_get_lnum(argvars);
2484     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2485     {
2486 	curwin->w_cursor.lnum = lnum;
2487 	rettv->vval.v_number = get_c_indent();
2488 	curwin->w_cursor = pos;
2489     }
2490     else
2491 #endif
2492 	rettv->vval.v_number = -1;
2493 }
2494 
2495 /*
2496  * "clearmatches()" function
2497  */
2498     static void
2499 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2500 {
2501 #ifdef FEAT_SEARCH_EXTRA
2502     clear_matches(curwin);
2503 #endif
2504 }
2505 
2506 /*
2507  * "col(string)" function
2508  */
2509     static void
2510 f_col(typval_T *argvars, typval_T *rettv)
2511 {
2512     colnr_T	col = 0;
2513     pos_T	*fp;
2514     int		fnum = curbuf->b_fnum;
2515 
2516     fp = var2fpos(&argvars[0], FALSE, &fnum);
2517     if (fp != NULL && fnum == curbuf->b_fnum)
2518     {
2519 	if (fp->col == MAXCOL)
2520 	{
2521 	    /* '> can be MAXCOL, get the length of the line then */
2522 	    if (fp->lnum <= curbuf->b_ml.ml_line_count)
2523 		col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2524 	    else
2525 		col = MAXCOL;
2526 	}
2527 	else
2528 	{
2529 	    col = fp->col + 1;
2530 	    /* col(".") when the cursor is on the NUL at the end of the line
2531 	     * because of "coladd" can be seen as an extra column. */
2532 	    if (virtual_active() && fp == &curwin->w_cursor)
2533 	    {
2534 		char_u	*p = ml_get_cursor();
2535 
2536 		if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2537 				 curwin->w_virtcol - curwin->w_cursor.coladd))
2538 		{
2539 		    int		l;
2540 
2541 		    if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2542 			col += l;
2543 		}
2544 	    }
2545 	}
2546     }
2547     rettv->vval.v_number = col;
2548 }
2549 
2550 #if defined(FEAT_INS_EXPAND)
2551 /*
2552  * "complete()" function
2553  */
2554     static void
2555 f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2556 {
2557     int	    startcol;
2558 
2559     if ((State & INSERT) == 0)
2560     {
2561 	emsg(_("E785: complete() can only be used in Insert mode"));
2562 	return;
2563     }
2564 
2565     /* Check for undo allowed here, because if something was already inserted
2566      * the line was already saved for undo and this check isn't done. */
2567     if (!undo_allowed())
2568 	return;
2569 
2570     if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2571     {
2572 	emsg(_(e_invarg));
2573 	return;
2574     }
2575 
2576     startcol = (int)tv_get_number_chk(&argvars[0], NULL);
2577     if (startcol <= 0)
2578 	return;
2579 
2580     set_completion(startcol - 1, argvars[1].vval.v_list);
2581 }
2582 
2583 /*
2584  * "complete_add()" function
2585  */
2586     static void
2587 f_complete_add(typval_T *argvars, typval_T *rettv)
2588 {
2589     rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2590 }
2591 
2592 /*
2593  * "complete_check()" function
2594  */
2595     static void
2596 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2597 {
2598     int		saved = RedrawingDisabled;
2599 
2600     RedrawingDisabled = 0;
2601     ins_compl_check_keys(0, TRUE);
2602     rettv->vval.v_number = compl_interrupted;
2603     RedrawingDisabled = saved;
2604 }
2605 
2606 /*
2607  * "complete_info()" function
2608  */
2609     static void
2610 f_complete_info(typval_T *argvars, typval_T *rettv)
2611 {
2612     list_T	*what_list = NULL;
2613 
2614     if (rettv_dict_alloc(rettv) != OK)
2615 	return;
2616 
2617     if (argvars[0].v_type != VAR_UNKNOWN)
2618     {
2619 	if (argvars[0].v_type != VAR_LIST)
2620 	{
2621 	    emsg(_(e_listreq));
2622 	    return;
2623 	}
2624 	what_list = argvars[0].vval.v_list;
2625     }
2626     get_complete_info(what_list, rettv->vval.v_dict);
2627 }
2628 #endif
2629 
2630 /*
2631  * "confirm(message, buttons[, default [, type]])" function
2632  */
2633     static void
2634 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2635 {
2636 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2637     char_u	*message;
2638     char_u	*buttons = NULL;
2639     char_u	buf[NUMBUFLEN];
2640     char_u	buf2[NUMBUFLEN];
2641     int		def = 1;
2642     int		type = VIM_GENERIC;
2643     char_u	*typestr;
2644     int		error = FALSE;
2645 
2646     message = tv_get_string_chk(&argvars[0]);
2647     if (message == NULL)
2648 	error = TRUE;
2649     if (argvars[1].v_type != VAR_UNKNOWN)
2650     {
2651 	buttons = tv_get_string_buf_chk(&argvars[1], buf);
2652 	if (buttons == NULL)
2653 	    error = TRUE;
2654 	if (argvars[2].v_type != VAR_UNKNOWN)
2655 	{
2656 	    def = (int)tv_get_number_chk(&argvars[2], &error);
2657 	    if (argvars[3].v_type != VAR_UNKNOWN)
2658 	    {
2659 		typestr = tv_get_string_buf_chk(&argvars[3], buf2);
2660 		if (typestr == NULL)
2661 		    error = TRUE;
2662 		else
2663 		{
2664 		    switch (TOUPPER_ASC(*typestr))
2665 		    {
2666 			case 'E': type = VIM_ERROR; break;
2667 			case 'Q': type = VIM_QUESTION; break;
2668 			case 'I': type = VIM_INFO; break;
2669 			case 'W': type = VIM_WARNING; break;
2670 			case 'G': type = VIM_GENERIC; break;
2671 		    }
2672 		}
2673 	    }
2674 	}
2675     }
2676 
2677     if (buttons == NULL || *buttons == NUL)
2678 	buttons = (char_u *)_("&Ok");
2679 
2680     if (!error)
2681 	rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2682 							    def, NULL, FALSE);
2683 #endif
2684 }
2685 
2686 /*
2687  * "copy()" function
2688  */
2689     static void
2690 f_copy(typval_T *argvars, typval_T *rettv)
2691 {
2692     item_copy(&argvars[0], rettv, FALSE, 0);
2693 }
2694 
2695 #ifdef FEAT_FLOAT
2696 /*
2697  * "cos()" function
2698  */
2699     static void
2700 f_cos(typval_T *argvars, typval_T *rettv)
2701 {
2702     float_T	f = 0.0;
2703 
2704     rettv->v_type = VAR_FLOAT;
2705     if (get_float_arg(argvars, &f) == OK)
2706 	rettv->vval.v_float = cos(f);
2707     else
2708 	rettv->vval.v_float = 0.0;
2709 }
2710 
2711 /*
2712  * "cosh()" function
2713  */
2714     static void
2715 f_cosh(typval_T *argvars, typval_T *rettv)
2716 {
2717     float_T	f = 0.0;
2718 
2719     rettv->v_type = VAR_FLOAT;
2720     if (get_float_arg(argvars, &f) == OK)
2721 	rettv->vval.v_float = cosh(f);
2722     else
2723 	rettv->vval.v_float = 0.0;
2724 }
2725 #endif
2726 
2727 /*
2728  * "count()" function
2729  */
2730     static void
2731 f_count(typval_T *argvars, typval_T *rettv)
2732 {
2733     long	n = 0;
2734     int		ic = FALSE;
2735     int		error = FALSE;
2736 
2737     if (argvars[2].v_type != VAR_UNKNOWN)
2738 	ic = (int)tv_get_number_chk(&argvars[2], &error);
2739 
2740     if (argvars[0].v_type == VAR_STRING)
2741     {
2742 	char_u *expr = tv_get_string_chk(&argvars[1]);
2743 	char_u *p = argvars[0].vval.v_string;
2744 	char_u *next;
2745 
2746 	if (!error && expr != NULL && *expr != NUL && p != NULL)
2747 	{
2748 	    if (ic)
2749 	    {
2750 		size_t len = STRLEN(expr);
2751 
2752 		while (*p != NUL)
2753 		{
2754 		    if (MB_STRNICMP(p, expr, len) == 0)
2755 		    {
2756 			++n;
2757 			p += len;
2758 		    }
2759 		    else
2760 			MB_PTR_ADV(p);
2761 		}
2762 	    }
2763 	    else
2764 		while ((next = (char_u *)strstr((char *)p, (char *)expr))
2765 								       != NULL)
2766 		{
2767 		    ++n;
2768 		    p = next + STRLEN(expr);
2769 		}
2770 	}
2771 
2772     }
2773     else if (argvars[0].v_type == VAR_LIST)
2774     {
2775 	listitem_T	*li;
2776 	list_T		*l;
2777 	long		idx;
2778 
2779 	if ((l = argvars[0].vval.v_list) != NULL)
2780 	{
2781 	    li = l->lv_first;
2782 	    if (argvars[2].v_type != VAR_UNKNOWN)
2783 	    {
2784 		if (argvars[3].v_type != VAR_UNKNOWN)
2785 		{
2786 		    idx = (long)tv_get_number_chk(&argvars[3], &error);
2787 		    if (!error)
2788 		    {
2789 			li = list_find(l, idx);
2790 			if (li == NULL)
2791 			    semsg(_(e_listidx), idx);
2792 		    }
2793 		}
2794 		if (error)
2795 		    li = NULL;
2796 	    }
2797 
2798 	    for ( ; li != NULL; li = li->li_next)
2799 		if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2800 		    ++n;
2801 	}
2802     }
2803     else if (argvars[0].v_type == VAR_DICT)
2804     {
2805 	int		todo;
2806 	dict_T		*d;
2807 	hashitem_T	*hi;
2808 
2809 	if ((d = argvars[0].vval.v_dict) != NULL)
2810 	{
2811 	    if (argvars[2].v_type != VAR_UNKNOWN)
2812 	    {
2813 		if (argvars[3].v_type != VAR_UNKNOWN)
2814 		    emsg(_(e_invarg));
2815 	    }
2816 
2817 	    todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2818 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2819 	    {
2820 		if (!HASHITEM_EMPTY(hi))
2821 		{
2822 		    --todo;
2823 		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2824 			++n;
2825 		}
2826 	    }
2827 	}
2828     }
2829     else
2830 	semsg(_(e_listdictarg), "count()");
2831     rettv->vval.v_number = n;
2832 }
2833 
2834 /*
2835  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2836  *
2837  * Checks the existence of a cscope connection.
2838  */
2839     static void
2840 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2841 {
2842 #ifdef FEAT_CSCOPE
2843     int		num = 0;
2844     char_u	*dbpath = NULL;
2845     char_u	*prepend = NULL;
2846     char_u	buf[NUMBUFLEN];
2847 
2848     if (argvars[0].v_type != VAR_UNKNOWN
2849 	    && argvars[1].v_type != VAR_UNKNOWN)
2850     {
2851 	num = (int)tv_get_number(&argvars[0]);
2852 	dbpath = tv_get_string(&argvars[1]);
2853 	if (argvars[2].v_type != VAR_UNKNOWN)
2854 	    prepend = tv_get_string_buf(&argvars[2], buf);
2855     }
2856 
2857     rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2858 #endif
2859 }
2860 
2861 /*
2862  * "cursor(lnum, col)" function, or
2863  * "cursor(list)"
2864  *
2865  * Moves the cursor to the specified line and column.
2866  * Returns 0 when the position could be set, -1 otherwise.
2867  */
2868     static void
2869 f_cursor(typval_T *argvars, typval_T *rettv)
2870 {
2871     long	line, col;
2872     long	coladd = 0;
2873     int		set_curswant = TRUE;
2874 
2875     rettv->vval.v_number = -1;
2876     if (argvars[1].v_type == VAR_UNKNOWN)
2877     {
2878 	pos_T	    pos;
2879 	colnr_T	    curswant = -1;
2880 
2881 	if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2882 	{
2883 	    emsg(_(e_invarg));
2884 	    return;
2885 	}
2886 	line = pos.lnum;
2887 	col = pos.col;
2888 	coladd = pos.coladd;
2889 	if (curswant >= 0)
2890 	{
2891 	    curwin->w_curswant = curswant - 1;
2892 	    set_curswant = FALSE;
2893 	}
2894     }
2895     else
2896     {
2897 	line = tv_get_lnum(argvars);
2898 	col = (long)tv_get_number_chk(&argvars[1], NULL);
2899 	if (argvars[2].v_type != VAR_UNKNOWN)
2900 	    coladd = (long)tv_get_number_chk(&argvars[2], NULL);
2901     }
2902     if (line < 0 || col < 0 || coladd < 0)
2903 	return;		/* type error; errmsg already given */
2904     if (line > 0)
2905 	curwin->w_cursor.lnum = line;
2906     if (col > 0)
2907 	curwin->w_cursor.col = col - 1;
2908     curwin->w_cursor.coladd = coladd;
2909 
2910     /* Make sure the cursor is in a valid position. */
2911     check_cursor();
2912     /* Correct cursor for multi-byte character. */
2913     if (has_mbyte)
2914 	mb_adjust_cursor();
2915 
2916     curwin->w_set_curswant = set_curswant;
2917     rettv->vval.v_number = 0;
2918 }
2919 
2920 #ifdef MSWIN
2921 /*
2922  * "debugbreak()" function
2923  */
2924     static void
2925 f_debugbreak(typval_T *argvars, typval_T *rettv)
2926 {
2927     int		pid;
2928 
2929     rettv->vval.v_number = FAIL;
2930     pid = (int)tv_get_number(&argvars[0]);
2931     if (pid == 0)
2932 	emsg(_(e_invarg));
2933     else
2934     {
2935 	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2936 
2937 	if (hProcess != NULL)
2938 	{
2939 	    DebugBreakProcess(hProcess);
2940 	    CloseHandle(hProcess);
2941 	    rettv->vval.v_number = OK;
2942 	}
2943     }
2944 }
2945 #endif
2946 
2947 /*
2948  * "deepcopy()" function
2949  */
2950     static void
2951 f_deepcopy(typval_T *argvars, typval_T *rettv)
2952 {
2953     int		noref = 0;
2954     int		copyID;
2955 
2956     if (argvars[1].v_type != VAR_UNKNOWN)
2957 	noref = (int)tv_get_number_chk(&argvars[1], NULL);
2958     if (noref < 0 || noref > 1)
2959 	emsg(_(e_invarg));
2960     else
2961     {
2962 	copyID = get_copyID();
2963 	item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2964     }
2965 }
2966 
2967 /*
2968  * "delete()" function
2969  */
2970     static void
2971 f_delete(typval_T *argvars, typval_T *rettv)
2972 {
2973     char_u	nbuf[NUMBUFLEN];
2974     char_u	*name;
2975     char_u	*flags;
2976 
2977     rettv->vval.v_number = -1;
2978     if (check_restricted() || check_secure())
2979 	return;
2980 
2981     name = tv_get_string(&argvars[0]);
2982     if (name == NULL || *name == NUL)
2983     {
2984 	emsg(_(e_invarg));
2985 	return;
2986     }
2987 
2988     if (argvars[1].v_type != VAR_UNKNOWN)
2989 	flags = tv_get_string_buf(&argvars[1], nbuf);
2990     else
2991 	flags = (char_u *)"";
2992 
2993     if (*flags == NUL)
2994 	/* delete a file */
2995 	rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2996     else if (STRCMP(flags, "d") == 0)
2997 	/* delete an empty directory */
2998 	rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2999     else if (STRCMP(flags, "rf") == 0)
3000 	/* delete a directory recursively */
3001 	rettv->vval.v_number = delete_recursive(name);
3002     else
3003 	semsg(_(e_invexpr2), flags);
3004 }
3005 
3006 /*
3007  * "deletebufline()" function
3008  */
3009     static void
3010 f_deletebufline(typval_T *argvars, typval_T *rettv)
3011 {
3012     buf_T	*buf;
3013     linenr_T	first, last;
3014     linenr_T	lnum;
3015     long	count;
3016     int		is_curbuf;
3017     buf_T	*curbuf_save = NULL;
3018     win_T	*curwin_save = NULL;
3019     tabpage_T	*tp;
3020     win_T	*wp;
3021 
3022     buf = tv_get_buf(&argvars[0], FALSE);
3023     if (buf == NULL)
3024     {
3025 	rettv->vval.v_number = 1; /* FAIL */
3026 	return;
3027     }
3028     is_curbuf = buf == curbuf;
3029 
3030     first = tv_get_lnum_buf(&argvars[1], buf);
3031     if (argvars[2].v_type != VAR_UNKNOWN)
3032 	last = tv_get_lnum_buf(&argvars[2], buf);
3033     else
3034 	last = first;
3035 
3036     if (buf->b_ml.ml_mfp == NULL || first < 1
3037 			   || first > buf->b_ml.ml_line_count || last < first)
3038     {
3039 	rettv->vval.v_number = 1;	/* FAIL */
3040 	return;
3041     }
3042 
3043     if (!is_curbuf)
3044     {
3045 	curbuf_save = curbuf;
3046 	curwin_save = curwin;
3047 	curbuf = buf;
3048 	find_win_for_curbuf();
3049     }
3050     if (last > curbuf->b_ml.ml_line_count)
3051 	last = curbuf->b_ml.ml_line_count;
3052     count = last - first + 1;
3053 
3054     // When coming here from Insert mode, sync undo, so that this can be
3055     // undone separately from what was previously inserted.
3056     if (u_sync_once == 2)
3057     {
3058 	u_sync_once = 1; // notify that u_sync() was called
3059 	u_sync(TRUE);
3060     }
3061 
3062     if (u_save(first - 1, last + 1) == FAIL)
3063     {
3064 	rettv->vval.v_number = 1;	/* FAIL */
3065 	return;
3066     }
3067 
3068     for (lnum = first; lnum <= last; ++lnum)
3069 	ml_delete(first, TRUE);
3070 
3071     FOR_ALL_TAB_WINDOWS(tp, wp)
3072 	if (wp->w_buffer == buf)
3073 	{
3074 	    if (wp->w_cursor.lnum > last)
3075 		wp->w_cursor.lnum -= count;
3076 	    else if (wp->w_cursor.lnum> first)
3077 		wp->w_cursor.lnum = first;
3078 	    if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3079 		wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3080 	}
3081     check_cursor_col();
3082     deleted_lines_mark(first, count);
3083 
3084     if (!is_curbuf)
3085     {
3086 	curbuf = curbuf_save;
3087 	curwin = curwin_save;
3088     }
3089 }
3090 
3091 /*
3092  * "did_filetype()" function
3093  */
3094     static void
3095 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3096 {
3097     rettv->vval.v_number = did_filetype;
3098 }
3099 
3100 /*
3101  * "diff_filler()" function
3102  */
3103     static void
3104 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3105 {
3106 #ifdef FEAT_DIFF
3107     rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
3108 #endif
3109 }
3110 
3111 /*
3112  * "diff_hlID()" function
3113  */
3114     static void
3115 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3116 {
3117 #ifdef FEAT_DIFF
3118     linenr_T		lnum = tv_get_lnum(argvars);
3119     static linenr_T	prev_lnum = 0;
3120     static varnumber_T	changedtick = 0;
3121     static int		fnum = 0;
3122     static int		change_start = 0;
3123     static int		change_end = 0;
3124     static hlf_T	hlID = (hlf_T)0;
3125     int			filler_lines;
3126     int			col;
3127 
3128     if (lnum < 0)	/* ignore type error in {lnum} arg */
3129 	lnum = 0;
3130     if (lnum != prev_lnum
3131 	    || changedtick != CHANGEDTICK(curbuf)
3132 	    || fnum != curbuf->b_fnum)
3133     {
3134 	/* New line, buffer, change: need to get the values. */
3135 	filler_lines = diff_check(curwin, lnum);
3136 	if (filler_lines < 0)
3137 	{
3138 	    if (filler_lines == -1)
3139 	    {
3140 		change_start = MAXCOL;
3141 		change_end = -1;
3142 		if (diff_find_change(curwin, lnum, &change_start, &change_end))
3143 		    hlID = HLF_ADD;	/* added line */
3144 		else
3145 		    hlID = HLF_CHD;	/* changed line */
3146 	    }
3147 	    else
3148 		hlID = HLF_ADD;	/* added line */
3149 	}
3150 	else
3151 	    hlID = (hlf_T)0;
3152 	prev_lnum = lnum;
3153 	changedtick = CHANGEDTICK(curbuf);
3154 	fnum = curbuf->b_fnum;
3155     }
3156 
3157     if (hlID == HLF_CHD || hlID == HLF_TXD)
3158     {
3159 	col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
3160 	if (col >= change_start && col <= change_end)
3161 	    hlID = HLF_TXD;			/* changed text */
3162 	else
3163 	    hlID = HLF_CHD;			/* changed line */
3164     }
3165     rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3166 #endif
3167 }
3168 
3169 /*
3170  * "empty({expr})" function
3171  */
3172     static void
3173 f_empty(typval_T *argvars, typval_T *rettv)
3174 {
3175     int		n = FALSE;
3176 
3177     switch (argvars[0].v_type)
3178     {
3179 	case VAR_STRING:
3180 	case VAR_FUNC:
3181 	    n = argvars[0].vval.v_string == NULL
3182 					  || *argvars[0].vval.v_string == NUL;
3183 	    break;
3184 	case VAR_PARTIAL:
3185 	    n = FALSE;
3186 	    break;
3187 	case VAR_NUMBER:
3188 	    n = argvars[0].vval.v_number == 0;
3189 	    break;
3190 	case VAR_FLOAT:
3191 #ifdef FEAT_FLOAT
3192 	    n = argvars[0].vval.v_float == 0.0;
3193 	    break;
3194 #endif
3195 	case VAR_LIST:
3196 	    n = argvars[0].vval.v_list == NULL
3197 				  || argvars[0].vval.v_list->lv_first == NULL;
3198 	    break;
3199 	case VAR_DICT:
3200 	    n = argvars[0].vval.v_dict == NULL
3201 			|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3202 	    break;
3203 	case VAR_SPECIAL:
3204 	    n = argvars[0].vval.v_number != VVAL_TRUE;
3205 	    break;
3206 
3207 	case VAR_BLOB:
3208 	    n = argvars[0].vval.v_blob == NULL
3209 		|| argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3210 	    break;
3211 
3212 	case VAR_JOB:
3213 #ifdef FEAT_JOB_CHANNEL
3214 	    n = argvars[0].vval.v_job == NULL
3215 			   || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3216 	    break;
3217 #endif
3218 	case VAR_CHANNEL:
3219 #ifdef FEAT_JOB_CHANNEL
3220 	    n = argvars[0].vval.v_channel == NULL
3221 			       || !channel_is_open(argvars[0].vval.v_channel);
3222 	    break;
3223 #endif
3224 	case VAR_UNKNOWN:
3225 	    internal_error("f_empty(UNKNOWN)");
3226 	    n = TRUE;
3227 	    break;
3228     }
3229 
3230     rettv->vval.v_number = n;
3231 }
3232 
3233 /*
3234  * "escape({string}, {chars})" function
3235  */
3236     static void
3237 f_escape(typval_T *argvars, typval_T *rettv)
3238 {
3239     char_u	buf[NUMBUFLEN];
3240 
3241     rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3242 					 tv_get_string_buf(&argvars[1], buf));
3243     rettv->v_type = VAR_STRING;
3244 }
3245 
3246 /*
3247  * "eval()" function
3248  */
3249     static void
3250 f_eval(typval_T *argvars, typval_T *rettv)
3251 {
3252     char_u	*s, *p;
3253 
3254     s = tv_get_string_chk(&argvars[0]);
3255     if (s != NULL)
3256 	s = skipwhite(s);
3257 
3258     p = s;
3259     if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3260     {
3261 	if (p != NULL && !aborting())
3262 	    semsg(_(e_invexpr2), p);
3263 	need_clr_eos = FALSE;
3264 	rettv->v_type = VAR_NUMBER;
3265 	rettv->vval.v_number = 0;
3266     }
3267     else if (*s != NUL)
3268 	emsg(_(e_trailing));
3269 }
3270 
3271 /*
3272  * "eventhandler()" function
3273  */
3274     static void
3275 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3276 {
3277     rettv->vval.v_number = vgetc_busy;
3278 }
3279 
3280 /*
3281  * "executable()" function
3282  */
3283     static void
3284 f_executable(typval_T *argvars, typval_T *rettv)
3285 {
3286     char_u *name = tv_get_string(&argvars[0]);
3287 
3288     /* Check in $PATH and also check directly if there is a directory name. */
3289     rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3290 		 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3291 }
3292 
3293 static garray_T	redir_execute_ga;
3294 
3295 /*
3296  * Append "value[value_len]" to the execute() output.
3297  */
3298     void
3299 execute_redir_str(char_u *value, int value_len)
3300 {
3301     int		len;
3302 
3303     if (value_len == -1)
3304 	len = (int)STRLEN(value);	/* Append the entire string */
3305     else
3306 	len = value_len;		/* Append only "value_len" characters */
3307     if (ga_grow(&redir_execute_ga, len) == OK)
3308     {
3309 	mch_memmove((char *)redir_execute_ga.ga_data
3310 				       + redir_execute_ga.ga_len, value, len);
3311 	redir_execute_ga.ga_len += len;
3312     }
3313 }
3314 
3315 /*
3316  * Get next line from a list.
3317  * Called by do_cmdline() to get the next line.
3318  * Returns allocated string, or NULL for end of function.
3319  */
3320 
3321     static char_u *
3322 get_list_line(
3323     int	    c UNUSED,
3324     void    *cookie,
3325     int	    indent UNUSED)
3326 {
3327     listitem_T **p = (listitem_T **)cookie;
3328     listitem_T *item = *p;
3329     char_u	buf[NUMBUFLEN];
3330     char_u	*s;
3331 
3332     if (item == NULL)
3333 	return NULL;
3334     s = tv_get_string_buf_chk(&item->li_tv, buf);
3335     *p = item->li_next;
3336     return s == NULL ? NULL : vim_strsave(s);
3337 }
3338 
3339 /*
3340  * "execute()" function
3341  */
3342     static void
3343 f_execute(typval_T *argvars, typval_T *rettv)
3344 {
3345     char_u	*cmd = NULL;
3346     list_T	*list = NULL;
3347     int		save_msg_silent = msg_silent;
3348     int		save_emsg_silent = emsg_silent;
3349     int		save_emsg_noredir = emsg_noredir;
3350     int		save_redir_execute = redir_execute;
3351     int		save_redir_off = redir_off;
3352     garray_T	save_ga;
3353     int		save_msg_col = msg_col;
3354     int		echo_output = FALSE;
3355 
3356     rettv->vval.v_string = NULL;
3357     rettv->v_type = VAR_STRING;
3358 
3359     if (argvars[0].v_type == VAR_LIST)
3360     {
3361 	list = argvars[0].vval.v_list;
3362 	if (list == NULL || list->lv_first == NULL)
3363 	    /* empty list, no commands, empty output */
3364 	    return;
3365 	++list->lv_refcount;
3366     }
3367     else
3368     {
3369 	cmd = tv_get_string_chk(&argvars[0]);
3370 	if (cmd == NULL)
3371 	    return;
3372     }
3373 
3374     if (argvars[1].v_type != VAR_UNKNOWN)
3375     {
3376 	char_u	buf[NUMBUFLEN];
3377 	char_u  *s = tv_get_string_buf_chk(&argvars[1], buf);
3378 
3379 	if (s == NULL)
3380 	    return;
3381 	if (*s == NUL)
3382 	    echo_output = TRUE;
3383 	if (STRNCMP(s, "silent", 6) == 0)
3384 	    ++msg_silent;
3385 	if (STRCMP(s, "silent!") == 0)
3386 	{
3387 	    emsg_silent = TRUE;
3388 	    emsg_noredir = TRUE;
3389 	}
3390     }
3391     else
3392 	++msg_silent;
3393 
3394     if (redir_execute)
3395 	save_ga = redir_execute_ga;
3396     ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3397     redir_execute = TRUE;
3398     redir_off = FALSE;
3399     if (!echo_output)
3400 	msg_col = 0;  // prevent leading spaces
3401 
3402     if (cmd != NULL)
3403 	do_cmdline_cmd(cmd);
3404     else
3405     {
3406 	listitem_T	*item = list->lv_first;
3407 
3408 	do_cmdline(NULL, get_list_line, (void *)&item,
3409 		      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3410 	--list->lv_refcount;
3411     }
3412 
3413     /* Need to append a NUL to the result. */
3414     if (ga_grow(&redir_execute_ga, 1) == OK)
3415     {
3416 	((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3417 	rettv->vval.v_string = redir_execute_ga.ga_data;
3418     }
3419     else
3420     {
3421 	ga_clear(&redir_execute_ga);
3422 	rettv->vval.v_string = NULL;
3423     }
3424     msg_silent = save_msg_silent;
3425     emsg_silent = save_emsg_silent;
3426     emsg_noredir = save_emsg_noredir;
3427 
3428     redir_execute = save_redir_execute;
3429     if (redir_execute)
3430 	redir_execute_ga = save_ga;
3431     redir_off = save_redir_off;
3432 
3433     // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
3434     if (echo_output)
3435 	// When not working silently: put it in column zero.  A following
3436 	// "echon" will overwrite the message, unavoidably.
3437 	msg_col = 0;
3438     else
3439 	// When working silently: Put it back where it was, since nothing
3440 	// should have been written.
3441 	msg_col = save_msg_col;
3442 }
3443 
3444 /*
3445  * "exepath()" function
3446  */
3447     static void
3448 f_exepath(typval_T *argvars, typval_T *rettv)
3449 {
3450     char_u *p = NULL;
3451 
3452     (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
3453     rettv->v_type = VAR_STRING;
3454     rettv->vval.v_string = p;
3455 }
3456 
3457 /*
3458  * "exists()" function
3459  */
3460     static void
3461 f_exists(typval_T *argvars, typval_T *rettv)
3462 {
3463     char_u	*p;
3464     int		n = FALSE;
3465 
3466     p = tv_get_string(&argvars[0]);
3467     if (*p == '$')			/* environment variable */
3468     {
3469 	/* first try "normal" environment variables (fast) */
3470 	if (mch_getenv(p + 1) != NULL)
3471 	    n = TRUE;
3472 	else
3473 	{
3474 	    /* try expanding things like $VIM and ${HOME} */
3475 	    p = expand_env_save(p);
3476 	    if (p != NULL && *p != '$')
3477 		n = TRUE;
3478 	    vim_free(p);
3479 	}
3480     }
3481     else if (*p == '&' || *p == '+')			/* option */
3482     {
3483 	n = (get_option_tv(&p, NULL, TRUE) == OK);
3484 	if (*skipwhite(p) != NUL)
3485 	    n = FALSE;			/* trailing garbage */
3486     }
3487     else if (*p == '*')			/* internal or user defined function */
3488     {
3489 	n = function_exists(p + 1, FALSE);
3490     }
3491     else if (*p == ':')
3492     {
3493 	n = cmd_exists(p + 1);
3494     }
3495     else if (*p == '#')
3496     {
3497 	if (p[1] == '#')
3498 	    n = autocmd_supported(p + 2);
3499 	else
3500 	    n = au_exists(p + 1);
3501     }
3502     else				/* internal variable */
3503     {
3504 	n = var_exists(p);
3505     }
3506 
3507     rettv->vval.v_number = n;
3508 }
3509 
3510 #ifdef FEAT_FLOAT
3511 /*
3512  * "exp()" function
3513  */
3514     static void
3515 f_exp(typval_T *argvars, typval_T *rettv)
3516 {
3517     float_T	f = 0.0;
3518 
3519     rettv->v_type = VAR_FLOAT;
3520     if (get_float_arg(argvars, &f) == OK)
3521 	rettv->vval.v_float = exp(f);
3522     else
3523 	rettv->vval.v_float = 0.0;
3524 }
3525 #endif
3526 
3527 /*
3528  * "expand()" function
3529  */
3530     static void
3531 f_expand(typval_T *argvars, typval_T *rettv)
3532 {
3533     char_u	*s;
3534     int		len;
3535     char	*errormsg;
3536     int		options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3537     expand_T	xpc;
3538     int		error = FALSE;
3539     char_u	*result;
3540 
3541     rettv->v_type = VAR_STRING;
3542     if (argvars[1].v_type != VAR_UNKNOWN
3543 	    && argvars[2].v_type != VAR_UNKNOWN
3544 	    && tv_get_number_chk(&argvars[2], &error)
3545 	    && !error)
3546     {
3547 	rettv_list_set(rettv, NULL);
3548     }
3549 
3550     s = tv_get_string(&argvars[0]);
3551     if (*s == '%' || *s == '#' || *s == '<')
3552     {
3553 	++emsg_off;
3554 	result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3555 	--emsg_off;
3556 	if (rettv->v_type == VAR_LIST)
3557 	{
3558 	    if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3559 		list_append_string(rettv->vval.v_list, result, -1);
3560 	    else
3561 		vim_free(result);
3562 	}
3563 	else
3564 	    rettv->vval.v_string = result;
3565     }
3566     else
3567     {
3568 	/* When the optional second argument is non-zero, don't remove matches
3569 	 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3570 	if (argvars[1].v_type != VAR_UNKNOWN
3571 				    && tv_get_number_chk(&argvars[1], &error))
3572 	    options |= WILD_KEEP_ALL;
3573 	if (!error)
3574 	{
3575 	    ExpandInit(&xpc);
3576 	    xpc.xp_context = EXPAND_FILES;
3577 	    if (p_wic)
3578 		options += WILD_ICASE;
3579 	    if (rettv->v_type == VAR_STRING)
3580 		rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3581 							   options, WILD_ALL);
3582 	    else if (rettv_list_alloc(rettv) != FAIL)
3583 	    {
3584 		int i;
3585 
3586 		ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3587 		for (i = 0; i < xpc.xp_numfiles; i++)
3588 		    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3589 		ExpandCleanup(&xpc);
3590 	    }
3591 	}
3592 	else
3593 	    rettv->vval.v_string = NULL;
3594     }
3595 }
3596 
3597 /*
3598  * "extend(list, list [, idx])" function
3599  * "extend(dict, dict [, action])" function
3600  */
3601     static void
3602 f_extend(typval_T *argvars, typval_T *rettv)
3603 {
3604     char_u      *arg_errmsg = (char_u *)N_("extend() argument");
3605 
3606     if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3607     {
3608 	list_T		*l1, *l2;
3609 	listitem_T	*item;
3610 	long		before;
3611 	int		error = FALSE;
3612 
3613 	l1 = argvars[0].vval.v_list;
3614 	l2 = argvars[1].vval.v_list;
3615 	if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3616 		&& l2 != NULL)
3617 	{
3618 	    if (argvars[2].v_type != VAR_UNKNOWN)
3619 	    {
3620 		before = (long)tv_get_number_chk(&argvars[2], &error);
3621 		if (error)
3622 		    return;		/* type error; errmsg already given */
3623 
3624 		if (before == l1->lv_len)
3625 		    item = NULL;
3626 		else
3627 		{
3628 		    item = list_find(l1, before);
3629 		    if (item == NULL)
3630 		    {
3631 			semsg(_(e_listidx), before);
3632 			return;
3633 		    }
3634 		}
3635 	    }
3636 	    else
3637 		item = NULL;
3638 	    list_extend(l1, l2, item);
3639 
3640 	    copy_tv(&argvars[0], rettv);
3641 	}
3642     }
3643     else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3644     {
3645 	dict_T	*d1, *d2;
3646 	char_u	*action;
3647 	int	i;
3648 
3649 	d1 = argvars[0].vval.v_dict;
3650 	d2 = argvars[1].vval.v_dict;
3651 	if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3652 		&& d2 != NULL)
3653 	{
3654 	    /* Check the third argument. */
3655 	    if (argvars[2].v_type != VAR_UNKNOWN)
3656 	    {
3657 		static char *(av[]) = {"keep", "force", "error"};
3658 
3659 		action = tv_get_string_chk(&argvars[2]);
3660 		if (action == NULL)
3661 		    return;		/* type error; errmsg already given */
3662 		for (i = 0; i < 3; ++i)
3663 		    if (STRCMP(action, av[i]) == 0)
3664 			break;
3665 		if (i == 3)
3666 		{
3667 		    semsg(_(e_invarg2), action);
3668 		    return;
3669 		}
3670 	    }
3671 	    else
3672 		action = (char_u *)"force";
3673 
3674 	    dict_extend(d1, d2, action);
3675 
3676 	    copy_tv(&argvars[0], rettv);
3677 	}
3678     }
3679     else
3680 	semsg(_(e_listdictarg), "extend()");
3681 }
3682 
3683 /*
3684  * "feedkeys()" function
3685  */
3686     static void
3687 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3688 {
3689     int		remap = TRUE;
3690     int		insert = FALSE;
3691     char_u	*keys, *flags;
3692     char_u	nbuf[NUMBUFLEN];
3693     int		typed = FALSE;
3694     int		execute = FALSE;
3695     int		dangerous = FALSE;
3696     int		lowlevel = FALSE;
3697     char_u	*keys_esc;
3698 
3699     /* This is not allowed in the sandbox.  If the commands would still be
3700      * executed in the sandbox it would be OK, but it probably happens later,
3701      * when "sandbox" is no longer set. */
3702     if (check_secure())
3703 	return;
3704 
3705     keys = tv_get_string(&argvars[0]);
3706 
3707     if (argvars[1].v_type != VAR_UNKNOWN)
3708     {
3709 	flags = tv_get_string_buf(&argvars[1], nbuf);
3710 	for ( ; *flags != NUL; ++flags)
3711 	{
3712 	    switch (*flags)
3713 	    {
3714 		case 'n': remap = FALSE; break;
3715 		case 'm': remap = TRUE; break;
3716 		case 't': typed = TRUE; break;
3717 		case 'i': insert = TRUE; break;
3718 		case 'x': execute = TRUE; break;
3719 		case '!': dangerous = TRUE; break;
3720 		case 'L': lowlevel = TRUE; break;
3721 	    }
3722 	}
3723     }
3724 
3725     if (*keys != NUL || execute)
3726     {
3727 	/* Need to escape K_SPECIAL and CSI before putting the string in the
3728 	 * typeahead buffer. */
3729 	keys_esc = vim_strsave_escape_csi(keys);
3730 	if (keys_esc != NULL)
3731 	{
3732 	    if (lowlevel)
3733 	    {
3734 #ifdef USE_INPUT_BUF
3735 		add_to_input_buf(keys, (int)STRLEN(keys));
3736 #else
3737 		emsg(_("E980: lowlevel input not supported"));
3738 #endif
3739 	    }
3740 	    else
3741 	    {
3742 		ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3743 				  insert ? 0 : typebuf.tb_len, !typed, FALSE);
3744 		if (vgetc_busy
3745 #ifdef FEAT_TIMERS
3746 			|| timer_busy
3747 #endif
3748 			)
3749 		    typebuf_was_filled = TRUE;
3750 	    }
3751 	    vim_free(keys_esc);
3752 
3753 	    if (execute)
3754 	    {
3755 		int save_msg_scroll = msg_scroll;
3756 
3757 		/* Avoid a 1 second delay when the keys start Insert mode. */
3758 		msg_scroll = FALSE;
3759 
3760 		if (!dangerous)
3761 		    ++ex_normal_busy;
3762 		exec_normal(TRUE, FALSE, TRUE);
3763 		if (!dangerous)
3764 		    --ex_normal_busy;
3765 
3766 		msg_scroll |= save_msg_scroll;
3767 	    }
3768 	}
3769     }
3770 }
3771 
3772 /*
3773  * "filereadable()" function
3774  */
3775     static void
3776 f_filereadable(typval_T *argvars, typval_T *rettv)
3777 {
3778     int		fd;
3779     char_u	*p;
3780     int		n;
3781 
3782 #ifndef O_NONBLOCK
3783 # define O_NONBLOCK 0
3784 #endif
3785     p = tv_get_string(&argvars[0]);
3786     if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3787 					      O_RDONLY | O_NONBLOCK, 0)) >= 0)
3788     {
3789 	n = TRUE;
3790 	close(fd);
3791     }
3792     else
3793 	n = FALSE;
3794 
3795     rettv->vval.v_number = n;
3796 }
3797 
3798 /*
3799  * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3800  * rights to write into.
3801  */
3802     static void
3803 f_filewritable(typval_T *argvars, typval_T *rettv)
3804 {
3805     rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
3806 }
3807 
3808     static void
3809 findfilendir(
3810     typval_T	*argvars UNUSED,
3811     typval_T	*rettv,
3812     int		find_what UNUSED)
3813 {
3814 #ifdef FEAT_SEARCHPATH
3815     char_u	*fname;
3816     char_u	*fresult = NULL;
3817     char_u	*path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3818     char_u	*p;
3819     char_u	pathbuf[NUMBUFLEN];
3820     int		count = 1;
3821     int		first = TRUE;
3822     int		error = FALSE;
3823 #endif
3824 
3825     rettv->vval.v_string = NULL;
3826     rettv->v_type = VAR_STRING;
3827 
3828 #ifdef FEAT_SEARCHPATH
3829     fname = tv_get_string(&argvars[0]);
3830 
3831     if (argvars[1].v_type != VAR_UNKNOWN)
3832     {
3833 	p = tv_get_string_buf_chk(&argvars[1], pathbuf);
3834 	if (p == NULL)
3835 	    error = TRUE;
3836 	else
3837 	{
3838 	    if (*p != NUL)
3839 		path = p;
3840 
3841 	    if (argvars[2].v_type != VAR_UNKNOWN)
3842 		count = (int)tv_get_number_chk(&argvars[2], &error);
3843 	}
3844     }
3845 
3846     if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3847 	error = TRUE;
3848 
3849     if (*fname != NUL && !error)
3850     {
3851 	do
3852 	{
3853 	    if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3854 		vim_free(fresult);
3855 	    fresult = find_file_in_path_option(first ? fname : NULL,
3856 					       first ? (int)STRLEN(fname) : 0,
3857 					0, first, path,
3858 					find_what,
3859 					curbuf->b_ffname,
3860 					find_what == FINDFILE_DIR
3861 					    ? (char_u *)"" : curbuf->b_p_sua);
3862 	    first = FALSE;
3863 
3864 	    if (fresult != NULL && rettv->v_type == VAR_LIST)
3865 		list_append_string(rettv->vval.v_list, fresult, -1);
3866 
3867 	} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3868     }
3869 
3870     if (rettv->v_type == VAR_STRING)
3871 	rettv->vval.v_string = fresult;
3872 #endif
3873 }
3874 
3875 /*
3876  * "filter()" function
3877  */
3878     static void
3879 f_filter(typval_T *argvars, typval_T *rettv)
3880 {
3881     filter_map(argvars, rettv, FALSE);
3882 }
3883 
3884 /*
3885  * "finddir({fname}[, {path}[, {count}]])" function
3886  */
3887     static void
3888 f_finddir(typval_T *argvars, typval_T *rettv)
3889 {
3890     findfilendir(argvars, rettv, FINDFILE_DIR);
3891 }
3892 
3893 /*
3894  * "findfile({fname}[, {path}[, {count}]])" function
3895  */
3896     static void
3897 f_findfile(typval_T *argvars, typval_T *rettv)
3898 {
3899     findfilendir(argvars, rettv, FINDFILE_FILE);
3900 }
3901 
3902 #ifdef FEAT_FLOAT
3903 /*
3904  * "float2nr({float})" function
3905  */
3906     static void
3907 f_float2nr(typval_T *argvars, typval_T *rettv)
3908 {
3909     float_T	f = 0.0;
3910 
3911     if (get_float_arg(argvars, &f) == OK)
3912     {
3913 	if (f <= -VARNUM_MAX + DBL_EPSILON)
3914 	    rettv->vval.v_number = -VARNUM_MAX;
3915 	else if (f >= VARNUM_MAX - DBL_EPSILON)
3916 	    rettv->vval.v_number = VARNUM_MAX;
3917 	else
3918 	    rettv->vval.v_number = (varnumber_T)f;
3919     }
3920 }
3921 
3922 /*
3923  * "floor({float})" function
3924  */
3925     static void
3926 f_floor(typval_T *argvars, typval_T *rettv)
3927 {
3928     float_T	f = 0.0;
3929 
3930     rettv->v_type = VAR_FLOAT;
3931     if (get_float_arg(argvars, &f) == OK)
3932 	rettv->vval.v_float = floor(f);
3933     else
3934 	rettv->vval.v_float = 0.0;
3935 }
3936 
3937 /*
3938  * "fmod()" function
3939  */
3940     static void
3941 f_fmod(typval_T *argvars, typval_T *rettv)
3942 {
3943     float_T	fx = 0.0, fy = 0.0;
3944 
3945     rettv->v_type = VAR_FLOAT;
3946     if (get_float_arg(argvars, &fx) == OK
3947 				     && get_float_arg(&argvars[1], &fy) == OK)
3948 	rettv->vval.v_float = fmod(fx, fy);
3949     else
3950 	rettv->vval.v_float = 0.0;
3951 }
3952 #endif
3953 
3954 /*
3955  * "fnameescape({string})" function
3956  */
3957     static void
3958 f_fnameescape(typval_T *argvars, typval_T *rettv)
3959 {
3960     rettv->vval.v_string = vim_strsave_fnameescape(
3961 					   tv_get_string(&argvars[0]), FALSE);
3962     rettv->v_type = VAR_STRING;
3963 }
3964 
3965 /*
3966  * "fnamemodify({fname}, {mods})" function
3967  */
3968     static void
3969 f_fnamemodify(typval_T *argvars, typval_T *rettv)
3970 {
3971     char_u	*fname;
3972     char_u	*mods;
3973     int		usedlen = 0;
3974     int		len;
3975     char_u	*fbuf = NULL;
3976     char_u	buf[NUMBUFLEN];
3977 
3978     fname = tv_get_string_chk(&argvars[0]);
3979     mods = tv_get_string_buf_chk(&argvars[1], buf);
3980     if (fname == NULL || mods == NULL)
3981 	fname = NULL;
3982     else
3983     {
3984 	len = (int)STRLEN(fname);
3985 	(void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
3986     }
3987 
3988     rettv->v_type = VAR_STRING;
3989     if (fname == NULL)
3990 	rettv->vval.v_string = NULL;
3991     else
3992 	rettv->vval.v_string = vim_strnsave(fname, len);
3993     vim_free(fbuf);
3994 }
3995 
3996 /*
3997  * "foldclosed()" function
3998  */
3999     static void
4000 foldclosed_both(
4001     typval_T	*argvars UNUSED,
4002     typval_T	*rettv,
4003     int		end UNUSED)
4004 {
4005 #ifdef FEAT_FOLDING
4006     linenr_T	lnum;
4007     linenr_T	first, last;
4008 
4009     lnum = tv_get_lnum(argvars);
4010     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4011     {
4012 	if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4013 	{
4014 	    if (end)
4015 		rettv->vval.v_number = (varnumber_T)last;
4016 	    else
4017 		rettv->vval.v_number = (varnumber_T)first;
4018 	    return;
4019 	}
4020     }
4021 #endif
4022     rettv->vval.v_number = -1;
4023 }
4024 
4025 /*
4026  * "foldclosed()" function
4027  */
4028     static void
4029 f_foldclosed(typval_T *argvars, typval_T *rettv)
4030 {
4031     foldclosed_both(argvars, rettv, FALSE);
4032 }
4033 
4034 /*
4035  * "foldclosedend()" function
4036  */
4037     static void
4038 f_foldclosedend(typval_T *argvars, typval_T *rettv)
4039 {
4040     foldclosed_both(argvars, rettv, TRUE);
4041 }
4042 
4043 /*
4044  * "foldlevel()" function
4045  */
4046     static void
4047 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4048 {
4049 #ifdef FEAT_FOLDING
4050     linenr_T	lnum;
4051 
4052     lnum = tv_get_lnum(argvars);
4053     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4054 	rettv->vval.v_number = foldLevel(lnum);
4055 #endif
4056 }
4057 
4058 /*
4059  * "foldtext()" function
4060  */
4061     static void
4062 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4063 {
4064 #ifdef FEAT_FOLDING
4065     linenr_T	foldstart;
4066     linenr_T	foldend;
4067     char_u	*dashes;
4068     linenr_T	lnum;
4069     char_u	*s;
4070     char_u	*r;
4071     int		len;
4072     char	*txt;
4073     long	count;
4074 #endif
4075 
4076     rettv->v_type = VAR_STRING;
4077     rettv->vval.v_string = NULL;
4078 #ifdef FEAT_FOLDING
4079     foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4080     foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4081     dashes = get_vim_var_str(VV_FOLDDASHES);
4082     if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4083 	    && dashes != NULL)
4084     {
4085 	/* Find first non-empty line in the fold. */
4086 	for (lnum = foldstart; lnum < foldend; ++lnum)
4087 	    if (!linewhite(lnum))
4088 		break;
4089 
4090 	/* Find interesting text in this line. */
4091 	s = skipwhite(ml_get(lnum));
4092 	/* skip C comment-start */
4093 	if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4094 	{
4095 	    s = skipwhite(s + 2);
4096 	    if (*skipwhite(s) == NUL
4097 			    && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4098 	    {
4099 		s = skipwhite(ml_get(lnum + 1));
4100 		if (*s == '*')
4101 		    s = skipwhite(s + 1);
4102 	    }
4103 	}
4104 	count = (long)(foldend - foldstart + 1);
4105 	txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
4106 	r = alloc((unsigned)(STRLEN(txt)
4107 		    + STRLEN(dashes)	    /* for %s */
4108 		    + 20		    /* for %3ld */
4109 		    + STRLEN(s)));	    /* concatenated */
4110 	if (r != NULL)
4111 	{
4112 	    sprintf((char *)r, txt, dashes, count);
4113 	    len = (int)STRLEN(r);
4114 	    STRCAT(r, s);
4115 	    /* remove 'foldmarker' and 'commentstring' */
4116 	    foldtext_cleanup(r + len);
4117 	    rettv->vval.v_string = r;
4118 	}
4119     }
4120 #endif
4121 }
4122 
4123 /*
4124  * "foldtextresult(lnum)" function
4125  */
4126     static void
4127 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4128 {
4129 #ifdef FEAT_FOLDING
4130     linenr_T	lnum;
4131     char_u	*text;
4132     char_u	buf[FOLD_TEXT_LEN];
4133     foldinfo_T  foldinfo;
4134     int		fold_count;
4135     static int	entered = FALSE;
4136 #endif
4137 
4138     rettv->v_type = VAR_STRING;
4139     rettv->vval.v_string = NULL;
4140 #ifdef FEAT_FOLDING
4141     if (entered)
4142 	return; /* reject recursive use */
4143     entered = TRUE;
4144 
4145     lnum = tv_get_lnum(argvars);
4146     /* treat illegal types and illegal string values for {lnum} the same */
4147     if (lnum < 0)
4148 	lnum = 0;
4149     fold_count = foldedCount(curwin, lnum, &foldinfo);
4150     if (fold_count > 0)
4151     {
4152 	text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4153 							       &foldinfo, buf);
4154 	if (text == buf)
4155 	    text = vim_strsave(text);
4156 	rettv->vval.v_string = text;
4157     }
4158 
4159     entered = FALSE;
4160 #endif
4161 }
4162 
4163 /*
4164  * "foreground()" function
4165  */
4166     static void
4167 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4168 {
4169 #ifdef FEAT_GUI
4170     if (gui.in_use)
4171 	gui_mch_set_foreground();
4172 #else
4173 # ifdef MSWIN
4174     win32_set_foreground();
4175 # endif
4176 #endif
4177 }
4178 
4179     static void
4180 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
4181 {
4182     char_u	*s;
4183     char_u	*name;
4184     int		use_string = FALSE;
4185     partial_T   *arg_pt = NULL;
4186     char_u	*trans_name = NULL;
4187 
4188     if (argvars[0].v_type == VAR_FUNC)
4189     {
4190 	/* function(MyFunc, [arg], dict) */
4191 	s = argvars[0].vval.v_string;
4192     }
4193     else if (argvars[0].v_type == VAR_PARTIAL
4194 					 && argvars[0].vval.v_partial != NULL)
4195     {
4196 	/* function(dict.MyFunc, [arg]) */
4197 	arg_pt = argvars[0].vval.v_partial;
4198 	s = partial_name(arg_pt);
4199     }
4200     else
4201     {
4202 	/* function('MyFunc', [arg], dict) */
4203 	s = tv_get_string(&argvars[0]);
4204 	use_string = TRUE;
4205     }
4206 
4207     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
4208     {
4209 	name = s;
4210 	trans_name = trans_function_name(&name, FALSE,
4211 	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4212 	if (*name != NUL)
4213 	    s = NULL;
4214     }
4215 
4216     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4217 					 || (is_funcref && trans_name == NULL))
4218 	semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
4219     /* Don't check an autoload name for existence here. */
4220     else if (trans_name != NULL && (is_funcref
4221 				? find_func(trans_name) == NULL
4222 				: !translated_function_exists(trans_name)))
4223 	semsg(_("E700: Unknown function: %s"), s);
4224     else
4225     {
4226 	int	dict_idx = 0;
4227 	int	arg_idx = 0;
4228 	list_T	*list = NULL;
4229 
4230 	if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4231 	{
4232 	    char	sid_buf[25];
4233 	    int		off = *s == 's' ? 2 : 5;
4234 
4235 	    /* Expand s: and <SID> into <SNR>nr_, so that the function can
4236 	     * also be called from another script. Using trans_function_name()
4237 	     * would also work, but some plugins depend on the name being
4238 	     * printable text. */
4239 	    sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
4240 	    name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4241 	    if (name != NULL)
4242 	    {
4243 		STRCPY(name, sid_buf);
4244 		STRCAT(name, s + off);
4245 	    }
4246 	}
4247 	else
4248 	    name = vim_strsave(s);
4249 
4250 	if (argvars[1].v_type != VAR_UNKNOWN)
4251 	{
4252 	    if (argvars[2].v_type != VAR_UNKNOWN)
4253 	    {
4254 		/* function(name, [args], dict) */
4255 		arg_idx = 1;
4256 		dict_idx = 2;
4257 	    }
4258 	    else if (argvars[1].v_type == VAR_DICT)
4259 		/* function(name, dict) */
4260 		dict_idx = 1;
4261 	    else
4262 		/* function(name, [args]) */
4263 		arg_idx = 1;
4264 	    if (dict_idx > 0)
4265 	    {
4266 		if (argvars[dict_idx].v_type != VAR_DICT)
4267 		{
4268 		    emsg(_("E922: expected a dict"));
4269 		    vim_free(name);
4270 		    goto theend;
4271 		}
4272 		if (argvars[dict_idx].vval.v_dict == NULL)
4273 		    dict_idx = 0;
4274 	    }
4275 	    if (arg_idx > 0)
4276 	    {
4277 		if (argvars[arg_idx].v_type != VAR_LIST)
4278 		{
4279 		    emsg(_("E923: Second argument of function() must be a list or a dict"));
4280 		    vim_free(name);
4281 		    goto theend;
4282 		}
4283 		list = argvars[arg_idx].vval.v_list;
4284 		if (list == NULL || list->lv_len == 0)
4285 		    arg_idx = 0;
4286 	    }
4287 	}
4288 	if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
4289 	{
4290 	    partial_T	*pt = (partial_T *)alloc_clear(sizeof(partial_T));
4291 
4292 	    /* result is a VAR_PARTIAL */
4293 	    if (pt == NULL)
4294 		vim_free(name);
4295 	    else
4296 	    {
4297 		if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4298 		{
4299 		    listitem_T	*li;
4300 		    int		i = 0;
4301 		    int		arg_len = 0;
4302 		    int		lv_len = 0;
4303 
4304 		    if (arg_pt != NULL)
4305 			arg_len = arg_pt->pt_argc;
4306 		    if (list != NULL)
4307 			lv_len = list->lv_len;
4308 		    pt->pt_argc = arg_len + lv_len;
4309 		    pt->pt_argv = (typval_T *)alloc(
4310 					      sizeof(typval_T) * pt->pt_argc);
4311 		    if (pt->pt_argv == NULL)
4312 		    {
4313 			vim_free(pt);
4314 			vim_free(name);
4315 			goto theend;
4316 		    }
4317 		    for (i = 0; i < arg_len; i++)
4318 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4319 		    if (lv_len > 0)
4320 			for (li = list->lv_first; li != NULL;
4321 							 li = li->li_next)
4322 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
4323 		}
4324 
4325 		/* For "function(dict.func, [], dict)" and "func" is a partial
4326 		 * use "dict".  That is backwards compatible. */
4327 		if (dict_idx > 0)
4328 		{
4329 		    /* The dict is bound explicitly, pt_auto is FALSE. */
4330 		    pt->pt_dict = argvars[dict_idx].vval.v_dict;
4331 		    ++pt->pt_dict->dv_refcount;
4332 		}
4333 		else if (arg_pt != NULL)
4334 		{
4335 		    /* If the dict was bound automatically the result is also
4336 		     * bound automatically. */
4337 		    pt->pt_dict = arg_pt->pt_dict;
4338 		    pt->pt_auto = arg_pt->pt_auto;
4339 		    if (pt->pt_dict != NULL)
4340 			++pt->pt_dict->dv_refcount;
4341 		}
4342 
4343 		pt->pt_refcount = 1;
4344 		if (arg_pt != NULL && arg_pt->pt_func != NULL)
4345 		{
4346 		    pt->pt_func = arg_pt->pt_func;
4347 		    func_ptr_ref(pt->pt_func);
4348 		    vim_free(name);
4349 		}
4350 		else if (is_funcref)
4351 		{
4352 		    pt->pt_func = find_func(trans_name);
4353 		    func_ptr_ref(pt->pt_func);
4354 		    vim_free(name);
4355 		}
4356 		else
4357 		{
4358 		    pt->pt_name = name;
4359 		    func_ref(name);
4360 		}
4361 	    }
4362 	    rettv->v_type = VAR_PARTIAL;
4363 	    rettv->vval.v_partial = pt;
4364 	}
4365 	else
4366 	{
4367 	    /* result is a VAR_FUNC */
4368 	    rettv->v_type = VAR_FUNC;
4369 	    rettv->vval.v_string = name;
4370 	    func_ref(name);
4371 	}
4372     }
4373 theend:
4374     vim_free(trans_name);
4375 }
4376 
4377 /*
4378  * "funcref()" function
4379  */
4380     static void
4381 f_funcref(typval_T *argvars, typval_T *rettv)
4382 {
4383     common_function(argvars, rettv, TRUE);
4384 }
4385 
4386 /*
4387  * "function()" function
4388  */
4389     static void
4390 f_function(typval_T *argvars, typval_T *rettv)
4391 {
4392     common_function(argvars, rettv, FALSE);
4393 }
4394 
4395 /*
4396  * "garbagecollect()" function
4397  */
4398     static void
4399 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4400 {
4401     /* This is postponed until we are back at the toplevel, because we may be
4402      * using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]". */
4403     want_garbage_collect = TRUE;
4404 
4405     if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
4406 	garbage_collect_at_exit = TRUE;
4407 }
4408 
4409 /*
4410  * "get()" function
4411  */
4412     static void
4413 f_get(typval_T *argvars, typval_T *rettv)
4414 {
4415     listitem_T	*li;
4416     list_T	*l;
4417     dictitem_T	*di;
4418     dict_T	*d;
4419     typval_T	*tv = NULL;
4420 
4421     if (argvars[0].v_type == VAR_BLOB)
4422     {
4423 	int error = FALSE;
4424 	int idx = tv_get_number_chk(&argvars[1], &error);
4425 
4426 	if (!error)
4427 	{
4428 	    rettv->v_type = VAR_NUMBER;
4429 	    if (idx < 0)
4430 		idx = blob_len(argvars[0].vval.v_blob) + idx;
4431 	    if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4432 		rettv->vval.v_number = -1;
4433 	    else
4434 	    {
4435 		rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
4436 		tv = rettv;
4437 	    }
4438 	}
4439     }
4440     else if (argvars[0].v_type == VAR_LIST)
4441     {
4442 	if ((l = argvars[0].vval.v_list) != NULL)
4443 	{
4444 	    int		error = FALSE;
4445 
4446 	    li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
4447 	    if (!error && li != NULL)
4448 		tv = &li->li_tv;
4449 	}
4450     }
4451     else if (argvars[0].v_type == VAR_DICT)
4452     {
4453 	if ((d = argvars[0].vval.v_dict) != NULL)
4454 	{
4455 	    di = dict_find(d, tv_get_string(&argvars[1]), -1);
4456 	    if (di != NULL)
4457 		tv = &di->di_tv;
4458 	}
4459     }
4460     else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4461     {
4462 	partial_T	*pt;
4463 	partial_T	fref_pt;
4464 
4465 	if (argvars[0].v_type == VAR_PARTIAL)
4466 	    pt = argvars[0].vval.v_partial;
4467 	else
4468 	{
4469 	    vim_memset(&fref_pt, 0, sizeof(fref_pt));
4470 	    fref_pt.pt_name = argvars[0].vval.v_string;
4471 	    pt = &fref_pt;
4472 	}
4473 
4474 	if (pt != NULL)
4475 	{
4476 	    char_u *what = tv_get_string(&argvars[1]);
4477 	    char_u *n;
4478 
4479 	    if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4480 	    {
4481 		rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
4482 		n = partial_name(pt);
4483 		if (n == NULL)
4484 		    rettv->vval.v_string = NULL;
4485 		else
4486 		{
4487 		    rettv->vval.v_string = vim_strsave(n);
4488 		    if (rettv->v_type == VAR_FUNC)
4489 			func_ref(rettv->vval.v_string);
4490 		}
4491 	    }
4492 	    else if (STRCMP(what, "dict") == 0)
4493 		rettv_dict_set(rettv, pt->pt_dict);
4494 	    else if (STRCMP(what, "args") == 0)
4495 	    {
4496 		rettv->v_type = VAR_LIST;
4497 		if (rettv_list_alloc(rettv) == OK)
4498 		{
4499 		    int i;
4500 
4501 		    for (i = 0; i < pt->pt_argc; ++i)
4502 			list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4503 		}
4504 	    }
4505 	    else
4506 		semsg(_(e_invarg2), what);
4507 	    return;
4508 	}
4509     }
4510     else
4511 	semsg(_(e_listdictblobarg), "get()");
4512 
4513     if (tv == NULL)
4514     {
4515 	if (argvars[2].v_type != VAR_UNKNOWN)
4516 	    copy_tv(&argvars[2], rettv);
4517     }
4518     else
4519 	copy_tv(tv, rettv);
4520 }
4521 
4522 /*
4523  * Returns buffer options, variables and other attributes in a dictionary.
4524  */
4525     static dict_T *
4526 get_buffer_info(buf_T *buf)
4527 {
4528     dict_T	*dict;
4529     tabpage_T	*tp;
4530     win_T	*wp;
4531     list_T	*windows;
4532 
4533     dict = dict_alloc();
4534     if (dict == NULL)
4535 	return NULL;
4536 
4537     dict_add_number(dict, "bufnr", buf->b_fnum);
4538     dict_add_string(dict, "name", buf->b_ffname);
4539     dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4540 						     : buflist_findlnum(buf));
4541     dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4542     dict_add_number(dict, "listed", buf->b_p_bl);
4543     dict_add_number(dict, "changed", bufIsChanged(buf));
4544     dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4545     dict_add_number(dict, "hidden",
4546 			    buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
4547 
4548     /* Get a reference to buffer variables */
4549     dict_add_dict(dict, "variables", buf->b_vars);
4550 
4551     /* List of windows displaying this buffer */
4552     windows = list_alloc();
4553     if (windows != NULL)
4554     {
4555 	FOR_ALL_TAB_WINDOWS(tp, wp)
4556 	    if (wp->w_buffer == buf)
4557 		list_append_number(windows, (varnumber_T)wp->w_id);
4558 	dict_add_list(dict, "windows", windows);
4559     }
4560 
4561 #ifdef FEAT_SIGNS
4562     if (buf->b_signlist != NULL)
4563     {
4564 	/* List of signs placed in this buffer */
4565 	list_T	*signs = list_alloc();
4566 	if (signs != NULL)
4567 	{
4568 	    get_buffer_signs(buf, signs);
4569 	    dict_add_list(dict, "signs", signs);
4570 	}
4571     }
4572 #endif
4573 
4574     return dict;
4575 }
4576 
4577 /*
4578  * "getbufinfo()" function
4579  */
4580     static void
4581 f_getbufinfo(typval_T *argvars, typval_T *rettv)
4582 {
4583     buf_T	*buf = NULL;
4584     buf_T	*argbuf = NULL;
4585     dict_T	*d;
4586     int		filtered = FALSE;
4587     int		sel_buflisted = FALSE;
4588     int		sel_bufloaded = FALSE;
4589     int		sel_bufmodified = FALSE;
4590 
4591     if (rettv_list_alloc(rettv) != OK)
4592 	return;
4593 
4594     /* List of all the buffers or selected buffers */
4595     if (argvars[0].v_type == VAR_DICT)
4596     {
4597 	dict_T	*sel_d = argvars[0].vval.v_dict;
4598 
4599 	if (sel_d != NULL)
4600 	{
4601 	    dictitem_T	*di;
4602 
4603 	    filtered = TRUE;
4604 
4605 	    di = dict_find(sel_d, (char_u *)"buflisted", -1);
4606 	    if (di != NULL && tv_get_number(&di->di_tv))
4607 		sel_buflisted = TRUE;
4608 
4609 	    di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4610 	    if (di != NULL && tv_get_number(&di->di_tv))
4611 		sel_bufloaded = TRUE;
4612 
4613 	    di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4614 	    if (di != NULL && tv_get_number(&di->di_tv))
4615 		sel_bufmodified = TRUE;
4616 	}
4617     }
4618     else if (argvars[0].v_type != VAR_UNKNOWN)
4619     {
4620 	/* Information about one buffer.  Argument specifies the buffer */
4621 	(void)tv_get_number(&argvars[0]);   /* issue errmsg if type error */
4622 	++emsg_off;
4623 	argbuf = tv_get_buf(&argvars[0], FALSE);
4624 	--emsg_off;
4625 	if (argbuf == NULL)
4626 	    return;
4627     }
4628 
4629     /* Return information about all the buffers or a specified buffer */
4630     FOR_ALL_BUFFERS(buf)
4631     {
4632 	if (argbuf != NULL && argbuf != buf)
4633 	    continue;
4634 	if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
4635 			|| (sel_buflisted && !buf->b_p_bl)
4636 			|| (sel_bufmodified && !buf->b_changed)))
4637 	    continue;
4638 
4639 	d = get_buffer_info(buf);
4640 	if (d != NULL)
4641 	    list_append_dict(rettv->vval.v_list, d);
4642 	if (argbuf != NULL)
4643 	    return;
4644     }
4645 }
4646 
4647 /*
4648  * Get line or list of lines from buffer "buf" into "rettv".
4649  * Return a range (from start to end) of lines in rettv from the specified
4650  * buffer.
4651  * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4652  */
4653     static void
4654 get_buffer_lines(
4655     buf_T	*buf,
4656     linenr_T	start,
4657     linenr_T	end,
4658     int		retlist,
4659     typval_T	*rettv)
4660 {
4661     char_u	*p;
4662 
4663     rettv->v_type = VAR_STRING;
4664     rettv->vval.v_string = NULL;
4665     if (retlist && rettv_list_alloc(rettv) == FAIL)
4666 	return;
4667 
4668     if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4669 	return;
4670 
4671     if (!retlist)
4672     {
4673 	if (start >= 1 && start <= buf->b_ml.ml_line_count)
4674 	    p = ml_get_buf(buf, start, FALSE);
4675 	else
4676 	    p = (char_u *)"";
4677 	rettv->vval.v_string = vim_strsave(p);
4678     }
4679     else
4680     {
4681 	if (end < start)
4682 	    return;
4683 
4684 	if (start < 1)
4685 	    start = 1;
4686 	if (end > buf->b_ml.ml_line_count)
4687 	    end = buf->b_ml.ml_line_count;
4688 	while (start <= end)
4689 	    if (list_append_string(rettv->vval.v_list,
4690 				 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4691 		break;
4692     }
4693 }
4694 
4695 /*
4696  * "getbufline()" function
4697  */
4698     static void
4699 f_getbufline(typval_T *argvars, typval_T *rettv)
4700 {
4701     linenr_T	lnum;
4702     linenr_T	end;
4703     buf_T	*buf;
4704 
4705     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4706     ++emsg_off;
4707     buf = tv_get_buf(&argvars[0], FALSE);
4708     --emsg_off;
4709 
4710     lnum = tv_get_lnum_buf(&argvars[1], buf);
4711     if (argvars[2].v_type == VAR_UNKNOWN)
4712 	end = lnum;
4713     else
4714 	end = tv_get_lnum_buf(&argvars[2], buf);
4715 
4716     get_buffer_lines(buf, lnum, end, TRUE, rettv);
4717 }
4718 
4719 /*
4720  * "getbufvar()" function
4721  */
4722     static void
4723 f_getbufvar(typval_T *argvars, typval_T *rettv)
4724 {
4725     buf_T	*buf;
4726     buf_T	*save_curbuf;
4727     char_u	*varname;
4728     dictitem_T	*v;
4729     int		done = FALSE;
4730 
4731     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4732     varname = tv_get_string_chk(&argvars[1]);
4733     ++emsg_off;
4734     buf = tv_get_buf(&argvars[0], FALSE);
4735 
4736     rettv->v_type = VAR_STRING;
4737     rettv->vval.v_string = NULL;
4738 
4739     if (buf != NULL && varname != NULL)
4740     {
4741 	/* set curbuf to be our buf, temporarily */
4742 	save_curbuf = curbuf;
4743 	curbuf = buf;
4744 
4745 	if (*varname == '&')
4746 	{
4747 	    if (varname[1] == NUL)
4748 	    {
4749 		/* get all buffer-local options in a dict */
4750 		dict_T	*opts = get_winbuf_options(TRUE);
4751 
4752 		if (opts != NULL)
4753 		{
4754 		    rettv_dict_set(rettv, opts);
4755 		    done = TRUE;
4756 		}
4757 	    }
4758 	    else if (get_option_tv(&varname, rettv, TRUE) == OK)
4759 		/* buffer-local-option */
4760 		done = TRUE;
4761 	}
4762 	else
4763 	{
4764 	    /* Look up the variable. */
4765 	    /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4766 	    v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4767 							 'b', varname, FALSE);
4768 	    if (v != NULL)
4769 	    {
4770 		copy_tv(&v->di_tv, rettv);
4771 		done = TRUE;
4772 	    }
4773 	}
4774 
4775 	/* restore previous notion of curbuf */
4776 	curbuf = save_curbuf;
4777     }
4778 
4779     if (!done && argvars[2].v_type != VAR_UNKNOWN)
4780 	/* use the default value */
4781 	copy_tv(&argvars[2], rettv);
4782 
4783     --emsg_off;
4784 }
4785 
4786 /*
4787  * "getchangelist()" function
4788  */
4789     static void
4790 f_getchangelist(typval_T *argvars, typval_T *rettv)
4791 {
4792 #ifdef FEAT_JUMPLIST
4793     buf_T	*buf;
4794     int		i;
4795     list_T	*l;
4796     dict_T	*d;
4797 #endif
4798 
4799     if (rettv_list_alloc(rettv) != OK)
4800 	return;
4801 
4802 #ifdef FEAT_JUMPLIST
4803     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4804     ++emsg_off;
4805     buf = tv_get_buf(&argvars[0], FALSE);
4806     --emsg_off;
4807     if (buf == NULL)
4808 	return;
4809 
4810     l = list_alloc();
4811     if (l == NULL)
4812 	return;
4813 
4814     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4815 	return;
4816     /*
4817      * The current window change list index tracks only the position in the
4818      * current buffer change list. For other buffers, use the change list
4819      * length as the current index.
4820      */
4821     list_append_number(rettv->vval.v_list,
4822 	    (varnumber_T)((buf == curwin->w_buffer)
4823 		? curwin->w_changelistidx : buf->b_changelistlen));
4824 
4825     for (i = 0; i < buf->b_changelistlen; ++i)
4826     {
4827 	if (buf->b_changelist[i].lnum == 0)
4828 	    continue;
4829 	if ((d = dict_alloc()) == NULL)
4830 	    return;
4831 	if (list_append_dict(l, d) == FAIL)
4832 	    return;
4833 	dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4834 	dict_add_number(d, "col", (long)buf->b_changelist[i].col);
4835 	dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
4836     }
4837 #endif
4838 }
4839 /*
4840  * "getchar()" function
4841  */
4842     static void
4843 f_getchar(typval_T *argvars, typval_T *rettv)
4844 {
4845     varnumber_T		n;
4846     int			error = FALSE;
4847     int			save_reg_executing = reg_executing;
4848 
4849 #ifdef MESSAGE_QUEUE
4850     // vpeekc() used to check for messages, but that caused problems, invoking
4851     // a callback where it was not expected.  Some plugins use getchar(1) in a
4852     // loop to await a message, therefore make sure we check for messages here.
4853     parse_queued_messages();
4854 #endif
4855 
4856     /* Position the cursor.  Needed after a message that ends in a space. */
4857     windgoto(msg_row, msg_col);
4858 
4859     ++no_mapping;
4860     ++allow_keys;
4861     for (;;)
4862     {
4863 	if (argvars[0].v_type == VAR_UNKNOWN)
4864 	    /* getchar(): blocking wait. */
4865 	    n = plain_vgetc();
4866 	else if (tv_get_number_chk(&argvars[0], &error) == 1)
4867 	    /* getchar(1): only check if char avail */
4868 	    n = vpeekc_any();
4869 	else if (error || vpeekc_any() == NUL)
4870 	    /* illegal argument or getchar(0) and no char avail: return zero */
4871 	    n = 0;
4872 	else
4873 	    /* getchar(0) and char avail: return char */
4874 	    n = plain_vgetc();
4875 
4876 	if (n == K_IGNORE)
4877 	    continue;
4878 	break;
4879     }
4880     --no_mapping;
4881     --allow_keys;
4882     reg_executing = save_reg_executing;
4883 
4884     set_vim_var_nr(VV_MOUSE_WIN, 0);
4885     set_vim_var_nr(VV_MOUSE_WINID, 0);
4886     set_vim_var_nr(VV_MOUSE_LNUM, 0);
4887     set_vim_var_nr(VV_MOUSE_COL, 0);
4888 
4889     rettv->vval.v_number = n;
4890     if (IS_SPECIAL(n) || mod_mask != 0)
4891     {
4892 	char_u		temp[10];   /* modifier: 3, mbyte-char: 6, NUL: 1 */
4893 	int		i = 0;
4894 
4895 	/* Turn a special key into three bytes, plus modifier. */
4896 	if (mod_mask != 0)
4897 	{
4898 	    temp[i++] = K_SPECIAL;
4899 	    temp[i++] = KS_MODIFIER;
4900 	    temp[i++] = mod_mask;
4901 	}
4902 	if (IS_SPECIAL(n))
4903 	{
4904 	    temp[i++] = K_SPECIAL;
4905 	    temp[i++] = K_SECOND(n);
4906 	    temp[i++] = K_THIRD(n);
4907 	}
4908 	else if (has_mbyte)
4909 	    i += (*mb_char2bytes)(n, temp + i);
4910 	else
4911 	    temp[i++] = n;
4912 	temp[i++] = NUL;
4913 	rettv->v_type = VAR_STRING;
4914 	rettv->vval.v_string = vim_strsave(temp);
4915 
4916 #ifdef FEAT_MOUSE
4917 	if (is_mouse_key(n))
4918 	{
4919 	    int		row = mouse_row;
4920 	    int		col = mouse_col;
4921 	    win_T	*win;
4922 	    linenr_T	lnum;
4923 	    win_T	*wp;
4924 	    int		winnr = 1;
4925 
4926 	    if (row >= 0 && col >= 0)
4927 	    {
4928 		/* Find the window at the mouse coordinates and compute the
4929 		 * text position. */
4930 		win = mouse_find_win(&row, &col);
4931 		if (win == NULL)
4932 		    return;
4933 		(void)mouse_comp_pos(win, &row, &col, &lnum);
4934 		for (wp = firstwin; wp != win; wp = wp->w_next)
4935 		    ++winnr;
4936 		set_vim_var_nr(VV_MOUSE_WIN, winnr);
4937 		set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4938 		set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4939 		set_vim_var_nr(VV_MOUSE_COL, col + 1);
4940 	    }
4941 	}
4942 #endif
4943     }
4944 }
4945 
4946 /*
4947  * "getcharmod()" function
4948  */
4949     static void
4950 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4951 {
4952     rettv->vval.v_number = mod_mask;
4953 }
4954 
4955 /*
4956  * "getcharsearch()" function
4957  */
4958     static void
4959 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4960 {
4961     if (rettv_dict_alloc(rettv) != FAIL)
4962     {
4963 	dict_T *dict = rettv->vval.v_dict;
4964 
4965 	dict_add_string(dict, "char", last_csearch());
4966 	dict_add_number(dict, "forward", last_csearch_forward());
4967 	dict_add_number(dict, "until", last_csearch_until());
4968     }
4969 }
4970 
4971 /*
4972  * "getcmdline()" function
4973  */
4974     static void
4975 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4976 {
4977     rettv->v_type = VAR_STRING;
4978     rettv->vval.v_string = get_cmdline_str();
4979 }
4980 
4981 /*
4982  * "getcmdpos()" function
4983  */
4984     static void
4985 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4986 {
4987     rettv->vval.v_number = get_cmdline_pos() + 1;
4988 }
4989 
4990 /*
4991  * "getcmdtype()" function
4992  */
4993     static void
4994 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4995 {
4996     rettv->v_type = VAR_STRING;
4997     rettv->vval.v_string = alloc(2);
4998     if (rettv->vval.v_string != NULL)
4999     {
5000 	rettv->vval.v_string[0] = get_cmdline_type();
5001 	rettv->vval.v_string[1] = NUL;
5002     }
5003 }
5004 
5005 /*
5006  * "getcmdwintype()" function
5007  */
5008     static void
5009 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5010 {
5011     rettv->v_type = VAR_STRING;
5012     rettv->vval.v_string = NULL;
5013 #ifdef FEAT_CMDWIN
5014     rettv->vval.v_string = alloc(2);
5015     if (rettv->vval.v_string != NULL)
5016     {
5017 	rettv->vval.v_string[0] = cmdwin_type;
5018 	rettv->vval.v_string[1] = NUL;
5019     }
5020 #endif
5021 }
5022 
5023 #if defined(FEAT_CMDL_COMPL)
5024 /*
5025  * "getcompletion()" function
5026  */
5027     static void
5028 f_getcompletion(typval_T *argvars, typval_T *rettv)
5029 {
5030     char_u	*pat;
5031     expand_T	xpc;
5032     int		filtered = FALSE;
5033     int		options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5034 					| WILD_NO_BEEP;
5035 
5036     if (argvars[2].v_type != VAR_UNKNOWN)
5037 	filtered = tv_get_number_chk(&argvars[2], NULL);
5038 
5039     if (p_wic)
5040 	options |= WILD_ICASE;
5041 
5042     /* For filtered results, 'wildignore' is used */
5043     if (!filtered)
5044 	options |= WILD_KEEP_ALL;
5045 
5046     ExpandInit(&xpc);
5047     xpc.xp_pattern = tv_get_string(&argvars[0]);
5048     xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5049     xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
5050     if (xpc.xp_context == EXPAND_NOTHING)
5051     {
5052 	if (argvars[1].v_type == VAR_STRING)
5053 	    semsg(_(e_invarg2), argvars[1].vval.v_string);
5054 	else
5055 	    emsg(_(e_invarg));
5056 	return;
5057     }
5058 
5059 # if defined(FEAT_MENU)
5060     if (xpc.xp_context == EXPAND_MENUS)
5061     {
5062 	set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5063 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5064     }
5065 # endif
5066 #ifdef FEAT_CSCOPE
5067     if (xpc.xp_context == EXPAND_CSCOPE)
5068     {
5069 	set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5070 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5071     }
5072 #endif
5073 #ifdef FEAT_SIGNS
5074     if (xpc.xp_context == EXPAND_SIGN)
5075     {
5076 	set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5077 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5078     }
5079 #endif
5080 
5081     pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5082     if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5083     {
5084 	int	i;
5085 
5086 	ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5087 
5088 	for (i = 0; i < xpc.xp_numfiles; i++)
5089 	    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5090     }
5091     vim_free(pat);
5092     ExpandCleanup(&xpc);
5093 }
5094 #endif
5095 
5096 /*
5097  * "getcwd()" function
5098  */
5099     static void
5100 f_getcwd(typval_T *argvars, typval_T *rettv)
5101 {
5102     win_T	*wp = NULL;
5103     char_u	*cwd;
5104     int		global = FALSE;
5105 
5106     rettv->v_type = VAR_STRING;
5107     rettv->vval.v_string = NULL;
5108 
5109     if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5110 	global = TRUE;
5111     else
5112 	wp = find_tabwin(&argvars[0], &argvars[1]);
5113 
5114     if (wp != NULL && wp->w_localdir != NULL)
5115 	rettv->vval.v_string = vim_strsave(wp->w_localdir);
5116     else if (wp != NULL || global)
5117     {
5118 	if (globaldir != NULL)
5119 	    rettv->vval.v_string = vim_strsave(globaldir);
5120 	else
5121 	{
5122 	    cwd = alloc(MAXPATHL);
5123 	    if (cwd != NULL)
5124 	    {
5125 		if (mch_dirname(cwd, MAXPATHL) != FAIL)
5126 		    rettv->vval.v_string = vim_strsave(cwd);
5127 		vim_free(cwd);
5128 	    }
5129 	}
5130     }
5131 #ifdef BACKSLASH_IN_FILENAME
5132     if (rettv->vval.v_string != NULL)
5133 	slash_adjust(rettv->vval.v_string);
5134 #endif
5135 }
5136 
5137 /*
5138  * "getfontname()" function
5139  */
5140     static void
5141 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5142 {
5143     rettv->v_type = VAR_STRING;
5144     rettv->vval.v_string = NULL;
5145 #ifdef FEAT_GUI
5146     if (gui.in_use)
5147     {
5148 	GuiFont font;
5149 	char_u	*name = NULL;
5150 
5151 	if (argvars[0].v_type == VAR_UNKNOWN)
5152 	{
5153 	    /* Get the "Normal" font.  Either the name saved by
5154 	     * hl_set_font_name() or from the font ID. */
5155 	    font = gui.norm_font;
5156 	    name = hl_get_font_name();
5157 	}
5158 	else
5159 	{
5160 	    name = tv_get_string(&argvars[0]);
5161 	    if (STRCMP(name, "*") == 0)	    /* don't use font dialog */
5162 		return;
5163 	    font = gui_mch_get_font(name, FALSE);
5164 	    if (font == NOFONT)
5165 		return;	    /* Invalid font name, return empty string. */
5166 	}
5167 	rettv->vval.v_string = gui_mch_get_fontname(font, name);
5168 	if (argvars[0].v_type != VAR_UNKNOWN)
5169 	    gui_mch_free_font(font);
5170     }
5171 #endif
5172 }
5173 
5174 /*
5175  * "getfperm({fname})" function
5176  */
5177     static void
5178 f_getfperm(typval_T *argvars, typval_T *rettv)
5179 {
5180     char_u	*fname;
5181     stat_T	st;
5182     char_u	*perm = NULL;
5183     char_u	flags[] = "rwx";
5184     int		i;
5185 
5186     fname = tv_get_string(&argvars[0]);
5187 
5188     rettv->v_type = VAR_STRING;
5189     if (mch_stat((char *)fname, &st) >= 0)
5190     {
5191 	perm = vim_strsave((char_u *)"---------");
5192 	if (perm != NULL)
5193 	{
5194 	    for (i = 0; i < 9; i++)
5195 	    {
5196 		if (st.st_mode & (1 << (8 - i)))
5197 		    perm[i] = flags[i % 3];
5198 	    }
5199 	}
5200     }
5201     rettv->vval.v_string = perm;
5202 }
5203 
5204 /*
5205  * "getfsize({fname})" function
5206  */
5207     static void
5208 f_getfsize(typval_T *argvars, typval_T *rettv)
5209 {
5210     char_u	*fname;
5211     stat_T	st;
5212 
5213     fname = tv_get_string(&argvars[0]);
5214 
5215     rettv->v_type = VAR_NUMBER;
5216 
5217     if (mch_stat((char *)fname, &st) >= 0)
5218     {
5219 	if (mch_isdir(fname))
5220 	    rettv->vval.v_number = 0;
5221 	else
5222 	{
5223 	    rettv->vval.v_number = (varnumber_T)st.st_size;
5224 
5225 	    /* non-perfect check for overflow */
5226 	    if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5227 		rettv->vval.v_number = -2;
5228 	}
5229     }
5230     else
5231 	  rettv->vval.v_number = -1;
5232 }
5233 
5234 /*
5235  * "getftime({fname})" function
5236  */
5237     static void
5238 f_getftime(typval_T *argvars, typval_T *rettv)
5239 {
5240     char_u	*fname;
5241     stat_T	st;
5242 
5243     fname = tv_get_string(&argvars[0]);
5244 
5245     if (mch_stat((char *)fname, &st) >= 0)
5246 	rettv->vval.v_number = (varnumber_T)st.st_mtime;
5247     else
5248 	rettv->vval.v_number = -1;
5249 }
5250 
5251 /*
5252  * "getftype({fname})" function
5253  */
5254     static void
5255 f_getftype(typval_T *argvars, typval_T *rettv)
5256 {
5257     char_u	*fname;
5258     stat_T	st;
5259     char_u	*type = NULL;
5260     char	*t;
5261 
5262     fname = tv_get_string(&argvars[0]);
5263 
5264     rettv->v_type = VAR_STRING;
5265     if (mch_lstat((char *)fname, &st) >= 0)
5266     {
5267 	if (S_ISREG(st.st_mode))
5268 	    t = "file";
5269 	else if (S_ISDIR(st.st_mode))
5270 	    t = "dir";
5271 	else if (S_ISLNK(st.st_mode))
5272 	    t = "link";
5273 	else if (S_ISBLK(st.st_mode))
5274 	    t = "bdev";
5275 	else if (S_ISCHR(st.st_mode))
5276 	    t = "cdev";
5277 	else if (S_ISFIFO(st.st_mode))
5278 	    t = "fifo";
5279 	else if (S_ISSOCK(st.st_mode))
5280 	    t = "socket";
5281 	else
5282 	    t = "other";
5283 	type = vim_strsave((char_u *)t);
5284     }
5285     rettv->vval.v_string = type;
5286 }
5287 
5288 /*
5289  * "getjumplist()" function
5290  */
5291     static void
5292 f_getjumplist(typval_T *argvars, typval_T *rettv)
5293 {
5294 #ifdef FEAT_JUMPLIST
5295     win_T	*wp;
5296     int		i;
5297     list_T	*l;
5298     dict_T	*d;
5299 #endif
5300 
5301     if (rettv_list_alloc(rettv) != OK)
5302 	return;
5303 
5304 #ifdef FEAT_JUMPLIST
5305     wp = find_tabwin(&argvars[0], &argvars[1]);
5306     if (wp == NULL)
5307 	return;
5308 
5309     cleanup_jumplist(wp, TRUE);
5310 
5311     l = list_alloc();
5312     if (l == NULL)
5313 	return;
5314 
5315     if (list_append_list(rettv->vval.v_list, l) == FAIL)
5316 	return;
5317     list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5318 
5319     for (i = 0; i < wp->w_jumplistlen; ++i)
5320     {
5321 	if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5322 	    continue;
5323 	if ((d = dict_alloc()) == NULL)
5324 	    return;
5325 	if (list_append_dict(l, d) == FAIL)
5326 	    return;
5327 	dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5328 	dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
5329 	dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
5330 	dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
5331 	if (wp->w_jumplist[i].fname != NULL)
5332 	    dict_add_string(d, "filename", wp->w_jumplist[i].fname);
5333     }
5334 #endif
5335 }
5336 
5337 /*
5338  * "getline(lnum, [end])" function
5339  */
5340     static void
5341 f_getline(typval_T *argvars, typval_T *rettv)
5342 {
5343     linenr_T	lnum;
5344     linenr_T	end;
5345     int		retlist;
5346 
5347     lnum = tv_get_lnum(argvars);
5348     if (argvars[1].v_type == VAR_UNKNOWN)
5349     {
5350 	end = 0;
5351 	retlist = FALSE;
5352     }
5353     else
5354     {
5355 	end = tv_get_lnum(&argvars[1]);
5356 	retlist = TRUE;
5357     }
5358 
5359     get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5360 }
5361 
5362 #ifdef FEAT_QUICKFIX
5363     static void
5364 get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5365 {
5366     if (what_arg->v_type == VAR_UNKNOWN)
5367     {
5368 	if (rettv_list_alloc(rettv) == OK)
5369 	    if (is_qf || wp != NULL)
5370 		(void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
5371     }
5372     else
5373     {
5374 	if (rettv_dict_alloc(rettv) == OK)
5375 	    if (is_qf || (wp != NULL))
5376 	    {
5377 		if (what_arg->v_type == VAR_DICT)
5378 		{
5379 		    dict_T	*d = what_arg->vval.v_dict;
5380 
5381 		    if (d != NULL)
5382 			qf_get_properties(wp, d, rettv->vval.v_dict);
5383 		}
5384 		else
5385 		    emsg(_(e_dictreq));
5386 	    }
5387     }
5388 }
5389 #endif
5390 
5391 /*
5392  * "getloclist()" function
5393  */
5394     static void
5395 f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5396 {
5397 #ifdef FEAT_QUICKFIX
5398     win_T	*wp;
5399 
5400     wp = find_win_by_nr_or_id(&argvars[0]);
5401     get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5402 #endif
5403 }
5404 
5405 /*
5406  * "getmatches()" function
5407  */
5408     static void
5409 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5410 {
5411 #ifdef FEAT_SEARCH_EXTRA
5412     dict_T	*dict;
5413     matchitem_T	*cur = curwin->w_match_head;
5414     int		i;
5415 
5416     if (rettv_list_alloc(rettv) == OK)
5417     {
5418 	while (cur != NULL)
5419 	{
5420 	    dict = dict_alloc();
5421 	    if (dict == NULL)
5422 		return;
5423 	    if (cur->match.regprog == NULL)
5424 	    {
5425 		/* match added with matchaddpos() */
5426 		for (i = 0; i < MAXPOSMATCH; ++i)
5427 		{
5428 		    llpos_T	*llpos;
5429 		    char	buf[6];
5430 		    list_T	*l;
5431 
5432 		    llpos = &cur->pos.pos[i];
5433 		    if (llpos->lnum == 0)
5434 			break;
5435 		    l = list_alloc();
5436 		    if (l == NULL)
5437 			break;
5438 		    list_append_number(l, (varnumber_T)llpos->lnum);
5439 		    if (llpos->col > 0)
5440 		    {
5441 			list_append_number(l, (varnumber_T)llpos->col);
5442 			list_append_number(l, (varnumber_T)llpos->len);
5443 		    }
5444 		    sprintf(buf, "pos%d", i + 1);
5445 		    dict_add_list(dict, buf, l);
5446 		}
5447 	    }
5448 	    else
5449 	    {
5450 		dict_add_string(dict, "pattern", cur->pattern);
5451 	    }
5452 	    dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5453 	    dict_add_number(dict, "priority", (long)cur->priority);
5454 	    dict_add_number(dict, "id", (long)cur->id);
5455 # if defined(FEAT_CONCEAL)
5456 	    if (cur->conceal_char)
5457 	    {
5458 		char_u buf[MB_MAXBYTES + 1];
5459 
5460 		buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5461 		dict_add_string(dict, "conceal", (char_u *)&buf);
5462 	    }
5463 # endif
5464 	    list_append_dict(rettv->vval.v_list, dict);
5465 	    cur = cur->next;
5466 	}
5467     }
5468 #endif
5469 }
5470 
5471 /*
5472  * "getpid()" function
5473  */
5474     static void
5475 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5476 {
5477     rettv->vval.v_number = mch_get_pid();
5478 }
5479 
5480     static void
5481 getpos_both(
5482     typval_T	*argvars,
5483     typval_T	*rettv,
5484     int		getcurpos)
5485 {
5486     pos_T	*fp;
5487     list_T	*l;
5488     int		fnum = -1;
5489 
5490     if (rettv_list_alloc(rettv) == OK)
5491     {
5492 	l = rettv->vval.v_list;
5493 	if (getcurpos)
5494 	    fp = &curwin->w_cursor;
5495 	else
5496 	    fp = var2fpos(&argvars[0], TRUE, &fnum);
5497 	if (fnum != -1)
5498 	    list_append_number(l, (varnumber_T)fnum);
5499 	else
5500 	    list_append_number(l, (varnumber_T)0);
5501 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5502 							    : (varnumber_T)0);
5503 	list_append_number(l, (fp != NULL)
5504 		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5505 							    : (varnumber_T)0);
5506 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
5507 							      (varnumber_T)0);
5508 	if (getcurpos)
5509 	{
5510 	    int	    save_set_curswant = curwin->w_set_curswant;
5511 	    colnr_T save_curswant = curwin->w_curswant;
5512 	    colnr_T save_virtcol = curwin->w_virtcol;
5513 
5514 	    update_curswant();
5515 	    list_append_number(l, curwin->w_curswant == MAXCOL ?
5516 		    (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5517 
5518 	    // Do not change "curswant", as it is unexpected that a get
5519 	    // function has a side effect.
5520 	    if (save_set_curswant)
5521 	    {
5522 		curwin->w_set_curswant = save_set_curswant;
5523 		curwin->w_curswant = save_curswant;
5524 		curwin->w_virtcol = save_virtcol;
5525 		curwin->w_valid &= ~VALID_VIRTCOL;
5526 	    }
5527 	}
5528     }
5529     else
5530 	rettv->vval.v_number = FALSE;
5531 }
5532 
5533 /*
5534  * "getcurpos()" function
5535  */
5536     static void
5537 f_getcurpos(typval_T *argvars, typval_T *rettv)
5538 {
5539     getpos_both(argvars, rettv, TRUE);
5540 }
5541 
5542 /*
5543  * "getpos(string)" function
5544  */
5545     static void
5546 f_getpos(typval_T *argvars, typval_T *rettv)
5547 {
5548     getpos_both(argvars, rettv, FALSE);
5549 }
5550 
5551 /*
5552  * "getqflist()" function
5553  */
5554     static void
5555 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5556 {
5557 #ifdef FEAT_QUICKFIX
5558     get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
5559 #endif
5560 }
5561 
5562 /*
5563  * "getreg()" function
5564  */
5565     static void
5566 f_getreg(typval_T *argvars, typval_T *rettv)
5567 {
5568     char_u	*strregname;
5569     int		regname;
5570     int		arg2 = FALSE;
5571     int		return_list = FALSE;
5572     int		error = FALSE;
5573 
5574     if (argvars[0].v_type != VAR_UNKNOWN)
5575     {
5576 	strregname = tv_get_string_chk(&argvars[0]);
5577 	error = strregname == NULL;
5578 	if (argvars[1].v_type != VAR_UNKNOWN)
5579 	{
5580 	    arg2 = (int)tv_get_number_chk(&argvars[1], &error);
5581 	    if (!error && argvars[2].v_type != VAR_UNKNOWN)
5582 		return_list = (int)tv_get_number_chk(&argvars[2], &error);
5583 	}
5584     }
5585     else
5586 	strregname = get_vim_var_str(VV_REG);
5587 
5588     if (error)
5589 	return;
5590 
5591     regname = (strregname == NULL ? '"' : *strregname);
5592     if (regname == 0)
5593 	regname = '"';
5594 
5595     if (return_list)
5596     {
5597 	rettv->v_type = VAR_LIST;
5598 	rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5599 				      (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5600 	if (rettv->vval.v_list == NULL)
5601 	    (void)rettv_list_alloc(rettv);
5602 	else
5603 	    ++rettv->vval.v_list->lv_refcount;
5604     }
5605     else
5606     {
5607 	rettv->v_type = VAR_STRING;
5608 	rettv->vval.v_string = get_reg_contents(regname,
5609 						    arg2 ? GREG_EXPR_SRC : 0);
5610     }
5611 }
5612 
5613 /*
5614  * "getregtype()" function
5615  */
5616     static void
5617 f_getregtype(typval_T *argvars, typval_T *rettv)
5618 {
5619     char_u	*strregname;
5620     int		regname;
5621     char_u	buf[NUMBUFLEN + 2];
5622     long	reglen = 0;
5623 
5624     if (argvars[0].v_type != VAR_UNKNOWN)
5625     {
5626 	strregname = tv_get_string_chk(&argvars[0]);
5627 	if (strregname == NULL)	    /* type error; errmsg already given */
5628 	{
5629 	    rettv->v_type = VAR_STRING;
5630 	    rettv->vval.v_string = NULL;
5631 	    return;
5632 	}
5633     }
5634     else
5635 	/* Default to v:register */
5636 	strregname = get_vim_var_str(VV_REG);
5637 
5638     regname = (strregname == NULL ? '"' : *strregname);
5639     if (regname == 0)
5640 	regname = '"';
5641 
5642     buf[0] = NUL;
5643     buf[1] = NUL;
5644     switch (get_reg_type(regname, &reglen))
5645     {
5646 	case MLINE: buf[0] = 'V'; break;
5647 	case MCHAR: buf[0] = 'v'; break;
5648 	case MBLOCK:
5649 		buf[0] = Ctrl_V;
5650 		sprintf((char *)buf + 1, "%ld", reglen + 1);
5651 		break;
5652     }
5653     rettv->v_type = VAR_STRING;
5654     rettv->vval.v_string = vim_strsave(buf);
5655 }
5656 
5657 /*
5658  * Returns information (variables, options, etc.) about a tab page
5659  * as a dictionary.
5660  */
5661     static dict_T *
5662 get_tabpage_info(tabpage_T *tp, int tp_idx)
5663 {
5664     win_T	*wp;
5665     dict_T	*dict;
5666     list_T	*l;
5667 
5668     dict = dict_alloc();
5669     if (dict == NULL)
5670 	return NULL;
5671 
5672     dict_add_number(dict, "tabnr", tp_idx);
5673 
5674     l = list_alloc();
5675     if (l != NULL)
5676     {
5677 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5678 		wp; wp = wp->w_next)
5679 	    list_append_number(l, (varnumber_T)wp->w_id);
5680 	dict_add_list(dict, "windows", l);
5681     }
5682 
5683     /* Make a reference to tabpage variables */
5684     dict_add_dict(dict, "variables", tp->tp_vars);
5685 
5686     return dict;
5687 }
5688 
5689 /*
5690  * "gettabinfo()" function
5691  */
5692     static void
5693 f_gettabinfo(typval_T *argvars, typval_T *rettv)
5694 {
5695     tabpage_T	*tp, *tparg = NULL;
5696     dict_T	*d;
5697     int		tpnr = 0;
5698 
5699     if (rettv_list_alloc(rettv) != OK)
5700 	return;
5701 
5702     if (argvars[0].v_type != VAR_UNKNOWN)
5703     {
5704 	/* Information about one tab page */
5705 	tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
5706 	if (tparg == NULL)
5707 	    return;
5708     }
5709 
5710     /* Get information about a specific tab page or all tab pages */
5711     FOR_ALL_TABPAGES(tp)
5712     {
5713 	tpnr++;
5714 	if (tparg != NULL && tp != tparg)
5715 	    continue;
5716 	d = get_tabpage_info(tp, tpnr);
5717 	if (d != NULL)
5718 	    list_append_dict(rettv->vval.v_list, d);
5719 	if (tparg != NULL)
5720 	    return;
5721     }
5722 }
5723 
5724 /*
5725  * "gettabvar()" function
5726  */
5727     static void
5728 f_gettabvar(typval_T *argvars, typval_T *rettv)
5729 {
5730     win_T	*oldcurwin;
5731     tabpage_T	*tp, *oldtabpage;
5732     dictitem_T	*v;
5733     char_u	*varname;
5734     int		done = FALSE;
5735 
5736     rettv->v_type = VAR_STRING;
5737     rettv->vval.v_string = NULL;
5738 
5739     varname = tv_get_string_chk(&argvars[1]);
5740     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
5741     if (tp != NULL && varname != NULL)
5742     {
5743 	/* Set tp to be our tabpage, temporarily.  Also set the window to the
5744 	 * first window in the tabpage, otherwise the window is not valid. */
5745 	if (switch_win(&oldcurwin, &oldtabpage,
5746 		tp == curtab || tp->tp_firstwin == NULL ? firstwin
5747 					    : tp->tp_firstwin, tp, TRUE) == OK)
5748 	{
5749 	    /* look up the variable */
5750 	    /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5751 	    v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5752 	    if (v != NULL)
5753 	    {
5754 		copy_tv(&v->di_tv, rettv);
5755 		done = TRUE;
5756 	    }
5757 	}
5758 
5759 	/* restore previous notion of curwin */
5760 	restore_win(oldcurwin, oldtabpage, TRUE);
5761     }
5762 
5763     if (!done && argvars[2].v_type != VAR_UNKNOWN)
5764 	copy_tv(&argvars[2], rettv);
5765 }
5766 
5767 /*
5768  * "gettabwinvar()" function
5769  */
5770     static void
5771 f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5772 {
5773     getwinvar(argvars, rettv, 1);
5774 }
5775 
5776 /*
5777  * "gettagstack()" function
5778  */
5779     static void
5780 f_gettagstack(typval_T *argvars, typval_T *rettv)
5781 {
5782     win_T	*wp = curwin;			// default is current window
5783 
5784     if (rettv_dict_alloc(rettv) != OK)
5785 	return;
5786 
5787     if (argvars[0].v_type != VAR_UNKNOWN)
5788     {
5789 	wp = find_win_by_nr_or_id(&argvars[0]);
5790 	if (wp == NULL)
5791 	    return;
5792     }
5793 
5794     get_tagstack(wp, rettv->vval.v_dict);
5795 }
5796 
5797 /*
5798  * Returns information about a window as a dictionary.
5799  */
5800     static dict_T *
5801 get_win_info(win_T *wp, short tpnr, short winnr)
5802 {
5803     dict_T	*dict;
5804 
5805     dict = dict_alloc();
5806     if (dict == NULL)
5807 	return NULL;
5808 
5809     dict_add_number(dict, "tabnr", tpnr);
5810     dict_add_number(dict, "winnr", winnr);
5811     dict_add_number(dict, "winid", wp->w_id);
5812     dict_add_number(dict, "height", wp->w_height);
5813     dict_add_number(dict, "winrow", wp->w_winrow + 1);
5814     dict_add_number(dict, "topline", wp->w_topline);
5815     dict_add_number(dict, "botline", wp->w_botline - 1);
5816 #ifdef FEAT_MENU
5817     dict_add_number(dict, "winbar", wp->w_winbar_height);
5818 #endif
5819     dict_add_number(dict, "width", wp->w_width);
5820     dict_add_number(dict, "wincol", wp->w_wincol + 1);
5821     dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
5822 
5823 #ifdef FEAT_TERMINAL
5824     dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
5825 #endif
5826 #ifdef FEAT_QUICKFIX
5827     dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5828     dict_add_number(dict, "loclist",
5829 		      (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
5830 #endif
5831 
5832     /* Add a reference to window variables */
5833     dict_add_dict(dict, "variables", wp->w_vars);
5834 
5835     return dict;
5836 }
5837 
5838 /*
5839  * "getwininfo()" function
5840  */
5841     static void
5842 f_getwininfo(typval_T *argvars, typval_T *rettv)
5843 {
5844     tabpage_T	*tp;
5845     win_T	*wp = NULL, *wparg = NULL;
5846     dict_T	*d;
5847     short	tabnr = 0, winnr;
5848 
5849     if (rettv_list_alloc(rettv) != OK)
5850 	return;
5851 
5852     if (argvars[0].v_type != VAR_UNKNOWN)
5853     {
5854 	wparg = win_id2wp(tv_get_number(&argvars[0]));
5855 	if (wparg == NULL)
5856 	    return;
5857     }
5858 
5859     /* Collect information about either all the windows across all the tab
5860      * pages or one particular window.
5861      */
5862     FOR_ALL_TABPAGES(tp)
5863     {
5864 	tabnr++;
5865 	winnr = 0;
5866 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
5867 	{
5868 	    winnr++;
5869 	    if (wparg != NULL && wp != wparg)
5870 		continue;
5871 	    d = get_win_info(wp, tabnr, winnr);
5872 	    if (d != NULL)
5873 		list_append_dict(rettv->vval.v_list, d);
5874 	    if (wparg != NULL)
5875 		/* found information about a specific window */
5876 		return;
5877 	}
5878     }
5879 }
5880 
5881 /*
5882  * "win_findbuf()" function
5883  */
5884     static void
5885 f_win_findbuf(typval_T *argvars, typval_T *rettv)
5886 {
5887     if (rettv_list_alloc(rettv) != FAIL)
5888 	win_findbuf(argvars, rettv->vval.v_list);
5889 }
5890 
5891 /*
5892  * "win_getid()" function
5893  */
5894     static void
5895 f_win_getid(typval_T *argvars, typval_T *rettv)
5896 {
5897     rettv->vval.v_number = win_getid(argvars);
5898 }
5899 
5900 /*
5901  * "win_gotoid()" function
5902  */
5903     static void
5904 f_win_gotoid(typval_T *argvars, typval_T *rettv)
5905 {
5906     rettv->vval.v_number = win_gotoid(argvars);
5907 }
5908 
5909 /*
5910  * "win_id2tabwin()" function
5911  */
5912     static void
5913 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5914 {
5915     if (rettv_list_alloc(rettv) != FAIL)
5916 	win_id2tabwin(argvars, rettv->vval.v_list);
5917 }
5918 
5919 /*
5920  * "win_id2win()" function
5921  */
5922     static void
5923 f_win_id2win(typval_T *argvars, typval_T *rettv)
5924 {
5925     rettv->vval.v_number = win_id2win(argvars);
5926 }
5927 
5928 /*
5929  * "win_screenpos()" function
5930  */
5931     static void
5932 f_win_screenpos(typval_T *argvars, typval_T *rettv)
5933 {
5934     win_T	*wp;
5935 
5936     if (rettv_list_alloc(rettv) == FAIL)
5937 	return;
5938 
5939     wp = find_win_by_nr_or_id(&argvars[0]);
5940     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5941     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5942 }
5943 
5944 /*
5945  * "getwinpos({timeout})" function
5946  */
5947     static void
5948 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5949 {
5950     int x = -1;
5951     int y = -1;
5952 
5953     if (rettv_list_alloc(rettv) == FAIL)
5954 	return;
5955 #ifdef FEAT_GUI
5956     if (gui.in_use)
5957 	(void)gui_mch_get_winpos(&x, &y);
5958 # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5959     else
5960 # endif
5961 #endif
5962 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5963     {
5964 	varnumber_T timeout = 100;
5965 
5966 	if (argvars[0].v_type != VAR_UNKNOWN)
5967 	    timeout = tv_get_number(&argvars[0]);
5968 	term_get_winpos(&x, &y, timeout);
5969     }
5970 #endif
5971     list_append_number(rettv->vval.v_list, (varnumber_T)x);
5972     list_append_number(rettv->vval.v_list, (varnumber_T)y);
5973 }
5974 
5975 
5976 /*
5977  * "getwinposx()" function
5978  */
5979     static void
5980 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5981 {
5982     rettv->vval.v_number = -1;
5983 #ifdef FEAT_GUI
5984     if (gui.in_use)
5985     {
5986 	int	    x, y;
5987 
5988 	if (gui_mch_get_winpos(&x, &y) == OK)
5989 	    rettv->vval.v_number = x;
5990 	return;
5991     }
5992 #endif
5993 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5994     {
5995 	int	    x, y;
5996 
5997 	if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
5998 	    rettv->vval.v_number = x;
5999     }
6000 #endif
6001 }
6002 
6003 /*
6004  * "getwinposy()" function
6005  */
6006     static void
6007 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6008 {
6009     rettv->vval.v_number = -1;
6010 #ifdef FEAT_GUI
6011     if (gui.in_use)
6012     {
6013 	int	    x, y;
6014 
6015 	if (gui_mch_get_winpos(&x, &y) == OK)
6016 	    rettv->vval.v_number = y;
6017 	return;
6018     }
6019 #endif
6020 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6021     {
6022 	int	    x, y;
6023 
6024 	if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
6025 	    rettv->vval.v_number = y;
6026     }
6027 #endif
6028 }
6029 
6030 /*
6031  * "getwinvar()" function
6032  */
6033     static void
6034 f_getwinvar(typval_T *argvars, typval_T *rettv)
6035 {
6036     getwinvar(argvars, rettv, 0);
6037 }
6038 
6039 /*
6040  * "glob()" function
6041  */
6042     static void
6043 f_glob(typval_T *argvars, typval_T *rettv)
6044 {
6045     int		options = WILD_SILENT|WILD_USE_NL;
6046     expand_T	xpc;
6047     int		error = FALSE;
6048 
6049     /* When the optional second argument is non-zero, don't remove matches
6050      * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6051     rettv->v_type = VAR_STRING;
6052     if (argvars[1].v_type != VAR_UNKNOWN)
6053     {
6054 	if (tv_get_number_chk(&argvars[1], &error))
6055 	    options |= WILD_KEEP_ALL;
6056 	if (argvars[2].v_type != VAR_UNKNOWN)
6057 	{
6058 	    if (tv_get_number_chk(&argvars[2], &error))
6059 	    {
6060 		rettv_list_set(rettv, NULL);
6061 	    }
6062 	    if (argvars[3].v_type != VAR_UNKNOWN
6063 				    && tv_get_number_chk(&argvars[3], &error))
6064 		options |= WILD_ALLLINKS;
6065 	}
6066     }
6067     if (!error)
6068     {
6069 	ExpandInit(&xpc);
6070 	xpc.xp_context = EXPAND_FILES;
6071 	if (p_wic)
6072 	    options += WILD_ICASE;
6073 	if (rettv->v_type == VAR_STRING)
6074 	    rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
6075 						     NULL, options, WILD_ALL);
6076 	else if (rettv_list_alloc(rettv) != FAIL)
6077 	{
6078 	  int i;
6079 
6080 	  ExpandOne(&xpc, tv_get_string(&argvars[0]),
6081 						NULL, options, WILD_ALL_KEEP);
6082 	  for (i = 0; i < xpc.xp_numfiles; i++)
6083 	      list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6084 
6085 	  ExpandCleanup(&xpc);
6086 	}
6087     }
6088     else
6089 	rettv->vval.v_string = NULL;
6090 }
6091 
6092 /*
6093  * "globpath()" function
6094  */
6095     static void
6096 f_globpath(typval_T *argvars, typval_T *rettv)
6097 {
6098     int		flags = 0;
6099     char_u	buf1[NUMBUFLEN];
6100     char_u	*file = tv_get_string_buf_chk(&argvars[1], buf1);
6101     int		error = FALSE;
6102     garray_T	ga;
6103     int		i;
6104 
6105     /* When the optional second argument is non-zero, don't remove matches
6106     * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6107     rettv->v_type = VAR_STRING;
6108     if (argvars[2].v_type != VAR_UNKNOWN)
6109     {
6110 	if (tv_get_number_chk(&argvars[2], &error))
6111 	    flags |= WILD_KEEP_ALL;
6112 	if (argvars[3].v_type != VAR_UNKNOWN)
6113 	{
6114 	    if (tv_get_number_chk(&argvars[3], &error))
6115 	    {
6116 		rettv_list_set(rettv, NULL);
6117 	    }
6118 	    if (argvars[4].v_type != VAR_UNKNOWN
6119 				    && tv_get_number_chk(&argvars[4], &error))
6120 		flags |= WILD_ALLLINKS;
6121 	}
6122     }
6123     if (file != NULL && !error)
6124     {
6125 	ga_init2(&ga, (int)sizeof(char_u *), 10);
6126 	globpath(tv_get_string(&argvars[0]), file, &ga, flags);
6127 	if (rettv->v_type == VAR_STRING)
6128 	    rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6129 	else if (rettv_list_alloc(rettv) != FAIL)
6130 	    for (i = 0; i < ga.ga_len; ++i)
6131 		list_append_string(rettv->vval.v_list,
6132 					    ((char_u **)(ga.ga_data))[i], -1);
6133 	ga_clear_strings(&ga);
6134     }
6135     else
6136 	rettv->vval.v_string = NULL;
6137 }
6138 
6139 /*
6140  * "glob2regpat()" function
6141  */
6142     static void
6143 f_glob2regpat(typval_T *argvars, typval_T *rettv)
6144 {
6145     char_u	*pat = tv_get_string_chk(&argvars[0]);
6146 
6147     rettv->v_type = VAR_STRING;
6148     rettv->vval.v_string = (pat == NULL)
6149 			 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6150 }
6151 
6152 /* for VIM_VERSION_ defines */
6153 #include "version.h"
6154 
6155 /*
6156  * "has()" function
6157  */
6158     static void
6159 f_has(typval_T *argvars, typval_T *rettv)
6160 {
6161     int		i;
6162     char_u	*name;
6163     int		n = FALSE;
6164     static char	*(has_list[]) =
6165     {
6166 #ifdef AMIGA
6167 	"amiga",
6168 # ifdef FEAT_ARP
6169 	"arp",
6170 # endif
6171 #endif
6172 #ifdef __BEOS__
6173 	"beos",
6174 #endif
6175 #if defined(BSD) && !defined(MACOS_X)
6176 	"bsd",
6177 #endif
6178 #ifdef hpux
6179 	"hpux",
6180 #endif
6181 #ifdef __linux__
6182 	"linux",
6183 #endif
6184 #ifdef MACOS_X
6185 	"mac",		/* Mac OS X (and, once, Mac OS Classic) */
6186 	"osx",		/* Mac OS X */
6187 # ifdef MACOS_X_DARWIN
6188 	"macunix",	/* Mac OS X, with the darwin feature */
6189 	"osxdarwin",	/* synonym for macunix */
6190 # endif
6191 #endif
6192 #ifdef __QNX__
6193 	"qnx",
6194 #endif
6195 #ifdef SUN_SYSTEM
6196 	"sun",
6197 #else
6198 	"moon",
6199 #endif
6200 #ifdef UNIX
6201 	"unix",
6202 #endif
6203 #ifdef VMS
6204 	"vms",
6205 #endif
6206 #ifdef MSWIN
6207 	"win32",
6208 #endif
6209 #if defined(UNIX) && defined(__CYGWIN__)
6210 	"win32unix",
6211 #endif
6212 #ifdef _WIN64
6213 	"win64",
6214 #endif
6215 #ifdef EBCDIC
6216 	"ebcdic",
6217 #endif
6218 #ifndef CASE_INSENSITIVE_FILENAME
6219 	"fname_case",
6220 #endif
6221 #ifdef HAVE_ACL
6222 	"acl",
6223 #endif
6224 #ifdef FEAT_ARABIC
6225 	"arabic",
6226 #endif
6227 	"autocmd",
6228 #ifdef FEAT_AUTOCHDIR
6229 	"autochdir",
6230 #endif
6231 #ifdef FEAT_AUTOSERVERNAME
6232 	"autoservername",
6233 #endif
6234 #ifdef FEAT_BEVAL_GUI
6235 	"balloon_eval",
6236 # ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
6237 	"balloon_multiline",
6238 # endif
6239 #endif
6240 #ifdef FEAT_BEVAL_TERM
6241 	"balloon_eval_term",
6242 #endif
6243 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6244 	"builtin_terms",
6245 # ifdef ALL_BUILTIN_TCAPS
6246 	"all_builtin_terms",
6247 # endif
6248 #endif
6249 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6250 	|| defined(FEAT_GUI_MSWIN) \
6251 	|| defined(FEAT_GUI_MOTIF))
6252 	"browsefilter",
6253 #endif
6254 #ifdef FEAT_BYTEOFF
6255 	"byte_offset",
6256 #endif
6257 #ifdef FEAT_JOB_CHANNEL
6258 	"channel",
6259 #endif
6260 #ifdef FEAT_CINDENT
6261 	"cindent",
6262 #endif
6263 #ifdef FEAT_CLIENTSERVER
6264 	"clientserver",
6265 #endif
6266 #ifdef FEAT_CLIPBOARD
6267 	"clipboard",
6268 #endif
6269 #ifdef FEAT_CMDL_COMPL
6270 	"cmdline_compl",
6271 #endif
6272 #ifdef FEAT_CMDHIST
6273 	"cmdline_hist",
6274 #endif
6275 #ifdef FEAT_COMMENTS
6276 	"comments",
6277 #endif
6278 #ifdef FEAT_CONCEAL
6279 	"conceal",
6280 #endif
6281 #ifdef FEAT_CRYPT
6282 	"cryptv",
6283 	"crypt-blowfish",
6284 	"crypt-blowfish2",
6285 #endif
6286 #ifdef FEAT_CSCOPE
6287 	"cscope",
6288 #endif
6289 	"cursorbind",
6290 #ifdef CURSOR_SHAPE
6291 	"cursorshape",
6292 #endif
6293 #ifdef DEBUG
6294 	"debug",
6295 #endif
6296 #ifdef FEAT_CON_DIALOG
6297 	"dialog_con",
6298 #endif
6299 #ifdef FEAT_GUI_DIALOG
6300 	"dialog_gui",
6301 #endif
6302 #ifdef FEAT_DIFF
6303 	"diff",
6304 #endif
6305 #ifdef FEAT_DIGRAPHS
6306 	"digraphs",
6307 #endif
6308 #ifdef FEAT_DIRECTX
6309 	"directx",
6310 #endif
6311 #ifdef FEAT_DND
6312 	"dnd",
6313 #endif
6314 #ifdef FEAT_EMACS_TAGS
6315 	"emacs_tags",
6316 #endif
6317 	"eval",	    /* always present, of course! */
6318 	"ex_extra", /* graduated feature */
6319 #ifdef FEAT_SEARCH_EXTRA
6320 	"extra_search",
6321 #endif
6322 #ifdef FEAT_SEARCHPATH
6323 	"file_in_path",
6324 #endif
6325 #ifdef FEAT_FILTERPIPE
6326 	"filterpipe",
6327 #endif
6328 #ifdef FEAT_FIND_ID
6329 	"find_in_path",
6330 #endif
6331 #ifdef FEAT_FLOAT
6332 	"float",
6333 #endif
6334 #ifdef FEAT_FOLDING
6335 	"folding",
6336 #endif
6337 #ifdef FEAT_FOOTER
6338 	"footer",
6339 #endif
6340 #if !defined(USE_SYSTEM) && defined(UNIX)
6341 	"fork",
6342 #endif
6343 #ifdef FEAT_GETTEXT
6344 	"gettext",
6345 #endif
6346 #ifdef FEAT_GUI
6347 	"gui",
6348 #endif
6349 #ifdef FEAT_GUI_ATHENA
6350 # ifdef FEAT_GUI_NEXTAW
6351 	"gui_neXtaw",
6352 # else
6353 	"gui_athena",
6354 # endif
6355 #endif
6356 #ifdef FEAT_GUI_GTK
6357 	"gui_gtk",
6358 # ifdef USE_GTK3
6359 	"gui_gtk3",
6360 # else
6361 	"gui_gtk2",
6362 # endif
6363 #endif
6364 #ifdef FEAT_GUI_GNOME
6365 	"gui_gnome",
6366 #endif
6367 #ifdef FEAT_GUI_MAC
6368 	"gui_mac",
6369 #endif
6370 #ifdef FEAT_GUI_MOTIF
6371 	"gui_motif",
6372 #endif
6373 #ifdef FEAT_GUI_PHOTON
6374 	"gui_photon",
6375 #endif
6376 #ifdef FEAT_GUI_MSWIN
6377 	"gui_win32",
6378 #endif
6379 #ifdef FEAT_HANGULIN
6380 	"hangul_input",
6381 #endif
6382 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6383 	"iconv",
6384 #endif
6385 #ifdef FEAT_INS_EXPAND
6386 	"insert_expand",
6387 #endif
6388 #ifdef FEAT_JOB_CHANNEL
6389 	"job",
6390 #endif
6391 #ifdef FEAT_JUMPLIST
6392 	"jumplist",
6393 #endif
6394 #ifdef FEAT_KEYMAP
6395 	"keymap",
6396 #endif
6397 	"lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
6398 #ifdef FEAT_LANGMAP
6399 	"langmap",
6400 #endif
6401 #ifdef FEAT_LIBCALL
6402 	"libcall",
6403 #endif
6404 #ifdef FEAT_LINEBREAK
6405 	"linebreak",
6406 #endif
6407 #ifdef FEAT_LISP
6408 	"lispindent",
6409 #endif
6410 	"listcmds",
6411 #ifdef FEAT_LOCALMAP
6412 	"localmap",
6413 #endif
6414 #ifdef FEAT_LUA
6415 # ifndef DYNAMIC_LUA
6416 	"lua",
6417 # endif
6418 #endif
6419 #ifdef FEAT_MENU
6420 	"menu",
6421 #endif
6422 #ifdef FEAT_SESSION
6423 	"mksession",
6424 #endif
6425 #ifdef FEAT_MODIFY_FNAME
6426 	"modify_fname",
6427 #endif
6428 #ifdef FEAT_MOUSE
6429 	"mouse",
6430 #endif
6431 #ifdef FEAT_MOUSESHAPE
6432 	"mouseshape",
6433 #endif
6434 #if defined(UNIX) || defined(VMS)
6435 # ifdef FEAT_MOUSE_DEC
6436 	"mouse_dec",
6437 # endif
6438 # ifdef FEAT_MOUSE_GPM
6439 	"mouse_gpm",
6440 # endif
6441 # ifdef FEAT_MOUSE_JSB
6442 	"mouse_jsbterm",
6443 # endif
6444 # ifdef FEAT_MOUSE_NET
6445 	"mouse_netterm",
6446 # endif
6447 # ifdef FEAT_MOUSE_PTERM
6448 	"mouse_pterm",
6449 # endif
6450 # ifdef FEAT_MOUSE_XTERM
6451 	"mouse_sgr",
6452 # endif
6453 # ifdef FEAT_SYSMOUSE
6454 	"mouse_sysmouse",
6455 # endif
6456 # ifdef FEAT_MOUSE_URXVT
6457 	"mouse_urxvt",
6458 # endif
6459 # ifdef FEAT_MOUSE_XTERM
6460 	"mouse_xterm",
6461 # endif
6462 #endif
6463 	"multi_byte",
6464 #ifdef FEAT_MBYTE_IME
6465 	"multi_byte_ime",
6466 #endif
6467 #ifdef FEAT_MULTI_LANG
6468 	"multi_lang",
6469 #endif
6470 #ifdef FEAT_MZSCHEME
6471 #ifndef DYNAMIC_MZSCHEME
6472 	"mzscheme",
6473 #endif
6474 #endif
6475 #ifdef FEAT_NUM64
6476 	"num64",
6477 #endif
6478 #ifdef FEAT_OLE
6479 	"ole",
6480 #endif
6481 #ifdef FEAT_EVAL
6482 	"packages",
6483 #endif
6484 #ifdef FEAT_PATH_EXTRA
6485 	"path_extra",
6486 #endif
6487 #ifdef FEAT_PERL
6488 #ifndef DYNAMIC_PERL
6489 	"perl",
6490 #endif
6491 #endif
6492 #ifdef FEAT_PERSISTENT_UNDO
6493 	"persistent_undo",
6494 #endif
6495 #if defined(FEAT_PYTHON)
6496 	"python_compiled",
6497 # if defined(DYNAMIC_PYTHON)
6498 	"python_dynamic",
6499 # else
6500 	"python",
6501 	"pythonx",
6502 # endif
6503 #endif
6504 #if defined(FEAT_PYTHON3)
6505 	"python3_compiled",
6506 # if defined(DYNAMIC_PYTHON3)
6507 	"python3_dynamic",
6508 # else
6509 	"python3",
6510 	"pythonx",
6511 # endif
6512 #endif
6513 #ifdef FEAT_POSTSCRIPT
6514 	"postscript",
6515 #endif
6516 #ifdef FEAT_PRINTER
6517 	"printer",
6518 #endif
6519 #ifdef FEAT_PROFILE
6520 	"profile",
6521 #endif
6522 #ifdef FEAT_RELTIME
6523 	"reltime",
6524 #endif
6525 #ifdef FEAT_QUICKFIX
6526 	"quickfix",
6527 #endif
6528 #ifdef FEAT_RIGHTLEFT
6529 	"rightleft",
6530 #endif
6531 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6532 	"ruby",
6533 #endif
6534 	"scrollbind",
6535 #ifdef FEAT_CMDL_INFO
6536 	"showcmd",
6537 	"cmdline_info",
6538 #endif
6539 #ifdef FEAT_SIGNS
6540 	"signs",
6541 #endif
6542 #ifdef FEAT_SMARTINDENT
6543 	"smartindent",
6544 #endif
6545 #ifdef STARTUPTIME
6546 	"startuptime",
6547 #endif
6548 #ifdef FEAT_STL_OPT
6549 	"statusline",
6550 #endif
6551 #ifdef FEAT_NETBEANS_INTG
6552 	"netbeans_intg",
6553 #endif
6554 #ifdef FEAT_SPELL
6555 	"spell",
6556 #endif
6557 #ifdef FEAT_SYN_HL
6558 	"syntax",
6559 #endif
6560 #if defined(USE_SYSTEM) || !defined(UNIX)
6561 	"system",
6562 #endif
6563 #ifdef FEAT_TAG_BINS
6564 	"tag_binary",
6565 #endif
6566 #ifdef FEAT_TAG_OLDSTATIC
6567 	"tag_old_static",
6568 #endif
6569 #ifdef FEAT_TCL
6570 # ifndef DYNAMIC_TCL
6571 	"tcl",
6572 # endif
6573 #endif
6574 #ifdef FEAT_TERMGUICOLORS
6575 	"termguicolors",
6576 #endif
6577 #if defined(FEAT_TERMINAL) && !defined(MSWIN)
6578 	"terminal",
6579 #endif
6580 #ifdef TERMINFO
6581 	"terminfo",
6582 #endif
6583 #ifdef FEAT_TERMRESPONSE
6584 	"termresponse",
6585 #endif
6586 #ifdef FEAT_TEXTOBJ
6587 	"textobjects",
6588 #endif
6589 #ifdef FEAT_TEXT_PROP
6590 	"textprop",
6591 #endif
6592 #ifdef HAVE_TGETENT
6593 	"tgetent",
6594 #endif
6595 #ifdef FEAT_TIMERS
6596 	"timers",
6597 #endif
6598 #ifdef FEAT_TITLE
6599 	"title",
6600 #endif
6601 #ifdef FEAT_TOOLBAR
6602 	"toolbar",
6603 #endif
6604 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6605 	"unnamedplus",
6606 #endif
6607 #ifdef FEAT_USR_CMDS
6608 	"user-commands",    /* was accidentally included in 5.4 */
6609 	"user_commands",
6610 #endif
6611 #ifdef FEAT_VARTABS
6612 	"vartabs",
6613 #endif
6614 #ifdef FEAT_VIMINFO
6615 	"viminfo",
6616 #endif
6617 	"vertsplit",
6618 	"virtualedit",
6619 	"visual",
6620 	"visualextra",
6621 	"vreplace",
6622 #ifdef FEAT_VTP
6623 	"vtp",
6624 #endif
6625 #ifdef FEAT_WILDIGN
6626 	"wildignore",
6627 #endif
6628 #ifdef FEAT_WILDMENU
6629 	"wildmenu",
6630 #endif
6631 	"windows",
6632 #ifdef FEAT_WAK
6633 	"winaltkeys",
6634 #endif
6635 #ifdef FEAT_WRITEBACKUP
6636 	"writebackup",
6637 #endif
6638 #ifdef FEAT_XIM
6639 	"xim",
6640 #endif
6641 #ifdef FEAT_XFONTSET
6642 	"xfontset",
6643 #endif
6644 #ifdef FEAT_XPM_W32
6645 	"xpm",
6646 	"xpm_w32",	/* for backward compatibility */
6647 #else
6648 # if defined(HAVE_XPM)
6649 	"xpm",
6650 # endif
6651 #endif
6652 #ifdef USE_XSMP
6653 	"xsmp",
6654 #endif
6655 #ifdef USE_XSMP_INTERACT
6656 	"xsmp_interact",
6657 #endif
6658 #ifdef FEAT_XCLIPBOARD
6659 	"xterm_clipboard",
6660 #endif
6661 #ifdef FEAT_XTERM_SAVE
6662 	"xterm_save",
6663 #endif
6664 #if defined(UNIX) && defined(FEAT_X11)
6665 	"X11",
6666 #endif
6667 	NULL
6668     };
6669 
6670     name = tv_get_string(&argvars[0]);
6671     for (i = 0; has_list[i] != NULL; ++i)
6672 	if (STRICMP(name, has_list[i]) == 0)
6673 	{
6674 	    n = TRUE;
6675 	    break;
6676 	}
6677 
6678     if (n == FALSE)
6679     {
6680 	if (STRNICMP(name, "patch", 5) == 0)
6681 	{
6682 	    if (name[5] == '-'
6683 		    && STRLEN(name) >= 11
6684 		    && vim_isdigit(name[6])
6685 		    && vim_isdigit(name[8])
6686 		    && vim_isdigit(name[10]))
6687 	    {
6688 		int major = atoi((char *)name + 6);
6689 		int minor = atoi((char *)name + 8);
6690 
6691 		/* Expect "patch-9.9.01234". */
6692 		n = (major < VIM_VERSION_MAJOR
6693 		     || (major == VIM_VERSION_MAJOR
6694 			 && (minor < VIM_VERSION_MINOR
6695 			     || (minor == VIM_VERSION_MINOR
6696 				 && has_patch(atoi((char *)name + 10))))));
6697 	    }
6698 	    else
6699 		n = has_patch(atoi((char *)name + 5));
6700 	}
6701 	else if (STRICMP(name, "vim_starting") == 0)
6702 	    n = (starting != 0);
6703 	else if (STRICMP(name, "ttyin") == 0)
6704 	    n = mch_input_isatty();
6705 	else if (STRICMP(name, "ttyout") == 0)
6706 	    n = stdout_isatty;
6707 	else if (STRICMP(name, "multi_byte_encoding") == 0)
6708 	    n = has_mbyte;
6709 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
6710 	else if (STRICMP(name, "balloon_multiline") == 0)
6711 	    n = multiline_balloon_available();
6712 #endif
6713 #ifdef DYNAMIC_TCL
6714 	else if (STRICMP(name, "tcl") == 0)
6715 	    n = tcl_enabled(FALSE);
6716 #endif
6717 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6718 	else if (STRICMP(name, "iconv") == 0)
6719 	    n = iconv_enabled(FALSE);
6720 #endif
6721 #ifdef DYNAMIC_LUA
6722 	else if (STRICMP(name, "lua") == 0)
6723 	    n = lua_enabled(FALSE);
6724 #endif
6725 #ifdef DYNAMIC_MZSCHEME
6726 	else if (STRICMP(name, "mzscheme") == 0)
6727 	    n = mzscheme_enabled(FALSE);
6728 #endif
6729 #ifdef DYNAMIC_RUBY
6730 	else if (STRICMP(name, "ruby") == 0)
6731 	    n = ruby_enabled(FALSE);
6732 #endif
6733 #ifdef DYNAMIC_PYTHON
6734 	else if (STRICMP(name, "python") == 0)
6735 	    n = python_enabled(FALSE);
6736 #endif
6737 #ifdef DYNAMIC_PYTHON3
6738 	else if (STRICMP(name, "python3") == 0)
6739 	    n = python3_enabled(FALSE);
6740 #endif
6741 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6742 	else if (STRICMP(name, "pythonx") == 0)
6743 	{
6744 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6745 	    if (p_pyx == 0)
6746 		n = python3_enabled(FALSE) || python_enabled(FALSE);
6747 	    else if (p_pyx == 3)
6748 		n = python3_enabled(FALSE);
6749 	    else if (p_pyx == 2)
6750 		n = python_enabled(FALSE);
6751 # elif defined(DYNAMIC_PYTHON)
6752 	    n = python_enabled(FALSE);
6753 # elif defined(DYNAMIC_PYTHON3)
6754 	    n = python3_enabled(FALSE);
6755 # endif
6756 	}
6757 #endif
6758 #ifdef DYNAMIC_PERL
6759 	else if (STRICMP(name, "perl") == 0)
6760 	    n = perl_enabled(FALSE);
6761 #endif
6762 #ifdef FEAT_GUI
6763 	else if (STRICMP(name, "gui_running") == 0)
6764 	    n = (gui.in_use || gui.starting);
6765 # ifdef FEAT_BROWSE
6766 	else if (STRICMP(name, "browse") == 0)
6767 	    n = gui.in_use;	/* gui_mch_browse() works when GUI is running */
6768 # endif
6769 #endif
6770 #ifdef FEAT_SYN_HL
6771 	else if (STRICMP(name, "syntax_items") == 0)
6772 	    n = syntax_present(curwin);
6773 #endif
6774 #ifdef FEAT_VTP
6775 	else if (STRICMP(name, "vcon") == 0)
6776 	    n = is_term_win32() && has_vtp_working();
6777 #endif
6778 #ifdef FEAT_NETBEANS_INTG
6779 	else if (STRICMP(name, "netbeans_enabled") == 0)
6780 	    n = netbeans_active();
6781 #endif
6782 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6783 	else if (STRICMP(name, "terminal") == 0)
6784 	    n = terminal_enabled();
6785 #endif
6786 #if defined(FEAT_TERMINAL) && defined(MSWIN)
6787 	else if (STRICMP(name, "conpty") == 0)
6788 	    n = use_conpty();
6789 #endif
6790     }
6791 
6792     rettv->vval.v_number = n;
6793 }
6794 
6795 /*
6796  * "has_key()" function
6797  */
6798     static void
6799 f_has_key(typval_T *argvars, typval_T *rettv)
6800 {
6801     if (argvars[0].v_type != VAR_DICT)
6802     {
6803 	emsg(_(e_dictreq));
6804 	return;
6805     }
6806     if (argvars[0].vval.v_dict == NULL)
6807 	return;
6808 
6809     rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6810 				      tv_get_string(&argvars[1]), -1) != NULL;
6811 }
6812 
6813 /*
6814  * "haslocaldir()" function
6815  */
6816     static void
6817 f_haslocaldir(typval_T *argvars, typval_T *rettv)
6818 {
6819     win_T	*wp = NULL;
6820 
6821     wp = find_tabwin(&argvars[0], &argvars[1]);
6822     rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6823 }
6824 
6825 /*
6826  * "hasmapto()" function
6827  */
6828     static void
6829 f_hasmapto(typval_T *argvars, typval_T *rettv)
6830 {
6831     char_u	*name;
6832     char_u	*mode;
6833     char_u	buf[NUMBUFLEN];
6834     int		abbr = FALSE;
6835 
6836     name = tv_get_string(&argvars[0]);
6837     if (argvars[1].v_type == VAR_UNKNOWN)
6838 	mode = (char_u *)"nvo";
6839     else
6840     {
6841 	mode = tv_get_string_buf(&argvars[1], buf);
6842 	if (argvars[2].v_type != VAR_UNKNOWN)
6843 	    abbr = (int)tv_get_number(&argvars[2]);
6844     }
6845 
6846     if (map_to_exists(name, mode, abbr))
6847 	rettv->vval.v_number = TRUE;
6848     else
6849 	rettv->vval.v_number = FALSE;
6850 }
6851 
6852 /*
6853  * "histadd()" function
6854  */
6855     static void
6856 f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6857 {
6858 #ifdef FEAT_CMDHIST
6859     int		histype;
6860     char_u	*str;
6861     char_u	buf[NUMBUFLEN];
6862 #endif
6863 
6864     rettv->vval.v_number = FALSE;
6865     if (check_secure())
6866 	return;
6867 #ifdef FEAT_CMDHIST
6868     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6869     histype = str != NULL ? get_histtype(str) : -1;
6870     if (histype >= 0)
6871     {
6872 	str = tv_get_string_buf(&argvars[1], buf);
6873 	if (*str != NUL)
6874 	{
6875 	    init_history();
6876 	    add_to_history(histype, str, FALSE, NUL);
6877 	    rettv->vval.v_number = TRUE;
6878 	    return;
6879 	}
6880     }
6881 #endif
6882 }
6883 
6884 /*
6885  * "histdel()" function
6886  */
6887     static void
6888 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6889 {
6890 #ifdef FEAT_CMDHIST
6891     int		n;
6892     char_u	buf[NUMBUFLEN];
6893     char_u	*str;
6894 
6895     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6896     if (str == NULL)
6897 	n = 0;
6898     else if (argvars[1].v_type == VAR_UNKNOWN)
6899 	/* only one argument: clear entire history */
6900 	n = clr_history(get_histtype(str));
6901     else if (argvars[1].v_type == VAR_NUMBER)
6902 	/* index given: remove that entry */
6903 	n = del_history_idx(get_histtype(str),
6904 					  (int)tv_get_number(&argvars[1]));
6905     else
6906 	/* string given: remove all matching entries */
6907 	n = del_history_entry(get_histtype(str),
6908 				      tv_get_string_buf(&argvars[1], buf));
6909     rettv->vval.v_number = n;
6910 #endif
6911 }
6912 
6913 /*
6914  * "histget()" function
6915  */
6916     static void
6917 f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6918 {
6919 #ifdef FEAT_CMDHIST
6920     int		type;
6921     int		idx;
6922     char_u	*str;
6923 
6924     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6925     if (str == NULL)
6926 	rettv->vval.v_string = NULL;
6927     else
6928     {
6929 	type = get_histtype(str);
6930 	if (argvars[1].v_type == VAR_UNKNOWN)
6931 	    idx = get_history_idx(type);
6932 	else
6933 	    idx = (int)tv_get_number_chk(&argvars[1], NULL);
6934 						    /* -1 on type error */
6935 	rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6936     }
6937 #else
6938     rettv->vval.v_string = NULL;
6939 #endif
6940     rettv->v_type = VAR_STRING;
6941 }
6942 
6943 /*
6944  * "histnr()" function
6945  */
6946     static void
6947 f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6948 {
6949     int		i;
6950 
6951 #ifdef FEAT_CMDHIST
6952     char_u	*history = tv_get_string_chk(&argvars[0]);
6953 
6954     i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6955     if (i >= HIST_CMD && i < HIST_COUNT)
6956 	i = get_history_idx(i);
6957     else
6958 #endif
6959 	i = -1;
6960     rettv->vval.v_number = i;
6961 }
6962 
6963 /*
6964  * "highlightID(name)" function
6965  */
6966     static void
6967 f_hlID(typval_T *argvars, typval_T *rettv)
6968 {
6969     rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
6970 }
6971 
6972 /*
6973  * "highlight_exists()" function
6974  */
6975     static void
6976 f_hlexists(typval_T *argvars, typval_T *rettv)
6977 {
6978     rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
6979 }
6980 
6981 /*
6982  * "hostname()" function
6983  */
6984     static void
6985 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6986 {
6987     char_u hostname[256];
6988 
6989     mch_get_host_name(hostname, 256);
6990     rettv->v_type = VAR_STRING;
6991     rettv->vval.v_string = vim_strsave(hostname);
6992 }
6993 
6994 /*
6995  * iconv() function
6996  */
6997     static void
6998 f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6999 {
7000     char_u	buf1[NUMBUFLEN];
7001     char_u	buf2[NUMBUFLEN];
7002     char_u	*from, *to, *str;
7003     vimconv_T	vimconv;
7004 
7005     rettv->v_type = VAR_STRING;
7006     rettv->vval.v_string = NULL;
7007 
7008     str = tv_get_string(&argvars[0]);
7009     from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7010     to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
7011     vimconv.vc_type = CONV_NONE;
7012     convert_setup(&vimconv, from, to);
7013 
7014     /* If the encodings are equal, no conversion needed. */
7015     if (vimconv.vc_type == CONV_NONE)
7016 	rettv->vval.v_string = vim_strsave(str);
7017     else
7018 	rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7019 
7020     convert_setup(&vimconv, NULL, NULL);
7021     vim_free(from);
7022     vim_free(to);
7023 }
7024 
7025 /*
7026  * "indent()" function
7027  */
7028     static void
7029 f_indent(typval_T *argvars, typval_T *rettv)
7030 {
7031     linenr_T	lnum;
7032 
7033     lnum = tv_get_lnum(argvars);
7034     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7035 	rettv->vval.v_number = get_indent_lnum(lnum);
7036     else
7037 	rettv->vval.v_number = -1;
7038 }
7039 
7040 /*
7041  * "index()" function
7042  */
7043     static void
7044 f_index(typval_T *argvars, typval_T *rettv)
7045 {
7046     list_T	*l;
7047     listitem_T	*item;
7048     blob_T	*b;
7049     long	idx = 0;
7050     int		ic = FALSE;
7051     int		error = FALSE;
7052 
7053     rettv->vval.v_number = -1;
7054     if (argvars[0].v_type == VAR_BLOB)
7055     {
7056 	typval_T	tv;
7057 	int		start = 0;
7058 
7059 	if (argvars[2].v_type != VAR_UNKNOWN)
7060 	{
7061 	    start = tv_get_number_chk(&argvars[2], &error);
7062 	    if (error)
7063 		return;
7064 	}
7065 	b = argvars[0].vval.v_blob;
7066 	if (b == NULL)
7067 	    return;
7068 	if (start < 0)
7069 	{
7070 	    start = blob_len(b) + start;
7071 	    if (start < 0)
7072 		start = 0;
7073 	}
7074 
7075 	for (idx = start; idx < blob_len(b); ++idx)
7076 	{
7077 	    tv.v_type = VAR_NUMBER;
7078 	    tv.vval.v_number = blob_get(b, idx);
7079 	    if (tv_equal(&tv, &argvars[1], ic, FALSE))
7080 	    {
7081 		rettv->vval.v_number = idx;
7082 		return;
7083 	    }
7084 	}
7085 	return;
7086     }
7087     else if (argvars[0].v_type != VAR_LIST)
7088     {
7089 	emsg(_(e_listblobreq));
7090 	return;
7091     }
7092 
7093     l = argvars[0].vval.v_list;
7094     if (l != NULL)
7095     {
7096 	item = l->lv_first;
7097 	if (argvars[2].v_type != VAR_UNKNOWN)
7098 	{
7099 	    /* Start at specified item.  Use the cached index that list_find()
7100 	     * sets, so that a negative number also works. */
7101 	    item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
7102 	    idx = l->lv_idx;
7103 	    if (argvars[3].v_type != VAR_UNKNOWN)
7104 		ic = (int)tv_get_number_chk(&argvars[3], &error);
7105 	    if (error)
7106 		item = NULL;
7107 	}
7108 
7109 	for ( ; item != NULL; item = item->li_next, ++idx)
7110 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7111 	    {
7112 		rettv->vval.v_number = idx;
7113 		break;
7114 	    }
7115     }
7116 }
7117 
7118 static int inputsecret_flag = 0;
7119 
7120 /*
7121  * "input()" function
7122  *     Also handles inputsecret() when inputsecret is set.
7123  */
7124     static void
7125 f_input(typval_T *argvars, typval_T *rettv)
7126 {
7127     get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7128 }
7129 
7130 /*
7131  * "inputdialog()" function
7132  */
7133     static void
7134 f_inputdialog(typval_T *argvars, typval_T *rettv)
7135 {
7136 #if defined(FEAT_GUI_TEXTDIALOG)
7137     /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7138     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7139     {
7140 	char_u	*message;
7141 	char_u	buf[NUMBUFLEN];
7142 	char_u	*defstr = (char_u *)"";
7143 
7144 	message = tv_get_string_chk(&argvars[0]);
7145 	if (argvars[1].v_type != VAR_UNKNOWN
7146 		&& (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
7147 	    vim_strncpy(IObuff, defstr, IOSIZE - 1);
7148 	else
7149 	    IObuff[0] = NUL;
7150 	if (message != NULL && defstr != NULL
7151 		&& do_dialog(VIM_QUESTION, NULL, message,
7152 			  (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7153 	    rettv->vval.v_string = vim_strsave(IObuff);
7154 	else
7155 	{
7156 	    if (message != NULL && defstr != NULL
7157 					&& argvars[1].v_type != VAR_UNKNOWN
7158 					&& argvars[2].v_type != VAR_UNKNOWN)
7159 		rettv->vval.v_string = vim_strsave(
7160 				      tv_get_string_buf(&argvars[2], buf));
7161 	    else
7162 		rettv->vval.v_string = NULL;
7163 	}
7164 	rettv->v_type = VAR_STRING;
7165     }
7166     else
7167 #endif
7168 	get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7169 }
7170 
7171 /*
7172  * "inputlist()" function
7173  */
7174     static void
7175 f_inputlist(typval_T *argvars, typval_T *rettv)
7176 {
7177     listitem_T	*li;
7178     int		selected;
7179     int		mouse_used;
7180 
7181 #ifdef NO_CONSOLE_INPUT
7182     /* While starting up, there is no place to enter text. When running tests
7183      * with --not-a-term we assume feedkeys() will be used. */
7184     if (no_console_input() && !is_not_a_term())
7185 	return;
7186 #endif
7187     if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7188     {
7189 	semsg(_(e_listarg), "inputlist()");
7190 	return;
7191     }
7192 
7193     msg_start();
7194     msg_row = Rows - 1;	/* for when 'cmdheight' > 1 */
7195     lines_left = Rows;	/* avoid more prompt */
7196     msg_scroll = TRUE;
7197     msg_clr_eos();
7198 
7199     for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7200     {
7201 	msg_puts((char *)tv_get_string(&li->li_tv));
7202 	msg_putchar('\n');
7203     }
7204 
7205     /* Ask for choice. */
7206     selected = prompt_for_number(&mouse_used);
7207     if (mouse_used)
7208 	selected -= lines_left;
7209 
7210     rettv->vval.v_number = selected;
7211 }
7212 
7213 static garray_T	    ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7214 
7215 /*
7216  * "inputrestore()" function
7217  */
7218     static void
7219 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7220 {
7221     if (ga_userinput.ga_len > 0)
7222     {
7223 	--ga_userinput.ga_len;
7224 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7225 						       + ga_userinput.ga_len);
7226 	/* default return is zero == OK */
7227     }
7228     else if (p_verbose > 1)
7229     {
7230 	verb_msg(_("called inputrestore() more often than inputsave()"));
7231 	rettv->vval.v_number = 1; /* Failed */
7232     }
7233 }
7234 
7235 /*
7236  * "inputsave()" function
7237  */
7238     static void
7239 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7240 {
7241     /* Add an entry to the stack of typeahead storage. */
7242     if (ga_grow(&ga_userinput, 1) == OK)
7243     {
7244 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
7245 						       + ga_userinput.ga_len);
7246 	++ga_userinput.ga_len;
7247 	/* default return is zero == OK */
7248     }
7249     else
7250 	rettv->vval.v_number = 1; /* Failed */
7251 }
7252 
7253 /*
7254  * "inputsecret()" function
7255  */
7256     static void
7257 f_inputsecret(typval_T *argvars, typval_T *rettv)
7258 {
7259     ++cmdline_star;
7260     ++inputsecret_flag;
7261     f_input(argvars, rettv);
7262     --cmdline_star;
7263     --inputsecret_flag;
7264 }
7265 
7266 /*
7267  * "insert()" function
7268  */
7269     static void
7270 f_insert(typval_T *argvars, typval_T *rettv)
7271 {
7272     long	before = 0;
7273     listitem_T	*item;
7274     list_T	*l;
7275     int		error = FALSE;
7276 
7277     if (argvars[0].v_type == VAR_BLOB)
7278     {
7279 	int	    val, len;
7280 	char_u	    *p;
7281 
7282 	len = blob_len(argvars[0].vval.v_blob);
7283 	if (argvars[2].v_type != VAR_UNKNOWN)
7284 	{
7285 	    before = (long)tv_get_number_chk(&argvars[2], &error);
7286 	    if (error)
7287 		return;		// type error; errmsg already given
7288 	    if (before < 0 || before > len)
7289 	    {
7290 		semsg(_(e_invarg2), tv_get_string(&argvars[2]));
7291 		return;
7292 	    }
7293 	}
7294 	val = tv_get_number_chk(&argvars[1], &error);
7295 	if (error)
7296 	    return;
7297 	if (val < 0 || val > 255)
7298 	{
7299 	    semsg(_(e_invarg2), tv_get_string(&argvars[1]));
7300 	    return;
7301 	}
7302 
7303 	if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7304 	    return;
7305 	p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7306 	mch_memmove(p + before + 1, p + before, (size_t)len - before);
7307 	*(p + before) = val;
7308 	++argvars[0].vval.v_blob->bv_ga.ga_len;
7309 
7310 	copy_tv(&argvars[0], rettv);
7311     }
7312     else if (argvars[0].v_type != VAR_LIST)
7313 	semsg(_(e_listblobarg), "insert()");
7314     else if ((l = argvars[0].vval.v_list) != NULL
7315 	    && !var_check_lock(l->lv_lock,
7316 				     (char_u *)N_("insert() argument"), TRUE))
7317     {
7318 	if (argvars[2].v_type != VAR_UNKNOWN)
7319 	    before = (long)tv_get_number_chk(&argvars[2], &error);
7320 	if (error)
7321 	    return;		/* type error; errmsg already given */
7322 
7323 	if (before == l->lv_len)
7324 	    item = NULL;
7325 	else
7326 	{
7327 	    item = list_find(l, before);
7328 	    if (item == NULL)
7329 	    {
7330 		semsg(_(e_listidx), before);
7331 		l = NULL;
7332 	    }
7333 	}
7334 	if (l != NULL)
7335 	{
7336 	    list_insert_tv(l, &argvars[1], item);
7337 	    copy_tv(&argvars[0], rettv);
7338 	}
7339     }
7340 }
7341 
7342 /*
7343  * "invert(expr)" function
7344  */
7345     static void
7346 f_invert(typval_T *argvars, typval_T *rettv)
7347 {
7348     rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
7349 }
7350 
7351 /*
7352  * "isdirectory()" function
7353  */
7354     static void
7355 f_isdirectory(typval_T *argvars, typval_T *rettv)
7356 {
7357     rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
7358 }
7359 
7360 /*
7361  * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7362  * or it refers to a List or Dictionary that is locked.
7363  */
7364     static int
7365 tv_islocked(typval_T *tv)
7366 {
7367     return (tv->v_lock & VAR_LOCKED)
7368 	|| (tv->v_type == VAR_LIST
7369 		&& tv->vval.v_list != NULL
7370 		&& (tv->vval.v_list->lv_lock & VAR_LOCKED))
7371 	|| (tv->v_type == VAR_DICT
7372 		&& tv->vval.v_dict != NULL
7373 		&& (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7374 }
7375 
7376 /*
7377  * "islocked()" function
7378  */
7379     static void
7380 f_islocked(typval_T *argvars, typval_T *rettv)
7381 {
7382     lval_T	lv;
7383     char_u	*end;
7384     dictitem_T	*di;
7385 
7386     rettv->vval.v_number = -1;
7387     end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
7388 			     GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
7389     if (end != NULL && lv.ll_name != NULL)
7390     {
7391 	if (*end != NUL)
7392 	    emsg(_(e_trailing));
7393 	else
7394 	{
7395 	    if (lv.ll_tv == NULL)
7396 	    {
7397 		di = find_var(lv.ll_name, NULL, TRUE);
7398 		if (di != NULL)
7399 		{
7400 		    /* Consider a variable locked when:
7401 		     * 1. the variable itself is locked
7402 		     * 2. the value of the variable is locked.
7403 		     * 3. the List or Dict value is locked.
7404 		     */
7405 		    rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7406 						   || tv_islocked(&di->di_tv));
7407 		}
7408 	    }
7409 	    else if (lv.ll_range)
7410 		emsg(_("E786: Range not allowed"));
7411 	    else if (lv.ll_newkey != NULL)
7412 		semsg(_(e_dictkey), lv.ll_newkey);
7413 	    else if (lv.ll_list != NULL)
7414 		/* List item. */
7415 		rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7416 	    else
7417 		/* Dictionary item. */
7418 		rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7419 	}
7420     }
7421 
7422     clear_lval(&lv);
7423 }
7424 
7425 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7426 /*
7427  * "isnan()" function
7428  */
7429     static void
7430 f_isnan(typval_T *argvars, typval_T *rettv)
7431 {
7432     rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7433 					    && isnan(argvars[0].vval.v_float);
7434 }
7435 #endif
7436 
7437 /*
7438  * "items(dict)" function
7439  */
7440     static void
7441 f_items(typval_T *argvars, typval_T *rettv)
7442 {
7443     dict_list(argvars, rettv, 2);
7444 }
7445 
7446 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7447 /*
7448  * Get the job from the argument.
7449  * Returns NULL if the job is invalid.
7450  */
7451     static job_T *
7452 get_job_arg(typval_T *tv)
7453 {
7454     job_T *job;
7455 
7456     if (tv->v_type != VAR_JOB)
7457     {
7458 	semsg(_(e_invarg2), tv_get_string(tv));
7459 	return NULL;
7460     }
7461     job = tv->vval.v_job;
7462 
7463     if (job == NULL)
7464 	emsg(_("E916: not a valid job"));
7465     return job;
7466 }
7467 
7468 /*
7469  * "job_getchannel()" function
7470  */
7471     static void
7472 f_job_getchannel(typval_T *argvars, typval_T *rettv)
7473 {
7474     job_T	*job = get_job_arg(&argvars[0]);
7475 
7476     if (job != NULL)
7477     {
7478 	rettv->v_type = VAR_CHANNEL;
7479 	rettv->vval.v_channel = job->jv_channel;
7480 	if (job->jv_channel != NULL)
7481 	    ++job->jv_channel->ch_refcount;
7482     }
7483 }
7484 
7485 /*
7486  * "job_info()" function
7487  */
7488     static void
7489 f_job_info(typval_T *argvars, typval_T *rettv)
7490 {
7491     if (argvars[0].v_type != VAR_UNKNOWN)
7492     {
7493 	job_T	*job = get_job_arg(&argvars[0]);
7494 
7495 	if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7496 	    job_info(job, rettv->vval.v_dict);
7497     }
7498     else if (rettv_list_alloc(rettv) == OK)
7499 	job_info_all(rettv->vval.v_list);
7500 }
7501 
7502 /*
7503  * "job_setoptions()" function
7504  */
7505     static void
7506 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7507 {
7508     job_T	*job = get_job_arg(&argvars[0]);
7509     jobopt_T	opt;
7510 
7511     if (job == NULL)
7512 	return;
7513     clear_job_options(&opt);
7514     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
7515 	job_set_options(job, &opt);
7516     free_job_options(&opt);
7517 }
7518 
7519 /*
7520  * "job_start()" function
7521  */
7522     static void
7523 f_job_start(typval_T *argvars, typval_T *rettv)
7524 {
7525     rettv->v_type = VAR_JOB;
7526     if (check_restricted() || check_secure())
7527 	return;
7528     rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
7529 }
7530 
7531 /*
7532  * "job_status()" function
7533  */
7534     static void
7535 f_job_status(typval_T *argvars, typval_T *rettv)
7536 {
7537     job_T	*job = get_job_arg(&argvars[0]);
7538 
7539     if (job != NULL)
7540     {
7541 	rettv->v_type = VAR_STRING;
7542 	rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7543     }
7544 }
7545 
7546 /*
7547  * "job_stop()" function
7548  */
7549     static void
7550 f_job_stop(typval_T *argvars, typval_T *rettv)
7551 {
7552     job_T	*job = get_job_arg(&argvars[0]);
7553 
7554     if (job != NULL)
7555 	rettv->vval.v_number = job_stop(job, argvars, NULL);
7556 }
7557 #endif
7558 
7559 /*
7560  * "join()" function
7561  */
7562     static void
7563 f_join(typval_T *argvars, typval_T *rettv)
7564 {
7565     garray_T	ga;
7566     char_u	*sep;
7567 
7568     if (argvars[0].v_type != VAR_LIST)
7569     {
7570 	emsg(_(e_listreq));
7571 	return;
7572     }
7573     if (argvars[0].vval.v_list == NULL)
7574 	return;
7575     if (argvars[1].v_type == VAR_UNKNOWN)
7576 	sep = (char_u *)" ";
7577     else
7578 	sep = tv_get_string_chk(&argvars[1]);
7579 
7580     rettv->v_type = VAR_STRING;
7581 
7582     if (sep != NULL)
7583     {
7584 	ga_init2(&ga, (int)sizeof(char), 80);
7585 	list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7586 	ga_append(&ga, NUL);
7587 	rettv->vval.v_string = (char_u *)ga.ga_data;
7588     }
7589     else
7590 	rettv->vval.v_string = NULL;
7591 }
7592 
7593 /*
7594  * "js_decode()" function
7595  */
7596     static void
7597 f_js_decode(typval_T *argvars, typval_T *rettv)
7598 {
7599     js_read_T	reader;
7600 
7601     reader.js_buf = tv_get_string(&argvars[0]);
7602     reader.js_fill = NULL;
7603     reader.js_used = 0;
7604     if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7605 	emsg(_(e_invarg));
7606 }
7607 
7608 /*
7609  * "js_encode()" function
7610  */
7611     static void
7612 f_js_encode(typval_T *argvars, typval_T *rettv)
7613 {
7614     rettv->v_type = VAR_STRING;
7615     rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7616 }
7617 
7618 /*
7619  * "json_decode()" function
7620  */
7621     static void
7622 f_json_decode(typval_T *argvars, typval_T *rettv)
7623 {
7624     js_read_T	reader;
7625 
7626     reader.js_buf = tv_get_string(&argvars[0]);
7627     reader.js_fill = NULL;
7628     reader.js_used = 0;
7629     json_decode_all(&reader, rettv, 0);
7630 }
7631 
7632 /*
7633  * "json_encode()" function
7634  */
7635     static void
7636 f_json_encode(typval_T *argvars, typval_T *rettv)
7637 {
7638     rettv->v_type = VAR_STRING;
7639     rettv->vval.v_string = json_encode(&argvars[0], 0);
7640 }
7641 
7642 /*
7643  * "keys()" function
7644  */
7645     static void
7646 f_keys(typval_T *argvars, typval_T *rettv)
7647 {
7648     dict_list(argvars, rettv, 0);
7649 }
7650 
7651 /*
7652  * "last_buffer_nr()" function.
7653  */
7654     static void
7655 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7656 {
7657     int		n = 0;
7658     buf_T	*buf;
7659 
7660     FOR_ALL_BUFFERS(buf)
7661 	if (n < buf->b_fnum)
7662 	    n = buf->b_fnum;
7663 
7664     rettv->vval.v_number = n;
7665 }
7666 
7667 /*
7668  * "len()" function
7669  */
7670     static void
7671 f_len(typval_T *argvars, typval_T *rettv)
7672 {
7673     switch (argvars[0].v_type)
7674     {
7675 	case VAR_STRING:
7676 	case VAR_NUMBER:
7677 	    rettv->vval.v_number = (varnumber_T)STRLEN(
7678 					       tv_get_string(&argvars[0]));
7679 	    break;
7680 	case VAR_BLOB:
7681 	    rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7682 	    break;
7683 	case VAR_LIST:
7684 	    rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7685 	    break;
7686 	case VAR_DICT:
7687 	    rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7688 	    break;
7689 	case VAR_UNKNOWN:
7690 	case VAR_SPECIAL:
7691 	case VAR_FLOAT:
7692 	case VAR_FUNC:
7693 	case VAR_PARTIAL:
7694 	case VAR_JOB:
7695 	case VAR_CHANNEL:
7696 	    emsg(_("E701: Invalid type for len()"));
7697 	    break;
7698     }
7699 }
7700 
7701     static void
7702 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
7703 {
7704 #ifdef FEAT_LIBCALL
7705     char_u		*string_in;
7706     char_u		**string_result;
7707     int			nr_result;
7708 #endif
7709 
7710     rettv->v_type = type;
7711     if (type != VAR_NUMBER)
7712 	rettv->vval.v_string = NULL;
7713 
7714     if (check_restricted() || check_secure())
7715 	return;
7716 
7717 #ifdef FEAT_LIBCALL
7718     /* The first two args must be strings, otherwise it's meaningless */
7719     if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7720     {
7721 	string_in = NULL;
7722 	if (argvars[2].v_type == VAR_STRING)
7723 	    string_in = argvars[2].vval.v_string;
7724 	if (type == VAR_NUMBER)
7725 	    string_result = NULL;
7726 	else
7727 	    string_result = &rettv->vval.v_string;
7728 	if (mch_libcall(argvars[0].vval.v_string,
7729 			     argvars[1].vval.v_string,
7730 			     string_in,
7731 			     argvars[2].vval.v_number,
7732 			     string_result,
7733 			     &nr_result) == OK
7734 		&& type == VAR_NUMBER)
7735 	    rettv->vval.v_number = nr_result;
7736     }
7737 #endif
7738 }
7739 
7740 /*
7741  * "libcall()" function
7742  */
7743     static void
7744 f_libcall(typval_T *argvars, typval_T *rettv)
7745 {
7746     libcall_common(argvars, rettv, VAR_STRING);
7747 }
7748 
7749 /*
7750  * "libcallnr()" function
7751  */
7752     static void
7753 f_libcallnr(typval_T *argvars, typval_T *rettv)
7754 {
7755     libcall_common(argvars, rettv, VAR_NUMBER);
7756 }
7757 
7758 /*
7759  * "line(string)" function
7760  */
7761     static void
7762 f_line(typval_T *argvars, typval_T *rettv)
7763 {
7764     linenr_T	lnum = 0;
7765     pos_T	*fp;
7766     int		fnum;
7767 
7768     fp = var2fpos(&argvars[0], TRUE, &fnum);
7769     if (fp != NULL)
7770 	lnum = fp->lnum;
7771     rettv->vval.v_number = lnum;
7772 }
7773 
7774 /*
7775  * "line2byte(lnum)" function
7776  */
7777     static void
7778 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7779 {
7780 #ifndef FEAT_BYTEOFF
7781     rettv->vval.v_number = -1;
7782 #else
7783     linenr_T	lnum;
7784 
7785     lnum = tv_get_lnum(argvars);
7786     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7787 	rettv->vval.v_number = -1;
7788     else
7789 	rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7790     if (rettv->vval.v_number >= 0)
7791 	++rettv->vval.v_number;
7792 #endif
7793 }
7794 
7795 /*
7796  * "lispindent(lnum)" function
7797  */
7798     static void
7799 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7800 {
7801 #ifdef FEAT_LISP
7802     pos_T	pos;
7803     linenr_T	lnum;
7804 
7805     pos = curwin->w_cursor;
7806     lnum = tv_get_lnum(argvars);
7807     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7808     {
7809 	curwin->w_cursor.lnum = lnum;
7810 	rettv->vval.v_number = get_lisp_indent();
7811 	curwin->w_cursor = pos;
7812     }
7813     else
7814 #endif
7815 	rettv->vval.v_number = -1;
7816 }
7817 
7818 /*
7819  * "localtime()" function
7820  */
7821     static void
7822 f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7823 {
7824     rettv->vval.v_number = (varnumber_T)time(NULL);
7825 }
7826 
7827     static void
7828 get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7829 {
7830     char_u	*keys;
7831     char_u	*which;
7832     char_u	buf[NUMBUFLEN];
7833     char_u	*keys_buf = NULL;
7834     char_u	*rhs;
7835     int		mode;
7836     int		abbr = FALSE;
7837     int		get_dict = FALSE;
7838     mapblock_T	*mp;
7839     int		buffer_local;
7840 
7841     /* return empty string for failure */
7842     rettv->v_type = VAR_STRING;
7843     rettv->vval.v_string = NULL;
7844 
7845     keys = tv_get_string(&argvars[0]);
7846     if (*keys == NUL)
7847 	return;
7848 
7849     if (argvars[1].v_type != VAR_UNKNOWN)
7850     {
7851 	which = tv_get_string_buf_chk(&argvars[1], buf);
7852 	if (argvars[2].v_type != VAR_UNKNOWN)
7853 	{
7854 	    abbr = (int)tv_get_number(&argvars[2]);
7855 	    if (argvars[3].v_type != VAR_UNKNOWN)
7856 		get_dict = (int)tv_get_number(&argvars[3]);
7857 	}
7858     }
7859     else
7860 	which = (char_u *)"";
7861     if (which == NULL)
7862 	return;
7863 
7864     mode = get_map_mode(&which, 0);
7865 
7866     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7867     rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7868     vim_free(keys_buf);
7869 
7870     if (!get_dict)
7871     {
7872 	/* Return a string. */
7873 	if (rhs != NULL)
7874 	{
7875 	    if (*rhs == NUL)
7876 		rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7877 	    else
7878 		rettv->vval.v_string = str2special_save(rhs, FALSE);
7879 	}
7880 
7881     }
7882     else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7883     {
7884 	/* Return a dictionary. */
7885 	char_u	    *lhs = str2special_save(mp->m_keys, TRUE);
7886 	char_u	    *mapmode = map_mode_to_chars(mp->m_mode);
7887 	dict_T	    *dict = rettv->vval.v_dict;
7888 
7889 	dict_add_string(dict, "lhs", lhs);
7890 	dict_add_string(dict, "rhs", mp->m_orig_str);
7891 	dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7892 	dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7893 	dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
7894 	dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7895 	dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
7896 	dict_add_number(dict, "buffer", (long)buffer_local);
7897 	dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7898 	dict_add_string(dict, "mode", mapmode);
7899 
7900 	vim_free(lhs);
7901 	vim_free(mapmode);
7902     }
7903 }
7904 
7905 #ifdef FEAT_FLOAT
7906 /*
7907  * "log()" function
7908  */
7909     static void
7910 f_log(typval_T *argvars, typval_T *rettv)
7911 {
7912     float_T	f = 0.0;
7913 
7914     rettv->v_type = VAR_FLOAT;
7915     if (get_float_arg(argvars, &f) == OK)
7916 	rettv->vval.v_float = log(f);
7917     else
7918 	rettv->vval.v_float = 0.0;
7919 }
7920 
7921 /*
7922  * "log10()" function
7923  */
7924     static void
7925 f_log10(typval_T *argvars, typval_T *rettv)
7926 {
7927     float_T	f = 0.0;
7928 
7929     rettv->v_type = VAR_FLOAT;
7930     if (get_float_arg(argvars, &f) == OK)
7931 	rettv->vval.v_float = log10(f);
7932     else
7933 	rettv->vval.v_float = 0.0;
7934 }
7935 #endif
7936 
7937 #ifdef FEAT_LUA
7938 /*
7939  * "luaeval()" function
7940  */
7941     static void
7942 f_luaeval(typval_T *argvars, typval_T *rettv)
7943 {
7944     char_u	*str;
7945     char_u	buf[NUMBUFLEN];
7946 
7947     if (check_restricted() || check_secure())
7948 	return;
7949 
7950     str = tv_get_string_buf(&argvars[0], buf);
7951     do_luaeval(str, argvars + 1, rettv);
7952 }
7953 #endif
7954 
7955 /*
7956  * "map()" function
7957  */
7958     static void
7959 f_map(typval_T *argvars, typval_T *rettv)
7960 {
7961     filter_map(argvars, rettv, TRUE);
7962 }
7963 
7964 /*
7965  * "maparg()" function
7966  */
7967     static void
7968 f_maparg(typval_T *argvars, typval_T *rettv)
7969 {
7970     get_maparg(argvars, rettv, TRUE);
7971 }
7972 
7973 /*
7974  * "mapcheck()" function
7975  */
7976     static void
7977 f_mapcheck(typval_T *argvars, typval_T *rettv)
7978 {
7979     get_maparg(argvars, rettv, FALSE);
7980 }
7981 
7982 typedef enum
7983 {
7984     MATCH_END,	    /* matchend() */
7985     MATCH_MATCH,    /* match() */
7986     MATCH_STR,	    /* matchstr() */
7987     MATCH_LIST,	    /* matchlist() */
7988     MATCH_POS	    /* matchstrpos() */
7989 } matchtype_T;
7990 
7991     static void
7992 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
7993 {
7994     char_u	*str = NULL;
7995     long	len = 0;
7996     char_u	*expr = NULL;
7997     char_u	*pat;
7998     regmatch_T	regmatch;
7999     char_u	patbuf[NUMBUFLEN];
8000     char_u	strbuf[NUMBUFLEN];
8001     char_u	*save_cpo;
8002     long	start = 0;
8003     long	nth = 1;
8004     colnr_T	startcol = 0;
8005     int		match = 0;
8006     list_T	*l = NULL;
8007     listitem_T	*li = NULL;
8008     long	idx = 0;
8009     char_u	*tofree = NULL;
8010 
8011     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8012     save_cpo = p_cpo;
8013     p_cpo = (char_u *)"";
8014 
8015     rettv->vval.v_number = -1;
8016     if (type == MATCH_LIST || type == MATCH_POS)
8017     {
8018 	/* type MATCH_LIST: return empty list when there are no matches.
8019 	 * type MATCH_POS: return ["", -1, -1, -1] */
8020 	if (rettv_list_alloc(rettv) == FAIL)
8021 	    goto theend;
8022 	if (type == MATCH_POS
8023 		&& (list_append_string(rettv->vval.v_list,
8024 					    (char_u *)"", 0) == FAIL
8025 		    || list_append_number(rettv->vval.v_list,
8026 					    (varnumber_T)-1) == FAIL
8027 		    || list_append_number(rettv->vval.v_list,
8028 					    (varnumber_T)-1) == FAIL
8029 		    || list_append_number(rettv->vval.v_list,
8030 					    (varnumber_T)-1) == FAIL))
8031 	{
8032 		list_free(rettv->vval.v_list);
8033 		rettv->vval.v_list = NULL;
8034 		goto theend;
8035 	}
8036     }
8037     else if (type == MATCH_STR)
8038     {
8039 	rettv->v_type = VAR_STRING;
8040 	rettv->vval.v_string = NULL;
8041     }
8042 
8043     if (argvars[0].v_type == VAR_LIST)
8044     {
8045 	if ((l = argvars[0].vval.v_list) == NULL)
8046 	    goto theend;
8047 	li = l->lv_first;
8048     }
8049     else
8050     {
8051 	expr = str = tv_get_string(&argvars[0]);
8052 	len = (long)STRLEN(str);
8053     }
8054 
8055     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
8056     if (pat == NULL)
8057 	goto theend;
8058 
8059     if (argvars[2].v_type != VAR_UNKNOWN)
8060     {
8061 	int	    error = FALSE;
8062 
8063 	start = (long)tv_get_number_chk(&argvars[2], &error);
8064 	if (error)
8065 	    goto theend;
8066 	if (l != NULL)
8067 	{
8068 	    li = list_find(l, start);
8069 	    if (li == NULL)
8070 		goto theend;
8071 	    idx = l->lv_idx;	/* use the cached index */
8072 	}
8073 	else
8074 	{
8075 	    if (start < 0)
8076 		start = 0;
8077 	    if (start > len)
8078 		goto theend;
8079 	    /* When "count" argument is there ignore matches before "start",
8080 	     * otherwise skip part of the string.  Differs when pattern is "^"
8081 	     * or "\<". */
8082 	    if (argvars[3].v_type != VAR_UNKNOWN)
8083 		startcol = start;
8084 	    else
8085 	    {
8086 		str += start;
8087 		len -= start;
8088 	    }
8089 	}
8090 
8091 	if (argvars[3].v_type != VAR_UNKNOWN)
8092 	    nth = (long)tv_get_number_chk(&argvars[3], &error);
8093 	if (error)
8094 	    goto theend;
8095     }
8096 
8097     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8098     if (regmatch.regprog != NULL)
8099     {
8100 	regmatch.rm_ic = p_ic;
8101 
8102 	for (;;)
8103 	{
8104 	    if (l != NULL)
8105 	    {
8106 		if (li == NULL)
8107 		{
8108 		    match = FALSE;
8109 		    break;
8110 		}
8111 		vim_free(tofree);
8112 		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8113 		if (str == NULL)
8114 		    break;
8115 	    }
8116 
8117 	    match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8118 
8119 	    if (match && --nth <= 0)
8120 		break;
8121 	    if (l == NULL && !match)
8122 		break;
8123 
8124 	    /* Advance to just after the match. */
8125 	    if (l != NULL)
8126 	    {
8127 		li = li->li_next;
8128 		++idx;
8129 	    }
8130 	    else
8131 	    {
8132 		startcol = (colnr_T)(regmatch.startp[0]
8133 				    + (*mb_ptr2len)(regmatch.startp[0]) - str);
8134 		if (startcol > (colnr_T)len
8135 				      || str + startcol <= regmatch.startp[0])
8136 		{
8137 		    match = FALSE;
8138 		    break;
8139 		}
8140 	    }
8141 	}
8142 
8143 	if (match)
8144 	{
8145 	    if (type == MATCH_POS)
8146 	    {
8147 		listitem_T *li1 = rettv->vval.v_list->lv_first;
8148 		listitem_T *li2 = li1->li_next;
8149 		listitem_T *li3 = li2->li_next;
8150 		listitem_T *li4 = li3->li_next;
8151 
8152 		vim_free(li1->li_tv.vval.v_string);
8153 		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8154 				(int)(regmatch.endp[0] - regmatch.startp[0]));
8155 		li3->li_tv.vval.v_number =
8156 				      (varnumber_T)(regmatch.startp[0] - expr);
8157 		li4->li_tv.vval.v_number =
8158 					(varnumber_T)(regmatch.endp[0] - expr);
8159 		if (l != NULL)
8160 		    li2->li_tv.vval.v_number = (varnumber_T)idx;
8161 	    }
8162 	    else if (type == MATCH_LIST)
8163 	    {
8164 		int i;
8165 
8166 		/* return list with matched string and submatches */
8167 		for (i = 0; i < NSUBEXP; ++i)
8168 		{
8169 		    if (regmatch.endp[i] == NULL)
8170 		    {
8171 			if (list_append_string(rettv->vval.v_list,
8172 						     (char_u *)"", 0) == FAIL)
8173 			    break;
8174 		    }
8175 		    else if (list_append_string(rettv->vval.v_list,
8176 				regmatch.startp[i],
8177 				(int)(regmatch.endp[i] - regmatch.startp[i]))
8178 			    == FAIL)
8179 			break;
8180 		}
8181 	    }
8182 	    else if (type == MATCH_STR)
8183 	    {
8184 		/* return matched string */
8185 		if (l != NULL)
8186 		    copy_tv(&li->li_tv, rettv);
8187 		else
8188 		    rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8189 				(int)(regmatch.endp[0] - regmatch.startp[0]));
8190 	    }
8191 	    else if (l != NULL)
8192 		rettv->vval.v_number = idx;
8193 	    else
8194 	    {
8195 		if (type != MATCH_END)
8196 		    rettv->vval.v_number =
8197 				      (varnumber_T)(regmatch.startp[0] - str);
8198 		else
8199 		    rettv->vval.v_number =
8200 					(varnumber_T)(regmatch.endp[0] - str);
8201 		rettv->vval.v_number += (varnumber_T)(str - expr);
8202 	    }
8203 	}
8204 	vim_regfree(regmatch.regprog);
8205     }
8206 
8207 theend:
8208     if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
8209 	/* matchstrpos() without a list: drop the second item. */
8210 	listitem_remove(rettv->vval.v_list,
8211 				       rettv->vval.v_list->lv_first->li_next);
8212     vim_free(tofree);
8213     p_cpo = save_cpo;
8214 }
8215 
8216 /*
8217  * "match()" function
8218  */
8219     static void
8220 f_match(typval_T *argvars, typval_T *rettv)
8221 {
8222     find_some_match(argvars, rettv, MATCH_MATCH);
8223 }
8224 
8225 #ifdef FEAT_SEARCH_EXTRA
8226     static int
8227 matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8228 {
8229     dictitem_T *di;
8230 
8231     if (tv->v_type != VAR_DICT)
8232     {
8233 	emsg(_(e_dictreq));
8234 	return FAIL;
8235     }
8236 
8237     if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
8238 	*conceal_char = dict_get_string(tv->vval.v_dict,
8239 						   (char_u *)"conceal", FALSE);
8240 
8241     if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8242     {
8243 	*win = find_win_by_nr_or_id(&di->di_tv);
8244 	if (*win == NULL)
8245 	{
8246 	    emsg(_("E957: Invalid window number"));
8247 	    return FAIL;
8248 	}
8249     }
8250 
8251     return OK;
8252 }
8253 #endif
8254 
8255 /*
8256  * "matchadd()" function
8257  */
8258     static void
8259 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8260 {
8261 #ifdef FEAT_SEARCH_EXTRA
8262     char_u	buf[NUMBUFLEN];
8263     char_u	*grp = tv_get_string_buf_chk(&argvars[0], buf);	/* group */
8264     char_u	*pat = tv_get_string_buf_chk(&argvars[1], buf);	/* pattern */
8265     int		prio = 10;	/* default priority */
8266     int		id = -1;
8267     int		error = FALSE;
8268     char_u	*conceal_char = NULL;
8269     win_T	*win = curwin;
8270 
8271     rettv->vval.v_number = -1;
8272 
8273     if (grp == NULL || pat == NULL)
8274 	return;
8275     if (argvars[2].v_type != VAR_UNKNOWN)
8276     {
8277 	prio = (int)tv_get_number_chk(&argvars[2], &error);
8278 	if (argvars[3].v_type != VAR_UNKNOWN)
8279 	{
8280 	    id = (int)tv_get_number_chk(&argvars[3], &error);
8281 	    if (argvars[4].v_type != VAR_UNKNOWN
8282 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8283 		return;
8284 	}
8285     }
8286     if (error == TRUE)
8287 	return;
8288     if (id >= 1 && id <= 3)
8289     {
8290 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
8291 	return;
8292     }
8293 
8294     rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
8295 								conceal_char);
8296 #endif
8297 }
8298 
8299 /*
8300  * "matchaddpos()" function
8301  */
8302     static void
8303 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8304 {
8305 #ifdef FEAT_SEARCH_EXTRA
8306     char_u	buf[NUMBUFLEN];
8307     char_u	*group;
8308     int		prio = 10;
8309     int		id = -1;
8310     int		error = FALSE;
8311     list_T	*l;
8312     char_u	*conceal_char = NULL;
8313     win_T	*win = curwin;
8314 
8315     rettv->vval.v_number = -1;
8316 
8317     group = tv_get_string_buf_chk(&argvars[0], buf);
8318     if (group == NULL)
8319 	return;
8320 
8321     if (argvars[1].v_type != VAR_LIST)
8322     {
8323 	semsg(_(e_listarg), "matchaddpos()");
8324 	return;
8325     }
8326     l = argvars[1].vval.v_list;
8327     if (l == NULL)
8328 	return;
8329 
8330     if (argvars[2].v_type != VAR_UNKNOWN)
8331     {
8332 	prio = (int)tv_get_number_chk(&argvars[2], &error);
8333 	if (argvars[3].v_type != VAR_UNKNOWN)
8334 	{
8335 	    id = (int)tv_get_number_chk(&argvars[3], &error);
8336 
8337 	    if (argvars[4].v_type != VAR_UNKNOWN
8338 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8339 		return;
8340 	}
8341     }
8342     if (error == TRUE)
8343 	return;
8344 
8345     /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8346     if (id == 1 || id == 2)
8347     {
8348 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
8349 	return;
8350     }
8351 
8352     rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
8353 								conceal_char);
8354 #endif
8355 }
8356 
8357 /*
8358  * "matcharg()" function
8359  */
8360     static void
8361 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8362 {
8363     if (rettv_list_alloc(rettv) == OK)
8364     {
8365 #ifdef FEAT_SEARCH_EXTRA
8366 	int	    id = (int)tv_get_number(&argvars[0]);
8367 	matchitem_T *m;
8368 
8369 	if (id >= 1 && id <= 3)
8370 	{
8371 	    if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8372 	    {
8373 		list_append_string(rettv->vval.v_list,
8374 						syn_id2name(m->hlg_id), -1);
8375 		list_append_string(rettv->vval.v_list, m->pattern, -1);
8376 	    }
8377 	    else
8378 	    {
8379 		list_append_string(rettv->vval.v_list, NULL, -1);
8380 		list_append_string(rettv->vval.v_list, NULL, -1);
8381 	    }
8382 	}
8383 #endif
8384     }
8385 }
8386 
8387 /*
8388  * "matchdelete()" function
8389  */
8390     static void
8391 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8392 {
8393 #ifdef FEAT_SEARCH_EXTRA
8394     rettv->vval.v_number = match_delete(curwin,
8395 				       (int)tv_get_number(&argvars[0]), TRUE);
8396 #endif
8397 }
8398 
8399 /*
8400  * "matchend()" function
8401  */
8402     static void
8403 f_matchend(typval_T *argvars, typval_T *rettv)
8404 {
8405     find_some_match(argvars, rettv, MATCH_END);
8406 }
8407 
8408 /*
8409  * "matchlist()" function
8410  */
8411     static void
8412 f_matchlist(typval_T *argvars, typval_T *rettv)
8413 {
8414     find_some_match(argvars, rettv, MATCH_LIST);
8415 }
8416 
8417 /*
8418  * "matchstr()" function
8419  */
8420     static void
8421 f_matchstr(typval_T *argvars, typval_T *rettv)
8422 {
8423     find_some_match(argvars, rettv, MATCH_STR);
8424 }
8425 
8426 /*
8427  * "matchstrpos()" function
8428  */
8429     static void
8430 f_matchstrpos(typval_T *argvars, typval_T *rettv)
8431 {
8432     find_some_match(argvars, rettv, MATCH_POS);
8433 }
8434 
8435     static void
8436 max_min(typval_T *argvars, typval_T *rettv, int domax)
8437 {
8438     varnumber_T	n = 0;
8439     varnumber_T	i;
8440     int		error = FALSE;
8441 
8442     if (argvars[0].v_type == VAR_LIST)
8443     {
8444 	list_T		*l;
8445 	listitem_T	*li;
8446 
8447 	l = argvars[0].vval.v_list;
8448 	if (l != NULL)
8449 	{
8450 	    li = l->lv_first;
8451 	    if (li != NULL)
8452 	    {
8453 		n = tv_get_number_chk(&li->li_tv, &error);
8454 		for (;;)
8455 		{
8456 		    li = li->li_next;
8457 		    if (li == NULL)
8458 			break;
8459 		    i = tv_get_number_chk(&li->li_tv, &error);
8460 		    if (domax ? i > n : i < n)
8461 			n = i;
8462 		}
8463 	    }
8464 	}
8465     }
8466     else if (argvars[0].v_type == VAR_DICT)
8467     {
8468 	dict_T		*d;
8469 	int		first = TRUE;
8470 	hashitem_T	*hi;
8471 	int		todo;
8472 
8473 	d = argvars[0].vval.v_dict;
8474 	if (d != NULL)
8475 	{
8476 	    todo = (int)d->dv_hashtab.ht_used;
8477 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8478 	    {
8479 		if (!HASHITEM_EMPTY(hi))
8480 		{
8481 		    --todo;
8482 		    i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
8483 		    if (first)
8484 		    {
8485 			n = i;
8486 			first = FALSE;
8487 		    }
8488 		    else if (domax ? i > n : i < n)
8489 			n = i;
8490 		}
8491 	    }
8492 	}
8493     }
8494     else
8495 	semsg(_(e_listdictarg), domax ? "max()" : "min()");
8496     rettv->vval.v_number = error ? 0 : n;
8497 }
8498 
8499 /*
8500  * "max()" function
8501  */
8502     static void
8503 f_max(typval_T *argvars, typval_T *rettv)
8504 {
8505     max_min(argvars, rettv, TRUE);
8506 }
8507 
8508 /*
8509  * "min()" function
8510  */
8511     static void
8512 f_min(typval_T *argvars, typval_T *rettv)
8513 {
8514     max_min(argvars, rettv, FALSE);
8515 }
8516 
8517 /*
8518  * Create the directory in which "dir" is located, and higher levels when
8519  * needed.
8520  * Return OK or FAIL.
8521  */
8522     static int
8523 mkdir_recurse(char_u *dir, int prot)
8524 {
8525     char_u	*p;
8526     char_u	*updir;
8527     int		r = FAIL;
8528 
8529     /* Get end of directory name in "dir".
8530      * We're done when it's "/" or "c:/". */
8531     p = gettail_sep(dir);
8532     if (p <= get_past_head(dir))
8533 	return OK;
8534 
8535     /* If the directory exists we're done.  Otherwise: create it.*/
8536     updir = vim_strnsave(dir, (int)(p - dir));
8537     if (updir == NULL)
8538 	return FAIL;
8539     if (mch_isdir(updir))
8540 	r = OK;
8541     else if (mkdir_recurse(updir, prot) == OK)
8542 	r = vim_mkdir_emsg(updir, prot);
8543     vim_free(updir);
8544     return r;
8545 }
8546 
8547 #ifdef vim_mkdir
8548 /*
8549  * "mkdir()" function
8550  */
8551     static void
8552 f_mkdir(typval_T *argvars, typval_T *rettv)
8553 {
8554     char_u	*dir;
8555     char_u	buf[NUMBUFLEN];
8556     int		prot = 0755;
8557 
8558     rettv->vval.v_number = FAIL;
8559     if (check_restricted() || check_secure())
8560 	return;
8561 
8562     dir = tv_get_string_buf(&argvars[0], buf);
8563     if (*dir == NUL)
8564 	return;
8565 
8566     if (*gettail(dir) == NUL)
8567 	/* remove trailing slashes */
8568 	*gettail_sep(dir) = NUL;
8569 
8570     if (argvars[1].v_type != VAR_UNKNOWN)
8571     {
8572 	if (argvars[2].v_type != VAR_UNKNOWN)
8573 	{
8574 	    prot = (int)tv_get_number_chk(&argvars[2], NULL);
8575 	    if (prot == -1)
8576 		return;
8577 	}
8578 	if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
8579 	{
8580 	    if (mch_isdir(dir))
8581 	    {
8582 		/* With the "p" flag it's OK if the dir already exists. */
8583 		rettv->vval.v_number = OK;
8584 		return;
8585 	    }
8586 	    mkdir_recurse(dir, prot);
8587 	}
8588     }
8589     rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
8590 }
8591 #endif
8592 
8593 /*
8594  * "mode()" function
8595  */
8596     static void
8597 f_mode(typval_T *argvars, typval_T *rettv)
8598 {
8599     char_u	buf[4];
8600 
8601     vim_memset(buf, 0, sizeof(buf));
8602 
8603     if (time_for_testing == 93784)
8604     {
8605 	/* Testing the two-character code. */
8606 	buf[0] = 'x';
8607 	buf[1] = '!';
8608     }
8609 #ifdef FEAT_TERMINAL
8610     else if (term_use_loop())
8611 	buf[0] = 't';
8612 #endif
8613     else if (VIsual_active)
8614     {
8615 	if (VIsual_select)
8616 	    buf[0] = VIsual_mode + 's' - 'v';
8617 	else
8618 	    buf[0] = VIsual_mode;
8619     }
8620     else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8621 		|| State == CONFIRM)
8622     {
8623 	buf[0] = 'r';
8624 	if (State == ASKMORE)
8625 	    buf[1] = 'm';
8626 	else if (State == CONFIRM)
8627 	    buf[1] = '?';
8628     }
8629     else if (State == EXTERNCMD)
8630 	buf[0] = '!';
8631     else if (State & INSERT)
8632     {
8633 	if (State & VREPLACE_FLAG)
8634 	{
8635 	    buf[0] = 'R';
8636 	    buf[1] = 'v';
8637 	}
8638 	else
8639 	{
8640 	    if (State & REPLACE_FLAG)
8641 		buf[0] = 'R';
8642 	    else
8643 		buf[0] = 'i';
8644 #ifdef FEAT_INS_EXPAND
8645 	    if (ins_compl_active())
8646 		buf[1] = 'c';
8647 	    else if (ctrl_x_mode_not_defined_yet())
8648 		buf[1] = 'x';
8649 #endif
8650 	}
8651     }
8652     else if ((State & CMDLINE) || exmode_active)
8653     {
8654 	buf[0] = 'c';
8655 	if (exmode_active == EXMODE_VIM)
8656 	    buf[1] = 'v';
8657 	else if (exmode_active == EXMODE_NORMAL)
8658 	    buf[1] = 'e';
8659     }
8660     else
8661     {
8662 	buf[0] = 'n';
8663 	if (finish_op)
8664 	{
8665 	    buf[1] = 'o';
8666 	    // to be able to detect force-linewise/blockwise/characterwise operations
8667 	    buf[2] = motion_force;
8668 	}
8669 	else if (restart_edit == 'I' || restart_edit == 'R'
8670 							|| restart_edit == 'V')
8671 	{
8672 	    buf[1] = 'i';
8673 	    buf[2] = restart_edit;
8674 	}
8675     }
8676 
8677     /* Clear out the minor mode when the argument is not a non-zero number or
8678      * non-empty string.  */
8679     if (!non_zero_arg(&argvars[0]))
8680 	buf[1] = NUL;
8681 
8682     rettv->vval.v_string = vim_strsave(buf);
8683     rettv->v_type = VAR_STRING;
8684 }
8685 
8686 #if defined(FEAT_MZSCHEME) || defined(PROTO)
8687 /*
8688  * "mzeval()" function
8689  */
8690     static void
8691 f_mzeval(typval_T *argvars, typval_T *rettv)
8692 {
8693     char_u	*str;
8694     char_u	buf[NUMBUFLEN];
8695 
8696     if (check_restricted() || check_secure())
8697 	return;
8698     str = tv_get_string_buf(&argvars[0], buf);
8699     do_mzeval(str, rettv);
8700 }
8701 
8702     void
8703 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8704 {
8705     typval_T argvars[3];
8706 
8707     argvars[0].v_type = VAR_STRING;
8708     argvars[0].vval.v_string = name;
8709     copy_tv(args, &argvars[1]);
8710     argvars[2].v_type = VAR_UNKNOWN;
8711     f_call(argvars, rettv);
8712     clear_tv(&argvars[1]);
8713 }
8714 #endif
8715 
8716 /*
8717  * "nextnonblank()" function
8718  */
8719     static void
8720 f_nextnonblank(typval_T *argvars, typval_T *rettv)
8721 {
8722     linenr_T	lnum;
8723 
8724     for (lnum = tv_get_lnum(argvars); ; ++lnum)
8725     {
8726 	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8727 	{
8728 	    lnum = 0;
8729 	    break;
8730 	}
8731 	if (*skipwhite(ml_get(lnum)) != NUL)
8732 	    break;
8733     }
8734     rettv->vval.v_number = lnum;
8735 }
8736 
8737 /*
8738  * "nr2char()" function
8739  */
8740     static void
8741 f_nr2char(typval_T *argvars, typval_T *rettv)
8742 {
8743     char_u	buf[NUMBUFLEN];
8744 
8745     if (has_mbyte)
8746     {
8747 	int	utf8 = 0;
8748 
8749 	if (argvars[1].v_type != VAR_UNKNOWN)
8750 	    utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8751 	if (utf8)
8752 	    buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
8753 	else
8754 	    buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
8755     }
8756     else
8757     {
8758 	buf[0] = (char_u)tv_get_number(&argvars[0]);
8759 	buf[1] = NUL;
8760     }
8761     rettv->v_type = VAR_STRING;
8762     rettv->vval.v_string = vim_strsave(buf);
8763 }
8764 
8765 /*
8766  * "or(expr, expr)" function
8767  */
8768     static void
8769 f_or(typval_T *argvars, typval_T *rettv)
8770 {
8771     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8772 					| tv_get_number_chk(&argvars[1], NULL);
8773 }
8774 
8775 /*
8776  * "pathshorten()" function
8777  */
8778     static void
8779 f_pathshorten(typval_T *argvars, typval_T *rettv)
8780 {
8781     char_u	*p;
8782 
8783     rettv->v_type = VAR_STRING;
8784     p = tv_get_string_chk(&argvars[0]);
8785     if (p == NULL)
8786 	rettv->vval.v_string = NULL;
8787     else
8788     {
8789 	p = vim_strsave(p);
8790 	rettv->vval.v_string = p;
8791 	if (p != NULL)
8792 	    shorten_dir(p);
8793     }
8794 }
8795 
8796 #ifdef FEAT_PERL
8797 /*
8798  * "perleval()" function
8799  */
8800     static void
8801 f_perleval(typval_T *argvars, typval_T *rettv)
8802 {
8803     char_u	*str;
8804     char_u	buf[NUMBUFLEN];
8805 
8806     str = tv_get_string_buf(&argvars[0], buf);
8807     do_perleval(str, rettv);
8808 }
8809 #endif
8810 
8811 #ifdef FEAT_FLOAT
8812 /*
8813  * "pow()" function
8814  */
8815     static void
8816 f_pow(typval_T *argvars, typval_T *rettv)
8817 {
8818     float_T	fx = 0.0, fy = 0.0;
8819 
8820     rettv->v_type = VAR_FLOAT;
8821     if (get_float_arg(argvars, &fx) == OK
8822 				     && get_float_arg(&argvars[1], &fy) == OK)
8823 	rettv->vval.v_float = pow(fx, fy);
8824     else
8825 	rettv->vval.v_float = 0.0;
8826 }
8827 #endif
8828 
8829 /*
8830  * "prevnonblank()" function
8831  */
8832     static void
8833 f_prevnonblank(typval_T *argvars, typval_T *rettv)
8834 {
8835     linenr_T	lnum;
8836 
8837     lnum = tv_get_lnum(argvars);
8838     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8839 	lnum = 0;
8840     else
8841 	while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8842 	    --lnum;
8843     rettv->vval.v_number = lnum;
8844 }
8845 
8846 /* This dummy va_list is here because:
8847  * - passing a NULL pointer doesn't work when va_list isn't a pointer
8848  * - locally in the function results in a "used before set" warning
8849  * - using va_start() to initialize it gives "function with fixed args" error */
8850 static va_list	ap;
8851 
8852 /*
8853  * "printf()" function
8854  */
8855     static void
8856 f_printf(typval_T *argvars, typval_T *rettv)
8857 {
8858     char_u	buf[NUMBUFLEN];
8859     int		len;
8860     char_u	*s;
8861     int		saved_did_emsg = did_emsg;
8862     char	*fmt;
8863 
8864     rettv->v_type = VAR_STRING;
8865     rettv->vval.v_string = NULL;
8866 
8867     /* Get the required length, allocate the buffer and do it for real. */
8868     did_emsg = FALSE;
8869     fmt = (char *)tv_get_string_buf(&argvars[0], buf);
8870     len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
8871     if (!did_emsg)
8872     {
8873 	s = alloc(len + 1);
8874 	if (s != NULL)
8875 	{
8876 	    rettv->vval.v_string = s;
8877 	    (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8878 							      ap, argvars + 1);
8879 	}
8880     }
8881     did_emsg |= saved_did_emsg;
8882 }
8883 
8884 #ifdef FEAT_JOB_CHANNEL
8885 /*
8886  * "prompt_setcallback({buffer}, {callback})" function
8887  */
8888     static void
8889 f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8890 {
8891     buf_T	*buf;
8892     char_u	*callback;
8893     partial_T	*partial;
8894 
8895     if (check_secure())
8896 	return;
8897     buf = tv_get_buf(&argvars[0], FALSE);
8898     if (buf == NULL)
8899 	return;
8900 
8901     callback = get_callback(&argvars[1], &partial);
8902     if (callback == NULL)
8903 	return;
8904 
8905     free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8906     if (partial == NULL)
8907 	buf->b_prompt_callback = vim_strsave(callback);
8908     else
8909 	/* pointer into the partial */
8910 	buf->b_prompt_callback = callback;
8911     buf->b_prompt_partial = partial;
8912 }
8913 
8914 /*
8915  * "prompt_setinterrupt({buffer}, {callback})" function
8916  */
8917     static void
8918 f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8919 {
8920     buf_T	*buf;
8921     char_u	*callback;
8922     partial_T	*partial;
8923 
8924     if (check_secure())
8925 	return;
8926     buf = tv_get_buf(&argvars[0], FALSE);
8927     if (buf == NULL)
8928 	return;
8929 
8930     callback = get_callback(&argvars[1], &partial);
8931     if (callback == NULL)
8932 	return;
8933 
8934     free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8935     if (partial == NULL)
8936 	buf->b_prompt_interrupt = vim_strsave(callback);
8937     else
8938 	/* pointer into the partial */
8939 	buf->b_prompt_interrupt = callback;
8940     buf->b_prompt_int_partial = partial;
8941 }
8942 
8943 /*
8944  * "prompt_setprompt({buffer}, {text})" function
8945  */
8946     static void
8947 f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8948 {
8949     buf_T	*buf;
8950     char_u	*text;
8951 
8952     if (check_secure())
8953 	return;
8954     buf = tv_get_buf(&argvars[0], FALSE);
8955     if (buf == NULL)
8956 	return;
8957 
8958     text = tv_get_string(&argvars[1]);
8959     vim_free(buf->b_prompt_text);
8960     buf->b_prompt_text = vim_strsave(text);
8961 }
8962 #endif
8963 
8964 /*
8965  * "pumvisible()" function
8966  */
8967     static void
8968 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8969 {
8970 #ifdef FEAT_INS_EXPAND
8971     if (pum_visible())
8972 	rettv->vval.v_number = 1;
8973 #endif
8974 }
8975 
8976 #ifdef FEAT_PYTHON3
8977 /*
8978  * "py3eval()" function
8979  */
8980     static void
8981 f_py3eval(typval_T *argvars, typval_T *rettv)
8982 {
8983     char_u	*str;
8984     char_u	buf[NUMBUFLEN];
8985 
8986     if (check_restricted() || check_secure())
8987 	return;
8988 
8989     if (p_pyx == 0)
8990 	p_pyx = 3;
8991 
8992     str = tv_get_string_buf(&argvars[0], buf);
8993     do_py3eval(str, rettv);
8994 }
8995 #endif
8996 
8997 #ifdef FEAT_PYTHON
8998 /*
8999  * "pyeval()" function
9000  */
9001     static void
9002 f_pyeval(typval_T *argvars, typval_T *rettv)
9003 {
9004     char_u	*str;
9005     char_u	buf[NUMBUFLEN];
9006 
9007     if (check_restricted() || check_secure())
9008 	return;
9009 
9010     if (p_pyx == 0)
9011 	p_pyx = 2;
9012 
9013     str = tv_get_string_buf(&argvars[0], buf);
9014     do_pyeval(str, rettv);
9015 }
9016 #endif
9017 
9018 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9019 /*
9020  * "pyxeval()" function
9021  */
9022     static void
9023 f_pyxeval(typval_T *argvars, typval_T *rettv)
9024 {
9025     if (check_restricted() || check_secure())
9026 	return;
9027 
9028 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9029     init_pyxversion();
9030     if (p_pyx == 2)
9031 	f_pyeval(argvars, rettv);
9032     else
9033 	f_py3eval(argvars, rettv);
9034 # elif defined(FEAT_PYTHON)
9035     f_pyeval(argvars, rettv);
9036 # elif defined(FEAT_PYTHON3)
9037     f_py3eval(argvars, rettv);
9038 # endif
9039 }
9040 #endif
9041 
9042 /*
9043  * "range()" function
9044  */
9045     static void
9046 f_range(typval_T *argvars, typval_T *rettv)
9047 {
9048     varnumber_T	start;
9049     varnumber_T	end;
9050     varnumber_T	stride = 1;
9051     varnumber_T	i;
9052     int		error = FALSE;
9053 
9054     start = tv_get_number_chk(&argvars[0], &error);
9055     if (argvars[1].v_type == VAR_UNKNOWN)
9056     {
9057 	end = start - 1;
9058 	start = 0;
9059     }
9060     else
9061     {
9062 	end = tv_get_number_chk(&argvars[1], &error);
9063 	if (argvars[2].v_type != VAR_UNKNOWN)
9064 	    stride = tv_get_number_chk(&argvars[2], &error);
9065     }
9066 
9067     if (error)
9068 	return;		/* type error; errmsg already given */
9069     if (stride == 0)
9070 	emsg(_("E726: Stride is zero"));
9071     else if (stride > 0 ? end + 1 < start : end - 1 > start)
9072 	emsg(_("E727: Start past end"));
9073     else
9074     {
9075 	if (rettv_list_alloc(rettv) == OK)
9076 	    for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9077 		if (list_append_number(rettv->vval.v_list,
9078 						      (varnumber_T)i) == FAIL)
9079 		    break;
9080     }
9081 }
9082 
9083 /*
9084  * "readfile()" function
9085  */
9086     static void
9087 f_readfile(typval_T *argvars, typval_T *rettv)
9088 {
9089     int		binary = FALSE;
9090     int		blob = FALSE;
9091     int		failed = FALSE;
9092     char_u	*fname;
9093     FILE	*fd;
9094     char_u	buf[(IOSIZE/256)*256];	/* rounded to avoid odd + 1 */
9095     int		io_size = sizeof(buf);
9096     int		readlen;		/* size of last fread() */
9097     char_u	*prev	 = NULL;	/* previously read bytes, if any */
9098     long	prevlen  = 0;		/* length of data in prev */
9099     long	prevsize = 0;		/* size of prev buffer */
9100     long	maxline  = MAXLNUM;
9101     long	cnt	 = 0;
9102     char_u	*p;			/* position in buf */
9103     char_u	*start;			/* start of current line */
9104 
9105     if (argvars[1].v_type != VAR_UNKNOWN)
9106     {
9107 	if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
9108 	    binary = TRUE;
9109 	if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9110 	    blob = TRUE;
9111 
9112 	if (argvars[2].v_type != VAR_UNKNOWN)
9113 	    maxline = (long)tv_get_number(&argvars[2]);
9114     }
9115 
9116     if (blob)
9117     {
9118 	if (rettv_blob_alloc(rettv) == FAIL)
9119 	    return;
9120     }
9121     else
9122     {
9123 	if (rettv_list_alloc(rettv) == FAIL)
9124 	    return;
9125     }
9126 
9127     /* Always open the file in binary mode, library functions have a mind of
9128      * their own about CR-LF conversion. */
9129     fname = tv_get_string(&argvars[0]);
9130     if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9131     {
9132 	semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
9133 	return;
9134     }
9135 
9136     if (blob)
9137     {
9138 	if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9139 	{
9140 	    emsg("cannot read file");
9141 	    blob_free(rettv->vval.v_blob);
9142 	}
9143 	fclose(fd);
9144 	return;
9145     }
9146 
9147     while (cnt < maxline || maxline < 0)
9148     {
9149 	readlen = (int)fread(buf, 1, io_size, fd);
9150 
9151 	/* This for loop processes what was read, but is also entered at end
9152 	 * of file so that either:
9153 	 * - an incomplete line gets written
9154 	 * - a "binary" file gets an empty line at the end if it ends in a
9155 	 *   newline.  */
9156 	for (p = buf, start = buf;
9157 		p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9158 		++p)
9159 	{
9160 	    if (*p == '\n' || readlen <= 0)
9161 	    {
9162 		listitem_T  *li;
9163 		char_u	    *s	= NULL;
9164 		long_u	    len = p - start;
9165 
9166 		/* Finished a line.  Remove CRs before NL. */
9167 		if (readlen > 0 && !binary)
9168 		{
9169 		    while (len > 0 && start[len - 1] == '\r')
9170 			--len;
9171 		    /* removal may cross back to the "prev" string */
9172 		    if (len == 0)
9173 			while (prevlen > 0 && prev[prevlen - 1] == '\r')
9174 			    --prevlen;
9175 		}
9176 		if (prevlen == 0)
9177 		    s = vim_strnsave(start, (int)len);
9178 		else
9179 		{
9180 		    /* Change "prev" buffer to be the right size.  This way
9181 		     * the bytes are only copied once, and very long lines are
9182 		     * allocated only once.  */
9183 		    if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9184 		    {
9185 			mch_memmove(s + prevlen, start, len);
9186 			s[prevlen + len] = NUL;
9187 			prev = NULL; /* the list will own the string */
9188 			prevlen = prevsize = 0;
9189 		    }
9190 		}
9191 		if (s == NULL)
9192 		{
9193 		    do_outofmem_msg((long_u) prevlen + len + 1);
9194 		    failed = TRUE;
9195 		    break;
9196 		}
9197 
9198 		if ((li = listitem_alloc()) == NULL)
9199 		{
9200 		    vim_free(s);
9201 		    failed = TRUE;
9202 		    break;
9203 		}
9204 		li->li_tv.v_type = VAR_STRING;
9205 		li->li_tv.v_lock = 0;
9206 		li->li_tv.vval.v_string = s;
9207 		list_append(rettv->vval.v_list, li);
9208 
9209 		start = p + 1; /* step over newline */
9210 		if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9211 		    break;
9212 	    }
9213 	    else if (*p == NUL)
9214 		*p = '\n';
9215 	    /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF.  Do this
9216 	     * when finding the BF and check the previous two bytes. */
9217 	    else if (*p == 0xbf && enc_utf8 && !binary)
9218 	    {
9219 		/* Find the two bytes before the 0xbf.	If p is at buf, or buf
9220 		 * + 1, these may be in the "prev" string. */
9221 		char_u back1 = p >= buf + 1 ? p[-1]
9222 				     : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9223 		char_u back2 = p >= buf + 2 ? p[-2]
9224 			  : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9225 			  : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9226 
9227 		if (back2 == 0xef && back1 == 0xbb)
9228 		{
9229 		    char_u *dest = p - 2;
9230 
9231 		    /* Usually a BOM is at the beginning of a file, and so at
9232 		     * the beginning of a line; then we can just step over it.
9233 		     */
9234 		    if (start == dest)
9235 			start = p + 1;
9236 		    else
9237 		    {
9238 			/* have to shuffle buf to close gap */
9239 			int adjust_prevlen = 0;
9240 
9241 			if (dest < buf)
9242 			{
9243 			    adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9244 			    dest = buf;
9245 			}
9246 			if (readlen > p - buf + 1)
9247 			    mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9248 			readlen -= 3 - adjust_prevlen;
9249 			prevlen -= adjust_prevlen;
9250 			p = dest - 1;
9251 		    }
9252 		}
9253 	    }
9254 	} /* for */
9255 
9256 	if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9257 	    break;
9258 	if (start < p)
9259 	{
9260 	    /* There's part of a line in buf, store it in "prev". */
9261 	    if (p - start + prevlen >= prevsize)
9262 	    {
9263 		/* need bigger "prev" buffer */
9264 		char_u *newprev;
9265 
9266 		/* A common use case is ordinary text files and "prev" gets a
9267 		 * fragment of a line, so the first allocation is made
9268 		 * small, to avoid repeatedly 'allocing' large and
9269 		 * 'reallocing' small. */
9270 		if (prevsize == 0)
9271 		    prevsize = (long)(p - start);
9272 		else
9273 		{
9274 		    long grow50pc = (prevsize * 3) / 2;
9275 		    long growmin  = (long)((p - start) * 2 + prevlen);
9276 		    prevsize = grow50pc > growmin ? grow50pc : growmin;
9277 		}
9278 		newprev = prev == NULL ? alloc(prevsize)
9279 						: vim_realloc(prev, prevsize);
9280 		if (newprev == NULL)
9281 		{
9282 		    do_outofmem_msg((long_u)prevsize);
9283 		    failed = TRUE;
9284 		    break;
9285 		}
9286 		prev = newprev;
9287 	    }
9288 	    /* Add the line part to end of "prev". */
9289 	    mch_memmove(prev + prevlen, start, p - start);
9290 	    prevlen += (long)(p - start);
9291 	}
9292     } /* while */
9293 
9294     /*
9295      * For a negative line count use only the lines at the end of the file,
9296      * free the rest.
9297      */
9298     if (!failed && maxline < 0)
9299 	while (cnt > -maxline)
9300 	{
9301 	    listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9302 	    --cnt;
9303 	}
9304 
9305     if (failed)
9306     {
9307 	list_free(rettv->vval.v_list);
9308 	/* readfile doc says an empty list is returned on error */
9309 	rettv->vval.v_list = list_alloc();
9310     }
9311 
9312     vim_free(prev);
9313     fclose(fd);
9314 }
9315 
9316     static void
9317 return_register(int regname, typval_T *rettv)
9318 {
9319     char_u buf[2] = {0, 0};
9320 
9321     buf[0] = (char_u)regname;
9322     rettv->v_type = VAR_STRING;
9323     rettv->vval.v_string = vim_strsave(buf);
9324 }
9325 
9326 /*
9327  * "reg_executing()" function
9328  */
9329     static void
9330 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9331 {
9332     return_register(reg_executing, rettv);
9333 }
9334 
9335 /*
9336  * "reg_recording()" function
9337  */
9338     static void
9339 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9340 {
9341     return_register(reg_recording, rettv);
9342 }
9343 
9344 #if defined(FEAT_RELTIME)
9345 /*
9346  * Convert a List to proftime_T.
9347  * Return FAIL when there is something wrong.
9348  */
9349     static int
9350 list2proftime(typval_T *arg, proftime_T *tm)
9351 {
9352     long	n1, n2;
9353     int	error = FALSE;
9354 
9355     if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9356 					     || arg->vval.v_list->lv_len != 2)
9357 	return FAIL;
9358     n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9359     n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9360 # ifdef MSWIN
9361     tm->HighPart = n1;
9362     tm->LowPart = n2;
9363 # else
9364     tm->tv_sec = n1;
9365     tm->tv_usec = n2;
9366 # endif
9367     return error ? FAIL : OK;
9368 }
9369 #endif /* FEAT_RELTIME */
9370 
9371 /*
9372  * "reltime()" function
9373  */
9374     static void
9375 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9376 {
9377 #ifdef FEAT_RELTIME
9378     proftime_T	res;
9379     proftime_T	start;
9380 
9381     if (argvars[0].v_type == VAR_UNKNOWN)
9382     {
9383 	/* No arguments: get current time. */
9384 	profile_start(&res);
9385     }
9386     else if (argvars[1].v_type == VAR_UNKNOWN)
9387     {
9388 	if (list2proftime(&argvars[0], &res) == FAIL)
9389 	    return;
9390 	profile_end(&res);
9391     }
9392     else
9393     {
9394 	/* Two arguments: compute the difference. */
9395 	if (list2proftime(&argvars[0], &start) == FAIL
9396 		|| list2proftime(&argvars[1], &res) == FAIL)
9397 	    return;
9398 	profile_sub(&res, &start);
9399     }
9400 
9401     if (rettv_list_alloc(rettv) == OK)
9402     {
9403 	long	n1, n2;
9404 
9405 # ifdef MSWIN
9406 	n1 = res.HighPart;
9407 	n2 = res.LowPart;
9408 # else
9409 	n1 = res.tv_sec;
9410 	n2 = res.tv_usec;
9411 # endif
9412 	list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9413 	list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9414     }
9415 #endif
9416 }
9417 
9418 #ifdef FEAT_FLOAT
9419 /*
9420  * "reltimefloat()" function
9421  */
9422     static void
9423 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9424 {
9425 # ifdef FEAT_RELTIME
9426     proftime_T	tm;
9427 # endif
9428 
9429     rettv->v_type = VAR_FLOAT;
9430     rettv->vval.v_float = 0;
9431 # ifdef FEAT_RELTIME
9432     if (list2proftime(&argvars[0], &tm) == OK)
9433 	rettv->vval.v_float = profile_float(&tm);
9434 # endif
9435 }
9436 #endif
9437 
9438 /*
9439  * "reltimestr()" function
9440  */
9441     static void
9442 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9443 {
9444 #ifdef FEAT_RELTIME
9445     proftime_T	tm;
9446 #endif
9447 
9448     rettv->v_type = VAR_STRING;
9449     rettv->vval.v_string = NULL;
9450 #ifdef FEAT_RELTIME
9451     if (list2proftime(&argvars[0], &tm) == OK)
9452 	rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9453 #endif
9454 }
9455 
9456 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9457     static void
9458 make_connection(void)
9459 {
9460     if (X_DISPLAY == NULL
9461 # ifdef FEAT_GUI
9462 	    && !gui.in_use
9463 # endif
9464 	    )
9465     {
9466 	x_force_connect = TRUE;
9467 	setup_term_clip();
9468 	x_force_connect = FALSE;
9469     }
9470 }
9471 
9472     static int
9473 check_connection(void)
9474 {
9475     make_connection();
9476     if (X_DISPLAY == NULL)
9477     {
9478 	emsg(_("E240: No connection to the X server"));
9479 	return FAIL;
9480     }
9481     return OK;
9482 }
9483 #endif
9484 
9485 #ifdef FEAT_CLIENTSERVER
9486     static void
9487 remote_common(typval_T *argvars, typval_T *rettv, int expr)
9488 {
9489     char_u	*server_name;
9490     char_u	*keys;
9491     char_u	*r = NULL;
9492     char_u	buf[NUMBUFLEN];
9493     int		timeout = 0;
9494 # ifdef MSWIN
9495     HWND	w;
9496 # else
9497     Window	w;
9498 # endif
9499 
9500     if (check_restricted() || check_secure())
9501 	return;
9502 
9503 # ifdef FEAT_X11
9504     if (check_connection() == FAIL)
9505 	return;
9506 # endif
9507     if (argvars[2].v_type != VAR_UNKNOWN
9508 	    && argvars[3].v_type != VAR_UNKNOWN)
9509 	timeout = tv_get_number(&argvars[3]);
9510 
9511     server_name = tv_get_string_chk(&argvars[0]);
9512     if (server_name == NULL)
9513 	return;		/* type error; errmsg already given */
9514     keys = tv_get_string_buf(&argvars[1], buf);
9515 # ifdef MSWIN
9516     if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
9517 # else
9518     if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9519 								  0, TRUE) < 0)
9520 # endif
9521     {
9522 	if (r != NULL)
9523 	{
9524 	    emsg((char *)r);	// sending worked but evaluation failed
9525 	    vim_free(r);
9526 	}
9527 	else
9528 	    semsg(_("E241: Unable to send to %s"), server_name);
9529 	return;
9530     }
9531 
9532     rettv->vval.v_string = r;
9533 
9534     if (argvars[2].v_type != VAR_UNKNOWN)
9535     {
9536 	dictitem_T	v;
9537 	char_u		str[30];
9538 	char_u		*idvar;
9539 
9540 	idvar = tv_get_string_chk(&argvars[2]);
9541 	if (idvar != NULL && *idvar != NUL)
9542 	{
9543 	    sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9544 	    v.di_tv.v_type = VAR_STRING;
9545 	    v.di_tv.vval.v_string = vim_strsave(str);
9546 	    set_var(idvar, &v.di_tv, FALSE);
9547 	    vim_free(v.di_tv.vval.v_string);
9548 	}
9549     }
9550 }
9551 #endif
9552 
9553 /*
9554  * "remote_expr()" function
9555  */
9556     static void
9557 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9558 {
9559     rettv->v_type = VAR_STRING;
9560     rettv->vval.v_string = NULL;
9561 #ifdef FEAT_CLIENTSERVER
9562     remote_common(argvars, rettv, TRUE);
9563 #endif
9564 }
9565 
9566 /*
9567  * "remote_foreground()" function
9568  */
9569     static void
9570 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9571 {
9572 #ifdef FEAT_CLIENTSERVER
9573 # ifdef MSWIN
9574     /* On Win32 it's done in this application. */
9575     {
9576 	char_u	*server_name = tv_get_string_chk(&argvars[0]);
9577 
9578 	if (server_name != NULL)
9579 	    serverForeground(server_name);
9580     }
9581 # else
9582     /* Send a foreground() expression to the server. */
9583     argvars[1].v_type = VAR_STRING;
9584     argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9585     argvars[2].v_type = VAR_UNKNOWN;
9586     rettv->v_type = VAR_STRING;
9587     rettv->vval.v_string = NULL;
9588     remote_common(argvars, rettv, TRUE);
9589     vim_free(argvars[1].vval.v_string);
9590 # endif
9591 #endif
9592 }
9593 
9594     static void
9595 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9596 {
9597 #ifdef FEAT_CLIENTSERVER
9598     dictitem_T	v;
9599     char_u	*s = NULL;
9600 # ifdef MSWIN
9601     long_u	n = 0;
9602 # endif
9603     char_u	*serverid;
9604 
9605     if (check_restricted() || check_secure())
9606     {
9607 	rettv->vval.v_number = -1;
9608 	return;
9609     }
9610     serverid = tv_get_string_chk(&argvars[0]);
9611     if (serverid == NULL)
9612     {
9613 	rettv->vval.v_number = -1;
9614 	return;		/* type error; errmsg already given */
9615     }
9616 # ifdef MSWIN
9617     sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9618     if (n == 0)
9619 	rettv->vval.v_number = -1;
9620     else
9621     {
9622 	s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
9623 	rettv->vval.v_number = (s != NULL);
9624     }
9625 # else
9626     if (check_connection() == FAIL)
9627 	return;
9628 
9629     rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9630 						serverStrToWin(serverid), &s);
9631 # endif
9632 
9633     if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9634     {
9635 	char_u		*retvar;
9636 
9637 	v.di_tv.v_type = VAR_STRING;
9638 	v.di_tv.vval.v_string = vim_strsave(s);
9639 	retvar = tv_get_string_chk(&argvars[1]);
9640 	if (retvar != NULL)
9641 	    set_var(retvar, &v.di_tv, FALSE);
9642 	vim_free(v.di_tv.vval.v_string);
9643     }
9644 #else
9645     rettv->vval.v_number = -1;
9646 #endif
9647 }
9648 
9649     static void
9650 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9651 {
9652     char_u	*r = NULL;
9653 
9654 #ifdef FEAT_CLIENTSERVER
9655     char_u	*serverid = tv_get_string_chk(&argvars[0]);
9656 
9657     if (serverid != NULL && !check_restricted() && !check_secure())
9658     {
9659 	int timeout = 0;
9660 # ifdef MSWIN
9661 	/* The server's HWND is encoded in the 'id' parameter */
9662 	long_u		n = 0;
9663 # endif
9664 
9665 	if (argvars[1].v_type != VAR_UNKNOWN)
9666 	    timeout = tv_get_number(&argvars[1]);
9667 
9668 # ifdef MSWIN
9669 	sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9670 	if (n != 0)
9671 	    r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
9672 	if (r == NULL)
9673 # else
9674 	if (check_connection() == FAIL
9675 		|| serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9676 						       &r, FALSE, timeout) < 0)
9677 # endif
9678 	    emsg(_("E277: Unable to read a server reply"));
9679     }
9680 #endif
9681     rettv->v_type = VAR_STRING;
9682     rettv->vval.v_string = r;
9683 }
9684 
9685 /*
9686  * "remote_send()" function
9687  */
9688     static void
9689 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9690 {
9691     rettv->v_type = VAR_STRING;
9692     rettv->vval.v_string = NULL;
9693 #ifdef FEAT_CLIENTSERVER
9694     remote_common(argvars, rettv, FALSE);
9695 #endif
9696 }
9697 
9698 /*
9699  * "remote_startserver()" function
9700  */
9701     static void
9702 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9703 {
9704 #ifdef FEAT_CLIENTSERVER
9705     char_u	*server = tv_get_string_chk(&argvars[0]);
9706 
9707     if (server == NULL)
9708 	return;		/* type error; errmsg already given */
9709     if (serverName != NULL)
9710 	emsg(_("E941: already started a server"));
9711     else
9712     {
9713 # ifdef FEAT_X11
9714 	if (check_connection() == OK)
9715 	    serverRegisterName(X_DISPLAY, server);
9716 # else
9717 	serverSetName(server);
9718 # endif
9719     }
9720 #else
9721     emsg(_("E942: +clientserver feature not available"));
9722 #endif
9723 }
9724 
9725 /*
9726  * "remove()" function
9727  */
9728     static void
9729 f_remove(typval_T *argvars, typval_T *rettv)
9730 {
9731     list_T	*l;
9732     listitem_T	*item, *item2;
9733     listitem_T	*li;
9734     long	idx;
9735     long	end;
9736     char_u	*key;
9737     dict_T	*d;
9738     dictitem_T	*di;
9739     char_u	*arg_errmsg = (char_u *)N_("remove() argument");
9740     int		error = FALSE;
9741 
9742     if (argvars[0].v_type == VAR_DICT)
9743     {
9744 	if (argvars[2].v_type != VAR_UNKNOWN)
9745 	    semsg(_(e_toomanyarg), "remove()");
9746 	else if ((d = argvars[0].vval.v_dict) != NULL
9747 		&& !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
9748 	{
9749 	    key = tv_get_string_chk(&argvars[1]);
9750 	    if (key != NULL)
9751 	    {
9752 		di = dict_find(d, key, -1);
9753 		if (di == NULL)
9754 		    semsg(_(e_dictkey), key);
9755 		else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9756 			    && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9757 		{
9758 		    *rettv = di->di_tv;
9759 		    init_tv(&di->di_tv);
9760 		    dictitem_remove(d, di);
9761 		}
9762 	    }
9763 	}
9764     }
9765     else if (argvars[0].v_type == VAR_BLOB)
9766     {
9767 	idx = (long)tv_get_number_chk(&argvars[1], &error);
9768 	if (!error)
9769 	{
9770 	    blob_T  *b = argvars[0].vval.v_blob;
9771 	    int	    len = blob_len(b);
9772 	    char_u  *p;
9773 
9774 	    if (idx < 0)
9775 		// count from the end
9776 		idx = len + idx;
9777 	    if (idx < 0 || idx >= len)
9778 	    {
9779 		semsg(_(e_blobidx), idx);
9780 		return;
9781 	    }
9782 	    if (argvars[2].v_type == VAR_UNKNOWN)
9783 	    {
9784 		// Remove one item, return its value.
9785 		p = (char_u *)b->bv_ga.ga_data;
9786 		rettv->vval.v_number = (varnumber_T) *(p + idx);
9787 		mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9788 		--b->bv_ga.ga_len;
9789 	    }
9790 	    else
9791 	    {
9792 		blob_T  *blob;
9793 
9794 		// Remove range of items, return list with values.
9795 		end = (long)tv_get_number_chk(&argvars[2], &error);
9796 		if (error)
9797 		    return;
9798 		if (end < 0)
9799 		    // count from the end
9800 		    end = len + end;
9801 		if (end >= len || idx > end)
9802 		{
9803 		    semsg(_(e_blobidx), end);
9804 		    return;
9805 		}
9806 		blob = blob_alloc();
9807 		if (blob == NULL)
9808 		    return;
9809 		blob->bv_ga.ga_len = end - idx + 1;
9810 		if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9811 		{
9812 		    vim_free(blob);
9813 		    return;
9814 		}
9815 		p = (char_u *)b->bv_ga.ga_data;
9816 		mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9817 						      (size_t)(end - idx + 1));
9818 		++blob->bv_refcount;
9819 		rettv->v_type = VAR_BLOB;
9820 		rettv->vval.v_blob = blob;
9821 
9822 		mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9823 		b->bv_ga.ga_len -= end - idx + 1;
9824 	    }
9825 	}
9826     }
9827     else if (argvars[0].v_type != VAR_LIST)
9828 	semsg(_(e_listdictblobarg), "remove()");
9829     else if ((l = argvars[0].vval.v_list) != NULL
9830 			      && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
9831     {
9832 	idx = (long)tv_get_number_chk(&argvars[1], &error);
9833 	if (error)
9834 	    ;		// type error: do nothing, errmsg already given
9835 	else if ((item = list_find(l, idx)) == NULL)
9836 	    semsg(_(e_listidx), idx);
9837 	else
9838 	{
9839 	    if (argvars[2].v_type == VAR_UNKNOWN)
9840 	    {
9841 		/* Remove one item, return its value. */
9842 		vimlist_remove(l, item, item);
9843 		*rettv = item->li_tv;
9844 		vim_free(item);
9845 	    }
9846 	    else
9847 	    {
9848 		// Remove range of items, return list with values.
9849 		end = (long)tv_get_number_chk(&argvars[2], &error);
9850 		if (error)
9851 		    ;		// type error: do nothing
9852 		else if ((item2 = list_find(l, end)) == NULL)
9853 		    semsg(_(e_listidx), end);
9854 		else
9855 		{
9856 		    int	    cnt = 0;
9857 
9858 		    for (li = item; li != NULL; li = li->li_next)
9859 		    {
9860 			++cnt;
9861 			if (li == item2)
9862 			    break;
9863 		    }
9864 		    if (li == NULL)  /* didn't find "item2" after "item" */
9865 			emsg(_(e_invrange));
9866 		    else
9867 		    {
9868 			vimlist_remove(l, item, item2);
9869 			if (rettv_list_alloc(rettv) == OK)
9870 			{
9871 			    l = rettv->vval.v_list;
9872 			    l->lv_first = item;
9873 			    l->lv_last = item2;
9874 			    item->li_prev = NULL;
9875 			    item2->li_next = NULL;
9876 			    l->lv_len = cnt;
9877 			}
9878 		    }
9879 		}
9880 	    }
9881 	}
9882     }
9883 }
9884 
9885 /*
9886  * "rename({from}, {to})" function
9887  */
9888     static void
9889 f_rename(typval_T *argvars, typval_T *rettv)
9890 {
9891     char_u	buf[NUMBUFLEN];
9892 
9893     if (check_restricted() || check_secure())
9894 	rettv->vval.v_number = -1;
9895     else
9896 	rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9897 				      tv_get_string_buf(&argvars[1], buf));
9898 }
9899 
9900 /*
9901  * "repeat()" function
9902  */
9903     static void
9904 f_repeat(typval_T *argvars, typval_T *rettv)
9905 {
9906     char_u	*p;
9907     int		n;
9908     int		slen;
9909     int		len;
9910     char_u	*r;
9911     int		i;
9912 
9913     n = (int)tv_get_number(&argvars[1]);
9914     if (argvars[0].v_type == VAR_LIST)
9915     {
9916 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9917 	    while (n-- > 0)
9918 		if (list_extend(rettv->vval.v_list,
9919 					argvars[0].vval.v_list, NULL) == FAIL)
9920 		    break;
9921     }
9922     else
9923     {
9924 	p = tv_get_string(&argvars[0]);
9925 	rettv->v_type = VAR_STRING;
9926 	rettv->vval.v_string = NULL;
9927 
9928 	slen = (int)STRLEN(p);
9929 	len = slen * n;
9930 	if (len <= 0)
9931 	    return;
9932 
9933 	r = alloc(len + 1);
9934 	if (r != NULL)
9935 	{
9936 	    for (i = 0; i < n; i++)
9937 		mch_memmove(r + i * slen, p, (size_t)slen);
9938 	    r[len] = NUL;
9939 	}
9940 
9941 	rettv->vval.v_string = r;
9942     }
9943 }
9944 
9945 /*
9946  * "resolve()" function
9947  */
9948     static void
9949 f_resolve(typval_T *argvars, typval_T *rettv)
9950 {
9951     char_u	*p;
9952 #ifdef HAVE_READLINK
9953     char_u	*buf = NULL;
9954 #endif
9955 
9956     p = tv_get_string(&argvars[0]);
9957 #ifdef FEAT_SHORTCUT
9958     {
9959 	char_u	*v = NULL;
9960 
9961 	v = mch_resolve_path(p, TRUE);
9962 	if (v != NULL)
9963 	    rettv->vval.v_string = v;
9964 	else
9965 	    rettv->vval.v_string = vim_strsave(p);
9966     }
9967 #else
9968 # ifdef HAVE_READLINK
9969     {
9970 	char_u	*cpy;
9971 	int	len;
9972 	char_u	*remain = NULL;
9973 	char_u	*q;
9974 	int	is_relative_to_current = FALSE;
9975 	int	has_trailing_pathsep = FALSE;
9976 	int	limit = 100;
9977 
9978 	p = vim_strsave(p);
9979 
9980 	if (p[0] == '.' && (vim_ispathsep(p[1])
9981 				   || (p[1] == '.' && (vim_ispathsep(p[2])))))
9982 	    is_relative_to_current = TRUE;
9983 
9984 	len = STRLEN(p);
9985 	if (len > 0 && after_pathsep(p, p + len))
9986 	{
9987 	    has_trailing_pathsep = TRUE;
9988 	    p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9989 	}
9990 
9991 	q = getnextcomp(p);
9992 	if (*q != NUL)
9993 	{
9994 	    /* Separate the first path component in "p", and keep the
9995 	     * remainder (beginning with the path separator). */
9996 	    remain = vim_strsave(q - 1);
9997 	    q[-1] = NUL;
9998 	}
9999 
10000 	buf = alloc(MAXPATHL + 1);
10001 	if (buf == NULL)
10002 	    goto fail;
10003 
10004 	for (;;)
10005 	{
10006 	    for (;;)
10007 	    {
10008 		len = readlink((char *)p, (char *)buf, MAXPATHL);
10009 		if (len <= 0)
10010 		    break;
10011 		buf[len] = NUL;
10012 
10013 		if (limit-- == 0)
10014 		{
10015 		    vim_free(p);
10016 		    vim_free(remain);
10017 		    emsg(_("E655: Too many symbolic links (cycle?)"));
10018 		    rettv->vval.v_string = NULL;
10019 		    goto fail;
10020 		}
10021 
10022 		/* Ensure that the result will have a trailing path separator
10023 		 * if the argument has one. */
10024 		if (remain == NULL && has_trailing_pathsep)
10025 		    add_pathsep(buf);
10026 
10027 		/* Separate the first path component in the link value and
10028 		 * concatenate the remainders. */
10029 		q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10030 		if (*q != NUL)
10031 		{
10032 		    if (remain == NULL)
10033 			remain = vim_strsave(q - 1);
10034 		    else
10035 		    {
10036 			cpy = concat_str(q - 1, remain);
10037 			if (cpy != NULL)
10038 			{
10039 			    vim_free(remain);
10040 			    remain = cpy;
10041 			}
10042 		    }
10043 		    q[-1] = NUL;
10044 		}
10045 
10046 		q = gettail(p);
10047 		if (q > p && *q == NUL)
10048 		{
10049 		    /* Ignore trailing path separator. */
10050 		    q[-1] = NUL;
10051 		    q = gettail(p);
10052 		}
10053 		if (q > p && !mch_isFullName(buf))
10054 		{
10055 		    /* symlink is relative to directory of argument */
10056 		    cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10057 		    if (cpy != NULL)
10058 		    {
10059 			STRCPY(cpy, p);
10060 			STRCPY(gettail(cpy), buf);
10061 			vim_free(p);
10062 			p = cpy;
10063 		    }
10064 		}
10065 		else
10066 		{
10067 		    vim_free(p);
10068 		    p = vim_strsave(buf);
10069 		}
10070 	    }
10071 
10072 	    if (remain == NULL)
10073 		break;
10074 
10075 	    /* Append the first path component of "remain" to "p". */
10076 	    q = getnextcomp(remain + 1);
10077 	    len = q - remain - (*q != NUL);
10078 	    cpy = vim_strnsave(p, STRLEN(p) + len);
10079 	    if (cpy != NULL)
10080 	    {
10081 		STRNCAT(cpy, remain, len);
10082 		vim_free(p);
10083 		p = cpy;
10084 	    }
10085 	    /* Shorten "remain". */
10086 	    if (*q != NUL)
10087 		STRMOVE(remain, q - 1);
10088 	    else
10089 		VIM_CLEAR(remain);
10090 	}
10091 
10092 	/* If the result is a relative path name, make it explicitly relative to
10093 	 * the current directory if and only if the argument had this form. */
10094 	if (!vim_ispathsep(*p))
10095 	{
10096 	    if (is_relative_to_current
10097 		    && *p != NUL
10098 		    && !(p[0] == '.'
10099 			&& (p[1] == NUL
10100 			    || vim_ispathsep(p[1])
10101 			    || (p[1] == '.'
10102 				&& (p[2] == NUL
10103 				    || vim_ispathsep(p[2]))))))
10104 	    {
10105 		/* Prepend "./". */
10106 		cpy = concat_str((char_u *)"./", p);
10107 		if (cpy != NULL)
10108 		{
10109 		    vim_free(p);
10110 		    p = cpy;
10111 		}
10112 	    }
10113 	    else if (!is_relative_to_current)
10114 	    {
10115 		/* Strip leading "./". */
10116 		q = p;
10117 		while (q[0] == '.' && vim_ispathsep(q[1]))
10118 		    q += 2;
10119 		if (q > p)
10120 		    STRMOVE(p, p + 2);
10121 	    }
10122 	}
10123 
10124 	/* Ensure that the result will have no trailing path separator
10125 	 * if the argument had none.  But keep "/" or "//". */
10126 	if (!has_trailing_pathsep)
10127 	{
10128 	    q = p + STRLEN(p);
10129 	    if (after_pathsep(p, q))
10130 		*gettail_sep(p) = NUL;
10131 	}
10132 
10133 	rettv->vval.v_string = p;
10134     }
10135 # else
10136     rettv->vval.v_string = vim_strsave(p);
10137 # endif
10138 #endif
10139 
10140     simplify_filename(rettv->vval.v_string);
10141 
10142 #ifdef HAVE_READLINK
10143 fail:
10144     vim_free(buf);
10145 #endif
10146     rettv->v_type = VAR_STRING;
10147 }
10148 
10149 /*
10150  * "reverse({list})" function
10151  */
10152     static void
10153 f_reverse(typval_T *argvars, typval_T *rettv)
10154 {
10155     list_T	*l;
10156     listitem_T	*li, *ni;
10157 
10158     if (argvars[0].v_type == VAR_BLOB)
10159     {
10160 	blob_T	*b = argvars[0].vval.v_blob;
10161 	int	i, len = blob_len(b);
10162 
10163 	for (i = 0; i < len / 2; i++)
10164 	{
10165 	    int tmp = blob_get(b, i);
10166 
10167 	    blob_set(b, i, blob_get(b, len - i - 1));
10168 	    blob_set(b, len - i - 1, tmp);
10169 	}
10170 	rettv_blob_set(rettv, b);
10171 	return;
10172     }
10173 
10174     if (argvars[0].v_type != VAR_LIST)
10175 	semsg(_(e_listblobarg), "reverse()");
10176     else if ((l = argvars[0].vval.v_list) != NULL
10177 	    && !var_check_lock(l->lv_lock,
10178 				    (char_u *)N_("reverse() argument"), TRUE))
10179     {
10180 	li = l->lv_last;
10181 	l->lv_first = l->lv_last = NULL;
10182 	l->lv_len = 0;
10183 	while (li != NULL)
10184 	{
10185 	    ni = li->li_prev;
10186 	    list_append(l, li);
10187 	    li = ni;
10188 	}
10189 	rettv_list_set(rettv, l);
10190 	l->lv_idx = l->lv_len - l->lv_idx - 1;
10191     }
10192 }
10193 
10194 #define SP_NOMOVE	0x01	    /* don't move cursor */
10195 #define SP_REPEAT	0x02	    /* repeat to find outer pair */
10196 #define SP_RETCOUNT	0x04	    /* return matchcount */
10197 #define SP_SETPCMARK	0x08	    /* set previous context mark */
10198 #define SP_START	0x10	    /* accept match at start position */
10199 #define SP_SUBPAT	0x20	    /* return nr of matching sub-pattern */
10200 #define SP_END		0x40	    /* leave cursor at end of match */
10201 #define SP_COLUMN	0x80	    /* start at cursor column */
10202 
10203 /*
10204  * Get flags for a search function.
10205  * Possibly sets "p_ws".
10206  * Returns BACKWARD, FORWARD or zero (for an error).
10207  */
10208     static int
10209 get_search_arg(typval_T *varp, int *flagsp)
10210 {
10211     int		dir = FORWARD;
10212     char_u	*flags;
10213     char_u	nbuf[NUMBUFLEN];
10214     int		mask;
10215 
10216     if (varp->v_type != VAR_UNKNOWN)
10217     {
10218 	flags = tv_get_string_buf_chk(varp, nbuf);
10219 	if (flags == NULL)
10220 	    return 0;		/* type error; errmsg already given */
10221 	while (*flags != NUL)
10222 	{
10223 	    switch (*flags)
10224 	    {
10225 		case 'b': dir = BACKWARD; break;
10226 		case 'w': p_ws = TRUE; break;
10227 		case 'W': p_ws = FALSE; break;
10228 		default:  mask = 0;
10229 			  if (flagsp != NULL)
10230 			     switch (*flags)
10231 			     {
10232 				 case 'c': mask = SP_START; break;
10233 				 case 'e': mask = SP_END; break;
10234 				 case 'm': mask = SP_RETCOUNT; break;
10235 				 case 'n': mask = SP_NOMOVE; break;
10236 				 case 'p': mask = SP_SUBPAT; break;
10237 				 case 'r': mask = SP_REPEAT; break;
10238 				 case 's': mask = SP_SETPCMARK; break;
10239 				 case 'z': mask = SP_COLUMN; break;
10240 			     }
10241 			  if (mask == 0)
10242 			  {
10243 			      semsg(_(e_invarg2), flags);
10244 			      dir = 0;
10245 			  }
10246 			  else
10247 			      *flagsp |= mask;
10248 	    }
10249 	    if (dir == 0)
10250 		break;
10251 	    ++flags;
10252 	}
10253     }
10254     return dir;
10255 }
10256 
10257 /*
10258  * Shared by search() and searchpos() functions.
10259  */
10260     static int
10261 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10262 {
10263     int		flags;
10264     char_u	*pat;
10265     pos_T	pos;
10266     pos_T	save_cursor;
10267     int		save_p_ws = p_ws;
10268     int		dir;
10269     int		retval = 0;	/* default: FAIL */
10270     long	lnum_stop = 0;
10271     proftime_T	tm;
10272 #ifdef FEAT_RELTIME
10273     long	time_limit = 0;
10274 #endif
10275     int		options = SEARCH_KEEP;
10276     int		subpatnum;
10277 
10278     pat = tv_get_string(&argvars[0]);
10279     dir = get_search_arg(&argvars[1], flagsp);	/* may set p_ws */
10280     if (dir == 0)
10281 	goto theend;
10282     flags = *flagsp;
10283     if (flags & SP_START)
10284 	options |= SEARCH_START;
10285     if (flags & SP_END)
10286 	options |= SEARCH_END;
10287     if (flags & SP_COLUMN)
10288 	options |= SEARCH_COL;
10289 
10290     /* Optional arguments: line number to stop searching and timeout. */
10291     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10292     {
10293 	lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
10294 	if (lnum_stop < 0)
10295 	    goto theend;
10296 #ifdef FEAT_RELTIME
10297 	if (argvars[3].v_type != VAR_UNKNOWN)
10298 	{
10299 	    time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
10300 	    if (time_limit < 0)
10301 		goto theend;
10302 	}
10303 #endif
10304     }
10305 
10306 #ifdef FEAT_RELTIME
10307     /* Set the time limit, if there is one. */
10308     profile_setlimit(time_limit, &tm);
10309 #endif
10310 
10311     /*
10312      * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10313      * Check to make sure only those flags are set.
10314      * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10315      * flags cannot be set. Check for that condition also.
10316      */
10317     if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10318 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10319     {
10320 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
10321 	goto theend;
10322     }
10323 
10324     pos = save_cursor = curwin->w_cursor;
10325     subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
10326 			   options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
10327     if (subpatnum != FAIL)
10328     {
10329 	if (flags & SP_SUBPAT)
10330 	    retval = subpatnum;
10331 	else
10332 	    retval = pos.lnum;
10333 	if (flags & SP_SETPCMARK)
10334 	    setpcmark();
10335 	curwin->w_cursor = pos;
10336 	if (match_pos != NULL)
10337 	{
10338 	    /* Store the match cursor position */
10339 	    match_pos->lnum = pos.lnum;
10340 	    match_pos->col = pos.col + 1;
10341 	}
10342 	/* "/$" will put the cursor after the end of the line, may need to
10343 	 * correct that here */
10344 	check_cursor();
10345     }
10346 
10347     /* If 'n' flag is used: restore cursor position. */
10348     if (flags & SP_NOMOVE)
10349 	curwin->w_cursor = save_cursor;
10350     else
10351 	curwin->w_set_curswant = TRUE;
10352 theend:
10353     p_ws = save_p_ws;
10354 
10355     return retval;
10356 }
10357 
10358 #ifdef FEAT_FLOAT
10359 
10360 /*
10361  * round() is not in C90, use ceil() or floor() instead.
10362  */
10363     float_T
10364 vim_round(float_T f)
10365 {
10366     return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10367 }
10368 
10369 /*
10370  * "round({float})" function
10371  */
10372     static void
10373 f_round(typval_T *argvars, typval_T *rettv)
10374 {
10375     float_T	f = 0.0;
10376 
10377     rettv->v_type = VAR_FLOAT;
10378     if (get_float_arg(argvars, &f) == OK)
10379 	rettv->vval.v_float = vim_round(f);
10380     else
10381 	rettv->vval.v_float = 0.0;
10382 }
10383 #endif
10384 
10385 #ifdef FEAT_RUBY
10386 /*
10387  * "rubyeval()" function
10388  */
10389     static void
10390 f_rubyeval(typval_T *argvars, typval_T *rettv)
10391 {
10392     char_u	*str;
10393     char_u	buf[NUMBUFLEN];
10394 
10395     str = tv_get_string_buf(&argvars[0], buf);
10396     do_rubyeval(str, rettv);
10397 }
10398 #endif
10399 
10400 /*
10401  * "screenattr()" function
10402  */
10403     static void
10404 f_screenattr(typval_T *argvars, typval_T *rettv)
10405 {
10406     int		row;
10407     int		col;
10408     int		c;
10409 
10410     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10411     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10412     if (row < 0 || row >= screen_Rows
10413 	    || col < 0 || col >= screen_Columns)
10414 	c = -1;
10415     else
10416 	c = ScreenAttrs[LineOffset[row] + col];
10417     rettv->vval.v_number = c;
10418 }
10419 
10420 /*
10421  * "screenchar()" function
10422  */
10423     static void
10424 f_screenchar(typval_T *argvars, typval_T *rettv)
10425 {
10426     int		row;
10427     int		col;
10428     int		off;
10429     int		c;
10430 
10431     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10432     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10433     if (row < 0 || row >= screen_Rows
10434 	    || col < 0 || col >= screen_Columns)
10435 	c = -1;
10436     else
10437     {
10438 	off = LineOffset[row] + col;
10439 	if (enc_utf8 && ScreenLinesUC[off] != 0)
10440 	    c = ScreenLinesUC[off];
10441 	else
10442 	    c = ScreenLines[off];
10443     }
10444     rettv->vval.v_number = c;
10445 }
10446 
10447 /*
10448  * "screencol()" function
10449  *
10450  * First column is 1 to be consistent with virtcol().
10451  */
10452     static void
10453 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10454 {
10455     rettv->vval.v_number = screen_screencol() + 1;
10456 }
10457 
10458 /*
10459  * "screenrow()" function
10460  */
10461     static void
10462 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10463 {
10464     rettv->vval.v_number = screen_screenrow() + 1;
10465 }
10466 
10467 /*
10468  * "search()" function
10469  */
10470     static void
10471 f_search(typval_T *argvars, typval_T *rettv)
10472 {
10473     int		flags = 0;
10474 
10475     rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10476 }
10477 
10478 /*
10479  * "searchdecl()" function
10480  */
10481     static void
10482 f_searchdecl(typval_T *argvars, typval_T *rettv)
10483 {
10484     int		locally = 1;
10485     int		thisblock = 0;
10486     int		error = FALSE;
10487     char_u	*name;
10488 
10489     rettv->vval.v_number = 1;	/* default: FAIL */
10490 
10491     name = tv_get_string_chk(&argvars[0]);
10492     if (argvars[1].v_type != VAR_UNKNOWN)
10493     {
10494 	locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
10495 	if (!error && argvars[2].v_type != VAR_UNKNOWN)
10496 	    thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
10497     }
10498     if (!error && name != NULL)
10499 	rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10500 				     locally, thisblock, SEARCH_KEEP) == FAIL;
10501 }
10502 
10503 /*
10504  * Used by searchpair() and searchpairpos()
10505  */
10506     static int
10507 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10508 {
10509     char_u	*spat, *mpat, *epat;
10510     typval_T	*skip;
10511     int		save_p_ws = p_ws;
10512     int		dir;
10513     int		flags = 0;
10514     char_u	nbuf1[NUMBUFLEN];
10515     char_u	nbuf2[NUMBUFLEN];
10516     int		retval = 0;		/* default: FAIL */
10517     long	lnum_stop = 0;
10518     long	time_limit = 0;
10519 
10520     /* Get the three pattern arguments: start, middle, end. Will result in an
10521      * error if not a valid argument. */
10522     spat = tv_get_string_chk(&argvars[0]);
10523     mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10524     epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
10525     if (spat == NULL || mpat == NULL || epat == NULL)
10526 	goto theend;	    /* type error */
10527 
10528     /* Handle the optional fourth argument: flags */
10529     dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10530     if (dir == 0)
10531 	goto theend;
10532 
10533     /* Don't accept SP_END or SP_SUBPAT.
10534      * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10535      */
10536     if ((flags & (SP_END | SP_SUBPAT)) != 0
10537 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10538     {
10539 	semsg(_(e_invarg2), tv_get_string(&argvars[3]));
10540 	goto theend;
10541     }
10542 
10543     /* Using 'r' implies 'W', otherwise it doesn't work. */
10544     if (flags & SP_REPEAT)
10545 	p_ws = FALSE;
10546 
10547     /* Optional fifth argument: skip expression */
10548     if (argvars[3].v_type == VAR_UNKNOWN
10549 	    || argvars[4].v_type == VAR_UNKNOWN)
10550 	skip = NULL;
10551     else
10552     {
10553 	skip = &argvars[4];
10554 	if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10555 	    && skip->v_type != VAR_STRING)
10556 	{
10557 	    /* Type error */
10558 	    semsg(_(e_invarg2), tv_get_string(&argvars[4]));
10559 	    goto theend;
10560 	}
10561 	if (argvars[5].v_type != VAR_UNKNOWN)
10562 	{
10563 	    lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
10564 	    if (lnum_stop < 0)
10565 	    {
10566 		semsg(_(e_invarg2), tv_get_string(&argvars[5]));
10567 		goto theend;
10568 	    }
10569 #ifdef FEAT_RELTIME
10570 	    if (argvars[6].v_type != VAR_UNKNOWN)
10571 	    {
10572 		time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
10573 		if (time_limit < 0)
10574 		{
10575 		    semsg(_(e_invarg2), tv_get_string(&argvars[6]));
10576 		    goto theend;
10577 		}
10578 	    }
10579 #endif
10580 	}
10581     }
10582 
10583     retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10584 					    match_pos, lnum_stop, time_limit);
10585 
10586 theend:
10587     p_ws = save_p_ws;
10588 
10589     return retval;
10590 }
10591 
10592 /*
10593  * "searchpair()" function
10594  */
10595     static void
10596 f_searchpair(typval_T *argvars, typval_T *rettv)
10597 {
10598     rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10599 }
10600 
10601 /*
10602  * "searchpairpos()" function
10603  */
10604     static void
10605 f_searchpairpos(typval_T *argvars, typval_T *rettv)
10606 {
10607     pos_T	match_pos;
10608     int		lnum = 0;
10609     int		col = 0;
10610 
10611     if (rettv_list_alloc(rettv) == FAIL)
10612 	return;
10613 
10614     if (searchpair_cmn(argvars, &match_pos) > 0)
10615     {
10616 	lnum = match_pos.lnum;
10617 	col = match_pos.col;
10618     }
10619 
10620     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10621     list_append_number(rettv->vval.v_list, (varnumber_T)col);
10622 }
10623 
10624 /*
10625  * Search for a start/middle/end thing.
10626  * Used by searchpair(), see its documentation for the details.
10627  * Returns 0 or -1 for no match,
10628  */
10629     long
10630 do_searchpair(
10631     char_u	*spat,	    /* start pattern */
10632     char_u	*mpat,	    /* middle pattern */
10633     char_u	*epat,	    /* end pattern */
10634     int		dir,	    /* BACKWARD or FORWARD */
10635     typval_T	*skip,	    /* skip expression */
10636     int		flags,	    /* SP_SETPCMARK and other SP_ values */
10637     pos_T	*match_pos,
10638     linenr_T	lnum_stop,  /* stop at this line if not zero */
10639     long	time_limit UNUSED) /* stop after this many msec */
10640 {
10641     char_u	*save_cpo;
10642     char_u	*pat, *pat2 = NULL, *pat3 = NULL;
10643     long	retval = 0;
10644     pos_T	pos;
10645     pos_T	firstpos;
10646     pos_T	foundpos;
10647     pos_T	save_cursor;
10648     pos_T	save_pos;
10649     int		n;
10650     int		r;
10651     int		nest = 1;
10652     int		use_skip = FALSE;
10653     int		err;
10654     int		options = SEARCH_KEEP;
10655     proftime_T	tm;
10656 
10657     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10658     save_cpo = p_cpo;
10659     p_cpo = empty_option;
10660 
10661 #ifdef FEAT_RELTIME
10662     /* Set the time limit, if there is one. */
10663     profile_setlimit(time_limit, &tm);
10664 #endif
10665 
10666     /* Make two search patterns: start/end (pat2, for in nested pairs) and
10667      * start/middle/end (pat3, for the top pair). */
10668     pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10669     pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
10670     if (pat2 == NULL || pat3 == NULL)
10671 	goto theend;
10672     sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
10673     if (*mpat == NUL)
10674 	STRCPY(pat3, pat2);
10675     else
10676 	sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
10677 							    spat, epat, mpat);
10678     if (flags & SP_START)
10679 	options |= SEARCH_START;
10680 
10681     if (skip != NULL)
10682     {
10683 	/* Empty string means to not use the skip expression. */
10684 	if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10685 	    use_skip = skip->vval.v_string != NULL
10686 						&& *skip->vval.v_string != NUL;
10687     }
10688 
10689     save_cursor = curwin->w_cursor;
10690     pos = curwin->w_cursor;
10691     CLEAR_POS(&firstpos);
10692     CLEAR_POS(&foundpos);
10693     pat = pat3;
10694     for (;;)
10695     {
10696 	n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
10697 				     options, RE_SEARCH, lnum_stop, &tm, NULL);
10698 	if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
10699 	    /* didn't find it or found the first match again: FAIL */
10700 	    break;
10701 
10702 	if (firstpos.lnum == 0)
10703 	    firstpos = pos;
10704 	if (EQUAL_POS(pos, foundpos))
10705 	{
10706 	    /* Found the same position again.  Can happen with a pattern that
10707 	     * has "\zs" at the end and searching backwards.  Advance one
10708 	     * character and try again. */
10709 	    if (dir == BACKWARD)
10710 		decl(&pos);
10711 	    else
10712 		incl(&pos);
10713 	}
10714 	foundpos = pos;
10715 
10716 	/* clear the start flag to avoid getting stuck here */
10717 	options &= ~SEARCH_START;
10718 
10719 	/* If the skip pattern matches, ignore this match. */
10720 	if (use_skip)
10721 	{
10722 	    save_pos = curwin->w_cursor;
10723 	    curwin->w_cursor = pos;
10724 	    err = FALSE;
10725 	    r = eval_expr_to_bool(skip, &err);
10726 	    curwin->w_cursor = save_pos;
10727 	    if (err)
10728 	    {
10729 		/* Evaluating {skip} caused an error, break here. */
10730 		curwin->w_cursor = save_cursor;
10731 		retval = -1;
10732 		break;
10733 	    }
10734 	    if (r)
10735 		continue;
10736 	}
10737 
10738 	if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10739 	{
10740 	    /* Found end when searching backwards or start when searching
10741 	     * forward: nested pair. */
10742 	    ++nest;
10743 	    pat = pat2;		/* nested, don't search for middle */
10744 	}
10745 	else
10746 	{
10747 	    /* Found end when searching forward or start when searching
10748 	     * backward: end of (nested) pair; or found middle in outer pair. */
10749 	    if (--nest == 1)
10750 		pat = pat3;	/* outer level, search for middle */
10751 	}
10752 
10753 	if (nest == 0)
10754 	{
10755 	    /* Found the match: return matchcount or line number. */
10756 	    if (flags & SP_RETCOUNT)
10757 		++retval;
10758 	    else
10759 		retval = pos.lnum;
10760 	    if (flags & SP_SETPCMARK)
10761 		setpcmark();
10762 	    curwin->w_cursor = pos;
10763 	    if (!(flags & SP_REPEAT))
10764 		break;
10765 	    nest = 1;	    /* search for next unmatched */
10766 	}
10767     }
10768 
10769     if (match_pos != NULL)
10770     {
10771 	/* Store the match cursor position */
10772 	match_pos->lnum = curwin->w_cursor.lnum;
10773 	match_pos->col = curwin->w_cursor.col + 1;
10774     }
10775 
10776     /* If 'n' flag is used or search failed: restore cursor position. */
10777     if ((flags & SP_NOMOVE) || retval == 0)
10778 	curwin->w_cursor = save_cursor;
10779 
10780 theend:
10781     vim_free(pat2);
10782     vim_free(pat3);
10783     if (p_cpo == empty_option)
10784 	p_cpo = save_cpo;
10785     else
10786 	/* Darn, evaluating the {skip} expression changed the value. */
10787 	free_string_option(save_cpo);
10788 
10789     return retval;
10790 }
10791 
10792 /*
10793  * "searchpos()" function
10794  */
10795     static void
10796 f_searchpos(typval_T *argvars, typval_T *rettv)
10797 {
10798     pos_T	match_pos;
10799     int		lnum = 0;
10800     int		col = 0;
10801     int		n;
10802     int		flags = 0;
10803 
10804     if (rettv_list_alloc(rettv) == FAIL)
10805 	return;
10806 
10807     n = search_cmn(argvars, &match_pos, &flags);
10808     if (n > 0)
10809     {
10810 	lnum = match_pos.lnum;
10811 	col = match_pos.col;
10812     }
10813 
10814     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10815     list_append_number(rettv->vval.v_list, (varnumber_T)col);
10816     if (flags & SP_SUBPAT)
10817 	list_append_number(rettv->vval.v_list, (varnumber_T)n);
10818 }
10819 
10820     static void
10821 f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10822 {
10823 #ifdef FEAT_CLIENTSERVER
10824     char_u	buf[NUMBUFLEN];
10825     char_u	*server = tv_get_string_chk(&argvars[0]);
10826     char_u	*reply = tv_get_string_buf_chk(&argvars[1], buf);
10827 
10828     rettv->vval.v_number = -1;
10829     if (server == NULL || reply == NULL)
10830 	return;
10831     if (check_restricted() || check_secure())
10832 	return;
10833 # ifdef FEAT_X11
10834     if (check_connection() == FAIL)
10835 	return;
10836 # endif
10837 
10838     if (serverSendReply(server, reply) < 0)
10839     {
10840 	emsg(_("E258: Unable to send to client"));
10841 	return;
10842     }
10843     rettv->vval.v_number = 0;
10844 #else
10845     rettv->vval.v_number = -1;
10846 #endif
10847 }
10848 
10849     static void
10850 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10851 {
10852     char_u	*r = NULL;
10853 
10854 #ifdef FEAT_CLIENTSERVER
10855 # ifdef MSWIN
10856     r = serverGetVimNames();
10857 # else
10858     make_connection();
10859     if (X_DISPLAY != NULL)
10860 	r = serverGetVimNames(X_DISPLAY);
10861 # endif
10862 #endif
10863     rettv->v_type = VAR_STRING;
10864     rettv->vval.v_string = r;
10865 }
10866 
10867 /*
10868  * "setbufline()" function
10869  */
10870     static void
10871 f_setbufline(typval_T *argvars, typval_T *rettv)
10872 {
10873     linenr_T	lnum;
10874     buf_T	*buf;
10875 
10876     buf = tv_get_buf(&argvars[0], FALSE);
10877     if (buf == NULL)
10878 	rettv->vval.v_number = 1; /* FAIL */
10879     else
10880     {
10881 	lnum = tv_get_lnum_buf(&argvars[1], buf);
10882 	set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
10883     }
10884 }
10885 
10886 /*
10887  * "setbufvar()" function
10888  */
10889     static void
10890 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10891 {
10892     buf_T	*buf;
10893     char_u	*varname, *bufvarname;
10894     typval_T	*varp;
10895     char_u	nbuf[NUMBUFLEN];
10896 
10897     if (check_secure())
10898 	return;
10899     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
10900     varname = tv_get_string_chk(&argvars[1]);
10901     buf = tv_get_buf(&argvars[0], FALSE);
10902     varp = &argvars[2];
10903 
10904     if (buf != NULL && varname != NULL && varp != NULL)
10905     {
10906 	if (*varname == '&')
10907 	{
10908 	    long	numval;
10909 	    char_u	*strval;
10910 	    int		error = FALSE;
10911 	    aco_save_T	aco;
10912 
10913 	    /* set curbuf to be our buf, temporarily */
10914 	    aucmd_prepbuf(&aco, buf);
10915 
10916 	    ++varname;
10917 	    numval = (long)tv_get_number_chk(varp, &error);
10918 	    strval = tv_get_string_buf_chk(varp, nbuf);
10919 	    if (!error && strval != NULL)
10920 		set_option_value(varname, numval, strval, OPT_LOCAL);
10921 
10922 	    /* reset notion of buffer */
10923 	    aucmd_restbuf(&aco);
10924 	}
10925 	else
10926 	{
10927 	    buf_T *save_curbuf = curbuf;
10928 
10929 	    bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10930 	    if (bufvarname != NULL)
10931 	    {
10932 		curbuf = buf;
10933 		STRCPY(bufvarname, "b:");
10934 		STRCPY(bufvarname + 2, varname);
10935 		set_var(bufvarname, varp, TRUE);
10936 		vim_free(bufvarname);
10937 		curbuf = save_curbuf;
10938 	    }
10939 	}
10940     }
10941 }
10942 
10943     static void
10944 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10945 {
10946     dict_T	*d;
10947     dictitem_T	*di;
10948     char_u	*csearch;
10949 
10950     if (argvars[0].v_type != VAR_DICT)
10951     {
10952 	emsg(_(e_dictreq));
10953 	return;
10954     }
10955 
10956     if ((d = argvars[0].vval.v_dict) != NULL)
10957     {
10958 	csearch = dict_get_string(d, (char_u *)"char", FALSE);
10959 	if (csearch != NULL)
10960 	{
10961 	    if (enc_utf8)
10962 	    {
10963 		int pcc[MAX_MCO];
10964 		int c = utfc_ptr2char(csearch, pcc);
10965 
10966 		set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10967 	    }
10968 	    else
10969 		set_last_csearch(PTR2CHAR(csearch),
10970 						csearch, MB_PTR2LEN(csearch));
10971 	}
10972 
10973 	di = dict_find(d, (char_u *)"forward", -1);
10974 	if (di != NULL)
10975 	    set_csearch_direction((int)tv_get_number(&di->di_tv)
10976 							? FORWARD : BACKWARD);
10977 
10978 	di = dict_find(d, (char_u *)"until", -1);
10979 	if (di != NULL)
10980 	    set_csearch_until(!!tv_get_number(&di->di_tv));
10981     }
10982 }
10983 
10984 /*
10985  * "setcmdpos()" function
10986  */
10987     static void
10988 f_setcmdpos(typval_T *argvars, typval_T *rettv)
10989 {
10990     int		pos = (int)tv_get_number(&argvars[0]) - 1;
10991 
10992     if (pos >= 0)
10993 	rettv->vval.v_number = set_cmdline_pos(pos);
10994 }
10995 
10996 /*
10997  * "setfperm({fname}, {mode})" function
10998  */
10999     static void
11000 f_setfperm(typval_T *argvars, typval_T *rettv)
11001 {
11002     char_u	*fname;
11003     char_u	modebuf[NUMBUFLEN];
11004     char_u	*mode_str;
11005     int		i;
11006     int		mask;
11007     int		mode = 0;
11008 
11009     rettv->vval.v_number = 0;
11010     fname = tv_get_string_chk(&argvars[0]);
11011     if (fname == NULL)
11012 	return;
11013     mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
11014     if (mode_str == NULL)
11015 	return;
11016     if (STRLEN(mode_str) != 9)
11017     {
11018 	semsg(_(e_invarg2), mode_str);
11019 	return;
11020     }
11021 
11022     mask = 1;
11023     for (i = 8; i >= 0; --i)
11024     {
11025 	if (mode_str[i] != '-')
11026 	    mode |= mask;
11027 	mask = mask << 1;
11028     }
11029     rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11030 }
11031 
11032 /*
11033  * "setline()" function
11034  */
11035     static void
11036 f_setline(typval_T *argvars, typval_T *rettv)
11037 {
11038     linenr_T	lnum = tv_get_lnum(&argvars[0]);
11039 
11040     set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
11041 }
11042 
11043 /*
11044  * Used by "setqflist()" and "setloclist()" functions
11045  */
11046     static void
11047 set_qf_ll_list(
11048     win_T	*wp UNUSED,
11049     typval_T	*list_arg UNUSED,
11050     typval_T	*action_arg UNUSED,
11051     typval_T	*what_arg UNUSED,
11052     typval_T	*rettv)
11053 {
11054 #ifdef FEAT_QUICKFIX
11055     static char *e_invact = N_("E927: Invalid action: '%s'");
11056     char_u	*act;
11057     int		action = 0;
11058     static int	recursive = 0;
11059 #endif
11060 
11061     rettv->vval.v_number = -1;
11062 
11063 #ifdef FEAT_QUICKFIX
11064     if (list_arg->v_type != VAR_LIST)
11065 	emsg(_(e_listreq));
11066     else if (recursive != 0)
11067 	emsg(_(e_au_recursive));
11068     else
11069     {
11070 	list_T  *l = list_arg->vval.v_list;
11071 	dict_T	*d = NULL;
11072 	int	valid_dict = TRUE;
11073 
11074 	if (action_arg->v_type == VAR_STRING)
11075 	{
11076 	    act = tv_get_string_chk(action_arg);
11077 	    if (act == NULL)
11078 		return;		/* type error; errmsg already given */
11079 	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11080 		    act[1] == NUL)
11081 		action = *act;
11082 	    else
11083 		semsg(_(e_invact), act);
11084 	}
11085 	else if (action_arg->v_type == VAR_UNKNOWN)
11086 	    action = ' ';
11087 	else
11088 	    emsg(_(e_stringreq));
11089 
11090 	if (action_arg->v_type != VAR_UNKNOWN
11091 		&& what_arg->v_type != VAR_UNKNOWN)
11092 	{
11093 	    if (what_arg->v_type == VAR_DICT)
11094 		d = what_arg->vval.v_dict;
11095 	    else
11096 	    {
11097 		emsg(_(e_dictreq));
11098 		valid_dict = FALSE;
11099 	    }
11100 	}
11101 
11102 	++recursive;
11103 	if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
11104 		     (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11105 		     d) == OK)
11106 	    rettv->vval.v_number = 0;
11107 	--recursive;
11108     }
11109 #endif
11110 }
11111 
11112 /*
11113  * "setloclist()" function
11114  */
11115     static void
11116 f_setloclist(typval_T *argvars, typval_T *rettv)
11117 {
11118     win_T	*win;
11119 
11120     rettv->vval.v_number = -1;
11121 
11122     win = find_win_by_nr_or_id(&argvars[0]);
11123     if (win != NULL)
11124 	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
11125 }
11126 
11127 /*
11128  * "setmatches()" function
11129  */
11130     static void
11131 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11132 {
11133 #ifdef FEAT_SEARCH_EXTRA
11134     list_T	*l;
11135     listitem_T	*li;
11136     dict_T	*d;
11137     list_T	*s = NULL;
11138 
11139     rettv->vval.v_number = -1;
11140     if (argvars[0].v_type != VAR_LIST)
11141     {
11142 	emsg(_(e_listreq));
11143 	return;
11144     }
11145     if ((l = argvars[0].vval.v_list) != NULL)
11146     {
11147 
11148 	/* To some extent make sure that we are dealing with a list from
11149 	 * "getmatches()". */
11150 	li = l->lv_first;
11151 	while (li != NULL)
11152 	{
11153 	    if (li->li_tv.v_type != VAR_DICT
11154 		    || (d = li->li_tv.vval.v_dict) == NULL)
11155 	    {
11156 		emsg(_(e_invarg));
11157 		return;
11158 	    }
11159 	    if (!(dict_find(d, (char_u *)"group", -1) != NULL
11160 			&& (dict_find(d, (char_u *)"pattern", -1) != NULL
11161 			    || dict_find(d, (char_u *)"pos1", -1) != NULL)
11162 			&& dict_find(d, (char_u *)"priority", -1) != NULL
11163 			&& dict_find(d, (char_u *)"id", -1) != NULL))
11164 	    {
11165 		emsg(_(e_invarg));
11166 		return;
11167 	    }
11168 	    li = li->li_next;
11169 	}
11170 
11171 	clear_matches(curwin);
11172 	li = l->lv_first;
11173 	while (li != NULL)
11174 	{
11175 	    int		i = 0;
11176 	    char_u	buf[5];
11177 	    dictitem_T  *di;
11178 	    char_u	*group;
11179 	    int		priority;
11180 	    int		id;
11181 	    char_u	*conceal;
11182 
11183 	    d = li->li_tv.vval.v_dict;
11184 	    if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11185 	    {
11186 		if (s == NULL)
11187 		{
11188 		    s = list_alloc();
11189 		    if (s == NULL)
11190 			return;
11191 		}
11192 
11193 		/* match from matchaddpos() */
11194 		for (i = 1; i < 9; i++)
11195 		{
11196 		    sprintf((char *)buf, (char *)"pos%d", i);
11197 		    if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11198 		    {
11199 			if (di->di_tv.v_type != VAR_LIST)
11200 			    return;
11201 
11202 			list_append_tv(s, &di->di_tv);
11203 			s->lv_refcount++;
11204 		    }
11205 		    else
11206 			break;
11207 		}
11208 	    }
11209 
11210 	    group = dict_get_string(d, (char_u *)"group", TRUE);
11211 	    priority = (int)dict_get_number(d, (char_u *)"priority");
11212 	    id = (int)dict_get_number(d, (char_u *)"id");
11213 	    conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
11214 			      ? dict_get_string(d, (char_u *)"conceal", TRUE)
11215 			      : NULL;
11216 	    if (i == 0)
11217 	    {
11218 		match_add(curwin, group,
11219 		    dict_get_string(d, (char_u *)"pattern", FALSE),
11220 		    priority, id, NULL, conceal);
11221 	    }
11222 	    else
11223 	    {
11224 		match_add(curwin, group, NULL, priority, id, s, conceal);
11225 		list_unref(s);
11226 		s = NULL;
11227 	    }
11228 	    vim_free(group);
11229 	    vim_free(conceal);
11230 
11231 	    li = li->li_next;
11232 	}
11233 	rettv->vval.v_number = 0;
11234     }
11235 #endif
11236 }
11237 
11238 /*
11239  * "setpos()" function
11240  */
11241     static void
11242 f_setpos(typval_T *argvars, typval_T *rettv)
11243 {
11244     pos_T	pos;
11245     int		fnum;
11246     char_u	*name;
11247     colnr_T	curswant = -1;
11248 
11249     rettv->vval.v_number = -1;
11250     name = tv_get_string_chk(argvars);
11251     if (name != NULL)
11252     {
11253 	if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11254 	{
11255 	    if (--pos.col < 0)
11256 		pos.col = 0;
11257 	    if (name[0] == '.' && name[1] == NUL)
11258 	    {
11259 		/* set cursor; "fnum" is ignored */
11260 		curwin->w_cursor = pos;
11261 		if (curswant >= 0)
11262 		{
11263 		    curwin->w_curswant = curswant - 1;
11264 		    curwin->w_set_curswant = FALSE;
11265 		}
11266 		check_cursor();
11267 		rettv->vval.v_number = 0;
11268 	    }
11269 	    else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11270 	    {
11271 		/* set mark */
11272 		if (setmark_pos(name[1], &pos, fnum) == OK)
11273 		    rettv->vval.v_number = 0;
11274 	    }
11275 	    else
11276 		emsg(_(e_invarg));
11277 	}
11278     }
11279 }
11280 
11281 /*
11282  * "setqflist()" function
11283  */
11284     static void
11285 f_setqflist(typval_T *argvars, typval_T *rettv)
11286 {
11287     set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
11288 }
11289 
11290 /*
11291  * "setreg()" function
11292  */
11293     static void
11294 f_setreg(typval_T *argvars, typval_T *rettv)
11295 {
11296     int		regname;
11297     char_u	*strregname;
11298     char_u	*stropt;
11299     char_u	*strval;
11300     int		append;
11301     char_u	yank_type;
11302     long	block_len;
11303 
11304     block_len = -1;
11305     yank_type = MAUTO;
11306     append = FALSE;
11307 
11308     strregname = tv_get_string_chk(argvars);
11309     rettv->vval.v_number = 1;		/* FAIL is default */
11310 
11311     if (strregname == NULL)
11312 	return;		/* type error; errmsg already given */
11313     regname = *strregname;
11314     if (regname == 0 || regname == '@')
11315 	regname = '"';
11316 
11317     if (argvars[2].v_type != VAR_UNKNOWN)
11318     {
11319 	stropt = tv_get_string_chk(&argvars[2]);
11320 	if (stropt == NULL)
11321 	    return;		/* type error */
11322 	for (; *stropt != NUL; ++stropt)
11323 	    switch (*stropt)
11324 	    {
11325 		case 'a': case 'A':	/* append */
11326 		    append = TRUE;
11327 		    break;
11328 		case 'v': case 'c':	/* character-wise selection */
11329 		    yank_type = MCHAR;
11330 		    break;
11331 		case 'V': case 'l':	/* line-wise selection */
11332 		    yank_type = MLINE;
11333 		    break;
11334 		case 'b': case Ctrl_V:	/* block-wise selection */
11335 		    yank_type = MBLOCK;
11336 		    if (VIM_ISDIGIT(stropt[1]))
11337 		    {
11338 			++stropt;
11339 			block_len = getdigits(&stropt) - 1;
11340 			--stropt;
11341 		    }
11342 		    break;
11343 	    }
11344     }
11345 
11346     if (argvars[1].v_type == VAR_LIST)
11347     {
11348 	char_u		**lstval;
11349 	char_u		**allocval;
11350 	char_u		buf[NUMBUFLEN];
11351 	char_u		**curval;
11352 	char_u		**curallocval;
11353 	list_T		*ll = argvars[1].vval.v_list;
11354 	listitem_T	*li;
11355 	int		len;
11356 
11357 	/* If the list is NULL handle like an empty list. */
11358 	len = ll == NULL ? 0 : ll->lv_len;
11359 
11360 	/* First half: use for pointers to result lines; second half: use for
11361 	 * pointers to allocated copies. */
11362 	lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11363 	if (lstval == NULL)
11364 	    return;
11365 	curval = lstval;
11366 	allocval = lstval + len + 2;
11367 	curallocval = allocval;
11368 
11369 	for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11370 							     li = li->li_next)
11371 	{
11372 	    strval = tv_get_string_buf_chk(&li->li_tv, buf);
11373 	    if (strval == NULL)
11374 		goto free_lstval;
11375 	    if (strval == buf)
11376 	    {
11377 		/* Need to make a copy, next tv_get_string_buf_chk() will
11378 		 * overwrite the string. */
11379 		strval = vim_strsave(buf);
11380 		if (strval == NULL)
11381 		    goto free_lstval;
11382 		*curallocval++ = strval;
11383 	    }
11384 	    *curval++ = strval;
11385 	}
11386 	*curval++ = NULL;
11387 
11388 	write_reg_contents_lst(regname, lstval, -1,
11389 						append, yank_type, block_len);
11390 free_lstval:
11391 	while (curallocval > allocval)
11392 	    vim_free(*--curallocval);
11393 	vim_free(lstval);
11394     }
11395     else
11396     {
11397 	strval = tv_get_string_chk(&argvars[1]);
11398 	if (strval == NULL)
11399 	    return;
11400 	write_reg_contents_ex(regname, strval, -1,
11401 						append, yank_type, block_len);
11402     }
11403     rettv->vval.v_number = 0;
11404 }
11405 
11406 /*
11407  * "settabvar()" function
11408  */
11409     static void
11410 f_settabvar(typval_T *argvars, typval_T *rettv)
11411 {
11412     tabpage_T	*save_curtab;
11413     tabpage_T	*tp;
11414     char_u	*varname, *tabvarname;
11415     typval_T	*varp;
11416 
11417     rettv->vval.v_number = 0;
11418 
11419     if (check_secure())
11420 	return;
11421 
11422     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11423     varname = tv_get_string_chk(&argvars[1]);
11424     varp = &argvars[2];
11425 
11426     if (varname != NULL && varp != NULL && tp != NULL)
11427     {
11428 	save_curtab = curtab;
11429 	goto_tabpage_tp(tp, FALSE, FALSE);
11430 
11431 	tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11432 	if (tabvarname != NULL)
11433 	{
11434 	    STRCPY(tabvarname, "t:");
11435 	    STRCPY(tabvarname + 2, varname);
11436 	    set_var(tabvarname, varp, TRUE);
11437 	    vim_free(tabvarname);
11438 	}
11439 
11440 	/* Restore current tabpage */
11441 	if (valid_tabpage(save_curtab))
11442 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
11443     }
11444 }
11445 
11446 /*
11447  * "settabwinvar()" function
11448  */
11449     static void
11450 f_settabwinvar(typval_T *argvars, typval_T *rettv)
11451 {
11452     setwinvar(argvars, rettv, 1);
11453 }
11454 
11455 /*
11456  * "settagstack()" function
11457  */
11458     static void
11459 f_settagstack(typval_T *argvars, typval_T *rettv)
11460 {
11461     static char *e_invact2 = N_("E962: Invalid action: '%s'");
11462     win_T	*wp;
11463     dict_T	*d;
11464     int		action = 'r';
11465 
11466     rettv->vval.v_number = -1;
11467 
11468     // first argument: window number or id
11469     wp = find_win_by_nr_or_id(&argvars[0]);
11470     if (wp == NULL)
11471 	return;
11472 
11473     // second argument: dict with items to set in the tag stack
11474     if (argvars[1].v_type != VAR_DICT)
11475     {
11476 	emsg(_(e_dictreq));
11477 	return;
11478     }
11479     d = argvars[1].vval.v_dict;
11480     if (d == NULL)
11481 	return;
11482 
11483     // third argument: action - 'a' for append and 'r' for replace.
11484     // default is to replace the stack.
11485     if (argvars[2].v_type == VAR_UNKNOWN)
11486 	action = 'r';
11487     else if (argvars[2].v_type == VAR_STRING)
11488     {
11489 	char_u	*actstr;
11490 	actstr = tv_get_string_chk(&argvars[2]);
11491 	if (actstr == NULL)
11492 	    return;
11493 	if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11494 	    action = *actstr;
11495 	else
11496 	{
11497 	    semsg(_(e_invact2), actstr);
11498 	    return;
11499 	}
11500     }
11501     else
11502     {
11503 	emsg(_(e_stringreq));
11504 	return;
11505     }
11506 
11507     if (set_tagstack(wp, d, action) == OK)
11508 	rettv->vval.v_number = 0;
11509 }
11510 
11511 /*
11512  * "setwinvar()" function
11513  */
11514     static void
11515 f_setwinvar(typval_T *argvars, typval_T *rettv)
11516 {
11517     setwinvar(argvars, rettv, 0);
11518 }
11519 
11520 #ifdef FEAT_CRYPT
11521 /*
11522  * "sha256({string})" function
11523  */
11524     static void
11525 f_sha256(typval_T *argvars, typval_T *rettv)
11526 {
11527     char_u	*p;
11528 
11529     p = tv_get_string(&argvars[0]);
11530     rettv->vval.v_string = vim_strsave(
11531 				    sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11532     rettv->v_type = VAR_STRING;
11533 }
11534 #endif /* FEAT_CRYPT */
11535 
11536 /*
11537  * "shellescape({string})" function
11538  */
11539     static void
11540 f_shellescape(typval_T *argvars, typval_T *rettv)
11541 {
11542     int do_special = non_zero_arg(&argvars[1]);
11543 
11544     rettv->vval.v_string = vim_strsave_shellescape(
11545 			   tv_get_string(&argvars[0]), do_special, do_special);
11546     rettv->v_type = VAR_STRING;
11547 }
11548 
11549 /*
11550  * shiftwidth() function
11551  */
11552     static void
11553 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11554 {
11555     rettv->vval.v_number = 0;
11556 
11557     if (argvars[0].v_type != VAR_UNKNOWN)
11558     {
11559 	long	col;
11560 
11561 	col = (long)tv_get_number_chk(argvars, NULL);
11562 	if (col < 0)
11563 	    return;	// type error; errmsg already given
11564 #ifdef FEAT_VARTABS
11565 	rettv->vval.v_number = get_sw_value_col(curbuf, col);
11566 	return;
11567 #endif
11568     }
11569 
11570     rettv->vval.v_number = get_sw_value(curbuf);
11571 }
11572 
11573 #ifdef FEAT_SIGNS
11574 /*
11575  * "sign_define()" function
11576  */
11577     static void
11578 f_sign_define(typval_T *argvars, typval_T *rettv)
11579 {
11580     char_u	*name;
11581     dict_T	*dict;
11582     char_u	*icon = NULL;
11583     char_u	*linehl = NULL;
11584     char_u	*text = NULL;
11585     char_u	*texthl = NULL;
11586 
11587     rettv->vval.v_number = -1;
11588 
11589     name = tv_get_string_chk(&argvars[0]);
11590     if (name == NULL)
11591 	return;
11592 
11593     if (argvars[1].v_type != VAR_UNKNOWN)
11594     {
11595 	if (argvars[1].v_type != VAR_DICT)
11596 	{
11597 	    emsg(_(e_dictreq));
11598 	    return;
11599 	}
11600 
11601 	// sign attributes
11602 	dict = argvars[1].vval.v_dict;
11603 	if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11604 	    icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11605 	if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11606 	    linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11607 	if (dict_find(dict, (char_u *)"text", -1) != NULL)
11608 	    text = dict_get_string(dict, (char_u *)"text", TRUE);
11609 	if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11610 	    texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11611     }
11612 
11613     if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11614 	rettv->vval.v_number = 0;
11615 
11616     vim_free(icon);
11617     vim_free(linehl);
11618     vim_free(text);
11619     vim_free(texthl);
11620 }
11621 
11622 /*
11623  * "sign_getdefined()" function
11624  */
11625     static void
11626 f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11627 {
11628     char_u	*name = NULL;
11629 
11630     if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11631 	return;
11632 
11633     if (argvars[0].v_type != VAR_UNKNOWN)
11634 	name = tv_get_string(&argvars[0]);
11635 
11636     sign_getlist(name, rettv->vval.v_list);
11637 }
11638 
11639 /*
11640  * "sign_getplaced()" function
11641  */
11642     static void
11643 f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11644 {
11645     buf_T	*buf = NULL;
11646     dict_T	*dict;
11647     dictitem_T	*di;
11648     linenr_T	lnum = 0;
11649     int		sign_id = 0;
11650     char_u	*group = NULL;
11651     int		notanum = FALSE;
11652 
11653     if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11654 	return;
11655 
11656     if (argvars[0].v_type != VAR_UNKNOWN)
11657     {
11658 	// get signs placed in the specified buffer
11659 	buf = get_buf_arg(&argvars[0]);
11660 	if (buf == NULL)
11661 	    return;
11662 
11663 	if (argvars[1].v_type != VAR_UNKNOWN)
11664 	{
11665 	    if (argvars[1].v_type != VAR_DICT ||
11666 				((dict = argvars[1].vval.v_dict) == NULL))
11667 	    {
11668 		emsg(_(e_dictreq));
11669 		return;
11670 	    }
11671 	    if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11672 	    {
11673 		// get signs placed at this line
11674 		(void)tv_get_number_chk(&di->di_tv, &notanum);
11675 		if (notanum)
11676 		    return;
11677 		lnum = tv_get_lnum(&di->di_tv);
11678 	    }
11679 	    if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11680 	    {
11681 		// get sign placed with this identifier
11682 		sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
11683 		if (notanum)
11684 		    return;
11685 	    }
11686 	    if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11687 	    {
11688 		group = tv_get_string_chk(&di->di_tv);
11689 		if (group == NULL)
11690 		    return;
11691 		if (*group == '\0')	// empty string means global group
11692 		    group = NULL;
11693 	    }
11694 	}
11695     }
11696 
11697     sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11698 }
11699 
11700 /*
11701  * "sign_jump()" function
11702  */
11703     static void
11704 f_sign_jump(typval_T *argvars, typval_T *rettv)
11705 {
11706     int		sign_id;
11707     char_u	*sign_group = NULL;
11708     buf_T	*buf;
11709     int		notanum = FALSE;
11710 
11711     rettv->vval.v_number = -1;
11712 
11713     // Sign identifier
11714     sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11715     if (notanum)
11716 	return;
11717     if (sign_id <= 0)
11718     {
11719 	emsg(_(e_invarg));
11720 	return;
11721     }
11722 
11723     // Sign group
11724     sign_group = tv_get_string_chk(&argvars[1]);
11725     if (sign_group == NULL)
11726 	return;
11727     if (sign_group[0] == '\0')
11728 	sign_group = NULL;			// global sign group
11729     else
11730     {
11731 	sign_group = vim_strsave(sign_group);
11732 	if (sign_group == NULL)
11733 	    return;
11734     }
11735 
11736     // Buffer to place the sign
11737     buf = get_buf_arg(&argvars[2]);
11738     if (buf == NULL)
11739 	goto cleanup;
11740 
11741     rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11742 
11743 cleanup:
11744     vim_free(sign_group);
11745 }
11746 
11747 /*
11748  * "sign_place()" function
11749  */
11750     static void
11751 f_sign_place(typval_T *argvars, typval_T *rettv)
11752 {
11753     int		sign_id;
11754     char_u	*group = NULL;
11755     char_u	*sign_name;
11756     buf_T	*buf;
11757     dict_T	*dict;
11758     dictitem_T	*di;
11759     linenr_T	lnum = 0;
11760     int		prio = SIGN_DEF_PRIO;
11761     int		notanum = FALSE;
11762 
11763     rettv->vval.v_number = -1;
11764 
11765     // Sign identifier
11766     sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11767     if (notanum)
11768 	return;
11769     if (sign_id < 0)
11770     {
11771 	emsg(_(e_invarg));
11772 	return;
11773     }
11774 
11775     // Sign group
11776     group = tv_get_string_chk(&argvars[1]);
11777     if (group == NULL)
11778 	return;
11779     if (group[0] == '\0')
11780 	group = NULL;			// global sign group
11781     else
11782     {
11783 	group = vim_strsave(group);
11784 	if (group == NULL)
11785 	    return;
11786     }
11787 
11788     // Sign name
11789     sign_name = tv_get_string_chk(&argvars[2]);
11790     if (sign_name == NULL)
11791 	goto cleanup;
11792 
11793     // Buffer to place the sign
11794     buf = get_buf_arg(&argvars[3]);
11795     if (buf == NULL)
11796 	goto cleanup;
11797 
11798     if (argvars[4].v_type != VAR_UNKNOWN)
11799     {
11800 	if (argvars[4].v_type != VAR_DICT ||
11801 				((dict = argvars[4].vval.v_dict) == NULL))
11802 	{
11803 	    emsg(_(e_dictreq));
11804 	    goto cleanup;
11805 	}
11806 
11807 	// Line number where the sign is to be placed
11808 	if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11809 	{
11810 	    (void)tv_get_number_chk(&di->di_tv, &notanum);
11811 	    if (notanum)
11812 		goto cleanup;
11813 	    lnum = tv_get_lnum(&di->di_tv);
11814 	}
11815 	if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11816 	{
11817 	    // Sign priority
11818 	    prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
11819 	    if (notanum)
11820 		goto cleanup;
11821 	}
11822     }
11823 
11824     if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11825 	rettv->vval.v_number = sign_id;
11826 
11827 cleanup:
11828     vim_free(group);
11829 }
11830 
11831 /*
11832  * "sign_undefine()" function
11833  */
11834     static void
11835 f_sign_undefine(typval_T *argvars, typval_T *rettv)
11836 {
11837     char_u *name;
11838 
11839     rettv->vval.v_number = -1;
11840 
11841     if (argvars[0].v_type == VAR_UNKNOWN)
11842     {
11843 	// Free all the signs
11844 	free_signs();
11845 	rettv->vval.v_number = 0;
11846     }
11847     else
11848     {
11849 	// Free only the specified sign
11850 	name = tv_get_string_chk(&argvars[0]);
11851 	if (name == NULL)
11852 	    return;
11853 
11854 	if (sign_undefine_by_name(name) == OK)
11855 	    rettv->vval.v_number = 0;
11856     }
11857 }
11858 
11859 /*
11860  * "sign_unplace()" function
11861  */
11862     static void
11863 f_sign_unplace(typval_T *argvars, typval_T *rettv)
11864 {
11865     dict_T	*dict;
11866     dictitem_T	*di;
11867     int		sign_id = 0;
11868     buf_T	*buf = NULL;
11869     char_u	*group = NULL;
11870 
11871     rettv->vval.v_number = -1;
11872 
11873     if (argvars[0].v_type != VAR_STRING)
11874     {
11875 	emsg(_(e_invarg));
11876 	return;
11877     }
11878 
11879     group = tv_get_string(&argvars[0]);
11880     if (group[0] == '\0')
11881 	group = NULL;			// global sign group
11882     else
11883     {
11884 	group = vim_strsave(group);
11885 	if (group == NULL)
11886 	    return;
11887     }
11888 
11889     if (argvars[1].v_type != VAR_UNKNOWN)
11890     {
11891 	if (argvars[1].v_type != VAR_DICT)
11892 	{
11893 	    emsg(_(e_dictreq));
11894 	    goto cleanup;
11895 	}
11896 	dict = argvars[1].vval.v_dict;
11897 
11898 	if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11899 	{
11900 	    buf = get_buf_arg(&di->di_tv);
11901 	    if (buf == NULL)
11902 		goto cleanup;
11903 	}
11904 	if (dict_find(dict, (char_u *)"id", -1) != NULL)
11905 	    sign_id = dict_get_number(dict, (char_u *)"id");
11906     }
11907 
11908     if (buf == NULL)
11909     {
11910 	// Delete the sign in all the buffers
11911 	FOR_ALL_BUFFERS(buf)
11912 	    if (sign_unplace(sign_id, group, buf, 0) == OK)
11913 		rettv->vval.v_number = 0;
11914     }
11915     else
11916     {
11917 	if (sign_unplace(sign_id, group, buf, 0) == OK)
11918 	    rettv->vval.v_number = 0;
11919     }
11920 
11921 cleanup:
11922     vim_free(group);
11923 }
11924 #endif
11925 
11926 /*
11927  * "simplify()" function
11928  */
11929     static void
11930 f_simplify(typval_T *argvars, typval_T *rettv)
11931 {
11932     char_u	*p;
11933 
11934     p = tv_get_string(&argvars[0]);
11935     rettv->vval.v_string = vim_strsave(p);
11936     simplify_filename(rettv->vval.v_string);	/* simplify in place */
11937     rettv->v_type = VAR_STRING;
11938 }
11939 
11940 #ifdef FEAT_FLOAT
11941 /*
11942  * "sin()" function
11943  */
11944     static void
11945 f_sin(typval_T *argvars, typval_T *rettv)
11946 {
11947     float_T	f = 0.0;
11948 
11949     rettv->v_type = VAR_FLOAT;
11950     if (get_float_arg(argvars, &f) == OK)
11951 	rettv->vval.v_float = sin(f);
11952     else
11953 	rettv->vval.v_float = 0.0;
11954 }
11955 
11956 /*
11957  * "sinh()" function
11958  */
11959     static void
11960 f_sinh(typval_T *argvars, typval_T *rettv)
11961 {
11962     float_T	f = 0.0;
11963 
11964     rettv->v_type = VAR_FLOAT;
11965     if (get_float_arg(argvars, &f) == OK)
11966 	rettv->vval.v_float = sinh(f);
11967     else
11968 	rettv->vval.v_float = 0.0;
11969 }
11970 #endif
11971 
11972 static int
11973 #ifdef __BORLANDC__
11974     _RTLENTRYF
11975 #endif
11976 	item_compare(const void *s1, const void *s2);
11977 static int
11978 #ifdef __BORLANDC__
11979     _RTLENTRYF
11980 #endif
11981 	item_compare2(const void *s1, const void *s2);
11982 
11983 /* struct used in the array that's given to qsort() */
11984 typedef struct
11985 {
11986     listitem_T	*item;
11987     int		idx;
11988 } sortItem_T;
11989 
11990 /* struct storing information about current sort */
11991 typedef struct
11992 {
11993     int		item_compare_ic;
11994     int		item_compare_numeric;
11995     int		item_compare_numbers;
11996 #ifdef FEAT_FLOAT
11997     int		item_compare_float;
11998 #endif
11999     char_u	*item_compare_func;
12000     partial_T	*item_compare_partial;
12001     dict_T	*item_compare_selfdict;
12002     int		item_compare_func_err;
12003     int		item_compare_keep_zero;
12004 } sortinfo_T;
12005 static sortinfo_T	*sortinfo = NULL;
12006 #define ITEM_COMPARE_FAIL 999
12007 
12008 /*
12009  * Compare functions for f_sort() and f_uniq() below.
12010  */
12011     static int
12012 #ifdef __BORLANDC__
12013 _RTLENTRYF
12014 #endif
12015 item_compare(const void *s1, const void *s2)
12016 {
12017     sortItem_T  *si1, *si2;
12018     typval_T	*tv1, *tv2;
12019     char_u	*p1, *p2;
12020     char_u	*tofree1 = NULL, *tofree2 = NULL;
12021     int		res;
12022     char_u	numbuf1[NUMBUFLEN];
12023     char_u	numbuf2[NUMBUFLEN];
12024 
12025     si1 = (sortItem_T *)s1;
12026     si2 = (sortItem_T *)s2;
12027     tv1 = &si1->item->li_tv;
12028     tv2 = &si2->item->li_tv;
12029 
12030     if (sortinfo->item_compare_numbers)
12031     {
12032 	varnumber_T	v1 = tv_get_number(tv1);
12033 	varnumber_T	v2 = tv_get_number(tv2);
12034 
12035 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12036     }
12037 
12038 #ifdef FEAT_FLOAT
12039     if (sortinfo->item_compare_float)
12040     {
12041 	float_T	v1 = tv_get_float(tv1);
12042 	float_T	v2 = tv_get_float(tv2);
12043 
12044 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12045     }
12046 #endif
12047 
12048     /* tv2string() puts quotes around a string and allocates memory.  Don't do
12049      * that for string variables. Use a single quote when comparing with a
12050      * non-string to do what the docs promise. */
12051     if (tv1->v_type == VAR_STRING)
12052     {
12053 	if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12054 	    p1 = (char_u *)"'";
12055 	else
12056 	    p1 = tv1->vval.v_string;
12057     }
12058     else
12059 	p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12060     if (tv2->v_type == VAR_STRING)
12061     {
12062 	if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12063 	    p2 = (char_u *)"'";
12064 	else
12065 	    p2 = tv2->vval.v_string;
12066     }
12067     else
12068 	p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12069     if (p1 == NULL)
12070 	p1 = (char_u *)"";
12071     if (p2 == NULL)
12072 	p2 = (char_u *)"";
12073     if (!sortinfo->item_compare_numeric)
12074     {
12075 	if (sortinfo->item_compare_ic)
12076 	    res = STRICMP(p1, p2);
12077 	else
12078 	    res = STRCMP(p1, p2);
12079     }
12080     else
12081     {
12082 	double n1, n2;
12083 	n1 = strtod((char *)p1, (char **)&p1);
12084 	n2 = strtod((char *)p2, (char **)&p2);
12085 	res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12086     }
12087 
12088     /* When the result would be zero, compare the item indexes.  Makes the
12089      * sort stable. */
12090     if (res == 0 && !sortinfo->item_compare_keep_zero)
12091 	res = si1->idx > si2->idx ? 1 : -1;
12092 
12093     vim_free(tofree1);
12094     vim_free(tofree2);
12095     return res;
12096 }
12097 
12098     static int
12099 #ifdef __BORLANDC__
12100 _RTLENTRYF
12101 #endif
12102 item_compare2(const void *s1, const void *s2)
12103 {
12104     sortItem_T  *si1, *si2;
12105     int		res;
12106     typval_T	rettv;
12107     typval_T	argv[3];
12108     int		dummy;
12109     char_u	*func_name;
12110     partial_T	*partial = sortinfo->item_compare_partial;
12111 
12112     /* shortcut after failure in previous call; compare all items equal */
12113     if (sortinfo->item_compare_func_err)
12114 	return 0;
12115 
12116     si1 = (sortItem_T *)s1;
12117     si2 = (sortItem_T *)s2;
12118 
12119     if (partial == NULL)
12120 	func_name = sortinfo->item_compare_func;
12121     else
12122 	func_name = partial_name(partial);
12123 
12124     /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
12125      * in the copy without changing the original list items. */
12126     copy_tv(&si1->item->li_tv, &argv[0]);
12127     copy_tv(&si2->item->li_tv, &argv[1]);
12128 
12129     rettv.v_type = VAR_UNKNOWN;		/* clear_tv() uses this */
12130     res = call_func(func_name, (int)STRLEN(func_name),
12131 				 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
12132 				 partial, sortinfo->item_compare_selfdict);
12133     clear_tv(&argv[0]);
12134     clear_tv(&argv[1]);
12135 
12136     if (res == FAIL)
12137 	res = ITEM_COMPARE_FAIL;
12138     else
12139 	res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
12140     if (sortinfo->item_compare_func_err)
12141 	res = ITEM_COMPARE_FAIL;  /* return value has wrong type */
12142     clear_tv(&rettv);
12143 
12144     /* When the result would be zero, compare the pointers themselves.  Makes
12145      * the sort stable. */
12146     if (res == 0 && !sortinfo->item_compare_keep_zero)
12147 	res = si1->idx > si2->idx ? 1 : -1;
12148 
12149     return res;
12150 }
12151 
12152 /*
12153  * "sort({list})" function
12154  */
12155     static void
12156 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12157 {
12158     list_T	*l;
12159     listitem_T	*li;
12160     sortItem_T	*ptrs;
12161     sortinfo_T	*old_sortinfo;
12162     sortinfo_T	info;
12163     long	len;
12164     long	i;
12165 
12166     /* Pointer to current info struct used in compare function. Save and
12167      * restore the current one for nested calls. */
12168     old_sortinfo = sortinfo;
12169     sortinfo = &info;
12170 
12171     if (argvars[0].v_type != VAR_LIST)
12172 	semsg(_(e_listarg), sort ? "sort()" : "uniq()");
12173     else
12174     {
12175 	l = argvars[0].vval.v_list;
12176 	if (l == NULL || var_check_lock(l->lv_lock,
12177 	     (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12178 									TRUE))
12179 	    goto theend;
12180 	rettv_list_set(rettv, l);
12181 
12182 	len = list_len(l);
12183 	if (len <= 1)
12184 	    goto theend;	/* short list sorts pretty quickly */
12185 
12186 	info.item_compare_ic = FALSE;
12187 	info.item_compare_numeric = FALSE;
12188 	info.item_compare_numbers = FALSE;
12189 #ifdef FEAT_FLOAT
12190 	info.item_compare_float = FALSE;
12191 #endif
12192 	info.item_compare_func = NULL;
12193 	info.item_compare_partial = NULL;
12194 	info.item_compare_selfdict = NULL;
12195 	if (argvars[1].v_type != VAR_UNKNOWN)
12196 	{
12197 	    /* optional second argument: {func} */
12198 	    if (argvars[1].v_type == VAR_FUNC)
12199 		info.item_compare_func = argvars[1].vval.v_string;
12200 	    else if (argvars[1].v_type == VAR_PARTIAL)
12201 		info.item_compare_partial = argvars[1].vval.v_partial;
12202 	    else
12203 	    {
12204 		int	    error = FALSE;
12205 
12206 		i = (long)tv_get_number_chk(&argvars[1], &error);
12207 		if (error)
12208 		    goto theend;	/* type error; errmsg already given */
12209 		if (i == 1)
12210 		    info.item_compare_ic = TRUE;
12211 		else if (argvars[1].v_type != VAR_NUMBER)
12212 		    info.item_compare_func = tv_get_string(&argvars[1]);
12213 		else if (i != 0)
12214 		{
12215 		    emsg(_(e_invarg));
12216 		    goto theend;
12217 		}
12218 		if (info.item_compare_func != NULL)
12219 		{
12220 		    if (*info.item_compare_func == NUL)
12221 		    {
12222 			/* empty string means default sort */
12223 			info.item_compare_func = NULL;
12224 		    }
12225 		    else if (STRCMP(info.item_compare_func, "n") == 0)
12226 		    {
12227 			info.item_compare_func = NULL;
12228 			info.item_compare_numeric = TRUE;
12229 		    }
12230 		    else if (STRCMP(info.item_compare_func, "N") == 0)
12231 		    {
12232 			info.item_compare_func = NULL;
12233 			info.item_compare_numbers = TRUE;
12234 		    }
12235 #ifdef FEAT_FLOAT
12236 		    else if (STRCMP(info.item_compare_func, "f") == 0)
12237 		    {
12238 			info.item_compare_func = NULL;
12239 			info.item_compare_float = TRUE;
12240 		    }
12241 #endif
12242 		    else if (STRCMP(info.item_compare_func, "i") == 0)
12243 		    {
12244 			info.item_compare_func = NULL;
12245 			info.item_compare_ic = TRUE;
12246 		    }
12247 		}
12248 	    }
12249 
12250 	    if (argvars[2].v_type != VAR_UNKNOWN)
12251 	    {
12252 		/* optional third argument: {dict} */
12253 		if (argvars[2].v_type != VAR_DICT)
12254 		{
12255 		    emsg(_(e_dictreq));
12256 		    goto theend;
12257 		}
12258 		info.item_compare_selfdict = argvars[2].vval.v_dict;
12259 	    }
12260 	}
12261 
12262 	/* Make an array with each entry pointing to an item in the List. */
12263 	ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12264 	if (ptrs == NULL)
12265 	    goto theend;
12266 
12267 	i = 0;
12268 	if (sort)
12269 	{
12270 	    /* sort(): ptrs will be the list to sort */
12271 	    for (li = l->lv_first; li != NULL; li = li->li_next)
12272 	    {
12273 		ptrs[i].item = li;
12274 		ptrs[i].idx = i;
12275 		++i;
12276 	    }
12277 
12278 	    info.item_compare_func_err = FALSE;
12279 	    info.item_compare_keep_zero = FALSE;
12280 	    /* test the compare function */
12281 	    if ((info.item_compare_func != NULL
12282 					 || info.item_compare_partial != NULL)
12283 		    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12284 							 == ITEM_COMPARE_FAIL)
12285 		emsg(_("E702: Sort compare function failed"));
12286 	    else
12287 	    {
12288 		/* Sort the array with item pointers. */
12289 		qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12290 		    info.item_compare_func == NULL
12291 					  && info.item_compare_partial == NULL
12292 					       ? item_compare : item_compare2);
12293 
12294 		if (!info.item_compare_func_err)
12295 		{
12296 		    /* Clear the List and append the items in sorted order. */
12297 		    l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12298 		    l->lv_len = 0;
12299 		    for (i = 0; i < len; ++i)
12300 			list_append(l, ptrs[i].item);
12301 		}
12302 	    }
12303 	}
12304 	else
12305 	{
12306 	    int	(*item_compare_func_ptr)(const void *, const void *);
12307 
12308 	    /* f_uniq(): ptrs will be a stack of items to remove */
12309 	    info.item_compare_func_err = FALSE;
12310 	    info.item_compare_keep_zero = TRUE;
12311 	    item_compare_func_ptr = info.item_compare_func != NULL
12312 					  || info.item_compare_partial != NULL
12313 					       ? item_compare2 : item_compare;
12314 
12315 	    for (li = l->lv_first; li != NULL && li->li_next != NULL;
12316 							     li = li->li_next)
12317 	    {
12318 		if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12319 									 == 0)
12320 		    ptrs[i++].item = li;
12321 		if (info.item_compare_func_err)
12322 		{
12323 		    emsg(_("E882: Uniq compare function failed"));
12324 		    break;
12325 		}
12326 	    }
12327 
12328 	    if (!info.item_compare_func_err)
12329 	    {
12330 		while (--i >= 0)
12331 		{
12332 		    li = ptrs[i].item->li_next;
12333 		    ptrs[i].item->li_next = li->li_next;
12334 		    if (li->li_next != NULL)
12335 			li->li_next->li_prev = ptrs[i].item;
12336 		    else
12337 			l->lv_last = ptrs[i].item;
12338 		    list_fix_watch(l, li);
12339 		    listitem_free(li);
12340 		    l->lv_len--;
12341 		}
12342 	    }
12343 	}
12344 
12345 	vim_free(ptrs);
12346     }
12347 theend:
12348     sortinfo = old_sortinfo;
12349 }
12350 
12351 /*
12352  * "sort({list})" function
12353  */
12354     static void
12355 f_sort(typval_T *argvars, typval_T *rettv)
12356 {
12357     do_sort_uniq(argvars, rettv, TRUE);
12358 }
12359 
12360 /*
12361  * "uniq({list})" function
12362  */
12363     static void
12364 f_uniq(typval_T *argvars, typval_T *rettv)
12365 {
12366     do_sort_uniq(argvars, rettv, FALSE);
12367 }
12368 
12369 /*
12370  * "soundfold({word})" function
12371  */
12372     static void
12373 f_soundfold(typval_T *argvars, typval_T *rettv)
12374 {
12375     char_u	*s;
12376 
12377     rettv->v_type = VAR_STRING;
12378     s = tv_get_string(&argvars[0]);
12379 #ifdef FEAT_SPELL
12380     rettv->vval.v_string = eval_soundfold(s);
12381 #else
12382     rettv->vval.v_string = vim_strsave(s);
12383 #endif
12384 }
12385 
12386 /*
12387  * "spellbadword()" function
12388  */
12389     static void
12390 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12391 {
12392     char_u	*word = (char_u *)"";
12393     hlf_T	attr = HLF_COUNT;
12394     int		len = 0;
12395 
12396     if (rettv_list_alloc(rettv) == FAIL)
12397 	return;
12398 
12399 #ifdef FEAT_SPELL
12400     if (argvars[0].v_type == VAR_UNKNOWN)
12401     {
12402 	/* Find the start and length of the badly spelled word. */
12403 	len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12404 	if (len != 0)
12405 	{
12406 	    word = ml_get_cursor();
12407 	    curwin->w_set_curswant = TRUE;
12408 	}
12409     }
12410     else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12411     {
12412 	char_u	*str = tv_get_string_chk(&argvars[0]);
12413 	int	capcol = -1;
12414 
12415 	if (str != NULL)
12416 	{
12417 	    /* Check the argument for spelling. */
12418 	    while (*str != NUL)
12419 	    {
12420 		len = spell_check(curwin, str, &attr, &capcol, FALSE);
12421 		if (attr != HLF_COUNT)
12422 		{
12423 		    word = str;
12424 		    break;
12425 		}
12426 		str += len;
12427 		capcol -= len;
12428 	    }
12429 	}
12430     }
12431 #endif
12432 
12433     list_append_string(rettv->vval.v_list, word, len);
12434     list_append_string(rettv->vval.v_list, (char_u *)(
12435 			attr == HLF_SPB ? "bad" :
12436 			attr == HLF_SPR ? "rare" :
12437 			attr == HLF_SPL ? "local" :
12438 			attr == HLF_SPC ? "caps" :
12439 			""), -1);
12440 }
12441 
12442 /*
12443  * "spellsuggest()" function
12444  */
12445     static void
12446 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12447 {
12448 #ifdef FEAT_SPELL
12449     char_u	*str;
12450     int		typeerr = FALSE;
12451     int		maxcount;
12452     garray_T	ga;
12453     int		i;
12454     listitem_T	*li;
12455     int		need_capital = FALSE;
12456 #endif
12457 
12458     if (rettv_list_alloc(rettv) == FAIL)
12459 	return;
12460 
12461 #ifdef FEAT_SPELL
12462     if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12463     {
12464 	str = tv_get_string(&argvars[0]);
12465 	if (argvars[1].v_type != VAR_UNKNOWN)
12466 	{
12467 	    maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
12468 	    if (maxcount <= 0)
12469 		return;
12470 	    if (argvars[2].v_type != VAR_UNKNOWN)
12471 	    {
12472 		need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
12473 		if (typeerr)
12474 		    return;
12475 	    }
12476 	}
12477 	else
12478 	    maxcount = 25;
12479 
12480 	spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12481 
12482 	for (i = 0; i < ga.ga_len; ++i)
12483 	{
12484 	    str = ((char_u **)ga.ga_data)[i];
12485 
12486 	    li = listitem_alloc();
12487 	    if (li == NULL)
12488 		vim_free(str);
12489 	    else
12490 	    {
12491 		li->li_tv.v_type = VAR_STRING;
12492 		li->li_tv.v_lock = 0;
12493 		li->li_tv.vval.v_string = str;
12494 		list_append(rettv->vval.v_list, li);
12495 	    }
12496 	}
12497 	ga_clear(&ga);
12498     }
12499 #endif
12500 }
12501 
12502     static void
12503 f_split(typval_T *argvars, typval_T *rettv)
12504 {
12505     char_u	*str;
12506     char_u	*end;
12507     char_u	*pat = NULL;
12508     regmatch_T	regmatch;
12509     char_u	patbuf[NUMBUFLEN];
12510     char_u	*save_cpo;
12511     int		match;
12512     colnr_T	col = 0;
12513     int		keepempty = FALSE;
12514     int		typeerr = FALSE;
12515 
12516     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12517     save_cpo = p_cpo;
12518     p_cpo = (char_u *)"";
12519 
12520     str = tv_get_string(&argvars[0]);
12521     if (argvars[1].v_type != VAR_UNKNOWN)
12522     {
12523 	pat = tv_get_string_buf_chk(&argvars[1], patbuf);
12524 	if (pat == NULL)
12525 	    typeerr = TRUE;
12526 	if (argvars[2].v_type != VAR_UNKNOWN)
12527 	    keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
12528     }
12529     if (pat == NULL || *pat == NUL)
12530 	pat = (char_u *)"[\\x01- ]\\+";
12531 
12532     if (rettv_list_alloc(rettv) == FAIL)
12533 	return;
12534     if (typeerr)
12535 	return;
12536 
12537     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12538     if (regmatch.regprog != NULL)
12539     {
12540 	regmatch.rm_ic = FALSE;
12541 	while (*str != NUL || keepempty)
12542 	{
12543 	    if (*str == NUL)
12544 		match = FALSE;	/* empty item at the end */
12545 	    else
12546 		match = vim_regexec_nl(&regmatch, str, col);
12547 	    if (match)
12548 		end = regmatch.startp[0];
12549 	    else
12550 		end = str + STRLEN(str);
12551 	    if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12552 			   && *str != NUL && match && end < regmatch.endp[0]))
12553 	    {
12554 		if (list_append_string(rettv->vval.v_list, str,
12555 						    (int)(end - str)) == FAIL)
12556 		    break;
12557 	    }
12558 	    if (!match)
12559 		break;
12560 	    // Advance to just after the match.
12561 	    if (regmatch.endp[0] > str)
12562 		col = 0;
12563 	    else
12564 		// Don't get stuck at the same match.
12565 		col = (*mb_ptr2len)(regmatch.endp[0]);
12566 	    str = regmatch.endp[0];
12567 	}
12568 
12569 	vim_regfree(regmatch.regprog);
12570     }
12571 
12572     p_cpo = save_cpo;
12573 }
12574 
12575 #ifdef FEAT_FLOAT
12576 /*
12577  * "sqrt()" function
12578  */
12579     static void
12580 f_sqrt(typval_T *argvars, typval_T *rettv)
12581 {
12582     float_T	f = 0.0;
12583 
12584     rettv->v_type = VAR_FLOAT;
12585     if (get_float_arg(argvars, &f) == OK)
12586 	rettv->vval.v_float = sqrt(f);
12587     else
12588 	rettv->vval.v_float = 0.0;
12589 }
12590 
12591 /*
12592  * "str2float()" function
12593  */
12594     static void
12595 f_str2float(typval_T *argvars, typval_T *rettv)
12596 {
12597     char_u *p = skipwhite(tv_get_string(&argvars[0]));
12598     int     isneg = (*p == '-');
12599 
12600     if (*p == '+' || *p == '-')
12601 	p = skipwhite(p + 1);
12602     (void)string2float(p, &rettv->vval.v_float);
12603     if (isneg)
12604 	rettv->vval.v_float *= -1;
12605     rettv->v_type = VAR_FLOAT;
12606 }
12607 #endif
12608 
12609 /*
12610  * "str2nr()" function
12611  */
12612     static void
12613 f_str2nr(typval_T *argvars, typval_T *rettv)
12614 {
12615     int		base = 10;
12616     char_u	*p;
12617     varnumber_T	n;
12618     int		what;
12619     int		isneg;
12620 
12621     if (argvars[1].v_type != VAR_UNKNOWN)
12622     {
12623 	base = (int)tv_get_number(&argvars[1]);
12624 	if (base != 2 && base != 8 && base != 10 && base != 16)
12625 	{
12626 	    emsg(_(e_invarg));
12627 	    return;
12628 	}
12629     }
12630 
12631     p = skipwhite(tv_get_string(&argvars[0]));
12632     isneg = (*p == '-');
12633     if (*p == '+' || *p == '-')
12634 	p = skipwhite(p + 1);
12635     switch (base)
12636     {
12637 	case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12638 	case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12639 	case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12640 	default: what = 0;
12641     }
12642     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
12643     if (isneg)
12644 	rettv->vval.v_number = -n;
12645     else
12646 	rettv->vval.v_number = n;
12647 
12648 }
12649 
12650 #ifdef HAVE_STRFTIME
12651 /*
12652  * "strftime({format}[, {time}])" function
12653  */
12654     static void
12655 f_strftime(typval_T *argvars, typval_T *rettv)
12656 {
12657     char_u	result_buf[256];
12658     struct tm	*curtime;
12659     time_t	seconds;
12660     char_u	*p;
12661 
12662     rettv->v_type = VAR_STRING;
12663 
12664     p = tv_get_string(&argvars[0]);
12665     if (argvars[1].v_type == VAR_UNKNOWN)
12666 	seconds = time(NULL);
12667     else
12668 	seconds = (time_t)tv_get_number(&argvars[1]);
12669     curtime = localtime(&seconds);
12670     /* MSVC returns NULL for an invalid value of seconds. */
12671     if (curtime == NULL)
12672 	rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12673     else
12674     {
12675 	vimconv_T   conv;
12676 	char_u	    *enc;
12677 
12678 	conv.vc_type = CONV_NONE;
12679 	enc = enc_locale();
12680 	convert_setup(&conv, p_enc, enc);
12681 	if (conv.vc_type != CONV_NONE)
12682 	    p = string_convert(&conv, p, NULL);
12683 	if (p != NULL)
12684 	    (void)strftime((char *)result_buf, sizeof(result_buf),
12685 							  (char *)p, curtime);
12686 	else
12687 	    result_buf[0] = NUL;
12688 
12689 	if (conv.vc_type != CONV_NONE)
12690 	    vim_free(p);
12691 	convert_setup(&conv, enc, p_enc);
12692 	if (conv.vc_type != CONV_NONE)
12693 	    rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12694 	else
12695 	    rettv->vval.v_string = vim_strsave(result_buf);
12696 
12697 	/* Release conversion descriptors */
12698 	convert_setup(&conv, NULL, NULL);
12699 	vim_free(enc);
12700     }
12701 }
12702 #endif
12703 
12704 /*
12705  * "strgetchar()" function
12706  */
12707     static void
12708 f_strgetchar(typval_T *argvars, typval_T *rettv)
12709 {
12710     char_u	*str;
12711     int		len;
12712     int		error = FALSE;
12713     int		charidx;
12714     int		byteidx = 0;
12715 
12716     rettv->vval.v_number = -1;
12717     str = tv_get_string_chk(&argvars[0]);
12718     if (str == NULL)
12719 	return;
12720     len = (int)STRLEN(str);
12721     charidx = (int)tv_get_number_chk(&argvars[1], &error);
12722     if (error)
12723 	return;
12724 
12725     while (charidx >= 0 && byteidx < len)
12726     {
12727 	if (charidx == 0)
12728 	{
12729 	    rettv->vval.v_number = mb_ptr2char(str + byteidx);
12730 	    break;
12731 	}
12732 	--charidx;
12733 	byteidx += MB_CPTR2LEN(str + byteidx);
12734     }
12735 }
12736 
12737 /*
12738  * "stridx()" function
12739  */
12740     static void
12741 f_stridx(typval_T *argvars, typval_T *rettv)
12742 {
12743     char_u	buf[NUMBUFLEN];
12744     char_u	*needle;
12745     char_u	*haystack;
12746     char_u	*save_haystack;
12747     char_u	*pos;
12748     int		start_idx;
12749 
12750     needle = tv_get_string_chk(&argvars[1]);
12751     save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
12752     rettv->vval.v_number = -1;
12753     if (needle == NULL || haystack == NULL)
12754 	return;		/* type error; errmsg already given */
12755 
12756     if (argvars[2].v_type != VAR_UNKNOWN)
12757     {
12758 	int	    error = FALSE;
12759 
12760 	start_idx = (int)tv_get_number_chk(&argvars[2], &error);
12761 	if (error || start_idx >= (int)STRLEN(haystack))
12762 	    return;
12763 	if (start_idx >= 0)
12764 	    haystack += start_idx;
12765     }
12766 
12767     pos	= (char_u *)strstr((char *)haystack, (char *)needle);
12768     if (pos != NULL)
12769 	rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12770 }
12771 
12772 /*
12773  * "string()" function
12774  */
12775     void
12776 f_string(typval_T *argvars, typval_T *rettv)
12777 {
12778     char_u	*tofree;
12779     char_u	numbuf[NUMBUFLEN];
12780 
12781     rettv->v_type = VAR_STRING;
12782     rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12783 								get_copyID());
12784     /* Make a copy if we have a value but it's not in allocated memory. */
12785     if (rettv->vval.v_string != NULL && tofree == NULL)
12786 	rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12787 }
12788 
12789 /*
12790  * "strlen()" function
12791  */
12792     static void
12793 f_strlen(typval_T *argvars, typval_T *rettv)
12794 {
12795     rettv->vval.v_number = (varnumber_T)(STRLEN(
12796 					      tv_get_string(&argvars[0])));
12797 }
12798 
12799 /*
12800  * "strchars()" function
12801  */
12802     static void
12803 f_strchars(typval_T *argvars, typval_T *rettv)
12804 {
12805     char_u		*s = tv_get_string(&argvars[0]);
12806     int			skipcc = 0;
12807     varnumber_T		len = 0;
12808     int			(*func_mb_ptr2char_adv)(char_u **pp);
12809 
12810     if (argvars[1].v_type != VAR_UNKNOWN)
12811 	skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
12812     if (skipcc < 0 || skipcc > 1)
12813 	emsg(_(e_invarg));
12814     else
12815     {
12816 	func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12817 	while (*s != NUL)
12818 	{
12819 	    func_mb_ptr2char_adv(&s);
12820 	    ++len;
12821 	}
12822 	rettv->vval.v_number = len;
12823     }
12824 }
12825 
12826 /*
12827  * "strdisplaywidth()" function
12828  */
12829     static void
12830 f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12831 {
12832     char_u	*s = tv_get_string(&argvars[0]);
12833     int		col = 0;
12834 
12835     if (argvars[1].v_type != VAR_UNKNOWN)
12836 	col = (int)tv_get_number(&argvars[1]);
12837 
12838     rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12839 }
12840 
12841 /*
12842  * "strwidth()" function
12843  */
12844     static void
12845 f_strwidth(typval_T *argvars, typval_T *rettv)
12846 {
12847     char_u	*s = tv_get_string(&argvars[0]);
12848 
12849     rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
12850 }
12851 
12852 /*
12853  * "strcharpart()" function
12854  */
12855     static void
12856 f_strcharpart(typval_T *argvars, typval_T *rettv)
12857 {
12858     char_u	*p;
12859     int		nchar;
12860     int		nbyte = 0;
12861     int		charlen;
12862     int		len = 0;
12863     int		slen;
12864     int		error = FALSE;
12865 
12866     p = tv_get_string(&argvars[0]);
12867     slen = (int)STRLEN(p);
12868 
12869     nchar = (int)tv_get_number_chk(&argvars[1], &error);
12870     if (!error)
12871     {
12872 	if (nchar > 0)
12873 	    while (nchar > 0 && nbyte < slen)
12874 	    {
12875 		nbyte += MB_CPTR2LEN(p + nbyte);
12876 		--nchar;
12877 	    }
12878 	else
12879 	    nbyte = nchar;
12880 	if (argvars[2].v_type != VAR_UNKNOWN)
12881 	{
12882 	    charlen = (int)tv_get_number(&argvars[2]);
12883 	    while (charlen > 0 && nbyte + len < slen)
12884 	    {
12885 		int off = nbyte + len;
12886 
12887 		if (off < 0)
12888 		    len += 1;
12889 		else
12890 		    len += MB_CPTR2LEN(p + off);
12891 		--charlen;
12892 	    }
12893 	}
12894 	else
12895 	    len = slen - nbyte;    /* default: all bytes that are available. */
12896     }
12897 
12898     /*
12899      * Only return the overlap between the specified part and the actual
12900      * string.
12901      */
12902     if (nbyte < 0)
12903     {
12904 	len += nbyte;
12905 	nbyte = 0;
12906     }
12907     else if (nbyte > slen)
12908 	nbyte = slen;
12909     if (len < 0)
12910 	len = 0;
12911     else if (nbyte + len > slen)
12912 	len = slen - nbyte;
12913 
12914     rettv->v_type = VAR_STRING;
12915     rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12916 }
12917 
12918 /*
12919  * "strpart()" function
12920  */
12921     static void
12922 f_strpart(typval_T *argvars, typval_T *rettv)
12923 {
12924     char_u	*p;
12925     int		n;
12926     int		len;
12927     int		slen;
12928     int		error = FALSE;
12929 
12930     p = tv_get_string(&argvars[0]);
12931     slen = (int)STRLEN(p);
12932 
12933     n = (int)tv_get_number_chk(&argvars[1], &error);
12934     if (error)
12935 	len = 0;
12936     else if (argvars[2].v_type != VAR_UNKNOWN)
12937 	len = (int)tv_get_number(&argvars[2]);
12938     else
12939 	len = slen - n;	    /* default len: all bytes that are available. */
12940 
12941     /*
12942      * Only return the overlap between the specified part and the actual
12943      * string.
12944      */
12945     if (n < 0)
12946     {
12947 	len += n;
12948 	n = 0;
12949     }
12950     else if (n > slen)
12951 	n = slen;
12952     if (len < 0)
12953 	len = 0;
12954     else if (n + len > slen)
12955 	len = slen - n;
12956 
12957     rettv->v_type = VAR_STRING;
12958     rettv->vval.v_string = vim_strnsave(p + n, len);
12959 }
12960 
12961 /*
12962  * "strridx()" function
12963  */
12964     static void
12965 f_strridx(typval_T *argvars, typval_T *rettv)
12966 {
12967     char_u	buf[NUMBUFLEN];
12968     char_u	*needle;
12969     char_u	*haystack;
12970     char_u	*rest;
12971     char_u	*lastmatch = NULL;
12972     int		haystack_len, end_idx;
12973 
12974     needle = tv_get_string_chk(&argvars[1]);
12975     haystack = tv_get_string_buf_chk(&argvars[0], buf);
12976 
12977     rettv->vval.v_number = -1;
12978     if (needle == NULL || haystack == NULL)
12979 	return;		/* type error; errmsg already given */
12980 
12981     haystack_len = (int)STRLEN(haystack);
12982     if (argvars[2].v_type != VAR_UNKNOWN)
12983     {
12984 	/* Third argument: upper limit for index */
12985 	end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
12986 	if (end_idx < 0)
12987 	    return;	/* can never find a match */
12988     }
12989     else
12990 	end_idx = haystack_len;
12991 
12992     if (*needle == NUL)
12993     {
12994 	/* Empty string matches past the end. */
12995 	lastmatch = haystack + end_idx;
12996     }
12997     else
12998     {
12999 	for (rest = haystack; *rest != '\0'; ++rest)
13000 	{
13001 	    rest = (char_u *)strstr((char *)rest, (char *)needle);
13002 	    if (rest == NULL || rest > haystack + end_idx)
13003 		break;
13004 	    lastmatch = rest;
13005 	}
13006     }
13007 
13008     if (lastmatch == NULL)
13009 	rettv->vval.v_number = -1;
13010     else
13011 	rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13012 }
13013 
13014 /*
13015  * "strtrans()" function
13016  */
13017     static void
13018 f_strtrans(typval_T *argvars, typval_T *rettv)
13019 {
13020     rettv->v_type = VAR_STRING;
13021     rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
13022 }
13023 
13024 /*
13025  * "submatch()" function
13026  */
13027     static void
13028 f_submatch(typval_T *argvars, typval_T *rettv)
13029 {
13030     int		error = FALSE;
13031     int		no;
13032     int		retList = 0;
13033 
13034     no = (int)tv_get_number_chk(&argvars[0], &error);
13035     if (error)
13036 	return;
13037     if (no < 0 || no >= NSUBEXP)
13038     {
13039 	semsg(_("E935: invalid submatch number: %d"), no);
13040 	return;
13041     }
13042     if (argvars[1].v_type != VAR_UNKNOWN)
13043 	retList = (int)tv_get_number_chk(&argvars[1], &error);
13044     if (error)
13045 	return;
13046 
13047     if (retList == 0)
13048     {
13049 	rettv->v_type = VAR_STRING;
13050 	rettv->vval.v_string = reg_submatch(no);
13051     }
13052     else
13053     {
13054 	rettv->v_type = VAR_LIST;
13055 	rettv->vval.v_list = reg_submatch_list(no);
13056     }
13057 }
13058 
13059 /*
13060  * "substitute()" function
13061  */
13062     static void
13063 f_substitute(typval_T *argvars, typval_T *rettv)
13064 {
13065     char_u	patbuf[NUMBUFLEN];
13066     char_u	subbuf[NUMBUFLEN];
13067     char_u	flagsbuf[NUMBUFLEN];
13068 
13069     char_u	*str = tv_get_string_chk(&argvars[0]);
13070     char_u	*pat = tv_get_string_buf_chk(&argvars[1], patbuf);
13071     char_u	*sub = NULL;
13072     typval_T	*expr = NULL;
13073     char_u	*flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
13074 
13075     if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13076 	expr = &argvars[2];
13077     else
13078 	sub = tv_get_string_buf_chk(&argvars[2], subbuf);
13079 
13080     rettv->v_type = VAR_STRING;
13081     if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13082 								|| flg == NULL)
13083 	rettv->vval.v_string = NULL;
13084     else
13085 	rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
13086 }
13087 
13088 /*
13089  * "swapinfo(swap_filename)" function
13090  */
13091     static void
13092 f_swapinfo(typval_T *argvars, typval_T *rettv)
13093 {
13094     if (rettv_dict_alloc(rettv) == OK)
13095 	get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
13096 }
13097 
13098 /*
13099  * "swapname(expr)" function
13100  */
13101     static void
13102 f_swapname(typval_T *argvars, typval_T *rettv)
13103 {
13104     buf_T	*buf;
13105 
13106     rettv->v_type = VAR_STRING;
13107     buf = tv_get_buf(&argvars[0], FALSE);
13108     if (buf == NULL || buf->b_ml.ml_mfp == NULL
13109 					|| buf->b_ml.ml_mfp->mf_fname == NULL)
13110 	rettv->vval.v_string = NULL;
13111     else
13112 	rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13113 }
13114 
13115 /*
13116  * "synID(lnum, col, trans)" function
13117  */
13118     static void
13119 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13120 {
13121     int		id = 0;
13122 #ifdef FEAT_SYN_HL
13123     linenr_T	lnum;
13124     colnr_T	col;
13125     int		trans;
13126     int		transerr = FALSE;
13127 
13128     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13129     col = (linenr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13130     trans = (int)tv_get_number_chk(&argvars[2], &transerr);
13131 
13132     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13133 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13134 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13135 #endif
13136 
13137     rettv->vval.v_number = id;
13138 }
13139 
13140 /*
13141  * "synIDattr(id, what [, mode])" function
13142  */
13143     static void
13144 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13145 {
13146     char_u	*p = NULL;
13147 #ifdef FEAT_SYN_HL
13148     int		id;
13149     char_u	*what;
13150     char_u	*mode;
13151     char_u	modebuf[NUMBUFLEN];
13152     int		modec;
13153 
13154     id = (int)tv_get_number(&argvars[0]);
13155     what = tv_get_string(&argvars[1]);
13156     if (argvars[2].v_type != VAR_UNKNOWN)
13157     {
13158 	mode = tv_get_string_buf(&argvars[2], modebuf);
13159 	modec = TOLOWER_ASC(mode[0]);
13160 	if (modec != 't' && modec != 'c' && modec != 'g')
13161 	    modec = 0;	/* replace invalid with current */
13162     }
13163     else
13164     {
13165 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13166 	if (USE_24BIT)
13167 	    modec = 'g';
13168 	else
13169 #endif
13170 	    if (t_colors > 1)
13171 	    modec = 'c';
13172 	else
13173 	    modec = 't';
13174     }
13175 
13176     switch (TOLOWER_ASC(what[0]))
13177     {
13178 	case 'b':
13179 		if (TOLOWER_ASC(what[1]) == 'g')	/* bg[#] */
13180 		    p = highlight_color(id, what, modec);
13181 		else					/* bold */
13182 		    p = highlight_has_attr(id, HL_BOLD, modec);
13183 		break;
13184 
13185 	case 'f':					/* fg[#] or font */
13186 		p = highlight_color(id, what, modec);
13187 		break;
13188 
13189 	case 'i':
13190 		if (TOLOWER_ASC(what[1]) == 'n')	/* inverse */
13191 		    p = highlight_has_attr(id, HL_INVERSE, modec);
13192 		else					/* italic */
13193 		    p = highlight_has_attr(id, HL_ITALIC, modec);
13194 		break;
13195 
13196 	case 'n':					/* name */
13197 		p = get_highlight_name_ext(NULL, id - 1, FALSE);
13198 		break;
13199 
13200 	case 'r':					/* reverse */
13201 		p = highlight_has_attr(id, HL_INVERSE, modec);
13202 		break;
13203 
13204 	case 's':
13205 		if (TOLOWER_ASC(what[1]) == 'p')	/* sp[#] */
13206 		    p = highlight_color(id, what, modec);
13207 							/* strikeout */
13208 		else if (TOLOWER_ASC(what[1]) == 't' &&
13209 			TOLOWER_ASC(what[2]) == 'r')
13210 		    p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
13211 		else					/* standout */
13212 		    p = highlight_has_attr(id, HL_STANDOUT, modec);
13213 		break;
13214 
13215 	case 'u':
13216 		if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13217 							/* underline */
13218 		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
13219 		else
13220 							/* undercurl */
13221 		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
13222 		break;
13223     }
13224 
13225     if (p != NULL)
13226 	p = vim_strsave(p);
13227 #endif
13228     rettv->v_type = VAR_STRING;
13229     rettv->vval.v_string = p;
13230 }
13231 
13232 /*
13233  * "synIDtrans(id)" function
13234  */
13235     static void
13236 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13237 {
13238     int		id;
13239 
13240 #ifdef FEAT_SYN_HL
13241     id = (int)tv_get_number(&argvars[0]);
13242 
13243     if (id > 0)
13244 	id = syn_get_final_id(id);
13245     else
13246 #endif
13247 	id = 0;
13248 
13249     rettv->vval.v_number = id;
13250 }
13251 
13252 /*
13253  * "synconcealed(lnum, col)" function
13254  */
13255     static void
13256 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13257 {
13258 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13259     linenr_T	lnum;
13260     colnr_T	col;
13261     int		syntax_flags = 0;
13262     int		cchar;
13263     int		matchid = 0;
13264     char_u	str[NUMBUFLEN];
13265 #endif
13266 
13267     rettv_list_set(rettv, NULL);
13268 
13269 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13270     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13271     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13272 
13273     vim_memset(str, NUL, sizeof(str));
13274 
13275     if (rettv_list_alloc(rettv) != FAIL)
13276     {
13277 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13278 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13279 	    && curwin->w_p_cole > 0)
13280 	{
13281 	    (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13282 	    syntax_flags = get_syntax_info(&matchid);
13283 
13284 	    /* get the conceal character */
13285 	    if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13286 	    {
13287 		cchar = syn_get_sub_char();
13288 		if (cchar == NUL && curwin->w_p_cole == 1)
13289 		    cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
13290 		if (cchar != NUL)
13291 		{
13292 		    if (has_mbyte)
13293 			(*mb_char2bytes)(cchar, str);
13294 		    else
13295 			str[0] = cchar;
13296 		}
13297 	    }
13298 	}
13299 
13300 	list_append_number(rettv->vval.v_list,
13301 					    (syntax_flags & HL_CONCEAL) != 0);
13302 	/* -1 to auto-determine strlen */
13303 	list_append_string(rettv->vval.v_list, str, -1);
13304 	list_append_number(rettv->vval.v_list, matchid);
13305     }
13306 #endif
13307 }
13308 
13309 /*
13310  * "synstack(lnum, col)" function
13311  */
13312     static void
13313 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13314 {
13315 #ifdef FEAT_SYN_HL
13316     linenr_T	lnum;
13317     colnr_T	col;
13318     int		i;
13319     int		id;
13320 #endif
13321 
13322     rettv_list_set(rettv, NULL);
13323 
13324 #ifdef FEAT_SYN_HL
13325     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13326     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13327 
13328     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13329 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13330 	    && rettv_list_alloc(rettv) != FAIL)
13331     {
13332 	(void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13333 	for (i = 0; ; ++i)
13334 	{
13335 	    id = syn_get_stack_item(i);
13336 	    if (id < 0)
13337 		break;
13338 	    if (list_append_number(rettv->vval.v_list, id) == FAIL)
13339 		break;
13340 	}
13341     }
13342 #endif
13343 }
13344 
13345     static void
13346 get_cmd_output_as_rettv(
13347     typval_T	*argvars,
13348     typval_T	*rettv,
13349     int		retlist)
13350 {
13351     char_u	*res = NULL;
13352     char_u	*p;
13353     char_u	*infile = NULL;
13354     int		err = FALSE;
13355     FILE	*fd;
13356     list_T	*list = NULL;
13357     int		flags = SHELL_SILENT;
13358 
13359     rettv->v_type = VAR_STRING;
13360     rettv->vval.v_string = NULL;
13361     if (check_restricted() || check_secure())
13362 	goto errret;
13363 
13364     if (argvars[1].v_type != VAR_UNKNOWN)
13365     {
13366 	/*
13367 	 * Write the text to a temp file, to be used for input of the shell
13368 	 * command.
13369 	 */
13370 	if ((infile = vim_tempname('i', TRUE)) == NULL)
13371 	{
13372 	    emsg(_(e_notmp));
13373 	    goto errret;
13374 	}
13375 
13376 	fd = mch_fopen((char *)infile, WRITEBIN);
13377 	if (fd == NULL)
13378 	{
13379 	    semsg(_(e_notopen), infile);
13380 	    goto errret;
13381 	}
13382 	if (argvars[1].v_type == VAR_NUMBER)
13383 	{
13384 	    linenr_T	lnum;
13385 	    buf_T	*buf;
13386 
13387 	    buf = buflist_findnr(argvars[1].vval.v_number);
13388 	    if (buf == NULL)
13389 	    {
13390 		semsg(_(e_nobufnr), argvars[1].vval.v_number);
13391 		fclose(fd);
13392 		goto errret;
13393 	    }
13394 
13395 	    for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13396 	    {
13397 		for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13398 		    if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13399 		    {
13400 			err = TRUE;
13401 			break;
13402 		    }
13403 		if (putc(NL, fd) == EOF)
13404 		{
13405 		    err = TRUE;
13406 		    break;
13407 		}
13408 	    }
13409 	}
13410 	else if (argvars[1].v_type == VAR_LIST)
13411 	{
13412 	    if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13413 		err = TRUE;
13414 	}
13415 	else
13416 	{
13417 	    size_t	len;
13418 	    char_u	buf[NUMBUFLEN];
13419 
13420 	    p = tv_get_string_buf_chk(&argvars[1], buf);
13421 	    if (p == NULL)
13422 	    {
13423 		fclose(fd);
13424 		goto errret;		/* type error; errmsg already given */
13425 	    }
13426 	    len = STRLEN(p);
13427 	    if (len > 0 && fwrite(p, len, 1, fd) != 1)
13428 		err = TRUE;
13429 	}
13430 	if (fclose(fd) != 0)
13431 	    err = TRUE;
13432 	if (err)
13433 	{
13434 	    emsg(_("E677: Error writing temp file"));
13435 	    goto errret;
13436 	}
13437     }
13438 
13439     /* Omit SHELL_COOKED when invoked with ":silent".  Avoids that the shell
13440      * echoes typeahead, that messes up the display. */
13441     if (!msg_silent)
13442 	flags += SHELL_COOKED;
13443 
13444     if (retlist)
13445     {
13446 	int		len;
13447 	listitem_T	*li;
13448 	char_u		*s = NULL;
13449 	char_u		*start;
13450 	char_u		*end;
13451 	int		i;
13452 
13453 	res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
13454 	if (res == NULL)
13455 	    goto errret;
13456 
13457 	list = list_alloc();
13458 	if (list == NULL)
13459 	    goto errret;
13460 
13461 	for (i = 0; i < len; ++i)
13462 	{
13463 	    start = res + i;
13464 	    while (i < len && res[i] != NL)
13465 		++i;
13466 	    end = res + i;
13467 
13468 	    s = alloc((unsigned)(end - start + 1));
13469 	    if (s == NULL)
13470 		goto errret;
13471 
13472 	    for (p = s; start < end; ++p, ++start)
13473 		*p = *start == NUL ? NL : *start;
13474 	    *p = NUL;
13475 
13476 	    li = listitem_alloc();
13477 	    if (li == NULL)
13478 	    {
13479 		vim_free(s);
13480 		goto errret;
13481 	    }
13482 	    li->li_tv.v_type = VAR_STRING;
13483 	    li->li_tv.v_lock = 0;
13484 	    li->li_tv.vval.v_string = s;
13485 	    list_append(list, li);
13486 	}
13487 
13488 	rettv_list_set(rettv, list);
13489 	list = NULL;
13490     }
13491     else
13492     {
13493 	res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
13494 #ifdef USE_CRNL
13495 	/* translate <CR><NL> into <NL> */
13496 	if (res != NULL)
13497 	{
13498 	    char_u	*s, *d;
13499 
13500 	    d = res;
13501 	    for (s = res; *s; ++s)
13502 	    {
13503 		if (s[0] == CAR && s[1] == NL)
13504 		    ++s;
13505 		*d++ = *s;
13506 	    }
13507 	    *d = NUL;
13508 	}
13509 #endif
13510 	rettv->vval.v_string = res;
13511 	res = NULL;
13512     }
13513 
13514 errret:
13515     if (infile != NULL)
13516     {
13517 	mch_remove(infile);
13518 	vim_free(infile);
13519     }
13520     if (res != NULL)
13521 	vim_free(res);
13522     if (list != NULL)
13523 	list_free(list);
13524 }
13525 
13526 /*
13527  * "system()" function
13528  */
13529     static void
13530 f_system(typval_T *argvars, typval_T *rettv)
13531 {
13532     get_cmd_output_as_rettv(argvars, rettv, FALSE);
13533 }
13534 
13535 /*
13536  * "systemlist()" function
13537  */
13538     static void
13539 f_systemlist(typval_T *argvars, typval_T *rettv)
13540 {
13541     get_cmd_output_as_rettv(argvars, rettv, TRUE);
13542 }
13543 
13544 /*
13545  * "tabpagebuflist()" function
13546  */
13547     static void
13548 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13549 {
13550     tabpage_T	*tp;
13551     win_T	*wp = NULL;
13552 
13553     if (argvars[0].v_type == VAR_UNKNOWN)
13554 	wp = firstwin;
13555     else
13556     {
13557 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
13558 	if (tp != NULL)
13559 	    wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13560     }
13561     if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13562     {
13563 	for (; wp != NULL; wp = wp->w_next)
13564 	    if (list_append_number(rettv->vval.v_list,
13565 						wp->w_buffer->b_fnum) == FAIL)
13566 		break;
13567     }
13568 }
13569 
13570 /*
13571  * "tabpagenr()" function
13572  */
13573     static void
13574 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13575 {
13576     int		nr = 1;
13577     char_u	*arg;
13578 
13579     if (argvars[0].v_type != VAR_UNKNOWN)
13580     {
13581 	arg = tv_get_string_chk(&argvars[0]);
13582 	nr = 0;
13583 	if (arg != NULL)
13584 	{
13585 	    if (STRCMP(arg, "$") == 0)
13586 		nr = tabpage_index(NULL) - 1;
13587 	    else
13588 		semsg(_(e_invexpr2), arg);
13589 	}
13590     }
13591     else
13592 	nr = tabpage_index(curtab);
13593     rettv->vval.v_number = nr;
13594 }
13595 
13596 
13597 /*
13598  * Common code for tabpagewinnr() and winnr().
13599  */
13600     static int
13601 get_winnr(tabpage_T *tp, typval_T *argvar)
13602 {
13603     win_T	*twin;
13604     int		nr = 1;
13605     win_T	*wp;
13606     char_u	*arg;
13607 
13608     twin = (tp == curtab) ? curwin : tp->tp_curwin;
13609     if (argvar->v_type != VAR_UNKNOWN)
13610     {
13611 	arg = tv_get_string_chk(argvar);
13612 	if (arg == NULL)
13613 	    nr = 0;		/* type error; errmsg already given */
13614 	else if (STRCMP(arg, "$") == 0)
13615 	    twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13616 	else if (STRCMP(arg, "#") == 0)
13617 	{
13618 	    twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13619 	    if (twin == NULL)
13620 		nr = 0;
13621 	}
13622 	else
13623 	{
13624 	    semsg(_(e_invexpr2), arg);
13625 	    nr = 0;
13626 	}
13627     }
13628 
13629     if (nr > 0)
13630 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13631 					      wp != twin; wp = wp->w_next)
13632 	{
13633 	    if (wp == NULL)
13634 	    {
13635 		/* didn't find it in this tabpage */
13636 		nr = 0;
13637 		break;
13638 	    }
13639 	    ++nr;
13640 	}
13641     return nr;
13642 }
13643 
13644 /*
13645  * "tabpagewinnr()" function
13646  */
13647     static void
13648 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13649 {
13650     int		nr = 1;
13651     tabpage_T	*tp;
13652 
13653     tp = find_tabpage((int)tv_get_number(&argvars[0]));
13654     if (tp == NULL)
13655 	nr = 0;
13656     else
13657 	nr = get_winnr(tp, &argvars[1]);
13658     rettv->vval.v_number = nr;
13659 }
13660 
13661 /*
13662  * "tagfiles()" function
13663  */
13664     static void
13665 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13666 {
13667     char_u	*fname;
13668     tagname_T	tn;
13669     int		first;
13670 
13671     if (rettv_list_alloc(rettv) == FAIL)
13672 	return;
13673     fname = alloc(MAXPATHL);
13674     if (fname == NULL)
13675 	return;
13676 
13677     for (first = TRUE; ; first = FALSE)
13678 	if (get_tagfname(&tn, first, fname) == FAIL
13679 		|| list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13680 	    break;
13681     tagname_free(&tn);
13682     vim_free(fname);
13683 }
13684 
13685 /*
13686  * "taglist()" function
13687  */
13688     static void
13689 f_taglist(typval_T *argvars, typval_T *rettv)
13690 {
13691     char_u  *fname = NULL;
13692     char_u  *tag_pattern;
13693 
13694     tag_pattern = tv_get_string(&argvars[0]);
13695 
13696     rettv->vval.v_number = FALSE;
13697     if (*tag_pattern == NUL)
13698 	return;
13699 
13700     if (argvars[1].v_type != VAR_UNKNOWN)
13701 	fname = tv_get_string(&argvars[1]);
13702     if (rettv_list_alloc(rettv) == OK)
13703 	(void)get_tags(rettv->vval.v_list, tag_pattern, fname);
13704 }
13705 
13706 /*
13707  * "tempname()" function
13708  */
13709     static void
13710 f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13711 {
13712     static int	x = 'A';
13713 
13714     rettv->v_type = VAR_STRING;
13715     rettv->vval.v_string = vim_tempname(x, FALSE);
13716 
13717     /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13718      * names.  Skip 'I' and 'O', they are used for shell redirection. */
13719     do
13720     {
13721 	if (x == 'Z')
13722 	    x = '0';
13723 	else if (x == '9')
13724 	    x = 'A';
13725 	else
13726 	{
13727 #ifdef EBCDIC
13728 	    if (x == 'I')
13729 		x = 'J';
13730 	    else if (x == 'R')
13731 		x = 'S';
13732 	    else
13733 #endif
13734 		++x;
13735 	}
13736     } while (x == 'I' || x == 'O');
13737 }
13738 
13739 #ifdef FEAT_FLOAT
13740 /*
13741  * "tan()" function
13742  */
13743     static void
13744 f_tan(typval_T *argvars, typval_T *rettv)
13745 {
13746     float_T	f = 0.0;
13747 
13748     rettv->v_type = VAR_FLOAT;
13749     if (get_float_arg(argvars, &f) == OK)
13750 	rettv->vval.v_float = tan(f);
13751     else
13752 	rettv->vval.v_float = 0.0;
13753 }
13754 
13755 /*
13756  * "tanh()" function
13757  */
13758     static void
13759 f_tanh(typval_T *argvars, typval_T *rettv)
13760 {
13761     float_T	f = 0.0;
13762 
13763     rettv->v_type = VAR_FLOAT;
13764     if (get_float_arg(argvars, &f) == OK)
13765 	rettv->vval.v_float = tanh(f);
13766     else
13767 	rettv->vval.v_float = 0.0;
13768 }
13769 #endif
13770 
13771 /*
13772  * "test_alloc_fail(id, countdown, repeat)" function
13773  */
13774     static void
13775 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13776 {
13777     if (argvars[0].v_type != VAR_NUMBER
13778 	    || argvars[0].vval.v_number <= 0
13779 	    || argvars[1].v_type != VAR_NUMBER
13780 	    || argvars[1].vval.v_number < 0
13781 	    || argvars[2].v_type != VAR_NUMBER)
13782 	emsg(_(e_invarg));
13783     else
13784     {
13785 	alloc_fail_id = argvars[0].vval.v_number;
13786 	if (alloc_fail_id >= aid_last)
13787 	    emsg(_(e_invarg));
13788 	alloc_fail_countdown = argvars[1].vval.v_number;
13789 	alloc_fail_repeat = argvars[2].vval.v_number;
13790 	did_outofmem_msg = FALSE;
13791     }
13792 }
13793 
13794 /*
13795  * "test_autochdir()"
13796  */
13797     static void
13798 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13799 {
13800 #if defined(FEAT_AUTOCHDIR)
13801     test_autochdir = TRUE;
13802 #endif
13803 }
13804 
13805 /*
13806  * "test_feedinput()"
13807  */
13808     static void
13809 f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13810 {
13811 #ifdef USE_INPUT_BUF
13812     char_u	*val = tv_get_string_chk(&argvars[0]);
13813 
13814     if (val != NULL)
13815     {
13816 	trash_input_buf();
13817 	add_to_input_buf_csi(val, (int)STRLEN(val));
13818     }
13819 #endif
13820 }
13821 
13822 /*
13823  * "test_option_not_set({name})" function
13824  */
13825     static void
13826 f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13827 {
13828     char_u *name = (char_u *)"";
13829 
13830     if (argvars[0].v_type != VAR_STRING)
13831 	emsg(_(e_invarg));
13832     else
13833     {
13834 	name = tv_get_string(&argvars[0]);
13835 	if (reset_option_was_set(name) == FAIL)
13836 	    semsg(_(e_invarg2), name);
13837     }
13838 }
13839 
13840 /*
13841  * "test_override({name}, {val})" function
13842  */
13843     static void
13844 f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
13845 {
13846     char_u *name = (char_u *)"";
13847     int     val;
13848     static int save_starting = -1;
13849 
13850     if (argvars[0].v_type != VAR_STRING
13851 	    || (argvars[1].v_type) != VAR_NUMBER)
13852 	emsg(_(e_invarg));
13853     else
13854     {
13855 	name = tv_get_string(&argvars[0]);
13856 	val = (int)tv_get_number(&argvars[1]);
13857 
13858 	if (STRCMP(name, (char_u *)"redraw") == 0)
13859 	    disable_redraw_for_testing = val;
13860 	else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13861 	    ignore_redraw_flag_for_testing = val;
13862 	else if (STRCMP(name, (char_u *)"char_avail") == 0)
13863 	    disable_char_avail_for_testing = val;
13864 	else if (STRCMP(name, (char_u *)"starting") == 0)
13865 	{
13866 	    if (val)
13867 	    {
13868 		if (save_starting < 0)
13869 		    save_starting = starting;
13870 		starting = 0;
13871 	    }
13872 	    else
13873 	    {
13874 		starting = save_starting;
13875 		save_starting = -1;
13876 	    }
13877 	}
13878 	else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13879 	    nfa_fail_for_testing = val;
13880 	else if (STRCMP(name, (char_u *)"ALL") == 0)
13881 	{
13882 	    disable_char_avail_for_testing = FALSE;
13883 	    disable_redraw_for_testing = FALSE;
13884 	    ignore_redraw_flag_for_testing = FALSE;
13885 	    nfa_fail_for_testing = FALSE;
13886 	    if (save_starting >= 0)
13887 	    {
13888 		starting = save_starting;
13889 		save_starting = -1;
13890 	    }
13891 	}
13892 	else
13893 	    semsg(_(e_invarg2), name);
13894     }
13895 }
13896 
13897 /*
13898  * "test_refcount({expr})" function
13899  */
13900     static void
13901 f_test_refcount(typval_T *argvars, typval_T *rettv)
13902 {
13903     int retval = -1;
13904 
13905     switch (argvars[0].v_type)
13906     {
13907 	case VAR_UNKNOWN:
13908 	case VAR_NUMBER:
13909 	case VAR_FLOAT:
13910 	case VAR_SPECIAL:
13911 	case VAR_STRING:
13912 	    break;
13913 	case VAR_JOB:
13914 #ifdef FEAT_JOB_CHANNEL
13915 	    if (argvars[0].vval.v_job != NULL)
13916 		retval = argvars[0].vval.v_job->jv_refcount - 1;
13917 #endif
13918 	    break;
13919 	case VAR_CHANNEL:
13920 #ifdef FEAT_JOB_CHANNEL
13921 	    if (argvars[0].vval.v_channel != NULL)
13922 		retval = argvars[0].vval.v_channel->ch_refcount - 1;
13923 #endif
13924 	    break;
13925 	case VAR_FUNC:
13926 	    if (argvars[0].vval.v_string != NULL)
13927 	    {
13928 		ufunc_T *fp;
13929 
13930 		fp = find_func(argvars[0].vval.v_string);
13931 		if (fp != NULL)
13932 		    retval = fp->uf_refcount;
13933 	    }
13934 	    break;
13935 	case VAR_PARTIAL:
13936 	    if (argvars[0].vval.v_partial != NULL)
13937 		retval = argvars[0].vval.v_partial->pt_refcount - 1;
13938 	    break;
13939 	case VAR_BLOB:
13940 	    if (argvars[0].vval.v_blob != NULL)
13941 		retval = argvars[0].vval.v_blob->bv_refcount - 1;
13942 	    break;
13943 	case VAR_LIST:
13944 	    if (argvars[0].vval.v_list != NULL)
13945 		retval = argvars[0].vval.v_list->lv_refcount - 1;
13946 	    break;
13947 	case VAR_DICT:
13948 	    if (argvars[0].vval.v_dict != NULL)
13949 		retval = argvars[0].vval.v_dict->dv_refcount - 1;
13950 	    break;
13951     }
13952 
13953     rettv->v_type = VAR_NUMBER;
13954     rettv->vval.v_number = retval;
13955 
13956 }
13957 
13958 /*
13959  * "test_garbagecollect_now()" function
13960  */
13961     static void
13962 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13963 {
13964     /* This is dangerous, any Lists and Dicts used internally may be freed
13965      * while still in use. */
13966     garbage_collect(TRUE);
13967 }
13968 
13969 /*
13970  * "test_ignore_error()" function
13971  */
13972     static void
13973 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13974 {
13975      ignore_error_for_testing(tv_get_string(&argvars[0]));
13976 }
13977 
13978     static void
13979 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13980 {
13981     rettv->v_type = VAR_BLOB;
13982     rettv->vval.v_blob = NULL;
13983 }
13984 
13985 #ifdef FEAT_JOB_CHANNEL
13986     static void
13987 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13988 {
13989     rettv->v_type = VAR_CHANNEL;
13990     rettv->vval.v_channel = NULL;
13991 }
13992 #endif
13993 
13994     static void
13995 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13996 {
13997     rettv_dict_set(rettv, NULL);
13998 }
13999 
14000 #ifdef FEAT_JOB_CHANNEL
14001     static void
14002 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14003 {
14004     rettv->v_type = VAR_JOB;
14005     rettv->vval.v_job = NULL;
14006 }
14007 #endif
14008 
14009     static void
14010 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14011 {
14012     rettv_list_set(rettv, NULL);
14013 }
14014 
14015     static void
14016 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14017 {
14018     rettv->v_type = VAR_PARTIAL;
14019     rettv->vval.v_partial = NULL;
14020 }
14021 
14022     static void
14023 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14024 {
14025     rettv->v_type = VAR_STRING;
14026     rettv->vval.v_string = NULL;
14027 }
14028 
14029 #ifdef FEAT_GUI
14030     static void
14031 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14032 {
14033     char_u	*which;
14034     long	value;
14035     int		dragging;
14036     scrollbar_T *sb = NULL;
14037 
14038     if (argvars[0].v_type != VAR_STRING
14039 	    || (argvars[1].v_type) != VAR_NUMBER
14040 	    || (argvars[2].v_type) != VAR_NUMBER)
14041     {
14042 	emsg(_(e_invarg));
14043 	return;
14044     }
14045     which = tv_get_string(&argvars[0]);
14046     value = tv_get_number(&argvars[1]);
14047     dragging = tv_get_number(&argvars[2]);
14048 
14049     if (STRCMP(which, "left") == 0)
14050 	sb = &curwin->w_scrollbars[SBAR_LEFT];
14051     else if (STRCMP(which, "right") == 0)
14052 	sb = &curwin->w_scrollbars[SBAR_RIGHT];
14053     else if (STRCMP(which, "hor") == 0)
14054 	sb = &gui.bottom_sbar;
14055     if (sb == NULL)
14056     {
14057 	semsg(_(e_invarg2), which);
14058 	return;
14059     }
14060     gui_drag_scrollbar(sb, value, dragging);
14061 # ifndef USE_ON_FLY_SCROLL
14062     // need to loop through normal_cmd() to handle the scroll events
14063     exec_normal(FALSE, TRUE, FALSE);
14064 # endif
14065 }
14066 #endif
14067 
14068     static void
14069 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14070 {
14071     time_for_testing = (time_t)tv_get_number(&argvars[0]);
14072 }
14073 
14074 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14075 /*
14076  * Get a callback from "arg".  It can be a Funcref or a function name.
14077  * When "arg" is zero return an empty string.
14078  * Return NULL for an invalid argument.
14079  */
14080     char_u *
14081 get_callback(typval_T *arg, partial_T **pp)
14082 {
14083     if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14084     {
14085 	*pp = arg->vval.v_partial;
14086 	++(*pp)->pt_refcount;
14087 	return partial_name(*pp);
14088     }
14089     *pp = NULL;
14090     if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
14091     {
14092 	func_ref(arg->vval.v_string);
14093 	return arg->vval.v_string;
14094     }
14095     if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14096 	return (char_u *)"";
14097     emsg(_("E921: Invalid callback argument"));
14098     return NULL;
14099 }
14100 
14101 /*
14102  * Unref/free "callback" and "partial" returned by get_callback().
14103  */
14104     void
14105 free_callback(char_u *callback, partial_T *partial)
14106 {
14107     if (partial != NULL)
14108 	partial_unref(partial);
14109     else if (callback != NULL)
14110     {
14111 	func_unref(callback);
14112 	vim_free(callback);
14113     }
14114 }
14115 #endif
14116 
14117 #ifdef FEAT_TIMERS
14118 /*
14119  * "timer_info([timer])" function
14120  */
14121     static void
14122 f_timer_info(typval_T *argvars, typval_T *rettv)
14123 {
14124     timer_T *timer = NULL;
14125 
14126     if (rettv_list_alloc(rettv) != OK)
14127 	return;
14128     if (argvars[0].v_type != VAR_UNKNOWN)
14129     {
14130 	if (argvars[0].v_type != VAR_NUMBER)
14131 	    emsg(_(e_number_exp));
14132 	else
14133 	{
14134 	    timer = find_timer((int)tv_get_number(&argvars[0]));
14135 	    if (timer != NULL)
14136 		add_timer_info(rettv, timer);
14137 	}
14138     }
14139     else
14140 	add_timer_info_all(rettv);
14141 }
14142 
14143 /*
14144  * "timer_pause(timer, paused)" function
14145  */
14146     static void
14147 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14148 {
14149     timer_T	*timer = NULL;
14150     int		paused = (int)tv_get_number(&argvars[1]);
14151 
14152     if (argvars[0].v_type != VAR_NUMBER)
14153 	emsg(_(e_number_exp));
14154     else
14155     {
14156 	timer = find_timer((int)tv_get_number(&argvars[0]));
14157 	if (timer != NULL)
14158 	    timer->tr_paused = paused;
14159     }
14160 }
14161 
14162 /*
14163  * "timer_start(time, callback [, options])" function
14164  */
14165     static void
14166 f_timer_start(typval_T *argvars, typval_T *rettv)
14167 {
14168     long	msec = (long)tv_get_number(&argvars[0]);
14169     timer_T	*timer;
14170     int		repeat = 0;
14171     char_u	*callback;
14172     dict_T	*dict;
14173     partial_T	*partial;
14174 
14175     rettv->vval.v_number = -1;
14176     if (check_secure())
14177 	return;
14178     if (argvars[2].v_type != VAR_UNKNOWN)
14179     {
14180 	if (argvars[2].v_type != VAR_DICT
14181 				   || (dict = argvars[2].vval.v_dict) == NULL)
14182 	{
14183 	    semsg(_(e_invarg2), tv_get_string(&argvars[2]));
14184 	    return;
14185 	}
14186 	if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
14187 	    repeat = dict_get_number(dict, (char_u *)"repeat");
14188     }
14189 
14190     callback = get_callback(&argvars[1], &partial);
14191     if (callback == NULL)
14192 	return;
14193 
14194     timer = create_timer(msec, repeat);
14195     if (timer == NULL)
14196 	free_callback(callback, partial);
14197     else
14198     {
14199 	if (partial == NULL)
14200 	    timer->tr_callback = vim_strsave(callback);
14201 	else
14202 	    /* pointer into the partial */
14203 	    timer->tr_callback = callback;
14204 	timer->tr_partial = partial;
14205 	rettv->vval.v_number = (varnumber_T)timer->tr_id;
14206     }
14207 }
14208 
14209 /*
14210  * "timer_stop(timer)" function
14211  */
14212     static void
14213 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14214 {
14215     timer_T *timer;
14216 
14217     if (argvars[0].v_type != VAR_NUMBER)
14218     {
14219 	emsg(_(e_number_exp));
14220 	return;
14221     }
14222     timer = find_timer((int)tv_get_number(&argvars[0]));
14223     if (timer != NULL)
14224 	stop_timer(timer);
14225 }
14226 
14227 /*
14228  * "timer_stopall()" function
14229  */
14230     static void
14231 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14232 {
14233     stop_all_timers();
14234 }
14235 #endif
14236 
14237 /*
14238  * "tolower(string)" function
14239  */
14240     static void
14241 f_tolower(typval_T *argvars, typval_T *rettv)
14242 {
14243     rettv->v_type = VAR_STRING;
14244     rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
14245 }
14246 
14247 /*
14248  * "toupper(string)" function
14249  */
14250     static void
14251 f_toupper(typval_T *argvars, typval_T *rettv)
14252 {
14253     rettv->v_type = VAR_STRING;
14254     rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
14255 }
14256 
14257 /*
14258  * "tr(string, fromstr, tostr)" function
14259  */
14260     static void
14261 f_tr(typval_T *argvars, typval_T *rettv)
14262 {
14263     char_u	*in_str;
14264     char_u	*fromstr;
14265     char_u	*tostr;
14266     char_u	*p;
14267     int		inlen;
14268     int		fromlen;
14269     int		tolen;
14270     int		idx;
14271     char_u	*cpstr;
14272     int		cplen;
14273     int		first = TRUE;
14274     char_u	buf[NUMBUFLEN];
14275     char_u	buf2[NUMBUFLEN];
14276     garray_T	ga;
14277 
14278     in_str = tv_get_string(&argvars[0]);
14279     fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14280     tostr = tv_get_string_buf_chk(&argvars[2], buf2);
14281 
14282     /* Default return value: empty string. */
14283     rettv->v_type = VAR_STRING;
14284     rettv->vval.v_string = NULL;
14285     if (fromstr == NULL || tostr == NULL)
14286 	    return;		/* type error; errmsg already given */
14287     ga_init2(&ga, (int)sizeof(char), 80);
14288 
14289     if (!has_mbyte)
14290 	/* not multi-byte: fromstr and tostr must be the same length */
14291 	if (STRLEN(fromstr) != STRLEN(tostr))
14292 	{
14293 error:
14294 	    semsg(_(e_invarg2), fromstr);
14295 	    ga_clear(&ga);
14296 	    return;
14297 	}
14298 
14299     /* fromstr and tostr have to contain the same number of chars */
14300     while (*in_str != NUL)
14301     {
14302 	if (has_mbyte)
14303 	{
14304 	    inlen = (*mb_ptr2len)(in_str);
14305 	    cpstr = in_str;
14306 	    cplen = inlen;
14307 	    idx = 0;
14308 	    for (p = fromstr; *p != NUL; p += fromlen)
14309 	    {
14310 		fromlen = (*mb_ptr2len)(p);
14311 		if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14312 		{
14313 		    for (p = tostr; *p != NUL; p += tolen)
14314 		    {
14315 			tolen = (*mb_ptr2len)(p);
14316 			if (idx-- == 0)
14317 			{
14318 			    cplen = tolen;
14319 			    cpstr = p;
14320 			    break;
14321 			}
14322 		    }
14323 		    if (*p == NUL)	/* tostr is shorter than fromstr */
14324 			goto error;
14325 		    break;
14326 		}
14327 		++idx;
14328 	    }
14329 
14330 	    if (first && cpstr == in_str)
14331 	    {
14332 		/* Check that fromstr and tostr have the same number of
14333 		 * (multi-byte) characters.  Done only once when a character
14334 		 * of in_str doesn't appear in fromstr. */
14335 		first = FALSE;
14336 		for (p = tostr; *p != NUL; p += tolen)
14337 		{
14338 		    tolen = (*mb_ptr2len)(p);
14339 		    --idx;
14340 		}
14341 		if (idx != 0)
14342 		    goto error;
14343 	    }
14344 
14345 	    (void)ga_grow(&ga, cplen);
14346 	    mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14347 	    ga.ga_len += cplen;
14348 
14349 	    in_str += inlen;
14350 	}
14351 	else
14352 	{
14353 	    /* When not using multi-byte chars we can do it faster. */
14354 	    p = vim_strchr(fromstr, *in_str);
14355 	    if (p != NULL)
14356 		ga_append(&ga, tostr[p - fromstr]);
14357 	    else
14358 		ga_append(&ga, *in_str);
14359 	    ++in_str;
14360 	}
14361     }
14362 
14363     /* add a terminating NUL */
14364     (void)ga_grow(&ga, 1);
14365     ga_append(&ga, NUL);
14366 
14367     rettv->vval.v_string = ga.ga_data;
14368 }
14369 
14370 /*
14371  * "trim({expr})" function
14372  */
14373     static void
14374 f_trim(typval_T *argvars, typval_T *rettv)
14375 {
14376     char_u	buf1[NUMBUFLEN];
14377     char_u	buf2[NUMBUFLEN];
14378     char_u	*head = tv_get_string_buf_chk(&argvars[0], buf1);
14379     char_u	*mask = NULL;
14380     char_u	*tail;
14381     char_u	*prev;
14382     char_u	*p;
14383     int		c1;
14384 
14385     rettv->v_type = VAR_STRING;
14386     if (head == NULL)
14387     {
14388 	rettv->vval.v_string = NULL;
14389 	return;
14390     }
14391 
14392     if (argvars[1].v_type == VAR_STRING)
14393 	mask = tv_get_string_buf_chk(&argvars[1], buf2);
14394 
14395     while (*head != NUL)
14396     {
14397 	c1 = PTR2CHAR(head);
14398 	if (mask == NULL)
14399 	{
14400 	    if (c1 > ' ' && c1 != 0xa0)
14401 		break;
14402 	}
14403 	else
14404 	{
14405 	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
14406 		if (c1 == PTR2CHAR(p))
14407 		    break;
14408 	    if (*p == NUL)
14409 		break;
14410 	}
14411 	MB_PTR_ADV(head);
14412     }
14413 
14414     for (tail = head + STRLEN(head); tail > head; tail = prev)
14415     {
14416 	prev = tail;
14417 	MB_PTR_BACK(head, prev);
14418 	c1 = PTR2CHAR(prev);
14419 	if (mask == NULL)
14420 	{
14421 	    if (c1 > ' ' && c1 != 0xa0)
14422 		break;
14423 	}
14424 	else
14425 	{
14426 	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
14427 		if (c1 == PTR2CHAR(p))
14428 		    break;
14429 	    if (*p == NUL)
14430 		break;
14431 	}
14432     }
14433     rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14434 }
14435 
14436 #ifdef FEAT_FLOAT
14437 /*
14438  * "trunc({float})" function
14439  */
14440     static void
14441 f_trunc(typval_T *argvars, typval_T *rettv)
14442 {
14443     float_T	f = 0.0;
14444 
14445     rettv->v_type = VAR_FLOAT;
14446     if (get_float_arg(argvars, &f) == OK)
14447 	/* trunc() is not in C90, use floor() or ceil() instead. */
14448 	rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14449     else
14450 	rettv->vval.v_float = 0.0;
14451 }
14452 #endif
14453 
14454 /*
14455  * "type(expr)" function
14456  */
14457     static void
14458 f_type(typval_T *argvars, typval_T *rettv)
14459 {
14460     int n = -1;
14461 
14462     switch (argvars[0].v_type)
14463     {
14464 	case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14465 	case VAR_STRING: n = VAR_TYPE_STRING; break;
14466 	case VAR_PARTIAL:
14467 	case VAR_FUNC:   n = VAR_TYPE_FUNC; break;
14468 	case VAR_LIST:   n = VAR_TYPE_LIST; break;
14469 	case VAR_DICT:   n = VAR_TYPE_DICT; break;
14470 	case VAR_FLOAT:  n = VAR_TYPE_FLOAT; break;
14471 	case VAR_SPECIAL:
14472 	     if (argvars[0].vval.v_number == VVAL_FALSE
14473 		     || argvars[0].vval.v_number == VVAL_TRUE)
14474 		 n = VAR_TYPE_BOOL;
14475 	     else
14476 		 n = VAR_TYPE_NONE;
14477 	     break;
14478 	case VAR_JOB:     n = VAR_TYPE_JOB; break;
14479 	case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
14480 	case VAR_BLOB:    n = VAR_TYPE_BLOB; break;
14481 	case VAR_UNKNOWN:
14482 	     internal_error("f_type(UNKNOWN)");
14483 	     n = -1;
14484 	     break;
14485     }
14486     rettv->vval.v_number = n;
14487 }
14488 
14489 /*
14490  * "undofile(name)" function
14491  */
14492     static void
14493 f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14494 {
14495     rettv->v_type = VAR_STRING;
14496 #ifdef FEAT_PERSISTENT_UNDO
14497     {
14498 	char_u *fname = tv_get_string(&argvars[0]);
14499 
14500 	if (*fname == NUL)
14501 	{
14502 	    /* If there is no file name there will be no undo file. */
14503 	    rettv->vval.v_string = NULL;
14504 	}
14505 	else
14506 	{
14507 	    char_u *ffname = FullName_save(fname, FALSE);
14508 
14509 	    if (ffname != NULL)
14510 		rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14511 	    vim_free(ffname);
14512 	}
14513     }
14514 #else
14515     rettv->vval.v_string = NULL;
14516 #endif
14517 }
14518 
14519 /*
14520  * "undotree()" function
14521  */
14522     static void
14523 f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14524 {
14525     if (rettv_dict_alloc(rettv) == OK)
14526     {
14527 	dict_T *dict = rettv->vval.v_dict;
14528 	list_T *list;
14529 
14530 	dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14531 	dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14532 	dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14533 	dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14534 	dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14535 	dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
14536 
14537 	list = list_alloc();
14538 	if (list != NULL)
14539 	{
14540 	    u_eval_tree(curbuf->b_u_oldhead, list);
14541 	    dict_add_list(dict, "entries", list);
14542 	}
14543     }
14544 }
14545 
14546 /*
14547  * "values(dict)" function
14548  */
14549     static void
14550 f_values(typval_T *argvars, typval_T *rettv)
14551 {
14552     dict_list(argvars, rettv, 1);
14553 }
14554 
14555 /*
14556  * "virtcol(string)" function
14557  */
14558     static void
14559 f_virtcol(typval_T *argvars, typval_T *rettv)
14560 {
14561     colnr_T	vcol = 0;
14562     pos_T	*fp;
14563     int		fnum = curbuf->b_fnum;
14564 
14565     fp = var2fpos(&argvars[0], FALSE, &fnum);
14566     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14567 						    && fnum == curbuf->b_fnum)
14568     {
14569 	getvvcol(curwin, fp, NULL, NULL, &vcol);
14570 	++vcol;
14571     }
14572 
14573     rettv->vval.v_number = vcol;
14574 }
14575 
14576 /*
14577  * "visualmode()" function
14578  */
14579     static void
14580 f_visualmode(typval_T *argvars, typval_T *rettv)
14581 {
14582     char_u	str[2];
14583 
14584     rettv->v_type = VAR_STRING;
14585     str[0] = curbuf->b_visual_mode_eval;
14586     str[1] = NUL;
14587     rettv->vval.v_string = vim_strsave(str);
14588 
14589     /* A non-zero number or non-empty string argument: reset mode. */
14590     if (non_zero_arg(&argvars[0]))
14591 	curbuf->b_visual_mode_eval = NUL;
14592 }
14593 
14594 /*
14595  * "wildmenumode()" function
14596  */
14597     static void
14598 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14599 {
14600 #ifdef FEAT_WILDMENU
14601     if (wild_menu_showing)
14602 	rettv->vval.v_number = 1;
14603 #endif
14604 }
14605 
14606 /*
14607  * "winbufnr(nr)" function
14608  */
14609     static void
14610 f_winbufnr(typval_T *argvars, typval_T *rettv)
14611 {
14612     win_T	*wp;
14613 
14614     wp = find_win_by_nr_or_id(&argvars[0]);
14615     if (wp == NULL)
14616 	rettv->vval.v_number = -1;
14617     else
14618 	rettv->vval.v_number = wp->w_buffer->b_fnum;
14619 }
14620 
14621 /*
14622  * "wincol()" function
14623  */
14624     static void
14625 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14626 {
14627     validate_cursor();
14628     rettv->vval.v_number = curwin->w_wcol + 1;
14629 }
14630 
14631 /*
14632  * "winheight(nr)" function
14633  */
14634     static void
14635 f_winheight(typval_T *argvars, typval_T *rettv)
14636 {
14637     win_T	*wp;
14638 
14639     wp = find_win_by_nr_or_id(&argvars[0]);
14640     if (wp == NULL)
14641 	rettv->vval.v_number = -1;
14642     else
14643 	rettv->vval.v_number = wp->w_height;
14644 }
14645 
14646 /*
14647  * "winlayout()" function
14648  */
14649     static void
14650 f_winlayout(typval_T *argvars, typval_T *rettv)
14651 {
14652     tabpage_T	*tp;
14653 
14654     if (rettv_list_alloc(rettv) != OK)
14655 	return;
14656 
14657     if (argvars[0].v_type == VAR_UNKNOWN)
14658 	tp = curtab;
14659     else
14660     {
14661 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
14662 	if (tp == NULL)
14663 	    return;
14664     }
14665 
14666     get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14667 }
14668 
14669 /*
14670  * "winline()" function
14671  */
14672     static void
14673 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14674 {
14675     validate_cursor();
14676     rettv->vval.v_number = curwin->w_wrow + 1;
14677 }
14678 
14679 /*
14680  * "winnr()" function
14681  */
14682     static void
14683 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14684 {
14685     int		nr = 1;
14686 
14687     nr = get_winnr(curtab, &argvars[0]);
14688     rettv->vval.v_number = nr;
14689 }
14690 
14691 /*
14692  * "winrestcmd()" function
14693  */
14694     static void
14695 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14696 {
14697     win_T	*wp;
14698     int		winnr = 1;
14699     garray_T	ga;
14700     char_u	buf[50];
14701 
14702     ga_init2(&ga, (int)sizeof(char), 70);
14703     FOR_ALL_WINDOWS(wp)
14704     {
14705 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14706 	ga_concat(&ga, buf);
14707 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14708 	ga_concat(&ga, buf);
14709 	++winnr;
14710     }
14711     ga_append(&ga, NUL);
14712 
14713     rettv->vval.v_string = ga.ga_data;
14714     rettv->v_type = VAR_STRING;
14715 }
14716 
14717 /*
14718  * "winrestview()" function
14719  */
14720     static void
14721 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14722 {
14723     dict_T	*dict;
14724 
14725     if (argvars[0].v_type != VAR_DICT
14726 	    || (dict = argvars[0].vval.v_dict) == NULL)
14727 	emsg(_(e_invarg));
14728     else
14729     {
14730 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
14731 	    curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
14732 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
14733 	    curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
14734 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
14735 	    curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
14736 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14737 	{
14738 	    curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
14739 	    curwin->w_set_curswant = FALSE;
14740 	}
14741 
14742 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
14743 	    set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
14744 #ifdef FEAT_DIFF
14745 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
14746 	    curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
14747 #endif
14748 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
14749 	    curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
14750 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
14751 	    curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
14752 
14753 	check_cursor();
14754 	win_new_height(curwin, curwin->w_height);
14755 	win_new_width(curwin, curwin->w_width);
14756 	changed_window_setting();
14757 
14758 	if (curwin->w_topline <= 0)
14759 	    curwin->w_topline = 1;
14760 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14761 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
14762 #ifdef FEAT_DIFF
14763 	check_topfill(curwin, TRUE);
14764 #endif
14765     }
14766 }
14767 
14768 /*
14769  * "winsaveview()" function
14770  */
14771     static void
14772 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14773 {
14774     dict_T	*dict;
14775 
14776     if (rettv_dict_alloc(rettv) == FAIL)
14777 	return;
14778     dict = rettv->vval.v_dict;
14779 
14780     dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14781     dict_add_number(dict, "col", (long)curwin->w_cursor.col);
14782     dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
14783     update_curswant();
14784     dict_add_number(dict, "curswant", (long)curwin->w_curswant);
14785 
14786     dict_add_number(dict, "topline", (long)curwin->w_topline);
14787 #ifdef FEAT_DIFF
14788     dict_add_number(dict, "topfill", (long)curwin->w_topfill);
14789 #endif
14790     dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14791     dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
14792 }
14793 
14794 /*
14795  * "winwidth(nr)" function
14796  */
14797     static void
14798 f_winwidth(typval_T *argvars, typval_T *rettv)
14799 {
14800     win_T	*wp;
14801 
14802     wp = find_win_by_nr_or_id(&argvars[0]);
14803     if (wp == NULL)
14804 	rettv->vval.v_number = -1;
14805     else
14806 	rettv->vval.v_number = wp->w_width;
14807 }
14808 
14809 /*
14810  * "wordcount()" function
14811  */
14812     static void
14813 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14814 {
14815     if (rettv_dict_alloc(rettv) == FAIL)
14816 	return;
14817     cursor_pos_info(rettv->vval.v_dict);
14818 }
14819 
14820 /*
14821  * "writefile()" function
14822  */
14823     static void
14824 f_writefile(typval_T *argvars, typval_T *rettv)
14825 {
14826     int		binary = FALSE;
14827     int		append = FALSE;
14828 #ifdef HAVE_FSYNC
14829     int		do_fsync = p_fs;
14830 #endif
14831     char_u	*fname;
14832     FILE	*fd;
14833     int		ret = 0;
14834     listitem_T	*li;
14835     list_T	*list = NULL;
14836     blob_T	*blob = NULL;
14837 
14838     rettv->vval.v_number = -1;
14839     if (check_secure())
14840 	return;
14841 
14842     if (argvars[0].v_type == VAR_LIST)
14843     {
14844 	list = argvars[0].vval.v_list;
14845 	if (list == NULL)
14846 	    return;
14847 	for (li = list->lv_first; li != NULL; li = li->li_next)
14848 	    if (tv_get_string_chk(&li->li_tv) == NULL)
14849 		return;
14850     }
14851     else if (argvars[0].v_type == VAR_BLOB)
14852     {
14853 	blob = argvars[0].vval.v_blob;
14854 	if (blob == NULL)
14855 	    return;
14856     }
14857     else
14858     {
14859 	semsg(_(e_invarg2), "writefile()");
14860 	return;
14861     }
14862 
14863     if (argvars[2].v_type != VAR_UNKNOWN)
14864     {
14865 	char_u *arg2 = tv_get_string_chk(&argvars[2]);
14866 
14867 	if (arg2 == NULL)
14868 	    return;
14869 	if (vim_strchr(arg2, 'b') != NULL)
14870 	    binary = TRUE;
14871 	if (vim_strchr(arg2, 'a') != NULL)
14872 	    append = TRUE;
14873 #ifdef HAVE_FSYNC
14874 	if (vim_strchr(arg2, 's') != NULL)
14875 	    do_fsync = TRUE;
14876 	else if (vim_strchr(arg2, 'S') != NULL)
14877 	    do_fsync = FALSE;
14878 #endif
14879     }
14880 
14881     fname = tv_get_string_chk(&argvars[1]);
14882     if (fname == NULL)
14883 	return;
14884 
14885     /* Always open the file in binary mode, library functions have a mind of
14886      * their own about CR-LF conversion. */
14887     if (*fname == NUL || (fd = mch_fopen((char *)fname,
14888 				      append ? APPENDBIN : WRITEBIN)) == NULL)
14889     {
14890 	semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14891 	ret = -1;
14892     }
14893     else if (blob)
14894     {
14895 	if (write_blob(fd, blob) == FAIL)
14896 	    ret = -1;
14897 #ifdef HAVE_FSYNC
14898 	else if (do_fsync)
14899 	    // Ignore the error, the user wouldn't know what to do about it.
14900 	    // May happen for a device.
14901 	    vim_ignored = vim_fsync(fileno(fd));
14902 #endif
14903 	fclose(fd);
14904     }
14905     else
14906     {
14907 	if (write_list(fd, list, binary) == FAIL)
14908 	    ret = -1;
14909 #ifdef HAVE_FSYNC
14910 	else if (do_fsync)
14911 	    /* Ignore the error, the user wouldn't know what to do about it.
14912 	     * May happen for a device. */
14913 	    vim_ignored = vim_fsync(fileno(fd));
14914 #endif
14915 	fclose(fd);
14916     }
14917 
14918     rettv->vval.v_number = ret;
14919 }
14920 
14921 /*
14922  * "xor(expr, expr)" function
14923  */
14924     static void
14925 f_xor(typval_T *argvars, typval_T *rettv)
14926 {
14927     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14928 					^ tv_get_number_chk(&argvars[1], NULL);
14929 }
14930 
14931 #endif /* FEAT_EVAL */
14932