xref: /vim-8.2.3635/src/evalfunc.c (revision 94688b8a)
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 #endif
117 static void f_confirm(typval_T *argvars, typval_T *rettv);
118 static void f_copy(typval_T *argvars, typval_T *rettv);
119 #ifdef FEAT_FLOAT
120 static void f_cos(typval_T *argvars, typval_T *rettv);
121 static void f_cosh(typval_T *argvars, typval_T *rettv);
122 #endif
123 static void f_count(typval_T *argvars, typval_T *rettv);
124 static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
125 static void f_cursor(typval_T *argsvars, typval_T *rettv);
126 #ifdef WIN3264
127 static void f_debugbreak(typval_T *argvars, typval_T *rettv);
128 #endif
129 static void f_deepcopy(typval_T *argvars, typval_T *rettv);
130 static void f_delete(typval_T *argvars, typval_T *rettv);
131 static void f_deletebufline(typval_T *argvars, typval_T *rettv);
132 static void f_did_filetype(typval_T *argvars, typval_T *rettv);
133 static void f_diff_filler(typval_T *argvars, typval_T *rettv);
134 static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
135 static void f_empty(typval_T *argvars, typval_T *rettv);
136 static void f_escape(typval_T *argvars, typval_T *rettv);
137 static void f_eval(typval_T *argvars, typval_T *rettv);
138 static void f_eventhandler(typval_T *argvars, typval_T *rettv);
139 static void f_executable(typval_T *argvars, typval_T *rettv);
140 static void f_execute(typval_T *argvars, typval_T *rettv);
141 static void f_exepath(typval_T *argvars, typval_T *rettv);
142 static void f_exists(typval_T *argvars, typval_T *rettv);
143 #ifdef FEAT_FLOAT
144 static void f_exp(typval_T *argvars, typval_T *rettv);
145 #endif
146 static void f_expand(typval_T *argvars, typval_T *rettv);
147 static void f_extend(typval_T *argvars, typval_T *rettv);
148 static void f_feedkeys(typval_T *argvars, typval_T *rettv);
149 static void f_filereadable(typval_T *argvars, typval_T *rettv);
150 static void f_filewritable(typval_T *argvars, typval_T *rettv);
151 static void f_filter(typval_T *argvars, typval_T *rettv);
152 static void f_finddir(typval_T *argvars, typval_T *rettv);
153 static void f_findfile(typval_T *argvars, typval_T *rettv);
154 #ifdef FEAT_FLOAT
155 static void f_float2nr(typval_T *argvars, typval_T *rettv);
156 static void f_floor(typval_T *argvars, typval_T *rettv);
157 static void f_fmod(typval_T *argvars, typval_T *rettv);
158 #endif
159 static void f_fnameescape(typval_T *argvars, typval_T *rettv);
160 static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
161 static void f_foldclosed(typval_T *argvars, typval_T *rettv);
162 static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
163 static void f_foldlevel(typval_T *argvars, typval_T *rettv);
164 static void f_foldtext(typval_T *argvars, typval_T *rettv);
165 static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
166 static void f_foreground(typval_T *argvars, typval_T *rettv);
167 static void f_funcref(typval_T *argvars, typval_T *rettv);
168 static void f_function(typval_T *argvars, typval_T *rettv);
169 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
170 static void f_get(typval_T *argvars, typval_T *rettv);
171 static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
172 static void f_getbufline(typval_T *argvars, typval_T *rettv);
173 static void f_getbufvar(typval_T *argvars, typval_T *rettv);
174 static void f_getchangelist(typval_T *argvars, typval_T *rettv);
175 static void f_getchar(typval_T *argvars, typval_T *rettv);
176 static void f_getcharmod(typval_T *argvars, typval_T *rettv);
177 static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
178 static void f_getcmdline(typval_T *argvars, typval_T *rettv);
179 #if defined(FEAT_CMDL_COMPL)
180 static void f_getcompletion(typval_T *argvars, typval_T *rettv);
181 #endif
182 static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
183 static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
184 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
185 static void f_getcwd(typval_T *argvars, typval_T *rettv);
186 static void f_getfontname(typval_T *argvars, typval_T *rettv);
187 static void f_getfperm(typval_T *argvars, typval_T *rettv);
188 static void f_getfsize(typval_T *argvars, typval_T *rettv);
189 static void f_getftime(typval_T *argvars, typval_T *rettv);
190 static void f_getftype(typval_T *argvars, typval_T *rettv);
191 static void f_getjumplist(typval_T *argvars, typval_T *rettv);
192 static void f_getline(typval_T *argvars, typval_T *rettv);
193 static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
194 static void f_getmatches(typval_T *argvars, typval_T *rettv);
195 static void f_getpid(typval_T *argvars, typval_T *rettv);
196 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
197 static void f_getpos(typval_T *argvars, typval_T *rettv);
198 static void f_getqflist(typval_T *argvars, typval_T *rettv);
199 static void f_getreg(typval_T *argvars, typval_T *rettv);
200 static void f_getregtype(typval_T *argvars, typval_T *rettv);
201 static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
202 static void f_gettabvar(typval_T *argvars, typval_T *rettv);
203 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
204 static void f_gettagstack(typval_T *argvars, typval_T *rettv);
205 static void f_getwininfo(typval_T *argvars, typval_T *rettv);
206 static void f_getwinpos(typval_T *argvars, typval_T *rettv);
207 static void f_getwinposx(typval_T *argvars, typval_T *rettv);
208 static void f_getwinposy(typval_T *argvars, typval_T *rettv);
209 static void f_getwinvar(typval_T *argvars, typval_T *rettv);
210 static void f_glob(typval_T *argvars, typval_T *rettv);
211 static void f_globpath(typval_T *argvars, typval_T *rettv);
212 static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
213 static void f_has(typval_T *argvars, typval_T *rettv);
214 static void f_has_key(typval_T *argvars, typval_T *rettv);
215 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
216 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
217 static void f_histadd(typval_T *argvars, typval_T *rettv);
218 static void f_histdel(typval_T *argvars, typval_T *rettv);
219 static void f_histget(typval_T *argvars, typval_T *rettv);
220 static void f_histnr(typval_T *argvars, typval_T *rettv);
221 static void f_hlID(typval_T *argvars, typval_T *rettv);
222 static void f_hlexists(typval_T *argvars, typval_T *rettv);
223 static void f_hostname(typval_T *argvars, typval_T *rettv);
224 static void f_iconv(typval_T *argvars, typval_T *rettv);
225 static void f_indent(typval_T *argvars, typval_T *rettv);
226 static void f_index(typval_T *argvars, typval_T *rettv);
227 static void f_input(typval_T *argvars, typval_T *rettv);
228 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
229 static void f_inputlist(typval_T *argvars, typval_T *rettv);
230 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
231 static void f_inputsave(typval_T *argvars, typval_T *rettv);
232 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
233 static void f_insert(typval_T *argvars, typval_T *rettv);
234 static void f_invert(typval_T *argvars, typval_T *rettv);
235 static void f_isdirectory(typval_T *argvars, typval_T *rettv);
236 static void f_islocked(typval_T *argvars, typval_T *rettv);
237 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
238 static void f_isnan(typval_T *argvars, typval_T *rettv);
239 #endif
240 static void f_items(typval_T *argvars, typval_T *rettv);
241 #ifdef FEAT_JOB_CHANNEL
242 static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
243 static void f_job_info(typval_T *argvars, typval_T *rettv);
244 static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
245 static void f_job_start(typval_T *argvars, typval_T *rettv);
246 static void f_job_stop(typval_T *argvars, typval_T *rettv);
247 static void f_job_status(typval_T *argvars, typval_T *rettv);
248 #endif
249 static void f_join(typval_T *argvars, typval_T *rettv);
250 static void f_js_decode(typval_T *argvars, typval_T *rettv);
251 static void f_js_encode(typval_T *argvars, typval_T *rettv);
252 static void f_json_decode(typval_T *argvars, typval_T *rettv);
253 static void f_json_encode(typval_T *argvars, typval_T *rettv);
254 static void f_keys(typval_T *argvars, typval_T *rettv);
255 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
256 static void f_len(typval_T *argvars, typval_T *rettv);
257 static void f_libcall(typval_T *argvars, typval_T *rettv);
258 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
259 static void f_line(typval_T *argvars, typval_T *rettv);
260 static void f_line2byte(typval_T *argvars, typval_T *rettv);
261 static void f_lispindent(typval_T *argvars, typval_T *rettv);
262 static void f_localtime(typval_T *argvars, typval_T *rettv);
263 #ifdef FEAT_FLOAT
264 static void f_log(typval_T *argvars, typval_T *rettv);
265 static void f_log10(typval_T *argvars, typval_T *rettv);
266 #endif
267 #ifdef FEAT_LUA
268 static void f_luaeval(typval_T *argvars, typval_T *rettv);
269 #endif
270 static void f_map(typval_T *argvars, typval_T *rettv);
271 static void f_maparg(typval_T *argvars, typval_T *rettv);
272 static void f_mapcheck(typval_T *argvars, typval_T *rettv);
273 static void f_match(typval_T *argvars, typval_T *rettv);
274 static void f_matchadd(typval_T *argvars, typval_T *rettv);
275 static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
276 static void f_matcharg(typval_T *argvars, typval_T *rettv);
277 static void f_matchdelete(typval_T *argvars, typval_T *rettv);
278 static void f_matchend(typval_T *argvars, typval_T *rettv);
279 static void f_matchlist(typval_T *argvars, typval_T *rettv);
280 static void f_matchstr(typval_T *argvars, typval_T *rettv);
281 static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
282 static void f_max(typval_T *argvars, typval_T *rettv);
283 static void f_min(typval_T *argvars, typval_T *rettv);
284 #ifdef vim_mkdir
285 static void f_mkdir(typval_T *argvars, typval_T *rettv);
286 #endif
287 static void f_mode(typval_T *argvars, typval_T *rettv);
288 #ifdef FEAT_MZSCHEME
289 static void f_mzeval(typval_T *argvars, typval_T *rettv);
290 #endif
291 static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
292 static void f_nr2char(typval_T *argvars, typval_T *rettv);
293 static void f_or(typval_T *argvars, typval_T *rettv);
294 static void f_pathshorten(typval_T *argvars, typval_T *rettv);
295 #ifdef FEAT_PERL
296 static void f_perleval(typval_T *argvars, typval_T *rettv);
297 #endif
298 #ifdef FEAT_FLOAT
299 static void f_pow(typval_T *argvars, typval_T *rettv);
300 #endif
301 static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
302 static void f_printf(typval_T *argvars, typval_T *rettv);
303 #ifdef FEAT_JOB_CHANNEL
304 static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
305 static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
306 static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
307 #endif
308 static void f_pumvisible(typval_T *argvars, typval_T *rettv);
309 #ifdef FEAT_PYTHON3
310 static void f_py3eval(typval_T *argvars, typval_T *rettv);
311 #endif
312 #ifdef FEAT_PYTHON
313 static void f_pyeval(typval_T *argvars, typval_T *rettv);
314 #endif
315 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
316 static void f_pyxeval(typval_T *argvars, typval_T *rettv);
317 #endif
318 static void f_range(typval_T *argvars, typval_T *rettv);
319 static void f_readfile(typval_T *argvars, typval_T *rettv);
320 static void f_reg_executing(typval_T *argvars, typval_T *rettv);
321 static void f_reg_recording(typval_T *argvars, typval_T *rettv);
322 static void f_reltime(typval_T *argvars, typval_T *rettv);
323 #ifdef FEAT_FLOAT
324 static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
325 #endif
326 static void f_reltimestr(typval_T *argvars, typval_T *rettv);
327 static void f_remote_expr(typval_T *argvars, typval_T *rettv);
328 static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
329 static void f_remote_peek(typval_T *argvars, typval_T *rettv);
330 static void f_remote_read(typval_T *argvars, typval_T *rettv);
331 static void f_remote_send(typval_T *argvars, typval_T *rettv);
332 static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
333 static void f_remove(typval_T *argvars, typval_T *rettv);
334 static void f_rename(typval_T *argvars, typval_T *rettv);
335 static void f_repeat(typval_T *argvars, typval_T *rettv);
336 static void f_resolve(typval_T *argvars, typval_T *rettv);
337 static void f_reverse(typval_T *argvars, typval_T *rettv);
338 #ifdef FEAT_FLOAT
339 static void f_round(typval_T *argvars, typval_T *rettv);
340 #endif
341 static void f_screenattr(typval_T *argvars, typval_T *rettv);
342 static void f_screenchar(typval_T *argvars, typval_T *rettv);
343 static void f_screencol(typval_T *argvars, typval_T *rettv);
344 static void f_screenrow(typval_T *argvars, typval_T *rettv);
345 static void f_search(typval_T *argvars, typval_T *rettv);
346 static void f_searchdecl(typval_T *argvars, typval_T *rettv);
347 static void f_searchpair(typval_T *argvars, typval_T *rettv);
348 static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
349 static void f_searchpos(typval_T *argvars, typval_T *rettv);
350 static void f_server2client(typval_T *argvars, typval_T *rettv);
351 static void f_serverlist(typval_T *argvars, typval_T *rettv);
352 static void f_setbufline(typval_T *argvars, typval_T *rettv);
353 static void f_setbufvar(typval_T *argvars, typval_T *rettv);
354 static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
355 static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
356 static void f_setfperm(typval_T *argvars, typval_T *rettv);
357 static void f_setline(typval_T *argvars, typval_T *rettv);
358 static void f_setloclist(typval_T *argvars, typval_T *rettv);
359 static void f_setmatches(typval_T *argvars, typval_T *rettv);
360 static void f_setpos(typval_T *argvars, typval_T *rettv);
361 static void f_setqflist(typval_T *argvars, typval_T *rettv);
362 static void f_setreg(typval_T *argvars, typval_T *rettv);
363 static void f_settabvar(typval_T *argvars, typval_T *rettv);
364 static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
365 static void f_settagstack(typval_T *argvars, typval_T *rettv);
366 static void f_setwinvar(typval_T *argvars, typval_T *rettv);
367 #ifdef FEAT_CRYPT
368 static void f_sha256(typval_T *argvars, typval_T *rettv);
369 #endif /* FEAT_CRYPT */
370 static void f_shellescape(typval_T *argvars, typval_T *rettv);
371 static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
372 #ifdef FEAT_SIGNS
373 static void f_sign_define(typval_T *argvars, typval_T *rettv);
374 static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
375 static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
376 static void f_sign_jump(typval_T *argvars, typval_T *rettv);
377 static void f_sign_place(typval_T *argvars, typval_T *rettv);
378 static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
379 static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
380 #endif
381 static void f_simplify(typval_T *argvars, typval_T *rettv);
382 #ifdef FEAT_FLOAT
383 static void f_sin(typval_T *argvars, typval_T *rettv);
384 static void f_sinh(typval_T *argvars, typval_T *rettv);
385 #endif
386 static void f_sort(typval_T *argvars, typval_T *rettv);
387 static void f_soundfold(typval_T *argvars, typval_T *rettv);
388 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
389 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
390 static void f_split(typval_T *argvars, typval_T *rettv);
391 #ifdef FEAT_FLOAT
392 static void f_sqrt(typval_T *argvars, typval_T *rettv);
393 static void f_str2float(typval_T *argvars, typval_T *rettv);
394 #endif
395 static void f_str2nr(typval_T *argvars, typval_T *rettv);
396 static void f_strchars(typval_T *argvars, typval_T *rettv);
397 #ifdef HAVE_STRFTIME
398 static void f_strftime(typval_T *argvars, typval_T *rettv);
399 #endif
400 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
401 static void f_stridx(typval_T *argvars, typval_T *rettv);
402 static void f_strlen(typval_T *argvars, typval_T *rettv);
403 static void f_strcharpart(typval_T *argvars, typval_T *rettv);
404 static void f_strpart(typval_T *argvars, typval_T *rettv);
405 static void f_strridx(typval_T *argvars, typval_T *rettv);
406 static void f_strtrans(typval_T *argvars, typval_T *rettv);
407 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
408 static void f_strwidth(typval_T *argvars, typval_T *rettv);
409 static void f_submatch(typval_T *argvars, typval_T *rettv);
410 static void f_substitute(typval_T *argvars, typval_T *rettv);
411 static void f_swapinfo(typval_T *argvars, typval_T *rettv);
412 static void f_swapname(typval_T *argvars, typval_T *rettv);
413 static void f_synID(typval_T *argvars, typval_T *rettv);
414 static void f_synIDattr(typval_T *argvars, typval_T *rettv);
415 static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
416 static void f_synstack(typval_T *argvars, typval_T *rettv);
417 static void f_synconcealed(typval_T *argvars, typval_T *rettv);
418 static void f_system(typval_T *argvars, typval_T *rettv);
419 static void f_systemlist(typval_T *argvars, typval_T *rettv);
420 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
421 static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
422 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
423 static void f_taglist(typval_T *argvars, typval_T *rettv);
424 static void f_tagfiles(typval_T *argvars, typval_T *rettv);
425 static void f_tempname(typval_T *argvars, typval_T *rettv);
426 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
427 static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
428 static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
429 static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
430 static void f_test_override(typval_T *argvars, typval_T *rettv);
431 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
432 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
433 static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
434 #ifdef FEAT_JOB_CHANNEL
435 static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
436 #endif
437 static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
438 #ifdef FEAT_JOB_CHANNEL
439 static void f_test_null_job(typval_T *argvars, typval_T *rettv);
440 #endif
441 static void f_test_null_list(typval_T *argvars, typval_T *rettv);
442 static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
443 static void f_test_null_string(typval_T *argvars, typval_T *rettv);
444 #ifdef FEAT_GUI
445 static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
446 #endif
447 static void f_test_settime(typval_T *argvars, typval_T *rettv);
448 #ifdef FEAT_FLOAT
449 static void f_tan(typval_T *argvars, typval_T *rettv);
450 static void f_tanh(typval_T *argvars, typval_T *rettv);
451 #endif
452 #ifdef FEAT_TIMERS
453 static void f_timer_info(typval_T *argvars, typval_T *rettv);
454 static void f_timer_pause(typval_T *argvars, typval_T *rettv);
455 static void f_timer_start(typval_T *argvars, typval_T *rettv);
456 static void f_timer_stop(typval_T *argvars, typval_T *rettv);
457 static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
458 #endif
459 static void f_tolower(typval_T *argvars, typval_T *rettv);
460 static void f_toupper(typval_T *argvars, typval_T *rettv);
461 static void f_tr(typval_T *argvars, typval_T *rettv);
462 static void f_trim(typval_T *argvars, typval_T *rettv);
463 #ifdef FEAT_FLOAT
464 static void f_trunc(typval_T *argvars, typval_T *rettv);
465 #endif
466 static void f_type(typval_T *argvars, typval_T *rettv);
467 static void f_undofile(typval_T *argvars, typval_T *rettv);
468 static void f_undotree(typval_T *argvars, typval_T *rettv);
469 static void f_uniq(typval_T *argvars, typval_T *rettv);
470 static void f_values(typval_T *argvars, typval_T *rettv);
471 static void f_virtcol(typval_T *argvars, typval_T *rettv);
472 static void f_visualmode(typval_T *argvars, typval_T *rettv);
473 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
474 static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
475 static void f_win_getid(typval_T *argvars, typval_T *rettv);
476 static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
477 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
478 static void f_win_id2win(typval_T *argvars, typval_T *rettv);
479 static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
480 static void f_winbufnr(typval_T *argvars, typval_T *rettv);
481 static void f_wincol(typval_T *argvars, typval_T *rettv);
482 static void f_winheight(typval_T *argvars, typval_T *rettv);
483 static void f_winlayout(typval_T *argvars, typval_T *rettv);
484 static void f_winline(typval_T *argvars, typval_T *rettv);
485 static void f_winnr(typval_T *argvars, typval_T *rettv);
486 static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
487 static void f_winrestview(typval_T *argvars, typval_T *rettv);
488 static void f_winsaveview(typval_T *argvars, typval_T *rettv);
489 static void f_winwidth(typval_T *argvars, typval_T *rettv);
490 static void f_writefile(typval_T *argvars, typval_T *rettv);
491 static void f_wordcount(typval_T *argvars, typval_T *rettv);
492 static void f_xor(typval_T *argvars, typval_T *rettv);
493 
494 /*
495  * Array with names and number of arguments of all internal functions
496  * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
497  */
498 static struct fst
499 {
500     char	*f_name;	/* function name */
501     char	f_min_argc;	/* minimal number of arguments */
502     char	f_max_argc;	/* maximal number of arguments */
503     void	(*f_func)(typval_T *args, typval_T *rvar);
504 				/* implementation of function */
505 } functions[] =
506 {
507 #ifdef FEAT_FLOAT
508     {"abs",		1, 1, f_abs},
509     {"acos",		1, 1, f_acos},	/* WJMc */
510 #endif
511     {"add",		2, 2, f_add},
512     {"and",		2, 2, f_and},
513     {"append",		2, 2, f_append},
514     {"appendbufline",	3, 3, f_appendbufline},
515     {"argc",		0, 1, f_argc},
516     {"argidx",		0, 0, f_argidx},
517     {"arglistid",	0, 2, f_arglistid},
518     {"argv",		0, 2, f_argv},
519 #ifdef FEAT_FLOAT
520     {"asin",		1, 1, f_asin},	/* WJMc */
521 #endif
522     {"assert_beeps",	1, 2, f_assert_beeps},
523     {"assert_equal",	2, 3, f_assert_equal},
524     {"assert_equalfile", 2, 2, f_assert_equalfile},
525     {"assert_exception", 1, 2, f_assert_exception},
526     {"assert_fails",	1, 3, f_assert_fails},
527     {"assert_false",	1, 2, f_assert_false},
528     {"assert_inrange",	3, 4, f_assert_inrange},
529     {"assert_match",	2, 3, f_assert_match},
530     {"assert_notequal",	2, 3, f_assert_notequal},
531     {"assert_notmatch",	2, 3, f_assert_notmatch},
532     {"assert_report",	1, 1, f_assert_report},
533     {"assert_true",	1, 2, f_assert_true},
534 #ifdef FEAT_FLOAT
535     {"atan",		1, 1, f_atan},
536     {"atan2",		2, 2, f_atan2},
537 #endif
538 #ifdef FEAT_BEVAL
539     {"balloon_show",	1, 1, f_balloon_show},
540 # if defined(FEAT_BEVAL_TERM)
541     {"balloon_split",	1, 1, f_balloon_split},
542 # endif
543 #endif
544     {"browse",		4, 4, f_browse},
545     {"browsedir",	2, 2, f_browsedir},
546     {"bufexists",	1, 1, f_bufexists},
547     {"buffer_exists",	1, 1, f_bufexists},	/* obsolete */
548     {"buffer_name",	1, 1, f_bufname},	/* obsolete */
549     {"buffer_number",	1, 1, f_bufnr},		/* obsolete */
550     {"buflisted",	1, 1, f_buflisted},
551     {"bufloaded",	1, 1, f_bufloaded},
552     {"bufname",		1, 1, f_bufname},
553     {"bufnr",		1, 2, f_bufnr},
554     {"bufwinid",	1, 1, f_bufwinid},
555     {"bufwinnr",	1, 1, f_bufwinnr},
556     {"byte2line",	1, 1, f_byte2line},
557     {"byteidx",		2, 2, f_byteidx},
558     {"byteidxcomp",	2, 2, f_byteidxcomp},
559     {"call",		2, 3, f_call},
560 #ifdef FEAT_FLOAT
561     {"ceil",		1, 1, f_ceil},
562 #endif
563 #ifdef FEAT_JOB_CHANNEL
564     {"ch_canread",	1, 1, f_ch_canread},
565     {"ch_close",	1, 1, f_ch_close},
566     {"ch_close_in",	1, 1, f_ch_close_in},
567     {"ch_evalexpr",	2, 3, f_ch_evalexpr},
568     {"ch_evalraw",	2, 3, f_ch_evalraw},
569     {"ch_getbufnr",	2, 2, f_ch_getbufnr},
570     {"ch_getjob",	1, 1, f_ch_getjob},
571     {"ch_info",		1, 1, f_ch_info},
572     {"ch_log",		1, 2, f_ch_log},
573     {"ch_logfile",	1, 2, f_ch_logfile},
574     {"ch_open",		1, 2, f_ch_open},
575     {"ch_read",		1, 2, f_ch_read},
576     {"ch_readblob",	1, 2, f_ch_readblob},
577     {"ch_readraw",	1, 2, f_ch_readraw},
578     {"ch_sendexpr",	2, 3, f_ch_sendexpr},
579     {"ch_sendraw",	2, 3, f_ch_sendraw},
580     {"ch_setoptions",	2, 2, f_ch_setoptions},
581     {"ch_status",	1, 2, f_ch_status},
582 #endif
583     {"changenr",	0, 0, f_changenr},
584     {"char2nr",		1, 2, f_char2nr},
585     {"cindent",		1, 1, f_cindent},
586     {"clearmatches",	0, 0, f_clearmatches},
587     {"col",		1, 1, f_col},
588 #if defined(FEAT_INS_EXPAND)
589     {"complete",	2, 2, f_complete},
590     {"complete_add",	1, 1, f_complete_add},
591     {"complete_check",	0, 0, f_complete_check},
592 #endif
593     {"confirm",		1, 4, f_confirm},
594     {"copy",		1, 1, f_copy},
595 #ifdef FEAT_FLOAT
596     {"cos",		1, 1, f_cos},
597     {"cosh",		1, 1, f_cosh},
598 #endif
599     {"count",		2, 4, f_count},
600     {"cscope_connection",0,3, f_cscope_connection},
601     {"cursor",		1, 3, f_cursor},
602 #ifdef WIN3264
603     {"debugbreak",	1, 1, f_debugbreak},
604 #endif
605     {"deepcopy",	1, 2, f_deepcopy},
606     {"delete",		1, 2, f_delete},
607     {"deletebufline",	2, 3, f_deletebufline},
608     {"did_filetype",	0, 0, f_did_filetype},
609     {"diff_filler",	1, 1, f_diff_filler},
610     {"diff_hlID",	2, 2, f_diff_hlID},
611     {"empty",		1, 1, f_empty},
612     {"escape",		2, 2, f_escape},
613     {"eval",		1, 1, f_eval},
614     {"eventhandler",	0, 0, f_eventhandler},
615     {"executable",	1, 1, f_executable},
616     {"execute",		1, 2, f_execute},
617     {"exepath",		1, 1, f_exepath},
618     {"exists",		1, 1, f_exists},
619 #ifdef FEAT_FLOAT
620     {"exp",		1, 1, f_exp},
621 #endif
622     {"expand",		1, 3, f_expand},
623     {"extend",		2, 3, f_extend},
624     {"feedkeys",	1, 2, f_feedkeys},
625     {"file_readable",	1, 1, f_filereadable},	/* obsolete */
626     {"filereadable",	1, 1, f_filereadable},
627     {"filewritable",	1, 1, f_filewritable},
628     {"filter",		2, 2, f_filter},
629     {"finddir",		1, 3, f_finddir},
630     {"findfile",	1, 3, f_findfile},
631 #ifdef FEAT_FLOAT
632     {"float2nr",	1, 1, f_float2nr},
633     {"floor",		1, 1, f_floor},
634     {"fmod",		2, 2, f_fmod},
635 #endif
636     {"fnameescape",	1, 1, f_fnameescape},
637     {"fnamemodify",	2, 2, f_fnamemodify},
638     {"foldclosed",	1, 1, f_foldclosed},
639     {"foldclosedend",	1, 1, f_foldclosedend},
640     {"foldlevel",	1, 1, f_foldlevel},
641     {"foldtext",	0, 0, f_foldtext},
642     {"foldtextresult",	1, 1, f_foldtextresult},
643     {"foreground",	0, 0, f_foreground},
644     {"funcref",		1, 3, f_funcref},
645     {"function",	1, 3, f_function},
646     {"garbagecollect",	0, 1, f_garbagecollect},
647     {"get",		2, 3, f_get},
648     {"getbufinfo",	0, 1, f_getbufinfo},
649     {"getbufline",	2, 3, f_getbufline},
650     {"getbufvar",	2, 3, f_getbufvar},
651     {"getchangelist",	1, 1, f_getchangelist},
652     {"getchar",		0, 1, f_getchar},
653     {"getcharmod",	0, 0, f_getcharmod},
654     {"getcharsearch",	0, 0, f_getcharsearch},
655     {"getcmdline",	0, 0, f_getcmdline},
656     {"getcmdpos",	0, 0, f_getcmdpos},
657     {"getcmdtype",	0, 0, f_getcmdtype},
658     {"getcmdwintype",	0, 0, f_getcmdwintype},
659 #if defined(FEAT_CMDL_COMPL)
660     {"getcompletion",	2, 3, f_getcompletion},
661 #endif
662     {"getcurpos",	0, 0, f_getcurpos},
663     {"getcwd",		0, 2, f_getcwd},
664     {"getfontname",	0, 1, f_getfontname},
665     {"getfperm",	1, 1, f_getfperm},
666     {"getfsize",	1, 1, f_getfsize},
667     {"getftime",	1, 1, f_getftime},
668     {"getftype",	1, 1, f_getftype},
669     {"getjumplist",	0, 2, f_getjumplist},
670     {"getline",		1, 2, f_getline},
671     {"getloclist",	1, 2, f_getloclist},
672     {"getmatches",	0, 0, f_getmatches},
673     {"getpid",		0, 0, f_getpid},
674     {"getpos",		1, 1, f_getpos},
675     {"getqflist",	0, 1, f_getqflist},
676     {"getreg",		0, 3, f_getreg},
677     {"getregtype",	0, 1, f_getregtype},
678     {"gettabinfo",	0, 1, f_gettabinfo},
679     {"gettabvar",	2, 3, f_gettabvar},
680     {"gettabwinvar",	3, 4, f_gettabwinvar},
681     {"gettagstack",	0, 1, f_gettagstack},
682     {"getwininfo",	0, 1, f_getwininfo},
683     {"getwinpos",	0, 1, f_getwinpos},
684     {"getwinposx",	0, 0, f_getwinposx},
685     {"getwinposy",	0, 0, f_getwinposy},
686     {"getwinvar",	2, 3, f_getwinvar},
687     {"glob",		1, 4, f_glob},
688     {"glob2regpat",	1, 1, f_glob2regpat},
689     {"globpath",	2, 5, f_globpath},
690     {"has",		1, 1, f_has},
691     {"has_key",		2, 2, f_has_key},
692     {"haslocaldir",	0, 2, f_haslocaldir},
693     {"hasmapto",	1, 3, f_hasmapto},
694     {"highlightID",	1, 1, f_hlID},		/* obsolete */
695     {"highlight_exists",1, 1, f_hlexists},	/* obsolete */
696     {"histadd",		2, 2, f_histadd},
697     {"histdel",		1, 2, f_histdel},
698     {"histget",		1, 2, f_histget},
699     {"histnr",		1, 1, f_histnr},
700     {"hlID",		1, 1, f_hlID},
701     {"hlexists",	1, 1, f_hlexists},
702     {"hostname",	0, 0, f_hostname},
703     {"iconv",		3, 3, f_iconv},
704     {"indent",		1, 1, f_indent},
705     {"index",		2, 4, f_index},
706     {"input",		1, 3, f_input},
707     {"inputdialog",	1, 3, f_inputdialog},
708     {"inputlist",	1, 1, f_inputlist},
709     {"inputrestore",	0, 0, f_inputrestore},
710     {"inputsave",	0, 0, f_inputsave},
711     {"inputsecret",	1, 2, f_inputsecret},
712     {"insert",		2, 3, f_insert},
713     {"invert",		1, 1, f_invert},
714     {"isdirectory",	1, 1, f_isdirectory},
715     {"islocked",	1, 1, f_islocked},
716 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
717     {"isnan",		1, 1, f_isnan},
718 #endif
719     {"items",		1, 1, f_items},
720 #ifdef FEAT_JOB_CHANNEL
721     {"job_getchannel",	1, 1, f_job_getchannel},
722     {"job_info",	0, 1, f_job_info},
723     {"job_setoptions",	2, 2, f_job_setoptions},
724     {"job_start",	1, 2, f_job_start},
725     {"job_status",	1, 1, f_job_status},
726     {"job_stop",	1, 2, f_job_stop},
727 #endif
728     {"join",		1, 2, f_join},
729     {"js_decode",	1, 1, f_js_decode},
730     {"js_encode",	1, 1, f_js_encode},
731     {"json_decode",	1, 1, f_json_decode},
732     {"json_encode",	1, 1, f_json_encode},
733     {"keys",		1, 1, f_keys},
734     {"last_buffer_nr",	0, 0, f_last_buffer_nr},/* obsolete */
735     {"len",		1, 1, f_len},
736     {"libcall",		3, 3, f_libcall},
737     {"libcallnr",	3, 3, f_libcallnr},
738     {"line",		1, 1, f_line},
739     {"line2byte",	1, 1, f_line2byte},
740     {"lispindent",	1, 1, f_lispindent},
741     {"localtime",	0, 0, f_localtime},
742 #ifdef FEAT_FLOAT
743     {"log",		1, 1, f_log},
744     {"log10",		1, 1, f_log10},
745 #endif
746 #ifdef FEAT_LUA
747     {"luaeval",		1, 2, f_luaeval},
748 #endif
749     {"map",		2, 2, f_map},
750     {"maparg",		1, 4, f_maparg},
751     {"mapcheck",	1, 3, f_mapcheck},
752     {"match",		2, 4, f_match},
753     {"matchadd",	2, 5, f_matchadd},
754     {"matchaddpos",	2, 5, f_matchaddpos},
755     {"matcharg",	1, 1, f_matcharg},
756     {"matchdelete",	1, 1, f_matchdelete},
757     {"matchend",	2, 4, f_matchend},
758     {"matchlist",	2, 4, f_matchlist},
759     {"matchstr",	2, 4, f_matchstr},
760     {"matchstrpos",	2, 4, f_matchstrpos},
761     {"max",		1, 1, f_max},
762     {"min",		1, 1, f_min},
763 #ifdef vim_mkdir
764     {"mkdir",		1, 3, f_mkdir},
765 #endif
766     {"mode",		0, 1, f_mode},
767 #ifdef FEAT_MZSCHEME
768     {"mzeval",		1, 1, f_mzeval},
769 #endif
770     {"nextnonblank",	1, 1, f_nextnonblank},
771     {"nr2char",		1, 2, f_nr2char},
772     {"or",		2, 2, f_or},
773     {"pathshorten",	1, 1, f_pathshorten},
774 #ifdef FEAT_PERL
775     {"perleval",	1, 1, f_perleval},
776 #endif
777 #ifdef FEAT_FLOAT
778     {"pow",		2, 2, f_pow},
779 #endif
780     {"prevnonblank",	1, 1, f_prevnonblank},
781     {"printf",		1, 19, f_printf},
782 #ifdef FEAT_JOB_CHANNEL
783     {"prompt_setcallback", 2, 2, f_prompt_setcallback},
784     {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
785     {"prompt_setprompt", 2, 2, f_prompt_setprompt},
786 #endif
787 #ifdef FEAT_TEXT_PROP
788     {"prop_add",	3, 3, f_prop_add},
789     {"prop_clear",	1, 3, f_prop_clear},
790     {"prop_list",	1, 2, f_prop_list},
791     {"prop_remove",	2, 3, f_prop_remove},
792     {"prop_type_add",	2, 2, f_prop_type_add},
793     {"prop_type_change", 2, 2, f_prop_type_change},
794     {"prop_type_delete", 1, 2, f_prop_type_delete},
795     {"prop_type_get",	1, 2, f_prop_type_get},
796     {"prop_type_list",	0, 1, f_prop_type_list},
797 #endif
798     {"pumvisible",	0, 0, f_pumvisible},
799 #ifdef FEAT_PYTHON3
800     {"py3eval",		1, 1, f_py3eval},
801 #endif
802 #ifdef FEAT_PYTHON
803     {"pyeval",		1, 1, f_pyeval},
804 #endif
805 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
806     {"pyxeval",		1, 1, f_pyxeval},
807 #endif
808     {"range",		1, 3, f_range},
809     {"readfile",	1, 3, f_readfile},
810     {"reg_executing",	0, 0, f_reg_executing},
811     {"reg_recording",	0, 0, f_reg_recording},
812     {"reltime",		0, 2, f_reltime},
813 #ifdef FEAT_FLOAT
814     {"reltimefloat",	1, 1, f_reltimefloat},
815 #endif
816     {"reltimestr",	1, 1, f_reltimestr},
817     {"remote_expr",	2, 4, f_remote_expr},
818     {"remote_foreground", 1, 1, f_remote_foreground},
819     {"remote_peek",	1, 2, f_remote_peek},
820     {"remote_read",	1, 2, f_remote_read},
821     {"remote_send",	2, 3, f_remote_send},
822     {"remote_startserver", 1, 1, f_remote_startserver},
823     {"remove",		2, 3, f_remove},
824     {"rename",		2, 2, f_rename},
825     {"repeat",		2, 2, f_repeat},
826     {"resolve",		1, 1, f_resolve},
827     {"reverse",		1, 1, f_reverse},
828 #ifdef FEAT_FLOAT
829     {"round",		1, 1, f_round},
830 #endif
831     {"screenattr",	2, 2, f_screenattr},
832     {"screenchar",	2, 2, f_screenchar},
833     {"screencol",	0, 0, f_screencol},
834     {"screenrow",	0, 0, f_screenrow},
835     {"search",		1, 4, f_search},
836     {"searchdecl",	1, 3, f_searchdecl},
837     {"searchpair",	3, 7, f_searchpair},
838     {"searchpairpos",	3, 7, f_searchpairpos},
839     {"searchpos",	1, 4, f_searchpos},
840     {"server2client",	2, 2, f_server2client},
841     {"serverlist",	0, 0, f_serverlist},
842     {"setbufline",	3, 3, f_setbufline},
843     {"setbufvar",	3, 3, f_setbufvar},
844     {"setcharsearch",	1, 1, f_setcharsearch},
845     {"setcmdpos",	1, 1, f_setcmdpos},
846     {"setfperm",	2, 2, f_setfperm},
847     {"setline",		2, 2, f_setline},
848     {"setloclist",	2, 4, f_setloclist},
849     {"setmatches",	1, 1, f_setmatches},
850     {"setpos",		2, 2, f_setpos},
851     {"setqflist",	1, 3, f_setqflist},
852     {"setreg",		2, 3, f_setreg},
853     {"settabvar",	3, 3, f_settabvar},
854     {"settabwinvar",	4, 4, f_settabwinvar},
855     {"settagstack",	2, 3, f_settagstack},
856     {"setwinvar",	3, 3, f_setwinvar},
857 #ifdef FEAT_CRYPT
858     {"sha256",		1, 1, f_sha256},
859 #endif
860     {"shellescape",	1, 2, f_shellescape},
861     {"shiftwidth",	0, 1, f_shiftwidth},
862 #ifdef FEAT_SIGNS
863     {"sign_define",	1, 2, f_sign_define},
864     {"sign_getdefined",	0, 1, f_sign_getdefined},
865     {"sign_getplaced",	0, 2, f_sign_getplaced},
866     {"sign_jump",	3, 3, f_sign_jump},
867     {"sign_place",	4, 5, f_sign_place},
868     {"sign_undefine",	0, 1, f_sign_undefine},
869     {"sign_unplace",	1, 2, f_sign_unplace},
870 #endif
871     {"simplify",	1, 1, f_simplify},
872 #ifdef FEAT_FLOAT
873     {"sin",		1, 1, f_sin},
874     {"sinh",		1, 1, f_sinh},
875 #endif
876     {"sort",		1, 3, f_sort},
877     {"soundfold",	1, 1, f_soundfold},
878     {"spellbadword",	0, 1, f_spellbadword},
879     {"spellsuggest",	1, 3, f_spellsuggest},
880     {"split",		1, 3, f_split},
881 #ifdef FEAT_FLOAT
882     {"sqrt",		1, 1, f_sqrt},
883     {"str2float",	1, 1, f_str2float},
884 #endif
885     {"str2nr",		1, 2, f_str2nr},
886     {"strcharpart",	2, 3, f_strcharpart},
887     {"strchars",	1, 2, f_strchars},
888     {"strdisplaywidth",	1, 2, f_strdisplaywidth},
889 #ifdef HAVE_STRFTIME
890     {"strftime",	1, 2, f_strftime},
891 #endif
892     {"strgetchar",	2, 2, f_strgetchar},
893     {"stridx",		2, 3, f_stridx},
894     {"string",		1, 1, f_string},
895     {"strlen",		1, 1, f_strlen},
896     {"strpart",		2, 3, f_strpart},
897     {"strridx",		2, 3, f_strridx},
898     {"strtrans",	1, 1, f_strtrans},
899     {"strwidth",	1, 1, f_strwidth},
900     {"submatch",	1, 2, f_submatch},
901     {"substitute",	4, 4, f_substitute},
902     {"swapinfo",	1, 1, f_swapinfo},
903     {"swapname",	1, 1, f_swapname},
904     {"synID",		3, 3, f_synID},
905     {"synIDattr",	2, 3, f_synIDattr},
906     {"synIDtrans",	1, 1, f_synIDtrans},
907     {"synconcealed",	2, 2, f_synconcealed},
908     {"synstack",	2, 2, f_synstack},
909     {"system",		1, 2, f_system},
910     {"systemlist",	1, 2, f_systemlist},
911     {"tabpagebuflist",	0, 1, f_tabpagebuflist},
912     {"tabpagenr",	0, 1, f_tabpagenr},
913     {"tabpagewinnr",	1, 2, f_tabpagewinnr},
914     {"tagfiles",	0, 0, f_tagfiles},
915     {"taglist",		1, 2, f_taglist},
916 #ifdef FEAT_FLOAT
917     {"tan",		1, 1, f_tan},
918     {"tanh",		1, 1, f_tanh},
919 #endif
920     {"tempname",	0, 0, f_tempname},
921 #ifdef FEAT_TERMINAL
922     {"term_dumpdiff",	2, 3, f_term_dumpdiff},
923     {"term_dumpload",	1, 2, f_term_dumpload},
924     {"term_dumpwrite",	2, 3, f_term_dumpwrite},
925     {"term_getaltscreen", 1, 1, f_term_getaltscreen},
926 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
927     {"term_getansicolors", 1, 1, f_term_getansicolors},
928 # endif
929     {"term_getattr",	2, 2, f_term_getattr},
930     {"term_getcursor",	1, 1, f_term_getcursor},
931     {"term_getjob",	1, 1, f_term_getjob},
932     {"term_getline",	2, 2, f_term_getline},
933     {"term_getscrolled", 1, 1, f_term_getscrolled},
934     {"term_getsize",	1, 1, f_term_getsize},
935     {"term_getstatus",	1, 1, f_term_getstatus},
936     {"term_gettitle",	1, 1, f_term_gettitle},
937     {"term_gettty",	1, 2, f_term_gettty},
938     {"term_list",	0, 0, f_term_list},
939     {"term_scrape",	2, 2, f_term_scrape},
940     {"term_sendkeys",	2, 2, f_term_sendkeys},
941 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
942     {"term_setansicolors", 2, 2, f_term_setansicolors},
943 # endif
944     {"term_setkill",	2, 2, f_term_setkill},
945     {"term_setrestore",	2, 2, f_term_setrestore},
946     {"term_setsize",	3, 3, f_term_setsize},
947     {"term_start",	1, 2, f_term_start},
948     {"term_wait",	1, 2, f_term_wait},
949 #endif
950     {"test_alloc_fail",	3, 3, f_test_alloc_fail},
951     {"test_autochdir",	0, 0, f_test_autochdir},
952     {"test_feedinput",	1, 1, f_test_feedinput},
953     {"test_garbagecollect_now",	0, 0, f_test_garbagecollect_now},
954     {"test_ignore_error",	1, 1, f_test_ignore_error},
955     {"test_null_blob", 0, 0, f_test_null_blob},
956 #ifdef FEAT_JOB_CHANNEL
957     {"test_null_channel", 0, 0, f_test_null_channel},
958 #endif
959     {"test_null_dict",	0, 0, f_test_null_dict},
960 #ifdef FEAT_JOB_CHANNEL
961     {"test_null_job",	0, 0, f_test_null_job},
962 #endif
963     {"test_null_list",	0, 0, f_test_null_list},
964     {"test_null_partial", 0, 0, f_test_null_partial},
965     {"test_null_string", 0, 0, f_test_null_string},
966     {"test_option_not_set", 1, 1, f_test_option_not_set},
967     {"test_override",    2, 2, f_test_override},
968 #ifdef FEAT_GUI
969     {"test_scrollbar",	3, 3, f_test_scrollbar},
970 #endif
971     {"test_settime",	1, 1, f_test_settime},
972 #ifdef FEAT_TIMERS
973     {"timer_info",	0, 1, f_timer_info},
974     {"timer_pause",	2, 2, f_timer_pause},
975     {"timer_start",	2, 3, f_timer_start},
976     {"timer_stop",	1, 1, f_timer_stop},
977     {"timer_stopall",	0, 0, f_timer_stopall},
978 #endif
979     {"tolower",		1, 1, f_tolower},
980     {"toupper",		1, 1, f_toupper},
981     {"tr",		3, 3, f_tr},
982     {"trim",		1, 2, f_trim},
983 #ifdef FEAT_FLOAT
984     {"trunc",		1, 1, f_trunc},
985 #endif
986     {"type",		1, 1, f_type},
987     {"undofile",	1, 1, f_undofile},
988     {"undotree",	0, 0, f_undotree},
989     {"uniq",		1, 3, f_uniq},
990     {"values",		1, 1, f_values},
991     {"virtcol",		1, 1, f_virtcol},
992     {"visualmode",	0, 1, f_visualmode},
993     {"wildmenumode",	0, 0, f_wildmenumode},
994     {"win_findbuf",	1, 1, f_win_findbuf},
995     {"win_getid",	0, 2, f_win_getid},
996     {"win_gotoid",	1, 1, f_win_gotoid},
997     {"win_id2tabwin",	1, 1, f_win_id2tabwin},
998     {"win_id2win",	1, 1, f_win_id2win},
999     {"win_screenpos",	1, 1, f_win_screenpos},
1000     {"winbufnr",	1, 1, f_winbufnr},
1001     {"wincol",		0, 0, f_wincol},
1002     {"winheight",	1, 1, f_winheight},
1003     {"winlayout",	0, 1, f_winlayout},
1004     {"winline",		0, 0, f_winline},
1005     {"winnr",		0, 1, f_winnr},
1006     {"winrestcmd",	0, 0, f_winrestcmd},
1007     {"winrestview",	1, 1, f_winrestview},
1008     {"winsaveview",	0, 0, f_winsaveview},
1009     {"winwidth",	1, 1, f_winwidth},
1010     {"wordcount",	0, 0, f_wordcount},
1011     {"writefile",	2, 3, f_writefile},
1012     {"xor",		2, 2, f_xor},
1013 };
1014 
1015 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1016 
1017 /*
1018  * Function given to ExpandGeneric() to obtain the list of internal
1019  * or user defined function names.
1020  */
1021     char_u *
1022 get_function_name(expand_T *xp, int idx)
1023 {
1024     static int	intidx = -1;
1025     char_u	*name;
1026 
1027     if (idx == 0)
1028 	intidx = -1;
1029     if (intidx < 0)
1030     {
1031 	name = get_user_func_name(xp, idx);
1032 	if (name != NULL)
1033 	    return name;
1034     }
1035     if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1036     {
1037 	STRCPY(IObuff, functions[intidx].f_name);
1038 	STRCAT(IObuff, "(");
1039 	if (functions[intidx].f_max_argc == 0)
1040 	    STRCAT(IObuff, ")");
1041 	return IObuff;
1042     }
1043 
1044     return NULL;
1045 }
1046 
1047 /*
1048  * Function given to ExpandGeneric() to obtain the list of internal or
1049  * user defined variable or function names.
1050  */
1051     char_u *
1052 get_expr_name(expand_T *xp, int idx)
1053 {
1054     static int	intidx = -1;
1055     char_u	*name;
1056 
1057     if (idx == 0)
1058 	intidx = -1;
1059     if (intidx < 0)
1060     {
1061 	name = get_function_name(xp, idx);
1062 	if (name != NULL)
1063 	    return name;
1064     }
1065     return get_user_var_name(xp, ++intidx);
1066 }
1067 
1068 #endif /* FEAT_CMDL_COMPL */
1069 
1070 /*
1071  * Find internal function in table above.
1072  * Return index, or -1 if not found
1073  */
1074     int
1075 find_internal_func(
1076     char_u	*name)		/* name of the function */
1077 {
1078     int		first = 0;
1079     int		last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1080     int		cmp;
1081     int		x;
1082 
1083     /*
1084      * Find the function name in the table. Binary search.
1085      */
1086     while (first <= last)
1087     {
1088 	x = first + ((unsigned)(last - first) >> 1);
1089 	cmp = STRCMP(name, functions[x].f_name);
1090 	if (cmp < 0)
1091 	    last = x - 1;
1092 	else if (cmp > 0)
1093 	    first = x + 1;
1094 	else
1095 	    return x;
1096     }
1097     return -1;
1098 }
1099 
1100     int
1101 call_internal_func(
1102 	char_u	    *name,
1103 	int	    argcount,
1104 	typval_T    *argvars,
1105 	typval_T    *rettv)
1106 {
1107     int i;
1108 
1109     i = find_internal_func(name);
1110     if (i < 0)
1111 	return ERROR_UNKNOWN;
1112     if (argcount < functions[i].f_min_argc)
1113 	return ERROR_TOOFEW;
1114     if (argcount > functions[i].f_max_argc)
1115 	return ERROR_TOOMANY;
1116     argvars[argcount].v_type = VAR_UNKNOWN;
1117     functions[i].f_func(argvars, rettv);
1118     return ERROR_NONE;
1119 }
1120 
1121 /*
1122  * Return TRUE for a non-zero Number and a non-empty String.
1123  */
1124     static int
1125 non_zero_arg(typval_T *argvars)
1126 {
1127     return ((argvars[0].v_type == VAR_NUMBER
1128 		&& argvars[0].vval.v_number != 0)
1129 	    || (argvars[0].v_type == VAR_SPECIAL
1130 		&& argvars[0].vval.v_number == VVAL_TRUE)
1131 	    || (argvars[0].v_type == VAR_STRING
1132 		&& argvars[0].vval.v_string != NULL
1133 		&& *argvars[0].vval.v_string != NUL));
1134 }
1135 
1136 /*
1137  * Get the lnum from the first argument.
1138  * Also accepts ".", "$", etc., but that only works for the current buffer.
1139  * Returns -1 on error.
1140  */
1141     static linenr_T
1142 tv_get_lnum(typval_T *argvars)
1143 {
1144     typval_T	rettv;
1145     linenr_T	lnum;
1146 
1147     lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1148     if (lnum == 0)  /* no valid number, try using line() */
1149     {
1150 	rettv.v_type = VAR_NUMBER;
1151 	f_line(argvars, &rettv);
1152 	lnum = (linenr_T)rettv.vval.v_number;
1153 	clear_tv(&rettv);
1154     }
1155     return lnum;
1156 }
1157 
1158 /*
1159  * Get the lnum from the first argument.
1160  * Also accepts "$", then "buf" is used.
1161  * Returns 0 on error.
1162  */
1163     static linenr_T
1164 tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1165 {
1166     if (argvars[0].v_type == VAR_STRING
1167 	    && argvars[0].vval.v_string != NULL
1168 	    && argvars[0].vval.v_string[0] == '$'
1169 	    && buf != NULL)
1170 	return buf->b_ml.ml_line_count;
1171     return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1172 }
1173 
1174 #ifdef FEAT_FLOAT
1175 /*
1176  * Get the float value of "argvars[0]" into "f".
1177  * Returns FAIL when the argument is not a Number or Float.
1178  */
1179     static int
1180 get_float_arg(typval_T *argvars, float_T *f)
1181 {
1182     if (argvars[0].v_type == VAR_FLOAT)
1183     {
1184 	*f = argvars[0].vval.v_float;
1185 	return OK;
1186     }
1187     if (argvars[0].v_type == VAR_NUMBER)
1188     {
1189 	*f = (float_T)argvars[0].vval.v_number;
1190 	return OK;
1191     }
1192     emsg(_("E808: Number or Float required"));
1193     return FAIL;
1194 }
1195 
1196 /*
1197  * "abs(expr)" function
1198  */
1199     static void
1200 f_abs(typval_T *argvars, typval_T *rettv)
1201 {
1202     if (argvars[0].v_type == VAR_FLOAT)
1203     {
1204 	rettv->v_type = VAR_FLOAT;
1205 	rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1206     }
1207     else
1208     {
1209 	varnumber_T	n;
1210 	int		error = FALSE;
1211 
1212 	n = tv_get_number_chk(&argvars[0], &error);
1213 	if (error)
1214 	    rettv->vval.v_number = -1;
1215 	else if (n > 0)
1216 	    rettv->vval.v_number = n;
1217 	else
1218 	    rettv->vval.v_number = -n;
1219     }
1220 }
1221 
1222 /*
1223  * "acos()" function
1224  */
1225     static void
1226 f_acos(typval_T *argvars, typval_T *rettv)
1227 {
1228     float_T	f = 0.0;
1229 
1230     rettv->v_type = VAR_FLOAT;
1231     if (get_float_arg(argvars, &f) == OK)
1232 	rettv->vval.v_float = acos(f);
1233     else
1234 	rettv->vval.v_float = 0.0;
1235 }
1236 #endif
1237 
1238 /*
1239  * "add(list, item)" function
1240  */
1241     static void
1242 f_add(typval_T *argvars, typval_T *rettv)
1243 {
1244     list_T	*l;
1245     blob_T	*b;
1246 
1247     rettv->vval.v_number = 1; /* Default: Failed */
1248     if (argvars[0].v_type == VAR_LIST)
1249     {
1250 	if ((l = argvars[0].vval.v_list) != NULL
1251 		&& !tv_check_lock(l->lv_lock,
1252 					 (char_u *)N_("add() argument"), TRUE)
1253 		&& list_append_tv(l, &argvars[1]) == OK)
1254 	    copy_tv(&argvars[0], rettv);
1255     }
1256     else if (argvars[0].v_type == VAR_BLOB)
1257     {
1258 	if ((b = argvars[0].vval.v_blob) != NULL
1259 		&& !tv_check_lock(b->bv_lock,
1260 					 (char_u *)N_("add() argument"), TRUE))
1261 	{
1262 	    int		error = FALSE;
1263 	    varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1264 
1265 	    if (!error)
1266 	    {
1267 		ga_append(&b->bv_ga, (int)n);
1268 		copy_tv(&argvars[0], rettv);
1269 	    }
1270 	}
1271     }
1272     else
1273 	emsg(_(e_listblobreq));
1274 }
1275 
1276 /*
1277  * "and(expr, expr)" function
1278  */
1279     static void
1280 f_and(typval_T *argvars, typval_T *rettv)
1281 {
1282     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1283 					& tv_get_number_chk(&argvars[1], NULL);
1284 }
1285 
1286 /*
1287  * If there is a window for "curbuf", make it the current window.
1288  */
1289     static void
1290 find_win_for_curbuf(void)
1291 {
1292     wininfo_T *wip;
1293 
1294     for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1295     {
1296 	if (wip->wi_win != NULL)
1297 	{
1298 	    curwin = wip->wi_win;
1299 	    break;
1300 	}
1301     }
1302 }
1303 
1304 /*
1305  * Set line or list of lines in buffer "buf".
1306  */
1307     static void
1308 set_buffer_lines(
1309 	buf_T	    *buf,
1310 	linenr_T    lnum_arg,
1311 	int	    append,
1312 	typval_T    *lines,
1313 	typval_T    *rettv)
1314 {
1315     linenr_T    lnum = lnum_arg + (append ? 1 : 0);
1316     char_u	*line = NULL;
1317     list_T	*l = NULL;
1318     listitem_T	*li = NULL;
1319     long	added = 0;
1320     linenr_T	append_lnum;
1321     buf_T	*curbuf_save = NULL;
1322     win_T	*curwin_save = NULL;
1323     int		is_curbuf = buf == curbuf;
1324 
1325     /* When using the current buffer ml_mfp will be set if needed.  Useful when
1326      * setline() is used on startup.  For other buffers the buffer must be
1327      * loaded. */
1328     if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
1329     {
1330 	rettv->vval.v_number = 1;	/* FAIL */
1331 	return;
1332     }
1333 
1334     if (!is_curbuf)
1335     {
1336 	curbuf_save = curbuf;
1337 	curwin_save = curwin;
1338 	curbuf = buf;
1339 	find_win_for_curbuf();
1340     }
1341 
1342     if (append)
1343 	// appendbufline() uses the line number below which we insert
1344 	append_lnum = lnum - 1;
1345     else
1346 	// setbufline() uses the line number above which we insert, we only
1347 	// append if it's below the last line
1348 	append_lnum = curbuf->b_ml.ml_line_count;
1349 
1350     if (lines->v_type == VAR_LIST)
1351     {
1352 	l = lines->vval.v_list;
1353 	li = l->lv_first;
1354     }
1355     else
1356 	line = tv_get_string_chk(lines);
1357 
1358     /* default result is zero == OK */
1359     for (;;)
1360     {
1361 	if (l != NULL)
1362 	{
1363 	    /* list argument, get next string */
1364 	    if (li == NULL)
1365 		break;
1366 	    line = tv_get_string_chk(&li->li_tv);
1367 	    li = li->li_next;
1368 	}
1369 
1370 	rettv->vval.v_number = 1;	/* FAIL */
1371 	if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1372 	    break;
1373 
1374 	/* When coming here from Insert mode, sync undo, so that this can be
1375 	 * undone separately from what was previously inserted. */
1376 	if (u_sync_once == 2)
1377 	{
1378 	    u_sync_once = 1; /* notify that u_sync() was called */
1379 	    u_sync(TRUE);
1380 	}
1381 
1382 	if (!append && lnum <= curbuf->b_ml.ml_line_count)
1383 	{
1384 	    // Existing line, replace it.
1385 	    // Removes any existing text properties.
1386 	    if (u_savesub(lnum) == OK && ml_replace_len(
1387 		      lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
1388 	    {
1389 		changed_bytes(lnum, 0);
1390 		if (is_curbuf && lnum == curwin->w_cursor.lnum)
1391 		    check_cursor_col();
1392 		rettv->vval.v_number = 0;	/* OK */
1393 	    }
1394 	}
1395 	else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1396 	{
1397 	    /* append the line */
1398 	    ++added;
1399 	    if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1400 		rettv->vval.v_number = 0;	/* OK */
1401 	}
1402 
1403 	if (l == NULL)			/* only one string argument */
1404 	    break;
1405 	++lnum;
1406     }
1407 
1408     if (added > 0)
1409     {
1410 	win_T	    *wp;
1411 	tabpage_T   *tp;
1412 
1413 	appended_lines_mark(append_lnum, added);
1414 	FOR_ALL_TAB_WINDOWS(tp, wp)
1415 	    if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1416 		wp->w_cursor.lnum += added;
1417 	check_cursor_col();
1418 
1419 #ifdef FEAT_JOB_CHANNEL
1420 	if (bt_prompt(curbuf) && (State & INSERT))
1421 	    // show the line with the prompt
1422 	    update_topline();
1423 #endif
1424     }
1425 
1426     if (!is_curbuf)
1427     {
1428 	curbuf = curbuf_save;
1429 	curwin = curwin_save;
1430     }
1431 }
1432 
1433 /*
1434  * "append(lnum, string/list)" function
1435  */
1436     static void
1437 f_append(typval_T *argvars, typval_T *rettv)
1438 {
1439     linenr_T	lnum = tv_get_lnum(&argvars[0]);
1440 
1441     set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1442 }
1443 
1444 /*
1445  * "appendbufline(buf, lnum, string/list)" function
1446  */
1447     static void
1448 f_appendbufline(typval_T *argvars, typval_T *rettv)
1449 {
1450     linenr_T	lnum;
1451     buf_T	*buf;
1452 
1453     buf = tv_get_buf(&argvars[0], FALSE);
1454     if (buf == NULL)
1455 	rettv->vval.v_number = 1; /* FAIL */
1456     else
1457     {
1458 	lnum = tv_get_lnum_buf(&argvars[1], buf);
1459 	set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1460     }
1461 }
1462 
1463 /*
1464  * "argc([window id])" function
1465  */
1466     static void
1467 f_argc(typval_T *argvars, typval_T *rettv)
1468 {
1469     win_T	*wp;
1470 
1471     if (argvars[0].v_type == VAR_UNKNOWN)
1472 	// use the current window
1473 	rettv->vval.v_number = ARGCOUNT;
1474     else if (argvars[0].v_type == VAR_NUMBER
1475 					   && tv_get_number(&argvars[0]) == -1)
1476 	// use the global argument list
1477 	rettv->vval.v_number = GARGCOUNT;
1478     else
1479     {
1480 	// use the argument list of the specified window
1481 	wp = find_win_by_nr_or_id(&argvars[0]);
1482 	if (wp != NULL)
1483 	    rettv->vval.v_number = WARGCOUNT(wp);
1484 	else
1485 	    rettv->vval.v_number = -1;
1486     }
1487 }
1488 
1489 /*
1490  * "argidx()" function
1491  */
1492     static void
1493 f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1494 {
1495     rettv->vval.v_number = curwin->w_arg_idx;
1496 }
1497 
1498 /*
1499  * "arglistid()" function
1500  */
1501     static void
1502 f_arglistid(typval_T *argvars, typval_T *rettv)
1503 {
1504     win_T	*wp;
1505 
1506     rettv->vval.v_number = -1;
1507     wp = find_tabwin(&argvars[0], &argvars[1]);
1508     if (wp != NULL)
1509 	rettv->vval.v_number = wp->w_alist->id;
1510 }
1511 
1512 /*
1513  * Get the argument list for a given window
1514  */
1515     static void
1516 get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1517 {
1518     int		idx;
1519 
1520     if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1521 	for (idx = 0; idx < argcount; ++idx)
1522 	    list_append_string(rettv->vval.v_list,
1523 						alist_name(&arglist[idx]), -1);
1524 }
1525 
1526 /*
1527  * "argv(nr)" function
1528  */
1529     static void
1530 f_argv(typval_T *argvars, typval_T *rettv)
1531 {
1532     int		idx;
1533     aentry_T	*arglist = NULL;
1534     int		argcount = -1;
1535 
1536     if (argvars[0].v_type != VAR_UNKNOWN)
1537     {
1538 	if (argvars[1].v_type == VAR_UNKNOWN)
1539 	{
1540 	    arglist = ARGLIST;
1541 	    argcount = ARGCOUNT;
1542 	}
1543 	else if (argvars[1].v_type == VAR_NUMBER
1544 					   && tv_get_number(&argvars[1]) == -1)
1545 	{
1546 	    arglist = GARGLIST;
1547 	    argcount = GARGCOUNT;
1548 	}
1549 	else
1550 	{
1551 	    win_T	*wp = find_win_by_nr_or_id(&argvars[1]);
1552 
1553 	    if (wp != NULL)
1554 	    {
1555 		/* Use the argument list of the specified window */
1556 		arglist = WARGLIST(wp);
1557 		argcount = WARGCOUNT(wp);
1558 	    }
1559 	}
1560 
1561 	rettv->v_type = VAR_STRING;
1562 	rettv->vval.v_string = NULL;
1563 	idx = tv_get_number_chk(&argvars[0], NULL);
1564 	if (arglist != NULL && idx >= 0 && idx < argcount)
1565 	    rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1566 	else if (idx == -1)
1567 	    get_arglist_as_rettv(arglist, argcount, rettv);
1568     }
1569     else
1570 	get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
1571 }
1572 
1573 /*
1574  * "assert_beeps(cmd [, error])" function
1575  */
1576     static void
1577 f_assert_beeps(typval_T *argvars, typval_T *rettv)
1578 {
1579     rettv->vval.v_number = assert_beeps(argvars);
1580 }
1581 
1582 /*
1583  * "assert_equal(expected, actual[, msg])" function
1584  */
1585     static void
1586 f_assert_equal(typval_T *argvars, typval_T *rettv)
1587 {
1588     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
1589 }
1590 
1591 /*
1592  * "assert_equalfile(fname-one, fname-two)" function
1593  */
1594     static void
1595 f_assert_equalfile(typval_T *argvars, typval_T *rettv)
1596 {
1597     rettv->vval.v_number = assert_equalfile(argvars);
1598 }
1599 
1600 /*
1601  * "assert_notequal(expected, actual[, msg])" function
1602  */
1603     static void
1604 f_assert_notequal(typval_T *argvars, typval_T *rettv)
1605 {
1606     rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
1607 }
1608 
1609 /*
1610  * "assert_exception(string[, msg])" function
1611  */
1612     static void
1613 f_assert_exception(typval_T *argvars, typval_T *rettv)
1614 {
1615     rettv->vval.v_number = assert_exception(argvars);
1616 }
1617 
1618 /*
1619  * "assert_fails(cmd [, error[, msg]])" function
1620  */
1621     static void
1622 f_assert_fails(typval_T *argvars, typval_T *rettv)
1623 {
1624     rettv->vval.v_number = assert_fails(argvars);
1625 }
1626 
1627 /*
1628  * "assert_false(actual[, msg])" function
1629  */
1630     static void
1631 f_assert_false(typval_T *argvars, typval_T *rettv)
1632 {
1633     rettv->vval.v_number = assert_bool(argvars, FALSE);
1634 }
1635 
1636 /*
1637  * "assert_inrange(lower, upper[, msg])" function
1638  */
1639     static void
1640 f_assert_inrange(typval_T *argvars, typval_T *rettv)
1641 {
1642     rettv->vval.v_number = assert_inrange(argvars);
1643 }
1644 
1645 /*
1646  * "assert_match(pattern, actual[, msg])" function
1647  */
1648     static void
1649 f_assert_match(typval_T *argvars, typval_T *rettv)
1650 {
1651     rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
1652 }
1653 
1654 /*
1655  * "assert_notmatch(pattern, actual[, msg])" function
1656  */
1657     static void
1658 f_assert_notmatch(typval_T *argvars, typval_T *rettv)
1659 {
1660     rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
1661 }
1662 
1663 /*
1664  * "assert_report(msg)" function
1665  */
1666     static void
1667 f_assert_report(typval_T *argvars, typval_T *rettv)
1668 {
1669     rettv->vval.v_number = assert_report(argvars);
1670 }
1671 
1672 /*
1673  * "assert_true(actual[, msg])" function
1674  */
1675     static void
1676 f_assert_true(typval_T *argvars, typval_T *rettv)
1677 {
1678     rettv->vval.v_number = assert_bool(argvars, TRUE);
1679 }
1680 
1681 #ifdef FEAT_FLOAT
1682 /*
1683  * "asin()" function
1684  */
1685     static void
1686 f_asin(typval_T *argvars, typval_T *rettv)
1687 {
1688     float_T	f = 0.0;
1689 
1690     rettv->v_type = VAR_FLOAT;
1691     if (get_float_arg(argvars, &f) == OK)
1692 	rettv->vval.v_float = asin(f);
1693     else
1694 	rettv->vval.v_float = 0.0;
1695 }
1696 
1697 /*
1698  * "atan()" function
1699  */
1700     static void
1701 f_atan(typval_T *argvars, typval_T *rettv)
1702 {
1703     float_T	f = 0.0;
1704 
1705     rettv->v_type = VAR_FLOAT;
1706     if (get_float_arg(argvars, &f) == OK)
1707 	rettv->vval.v_float = atan(f);
1708     else
1709 	rettv->vval.v_float = 0.0;
1710 }
1711 
1712 /*
1713  * "atan2()" function
1714  */
1715     static void
1716 f_atan2(typval_T *argvars, typval_T *rettv)
1717 {
1718     float_T	fx = 0.0, fy = 0.0;
1719 
1720     rettv->v_type = VAR_FLOAT;
1721     if (get_float_arg(argvars, &fx) == OK
1722 				     && get_float_arg(&argvars[1], &fy) == OK)
1723 	rettv->vval.v_float = atan2(fx, fy);
1724     else
1725 	rettv->vval.v_float = 0.0;
1726 }
1727 #endif
1728 
1729 /*
1730  * "balloon_show()" function
1731  */
1732 #ifdef FEAT_BEVAL
1733     static void
1734 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1735 {
1736     if (balloonEval != NULL)
1737     {
1738 	if (argvars[0].v_type == VAR_LIST
1739 # ifdef FEAT_GUI
1740 		&& !gui.in_use
1741 # endif
1742 	   )
1743 	    post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1744 	else
1745 	    post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
1746     }
1747 }
1748 
1749 # if defined(FEAT_BEVAL_TERM)
1750     static void
1751 f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1752 {
1753     if (rettv_list_alloc(rettv) == OK)
1754     {
1755 	char_u *msg = tv_get_string_chk(&argvars[0]);
1756 
1757 	if (msg != NULL)
1758 	{
1759 	    pumitem_T	*array;
1760 	    int		size = split_message(msg, &array);
1761 	    int		i;
1762 
1763 	    /* Skip the first and last item, they are always empty. */
1764 	    for (i = 1; i < size - 1; ++i)
1765 		list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
1766 	    while (size > 0)
1767 		vim_free(array[--size].pum_text);
1768 	    vim_free(array);
1769 	}
1770     }
1771 }
1772 # endif
1773 #endif
1774 
1775 /*
1776  * "browse(save, title, initdir, default)" function
1777  */
1778     static void
1779 f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1780 {
1781 #ifdef FEAT_BROWSE
1782     int		save;
1783     char_u	*title;
1784     char_u	*initdir;
1785     char_u	*defname;
1786     char_u	buf[NUMBUFLEN];
1787     char_u	buf2[NUMBUFLEN];
1788     int		error = FALSE;
1789 
1790     save = (int)tv_get_number_chk(&argvars[0], &error);
1791     title = tv_get_string_chk(&argvars[1]);
1792     initdir = tv_get_string_buf_chk(&argvars[2], buf);
1793     defname = tv_get_string_buf_chk(&argvars[3], buf2);
1794 
1795     if (error || title == NULL || initdir == NULL || defname == NULL)
1796 	rettv->vval.v_string = NULL;
1797     else
1798 	rettv->vval.v_string =
1799 		 do_browse(save ? BROWSE_SAVE : 0,
1800 				 title, defname, NULL, initdir, NULL, curbuf);
1801 #else
1802     rettv->vval.v_string = NULL;
1803 #endif
1804     rettv->v_type = VAR_STRING;
1805 }
1806 
1807 /*
1808  * "browsedir(title, initdir)" function
1809  */
1810     static void
1811 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1812 {
1813 #ifdef FEAT_BROWSE
1814     char_u	*title;
1815     char_u	*initdir;
1816     char_u	buf[NUMBUFLEN];
1817 
1818     title = tv_get_string_chk(&argvars[0]);
1819     initdir = tv_get_string_buf_chk(&argvars[1], buf);
1820 
1821     if (title == NULL || initdir == NULL)
1822 	rettv->vval.v_string = NULL;
1823     else
1824 	rettv->vval.v_string = do_browse(BROWSE_DIR,
1825 				    title, NULL, NULL, initdir, NULL, curbuf);
1826 #else
1827     rettv->vval.v_string = NULL;
1828 #endif
1829     rettv->v_type = VAR_STRING;
1830 }
1831 
1832 /*
1833  * Find a buffer by number or exact name.
1834  */
1835     static buf_T *
1836 find_buffer(typval_T *avar)
1837 {
1838     buf_T	*buf = NULL;
1839 
1840     if (avar->v_type == VAR_NUMBER)
1841 	buf = buflist_findnr((int)avar->vval.v_number);
1842     else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1843     {
1844 	buf = buflist_findname_exp(avar->vval.v_string);
1845 	if (buf == NULL)
1846 	{
1847 	    /* No full path name match, try a match with a URL or a "nofile"
1848 	     * buffer, these don't use the full path. */
1849 	    FOR_ALL_BUFFERS(buf)
1850 		if (buf->b_fname != NULL
1851 			&& (path_with_url(buf->b_fname)
1852 #ifdef FEAT_QUICKFIX
1853 			    || bt_nofile(buf)
1854 #endif
1855 			   )
1856 			&& STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1857 		    break;
1858 	}
1859     }
1860     return buf;
1861 }
1862 
1863 /*
1864  * "bufexists(expr)" function
1865  */
1866     static void
1867 f_bufexists(typval_T *argvars, typval_T *rettv)
1868 {
1869     rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1870 }
1871 
1872 /*
1873  * "buflisted(expr)" function
1874  */
1875     static void
1876 f_buflisted(typval_T *argvars, typval_T *rettv)
1877 {
1878     buf_T	*buf;
1879 
1880     buf = find_buffer(&argvars[0]);
1881     rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1882 }
1883 
1884 /*
1885  * "bufloaded(expr)" function
1886  */
1887     static void
1888 f_bufloaded(typval_T *argvars, typval_T *rettv)
1889 {
1890     buf_T	*buf;
1891 
1892     buf = find_buffer(&argvars[0]);
1893     rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1894 }
1895 
1896     buf_T *
1897 buflist_find_by_name(char_u *name, int curtab_only)
1898 {
1899     int		save_magic;
1900     char_u	*save_cpo;
1901     buf_T	*buf;
1902 
1903     /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1904     save_magic = p_magic;
1905     p_magic = TRUE;
1906     save_cpo = p_cpo;
1907     p_cpo = (char_u *)"";
1908 
1909     buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1910 						    TRUE, FALSE, curtab_only));
1911 
1912     p_magic = save_magic;
1913     p_cpo = save_cpo;
1914     return buf;
1915 }
1916 
1917 /*
1918  * Get buffer by number or pattern.
1919  */
1920     buf_T *
1921 tv_get_buf(typval_T *tv, int curtab_only)
1922 {
1923     char_u	*name = tv->vval.v_string;
1924     buf_T	*buf;
1925 
1926     if (tv->v_type == VAR_NUMBER)
1927 	return buflist_findnr((int)tv->vval.v_number);
1928     if (tv->v_type != VAR_STRING)
1929 	return NULL;
1930     if (name == NULL || *name == NUL)
1931 	return curbuf;
1932     if (name[0] == '$' && name[1] == NUL)
1933 	return lastbuf;
1934 
1935     buf = buflist_find_by_name(name, curtab_only);
1936 
1937     /* If not found, try expanding the name, like done for bufexists(). */
1938     if (buf == NULL)
1939 	buf = find_buffer(tv);
1940 
1941     return buf;
1942 }
1943 
1944 #ifdef FEAT_SIGNS
1945 /*
1946  * Get the buffer from "arg" and give an error and return NULL if it is not
1947  * valid.
1948  */
1949     static buf_T *
1950 get_buf_arg(typval_T *arg)
1951 {
1952     buf_T *buf;
1953 
1954     ++emsg_off;
1955     buf = tv_get_buf(arg, FALSE);
1956     --emsg_off;
1957     if (buf == NULL)
1958 	semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
1959     return buf;
1960 }
1961 #endif
1962 
1963 /*
1964  * "bufname(expr)" function
1965  */
1966     static void
1967 f_bufname(typval_T *argvars, typval_T *rettv)
1968 {
1969     buf_T	*buf;
1970 
1971     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
1972     ++emsg_off;
1973     buf = tv_get_buf(&argvars[0], FALSE);
1974     rettv->v_type = VAR_STRING;
1975     if (buf != NULL && buf->b_fname != NULL)
1976 	rettv->vval.v_string = vim_strsave(buf->b_fname);
1977     else
1978 	rettv->vval.v_string = NULL;
1979     --emsg_off;
1980 }
1981 
1982 /*
1983  * "bufnr(expr)" function
1984  */
1985     static void
1986 f_bufnr(typval_T *argvars, typval_T *rettv)
1987 {
1988     buf_T	*buf;
1989     int		error = FALSE;
1990     char_u	*name;
1991 
1992     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
1993     ++emsg_off;
1994     buf = tv_get_buf(&argvars[0], FALSE);
1995     --emsg_off;
1996 
1997     /* If the buffer isn't found and the second argument is not zero create a
1998      * new buffer. */
1999     if (buf == NULL
2000 	    && argvars[1].v_type != VAR_UNKNOWN
2001 	    && tv_get_number_chk(&argvars[1], &error) != 0
2002 	    && !error
2003 	    && (name = tv_get_string_chk(&argvars[0])) != NULL
2004 	    && !error)
2005 	buf = buflist_new(name, NULL, (linenr_T)1, 0);
2006 
2007     if (buf != NULL)
2008 	rettv->vval.v_number = buf->b_fnum;
2009     else
2010 	rettv->vval.v_number = -1;
2011 }
2012 
2013     static void
2014 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2015 {
2016     win_T	*wp;
2017     int		winnr = 0;
2018     buf_T	*buf;
2019 
2020     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
2021     ++emsg_off;
2022     buf = tv_get_buf(&argvars[0], TRUE);
2023     FOR_ALL_WINDOWS(wp)
2024     {
2025 	++winnr;
2026 	if (wp->w_buffer == buf)
2027 	    break;
2028     }
2029     rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
2030     --emsg_off;
2031 }
2032 
2033 /*
2034  * "bufwinid(nr)" function
2035  */
2036     static void
2037 f_bufwinid(typval_T *argvars, typval_T *rettv)
2038 {
2039     buf_win_common(argvars, rettv, FALSE);
2040 }
2041 
2042 /*
2043  * "bufwinnr(nr)" function
2044  */
2045     static void
2046 f_bufwinnr(typval_T *argvars, typval_T *rettv)
2047 {
2048     buf_win_common(argvars, rettv, TRUE);
2049 }
2050 
2051 /*
2052  * "byte2line(byte)" function
2053  */
2054     static void
2055 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2056 {
2057 #ifndef FEAT_BYTEOFF
2058     rettv->vval.v_number = -1;
2059 #else
2060     long	boff = 0;
2061 
2062     boff = tv_get_number(&argvars[0]) - 1;  /* boff gets -1 on type error */
2063     if (boff < 0)
2064 	rettv->vval.v_number = -1;
2065     else
2066 	rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2067 							  (linenr_T)0, &boff);
2068 #endif
2069 }
2070 
2071     static void
2072 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2073 {
2074     char_u	*t;
2075     char_u	*str;
2076     varnumber_T	idx;
2077 
2078     str = tv_get_string_chk(&argvars[0]);
2079     idx = tv_get_number_chk(&argvars[1], NULL);
2080     rettv->vval.v_number = -1;
2081     if (str == NULL || idx < 0)
2082 	return;
2083 
2084     t = str;
2085     for ( ; idx > 0; idx--)
2086     {
2087 	if (*t == NUL)		/* EOL reached */
2088 	    return;
2089 	if (enc_utf8 && comp)
2090 	    t += utf_ptr2len(t);
2091 	else
2092 	    t += (*mb_ptr2len)(t);
2093     }
2094     rettv->vval.v_number = (varnumber_T)(t - str);
2095 }
2096 
2097 /*
2098  * "byteidx()" function
2099  */
2100     static void
2101 f_byteidx(typval_T *argvars, typval_T *rettv)
2102 {
2103     byteidx(argvars, rettv, FALSE);
2104 }
2105 
2106 /*
2107  * "byteidxcomp()" function
2108  */
2109     static void
2110 f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2111 {
2112     byteidx(argvars, rettv, TRUE);
2113 }
2114 
2115 /*
2116  * "call(func, arglist [, dict])" function
2117  */
2118     static void
2119 f_call(typval_T *argvars, typval_T *rettv)
2120 {
2121     char_u	*func;
2122     partial_T   *partial = NULL;
2123     dict_T	*selfdict = NULL;
2124 
2125     if (argvars[1].v_type != VAR_LIST)
2126     {
2127 	emsg(_(e_listreq));
2128 	return;
2129     }
2130     if (argvars[1].vval.v_list == NULL)
2131 	return;
2132 
2133     if (argvars[0].v_type == VAR_FUNC)
2134 	func = argvars[0].vval.v_string;
2135     else if (argvars[0].v_type == VAR_PARTIAL)
2136     {
2137 	partial = argvars[0].vval.v_partial;
2138 	func = partial_name(partial);
2139     }
2140     else
2141 	func = tv_get_string(&argvars[0]);
2142     if (*func == NUL)
2143 	return;		/* type error or empty name */
2144 
2145     if (argvars[2].v_type != VAR_UNKNOWN)
2146     {
2147 	if (argvars[2].v_type != VAR_DICT)
2148 	{
2149 	    emsg(_(e_dictreq));
2150 	    return;
2151 	}
2152 	selfdict = argvars[2].vval.v_dict;
2153     }
2154 
2155     (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2156 }
2157 
2158 #ifdef FEAT_FLOAT
2159 /*
2160  * "ceil({float})" function
2161  */
2162     static void
2163 f_ceil(typval_T *argvars, typval_T *rettv)
2164 {
2165     float_T	f = 0.0;
2166 
2167     rettv->v_type = VAR_FLOAT;
2168     if (get_float_arg(argvars, &f) == OK)
2169 	rettv->vval.v_float = ceil(f);
2170     else
2171 	rettv->vval.v_float = 0.0;
2172 }
2173 #endif
2174 
2175 #ifdef FEAT_JOB_CHANNEL
2176 /*
2177  * "ch_canread()" function
2178  */
2179     static void
2180 f_ch_canread(typval_T *argvars, typval_T *rettv)
2181 {
2182     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2183 
2184     rettv->vval.v_number = 0;
2185     if (channel != NULL)
2186 	rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2187 			    || channel_has_readahead(channel, PART_OUT)
2188 			    || channel_has_readahead(channel, PART_ERR);
2189 }
2190 
2191 /*
2192  * "ch_close()" function
2193  */
2194     static void
2195 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2196 {
2197     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2198 
2199     if (channel != NULL)
2200     {
2201 	channel_close(channel, FALSE);
2202 	channel_clear(channel);
2203     }
2204 }
2205 
2206 /*
2207  * "ch_close()" function
2208  */
2209     static void
2210 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2211 {
2212     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2213 
2214     if (channel != NULL)
2215 	channel_close_in(channel);
2216 }
2217 
2218 /*
2219  * "ch_getbufnr()" function
2220  */
2221     static void
2222 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2223 {
2224     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2225 
2226     rettv->vval.v_number = -1;
2227     if (channel != NULL)
2228     {
2229 	char_u	*what = tv_get_string(&argvars[1]);
2230 	int	part;
2231 
2232 	if (STRCMP(what, "err") == 0)
2233 	    part = PART_ERR;
2234 	else if (STRCMP(what, "out") == 0)
2235 	    part = PART_OUT;
2236 	else if (STRCMP(what, "in") == 0)
2237 	    part = PART_IN;
2238 	else
2239 	    part = PART_SOCK;
2240 	if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2241 	    rettv->vval.v_number =
2242 			      channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2243     }
2244 }
2245 
2246 /*
2247  * "ch_getjob()" function
2248  */
2249     static void
2250 f_ch_getjob(typval_T *argvars, typval_T *rettv)
2251 {
2252     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2253 
2254     if (channel != NULL)
2255     {
2256 	rettv->v_type = VAR_JOB;
2257 	rettv->vval.v_job = channel->ch_job;
2258 	if (channel->ch_job != NULL)
2259 	    ++channel->ch_job->jv_refcount;
2260     }
2261 }
2262 
2263 /*
2264  * "ch_info()" function
2265  */
2266     static void
2267 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2268 {
2269     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2270 
2271     if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2272 	channel_info(channel, rettv->vval.v_dict);
2273 }
2274 
2275 /*
2276  * "ch_log()" function
2277  */
2278     static void
2279 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2280 {
2281     char_u	*msg = tv_get_string(&argvars[0]);
2282     channel_T	*channel = NULL;
2283 
2284     if (argvars[1].v_type != VAR_UNKNOWN)
2285 	channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2286 
2287     ch_log(channel, "%s", msg);
2288 }
2289 
2290 /*
2291  * "ch_logfile()" function
2292  */
2293     static void
2294 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2295 {
2296     char_u *fname;
2297     char_u *opt = (char_u *)"";
2298     char_u buf[NUMBUFLEN];
2299 
2300     /* Don't open a file in restricted mode. */
2301     if (check_restricted() || check_secure())
2302 	return;
2303     fname = tv_get_string(&argvars[0]);
2304     if (argvars[1].v_type == VAR_STRING)
2305 	opt = tv_get_string_buf(&argvars[1], buf);
2306     ch_logfile(fname, opt);
2307 }
2308 
2309 /*
2310  * "ch_open()" function
2311  */
2312     static void
2313 f_ch_open(typval_T *argvars, typval_T *rettv)
2314 {
2315     rettv->v_type = VAR_CHANNEL;
2316     if (check_restricted() || check_secure())
2317 	return;
2318     rettv->vval.v_channel = channel_open_func(argvars);
2319 }
2320 
2321 /*
2322  * "ch_read()" function
2323  */
2324     static void
2325 f_ch_read(typval_T *argvars, typval_T *rettv)
2326 {
2327     common_channel_read(argvars, rettv, FALSE, FALSE);
2328 }
2329 
2330 /*
2331  * "ch_readblob()" function
2332  */
2333     static void
2334 f_ch_readblob(typval_T *argvars, typval_T *rettv)
2335 {
2336     common_channel_read(argvars, rettv, TRUE, TRUE);
2337 }
2338 
2339 /*
2340  * "ch_readraw()" function
2341  */
2342     static void
2343 f_ch_readraw(typval_T *argvars, typval_T *rettv)
2344 {
2345     common_channel_read(argvars, rettv, TRUE, FALSE);
2346 }
2347 
2348 /*
2349  * "ch_evalexpr()" function
2350  */
2351     static void
2352 f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2353 {
2354     ch_expr_common(argvars, rettv, TRUE);
2355 }
2356 
2357 /*
2358  * "ch_sendexpr()" function
2359  */
2360     static void
2361 f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2362 {
2363     ch_expr_common(argvars, rettv, FALSE);
2364 }
2365 
2366 /*
2367  * "ch_evalraw()" function
2368  */
2369     static void
2370 f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2371 {
2372     ch_raw_common(argvars, rettv, TRUE);
2373 }
2374 
2375 /*
2376  * "ch_sendraw()" function
2377  */
2378     static void
2379 f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2380 {
2381     ch_raw_common(argvars, rettv, FALSE);
2382 }
2383 
2384 /*
2385  * "ch_setoptions()" function
2386  */
2387     static void
2388 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2389 {
2390     channel_T	*channel;
2391     jobopt_T	opt;
2392 
2393     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2394     if (channel == NULL)
2395 	return;
2396     clear_job_options(&opt);
2397     if (get_job_options(&argvars[1], &opt,
2398 			    JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
2399 	channel_set_options(channel, &opt);
2400     free_job_options(&opt);
2401 }
2402 
2403 /*
2404  * "ch_status()" function
2405  */
2406     static void
2407 f_ch_status(typval_T *argvars, typval_T *rettv)
2408 {
2409     channel_T	*channel;
2410     jobopt_T	opt;
2411     int		part = -1;
2412 
2413     /* return an empty string by default */
2414     rettv->v_type = VAR_STRING;
2415     rettv->vval.v_string = NULL;
2416 
2417     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2418 
2419     if (argvars[1].v_type != VAR_UNKNOWN)
2420     {
2421 	clear_job_options(&opt);
2422 	if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
2423 						     && (opt.jo_set & JO_PART))
2424 	    part = opt.jo_part;
2425     }
2426 
2427     rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
2428 }
2429 #endif
2430 
2431 /*
2432  * "changenr()" function
2433  */
2434     static void
2435 f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2436 {
2437     rettv->vval.v_number = curbuf->b_u_seq_cur;
2438 }
2439 
2440 /*
2441  * "char2nr(string)" function
2442  */
2443     static void
2444 f_char2nr(typval_T *argvars, typval_T *rettv)
2445 {
2446     if (has_mbyte)
2447     {
2448 	int	utf8 = 0;
2449 
2450 	if (argvars[1].v_type != VAR_UNKNOWN)
2451 	    utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
2452 
2453 	if (utf8)
2454 	    rettv->vval.v_number = (*utf_ptr2char)(tv_get_string(&argvars[0]));
2455 	else
2456 	    rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
2457     }
2458     else
2459 	rettv->vval.v_number = tv_get_string(&argvars[0])[0];
2460 }
2461 
2462 /*
2463  * "cindent(lnum)" function
2464  */
2465     static void
2466 f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2467 {
2468 #ifdef FEAT_CINDENT
2469     pos_T	pos;
2470     linenr_T	lnum;
2471 
2472     pos = curwin->w_cursor;
2473     lnum = tv_get_lnum(argvars);
2474     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2475     {
2476 	curwin->w_cursor.lnum = lnum;
2477 	rettv->vval.v_number = get_c_indent();
2478 	curwin->w_cursor = pos;
2479     }
2480     else
2481 #endif
2482 	rettv->vval.v_number = -1;
2483 }
2484 
2485 /*
2486  * "clearmatches()" function
2487  */
2488     static void
2489 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2490 {
2491 #ifdef FEAT_SEARCH_EXTRA
2492     clear_matches(curwin);
2493 #endif
2494 }
2495 
2496 /*
2497  * "col(string)" function
2498  */
2499     static void
2500 f_col(typval_T *argvars, typval_T *rettv)
2501 {
2502     colnr_T	col = 0;
2503     pos_T	*fp;
2504     int		fnum = curbuf->b_fnum;
2505 
2506     fp = var2fpos(&argvars[0], FALSE, &fnum);
2507     if (fp != NULL && fnum == curbuf->b_fnum)
2508     {
2509 	if (fp->col == MAXCOL)
2510 	{
2511 	    /* '> can be MAXCOL, get the length of the line then */
2512 	    if (fp->lnum <= curbuf->b_ml.ml_line_count)
2513 		col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2514 	    else
2515 		col = MAXCOL;
2516 	}
2517 	else
2518 	{
2519 	    col = fp->col + 1;
2520 	    /* col(".") when the cursor is on the NUL at the end of the line
2521 	     * because of "coladd" can be seen as an extra column. */
2522 	    if (virtual_active() && fp == &curwin->w_cursor)
2523 	    {
2524 		char_u	*p = ml_get_cursor();
2525 
2526 		if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2527 				 curwin->w_virtcol - curwin->w_cursor.coladd))
2528 		{
2529 		    int		l;
2530 
2531 		    if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2532 			col += l;
2533 		}
2534 	    }
2535 	}
2536     }
2537     rettv->vval.v_number = col;
2538 }
2539 
2540 #if defined(FEAT_INS_EXPAND)
2541 /*
2542  * "complete()" function
2543  */
2544     static void
2545 f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2546 {
2547     int	    startcol;
2548 
2549     if ((State & INSERT) == 0)
2550     {
2551 	emsg(_("E785: complete() can only be used in Insert mode"));
2552 	return;
2553     }
2554 
2555     /* Check for undo allowed here, because if something was already inserted
2556      * the line was already saved for undo and this check isn't done. */
2557     if (!undo_allowed())
2558 	return;
2559 
2560     if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2561     {
2562 	emsg(_(e_invarg));
2563 	return;
2564     }
2565 
2566     startcol = (int)tv_get_number_chk(&argvars[0], NULL);
2567     if (startcol <= 0)
2568 	return;
2569 
2570     set_completion(startcol - 1, argvars[1].vval.v_list);
2571 }
2572 
2573 /*
2574  * "complete_add()" function
2575  */
2576     static void
2577 f_complete_add(typval_T *argvars, typval_T *rettv)
2578 {
2579     rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2580 }
2581 
2582 /*
2583  * "complete_check()" function
2584  */
2585     static void
2586 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2587 {
2588     int		saved = RedrawingDisabled;
2589 
2590     RedrawingDisabled = 0;
2591     ins_compl_check_keys(0, TRUE);
2592     rettv->vval.v_number = compl_interrupted;
2593     RedrawingDisabled = saved;
2594 }
2595 #endif
2596 
2597 /*
2598  * "confirm(message, buttons[, default [, type]])" function
2599  */
2600     static void
2601 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2602 {
2603 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2604     char_u	*message;
2605     char_u	*buttons = NULL;
2606     char_u	buf[NUMBUFLEN];
2607     char_u	buf2[NUMBUFLEN];
2608     int		def = 1;
2609     int		type = VIM_GENERIC;
2610     char_u	*typestr;
2611     int		error = FALSE;
2612 
2613     message = tv_get_string_chk(&argvars[0]);
2614     if (message == NULL)
2615 	error = TRUE;
2616     if (argvars[1].v_type != VAR_UNKNOWN)
2617     {
2618 	buttons = tv_get_string_buf_chk(&argvars[1], buf);
2619 	if (buttons == NULL)
2620 	    error = TRUE;
2621 	if (argvars[2].v_type != VAR_UNKNOWN)
2622 	{
2623 	    def = (int)tv_get_number_chk(&argvars[2], &error);
2624 	    if (argvars[3].v_type != VAR_UNKNOWN)
2625 	    {
2626 		typestr = tv_get_string_buf_chk(&argvars[3], buf2);
2627 		if (typestr == NULL)
2628 		    error = TRUE;
2629 		else
2630 		{
2631 		    switch (TOUPPER_ASC(*typestr))
2632 		    {
2633 			case 'E': type = VIM_ERROR; break;
2634 			case 'Q': type = VIM_QUESTION; break;
2635 			case 'I': type = VIM_INFO; break;
2636 			case 'W': type = VIM_WARNING; break;
2637 			case 'G': type = VIM_GENERIC; break;
2638 		    }
2639 		}
2640 	    }
2641 	}
2642     }
2643 
2644     if (buttons == NULL || *buttons == NUL)
2645 	buttons = (char_u *)_("&Ok");
2646 
2647     if (!error)
2648 	rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2649 							    def, NULL, FALSE);
2650 #endif
2651 }
2652 
2653 /*
2654  * "copy()" function
2655  */
2656     static void
2657 f_copy(typval_T *argvars, typval_T *rettv)
2658 {
2659     item_copy(&argvars[0], rettv, FALSE, 0);
2660 }
2661 
2662 #ifdef FEAT_FLOAT
2663 /*
2664  * "cos()" function
2665  */
2666     static void
2667 f_cos(typval_T *argvars, typval_T *rettv)
2668 {
2669     float_T	f = 0.0;
2670 
2671     rettv->v_type = VAR_FLOAT;
2672     if (get_float_arg(argvars, &f) == OK)
2673 	rettv->vval.v_float = cos(f);
2674     else
2675 	rettv->vval.v_float = 0.0;
2676 }
2677 
2678 /*
2679  * "cosh()" function
2680  */
2681     static void
2682 f_cosh(typval_T *argvars, typval_T *rettv)
2683 {
2684     float_T	f = 0.0;
2685 
2686     rettv->v_type = VAR_FLOAT;
2687     if (get_float_arg(argvars, &f) == OK)
2688 	rettv->vval.v_float = cosh(f);
2689     else
2690 	rettv->vval.v_float = 0.0;
2691 }
2692 #endif
2693 
2694 /*
2695  * "count()" function
2696  */
2697     static void
2698 f_count(typval_T *argvars, typval_T *rettv)
2699 {
2700     long	n = 0;
2701     int		ic = FALSE;
2702     int		error = FALSE;
2703 
2704     if (argvars[2].v_type != VAR_UNKNOWN)
2705 	ic = (int)tv_get_number_chk(&argvars[2], &error);
2706 
2707     if (argvars[0].v_type == VAR_STRING)
2708     {
2709 	char_u *expr = tv_get_string_chk(&argvars[1]);
2710 	char_u *p = argvars[0].vval.v_string;
2711 	char_u *next;
2712 
2713 	if (!error && expr != NULL && *expr != NUL && p != NULL)
2714 	{
2715 	    if (ic)
2716 	    {
2717 		size_t len = STRLEN(expr);
2718 
2719 		while (*p != NUL)
2720 		{
2721 		    if (MB_STRNICMP(p, expr, len) == 0)
2722 		    {
2723 			++n;
2724 			p += len;
2725 		    }
2726 		    else
2727 			MB_PTR_ADV(p);
2728 		}
2729 	    }
2730 	    else
2731 		while ((next = (char_u *)strstr((char *)p, (char *)expr))
2732 								       != NULL)
2733 		{
2734 		    ++n;
2735 		    p = next + STRLEN(expr);
2736 		}
2737 	}
2738 
2739     }
2740     else if (argvars[0].v_type == VAR_LIST)
2741     {
2742 	listitem_T	*li;
2743 	list_T		*l;
2744 	long		idx;
2745 
2746 	if ((l = argvars[0].vval.v_list) != NULL)
2747 	{
2748 	    li = l->lv_first;
2749 	    if (argvars[2].v_type != VAR_UNKNOWN)
2750 	    {
2751 		if (argvars[3].v_type != VAR_UNKNOWN)
2752 		{
2753 		    idx = (long)tv_get_number_chk(&argvars[3], &error);
2754 		    if (!error)
2755 		    {
2756 			li = list_find(l, idx);
2757 			if (li == NULL)
2758 			    semsg(_(e_listidx), idx);
2759 		    }
2760 		}
2761 		if (error)
2762 		    li = NULL;
2763 	    }
2764 
2765 	    for ( ; li != NULL; li = li->li_next)
2766 		if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2767 		    ++n;
2768 	}
2769     }
2770     else if (argvars[0].v_type == VAR_DICT)
2771     {
2772 	int		todo;
2773 	dict_T		*d;
2774 	hashitem_T	*hi;
2775 
2776 	if ((d = argvars[0].vval.v_dict) != NULL)
2777 	{
2778 	    if (argvars[2].v_type != VAR_UNKNOWN)
2779 	    {
2780 		if (argvars[3].v_type != VAR_UNKNOWN)
2781 		    emsg(_(e_invarg));
2782 	    }
2783 
2784 	    todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2785 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2786 	    {
2787 		if (!HASHITEM_EMPTY(hi))
2788 		{
2789 		    --todo;
2790 		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2791 			++n;
2792 		}
2793 	    }
2794 	}
2795     }
2796     else
2797 	semsg(_(e_listdictarg), "count()");
2798     rettv->vval.v_number = n;
2799 }
2800 
2801 /*
2802  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2803  *
2804  * Checks the existence of a cscope connection.
2805  */
2806     static void
2807 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2808 {
2809 #ifdef FEAT_CSCOPE
2810     int		num = 0;
2811     char_u	*dbpath = NULL;
2812     char_u	*prepend = NULL;
2813     char_u	buf[NUMBUFLEN];
2814 
2815     if (argvars[0].v_type != VAR_UNKNOWN
2816 	    && argvars[1].v_type != VAR_UNKNOWN)
2817     {
2818 	num = (int)tv_get_number(&argvars[0]);
2819 	dbpath = tv_get_string(&argvars[1]);
2820 	if (argvars[2].v_type != VAR_UNKNOWN)
2821 	    prepend = tv_get_string_buf(&argvars[2], buf);
2822     }
2823 
2824     rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2825 #endif
2826 }
2827 
2828 /*
2829  * "cursor(lnum, col)" function, or
2830  * "cursor(list)"
2831  *
2832  * Moves the cursor to the specified line and column.
2833  * Returns 0 when the position could be set, -1 otherwise.
2834  */
2835     static void
2836 f_cursor(typval_T *argvars, typval_T *rettv)
2837 {
2838     long	line, col;
2839     long	coladd = 0;
2840     int		set_curswant = TRUE;
2841 
2842     rettv->vval.v_number = -1;
2843     if (argvars[1].v_type == VAR_UNKNOWN)
2844     {
2845 	pos_T	    pos;
2846 	colnr_T	    curswant = -1;
2847 
2848 	if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2849 	{
2850 	    emsg(_(e_invarg));
2851 	    return;
2852 	}
2853 	line = pos.lnum;
2854 	col = pos.col;
2855 	coladd = pos.coladd;
2856 	if (curswant >= 0)
2857 	{
2858 	    curwin->w_curswant = curswant - 1;
2859 	    set_curswant = FALSE;
2860 	}
2861     }
2862     else
2863     {
2864 	line = tv_get_lnum(argvars);
2865 	col = (long)tv_get_number_chk(&argvars[1], NULL);
2866 	if (argvars[2].v_type != VAR_UNKNOWN)
2867 	    coladd = (long)tv_get_number_chk(&argvars[2], NULL);
2868     }
2869     if (line < 0 || col < 0 || coladd < 0)
2870 	return;		/* type error; errmsg already given */
2871     if (line > 0)
2872 	curwin->w_cursor.lnum = line;
2873     if (col > 0)
2874 	curwin->w_cursor.col = col - 1;
2875     curwin->w_cursor.coladd = coladd;
2876 
2877     /* Make sure the cursor is in a valid position. */
2878     check_cursor();
2879     /* Correct cursor for multi-byte character. */
2880     if (has_mbyte)
2881 	mb_adjust_cursor();
2882 
2883     curwin->w_set_curswant = set_curswant;
2884     rettv->vval.v_number = 0;
2885 }
2886 
2887 #ifdef WIN3264
2888 /*
2889  * "debugbreak()" function
2890  */
2891     static void
2892 f_debugbreak(typval_T *argvars, typval_T *rettv)
2893 {
2894     int		pid;
2895 
2896     rettv->vval.v_number = FAIL;
2897     pid = (int)tv_get_number(&argvars[0]);
2898     if (pid == 0)
2899 	emsg(_(e_invarg));
2900     else
2901     {
2902 	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2903 
2904 	if (hProcess != NULL)
2905 	{
2906 	    DebugBreakProcess(hProcess);
2907 	    CloseHandle(hProcess);
2908 	    rettv->vval.v_number = OK;
2909 	}
2910     }
2911 }
2912 #endif
2913 
2914 /*
2915  * "deepcopy()" function
2916  */
2917     static void
2918 f_deepcopy(typval_T *argvars, typval_T *rettv)
2919 {
2920     int		noref = 0;
2921     int		copyID;
2922 
2923     if (argvars[1].v_type != VAR_UNKNOWN)
2924 	noref = (int)tv_get_number_chk(&argvars[1], NULL);
2925     if (noref < 0 || noref > 1)
2926 	emsg(_(e_invarg));
2927     else
2928     {
2929 	copyID = get_copyID();
2930 	item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2931     }
2932 }
2933 
2934 /*
2935  * "delete()" function
2936  */
2937     static void
2938 f_delete(typval_T *argvars, typval_T *rettv)
2939 {
2940     char_u	nbuf[NUMBUFLEN];
2941     char_u	*name;
2942     char_u	*flags;
2943 
2944     rettv->vval.v_number = -1;
2945     if (check_restricted() || check_secure())
2946 	return;
2947 
2948     name = tv_get_string(&argvars[0]);
2949     if (name == NULL || *name == NUL)
2950     {
2951 	emsg(_(e_invarg));
2952 	return;
2953     }
2954 
2955     if (argvars[1].v_type != VAR_UNKNOWN)
2956 	flags = tv_get_string_buf(&argvars[1], nbuf);
2957     else
2958 	flags = (char_u *)"";
2959 
2960     if (*flags == NUL)
2961 	/* delete a file */
2962 	rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2963     else if (STRCMP(flags, "d") == 0)
2964 	/* delete an empty directory */
2965 	rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2966     else if (STRCMP(flags, "rf") == 0)
2967 	/* delete a directory recursively */
2968 	rettv->vval.v_number = delete_recursive(name);
2969     else
2970 	semsg(_(e_invexpr2), flags);
2971 }
2972 
2973 /*
2974  * "deletebufline()" function
2975  */
2976     static void
2977 f_deletebufline(typval_T *argvars, typval_T *rettv)
2978 {
2979     buf_T	*buf;
2980     linenr_T	first, last;
2981     linenr_T	lnum;
2982     long	count;
2983     int		is_curbuf;
2984     buf_T	*curbuf_save = NULL;
2985     win_T	*curwin_save = NULL;
2986     tabpage_T	*tp;
2987     win_T	*wp;
2988 
2989     buf = tv_get_buf(&argvars[0], FALSE);
2990     if (buf == NULL)
2991     {
2992 	rettv->vval.v_number = 1; /* FAIL */
2993 	return;
2994     }
2995     is_curbuf = buf == curbuf;
2996 
2997     first = tv_get_lnum_buf(&argvars[1], buf);
2998     if (argvars[2].v_type != VAR_UNKNOWN)
2999 	last = tv_get_lnum_buf(&argvars[2], buf);
3000     else
3001 	last = first;
3002 
3003     if (buf->b_ml.ml_mfp == NULL || first < 1
3004 			   || first > buf->b_ml.ml_line_count || last < first)
3005     {
3006 	rettv->vval.v_number = 1;	/* FAIL */
3007 	return;
3008     }
3009 
3010     if (!is_curbuf)
3011     {
3012 	curbuf_save = curbuf;
3013 	curwin_save = curwin;
3014 	curbuf = buf;
3015 	find_win_for_curbuf();
3016     }
3017     if (last > curbuf->b_ml.ml_line_count)
3018 	last = curbuf->b_ml.ml_line_count;
3019     count = last - first + 1;
3020 
3021     // When coming here from Insert mode, sync undo, so that this can be
3022     // undone separately from what was previously inserted.
3023     if (u_sync_once == 2)
3024     {
3025 	u_sync_once = 1; // notify that u_sync() was called
3026 	u_sync(TRUE);
3027     }
3028 
3029     if (u_save(first - 1, last + 1) == FAIL)
3030     {
3031 	rettv->vval.v_number = 1;	/* FAIL */
3032 	return;
3033     }
3034 
3035     for (lnum = first; lnum <= last; ++lnum)
3036 	ml_delete(first, TRUE);
3037 
3038     FOR_ALL_TAB_WINDOWS(tp, wp)
3039 	if (wp->w_buffer == buf)
3040 	{
3041 	    if (wp->w_cursor.lnum > last)
3042 		wp->w_cursor.lnum -= count;
3043 	    else if (wp->w_cursor.lnum> first)
3044 		wp->w_cursor.lnum = first;
3045 	    if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3046 		wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3047 	}
3048     check_cursor_col();
3049     deleted_lines_mark(first, count);
3050 
3051     if (!is_curbuf)
3052     {
3053 	curbuf = curbuf_save;
3054 	curwin = curwin_save;
3055     }
3056 }
3057 
3058 /*
3059  * "did_filetype()" function
3060  */
3061     static void
3062 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3063 {
3064     rettv->vval.v_number = did_filetype;
3065 }
3066 
3067 /*
3068  * "diff_filler()" function
3069  */
3070     static void
3071 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3072 {
3073 #ifdef FEAT_DIFF
3074     rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
3075 #endif
3076 }
3077 
3078 /*
3079  * "diff_hlID()" function
3080  */
3081     static void
3082 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3083 {
3084 #ifdef FEAT_DIFF
3085     linenr_T		lnum = tv_get_lnum(argvars);
3086     static linenr_T	prev_lnum = 0;
3087     static varnumber_T	changedtick = 0;
3088     static int		fnum = 0;
3089     static int		change_start = 0;
3090     static int		change_end = 0;
3091     static hlf_T	hlID = (hlf_T)0;
3092     int			filler_lines;
3093     int			col;
3094 
3095     if (lnum < 0)	/* ignore type error in {lnum} arg */
3096 	lnum = 0;
3097     if (lnum != prev_lnum
3098 	    || changedtick != CHANGEDTICK(curbuf)
3099 	    || fnum != curbuf->b_fnum)
3100     {
3101 	/* New line, buffer, change: need to get the values. */
3102 	filler_lines = diff_check(curwin, lnum);
3103 	if (filler_lines < 0)
3104 	{
3105 	    if (filler_lines == -1)
3106 	    {
3107 		change_start = MAXCOL;
3108 		change_end = -1;
3109 		if (diff_find_change(curwin, lnum, &change_start, &change_end))
3110 		    hlID = HLF_ADD;	/* added line */
3111 		else
3112 		    hlID = HLF_CHD;	/* changed line */
3113 	    }
3114 	    else
3115 		hlID = HLF_ADD;	/* added line */
3116 	}
3117 	else
3118 	    hlID = (hlf_T)0;
3119 	prev_lnum = lnum;
3120 	changedtick = CHANGEDTICK(curbuf);
3121 	fnum = curbuf->b_fnum;
3122     }
3123 
3124     if (hlID == HLF_CHD || hlID == HLF_TXD)
3125     {
3126 	col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
3127 	if (col >= change_start && col <= change_end)
3128 	    hlID = HLF_TXD;			/* changed text */
3129 	else
3130 	    hlID = HLF_CHD;			/* changed line */
3131     }
3132     rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3133 #endif
3134 }
3135 
3136 /*
3137  * "empty({expr})" function
3138  */
3139     static void
3140 f_empty(typval_T *argvars, typval_T *rettv)
3141 {
3142     int		n = FALSE;
3143 
3144     switch (argvars[0].v_type)
3145     {
3146 	case VAR_STRING:
3147 	case VAR_FUNC:
3148 	    n = argvars[0].vval.v_string == NULL
3149 					  || *argvars[0].vval.v_string == NUL;
3150 	    break;
3151 	case VAR_PARTIAL:
3152 	    n = FALSE;
3153 	    break;
3154 	case VAR_NUMBER:
3155 	    n = argvars[0].vval.v_number == 0;
3156 	    break;
3157 	case VAR_FLOAT:
3158 #ifdef FEAT_FLOAT
3159 	    n = argvars[0].vval.v_float == 0.0;
3160 	    break;
3161 #endif
3162 	case VAR_LIST:
3163 	    n = argvars[0].vval.v_list == NULL
3164 				  || argvars[0].vval.v_list->lv_first == NULL;
3165 	    break;
3166 	case VAR_DICT:
3167 	    n = argvars[0].vval.v_dict == NULL
3168 			|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3169 	    break;
3170 	case VAR_SPECIAL:
3171 	    n = argvars[0].vval.v_number != VVAL_TRUE;
3172 	    break;
3173 
3174 	case VAR_BLOB:
3175 	    n = argvars[0].vval.v_blob == NULL
3176 		|| argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3177 	    break;
3178 
3179 	case VAR_JOB:
3180 #ifdef FEAT_JOB_CHANNEL
3181 	    n = argvars[0].vval.v_job == NULL
3182 			   || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3183 	    break;
3184 #endif
3185 	case VAR_CHANNEL:
3186 #ifdef FEAT_JOB_CHANNEL
3187 	    n = argvars[0].vval.v_channel == NULL
3188 			       || !channel_is_open(argvars[0].vval.v_channel);
3189 	    break;
3190 #endif
3191 	case VAR_UNKNOWN:
3192 	    internal_error("f_empty(UNKNOWN)");
3193 	    n = TRUE;
3194 	    break;
3195     }
3196 
3197     rettv->vval.v_number = n;
3198 }
3199 
3200 /*
3201  * "escape({string}, {chars})" function
3202  */
3203     static void
3204 f_escape(typval_T *argvars, typval_T *rettv)
3205 {
3206     char_u	buf[NUMBUFLEN];
3207 
3208     rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3209 					 tv_get_string_buf(&argvars[1], buf));
3210     rettv->v_type = VAR_STRING;
3211 }
3212 
3213 /*
3214  * "eval()" function
3215  */
3216     static void
3217 f_eval(typval_T *argvars, typval_T *rettv)
3218 {
3219     char_u	*s, *p;
3220 
3221     s = tv_get_string_chk(&argvars[0]);
3222     if (s != NULL)
3223 	s = skipwhite(s);
3224 
3225     p = s;
3226     if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3227     {
3228 	if (p != NULL && !aborting())
3229 	    semsg(_(e_invexpr2), p);
3230 	need_clr_eos = FALSE;
3231 	rettv->v_type = VAR_NUMBER;
3232 	rettv->vval.v_number = 0;
3233     }
3234     else if (*s != NUL)
3235 	emsg(_(e_trailing));
3236 }
3237 
3238 /*
3239  * "eventhandler()" function
3240  */
3241     static void
3242 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3243 {
3244     rettv->vval.v_number = vgetc_busy;
3245 }
3246 
3247 /*
3248  * "executable()" function
3249  */
3250     static void
3251 f_executable(typval_T *argvars, typval_T *rettv)
3252 {
3253     char_u *name = tv_get_string(&argvars[0]);
3254 
3255     /* Check in $PATH and also check directly if there is a directory name. */
3256     rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3257 		 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3258 }
3259 
3260 static garray_T	redir_execute_ga;
3261 
3262 /*
3263  * Append "value[value_len]" to the execute() output.
3264  */
3265     void
3266 execute_redir_str(char_u *value, int value_len)
3267 {
3268     int		len;
3269 
3270     if (value_len == -1)
3271 	len = (int)STRLEN(value);	/* Append the entire string */
3272     else
3273 	len = value_len;		/* Append only "value_len" characters */
3274     if (ga_grow(&redir_execute_ga, len) == OK)
3275     {
3276 	mch_memmove((char *)redir_execute_ga.ga_data
3277 				       + redir_execute_ga.ga_len, value, len);
3278 	redir_execute_ga.ga_len += len;
3279     }
3280 }
3281 
3282 /*
3283  * Get next line from a list.
3284  * Called by do_cmdline() to get the next line.
3285  * Returns allocated string, or NULL for end of function.
3286  */
3287 
3288     static char_u *
3289 get_list_line(
3290     int	    c UNUSED,
3291     void    *cookie,
3292     int	    indent UNUSED)
3293 {
3294     listitem_T **p = (listitem_T **)cookie;
3295     listitem_T *item = *p;
3296     char_u	buf[NUMBUFLEN];
3297     char_u	*s;
3298 
3299     if (item == NULL)
3300 	return NULL;
3301     s = tv_get_string_buf_chk(&item->li_tv, buf);
3302     *p = item->li_next;
3303     return s == NULL ? NULL : vim_strsave(s);
3304 }
3305 
3306 /*
3307  * "execute()" function
3308  */
3309     static void
3310 f_execute(typval_T *argvars, typval_T *rettv)
3311 {
3312     char_u	*cmd = NULL;
3313     list_T	*list = NULL;
3314     int		save_msg_silent = msg_silent;
3315     int		save_emsg_silent = emsg_silent;
3316     int		save_emsg_noredir = emsg_noredir;
3317     int		save_redir_execute = redir_execute;
3318     int		save_redir_off = redir_off;
3319     garray_T	save_ga;
3320     int		save_msg_col = msg_col;
3321     int		echo_output = FALSE;
3322 
3323     rettv->vval.v_string = NULL;
3324     rettv->v_type = VAR_STRING;
3325 
3326     if (argvars[0].v_type == VAR_LIST)
3327     {
3328 	list = argvars[0].vval.v_list;
3329 	if (list == NULL || list->lv_first == NULL)
3330 	    /* empty list, no commands, empty output */
3331 	    return;
3332 	++list->lv_refcount;
3333     }
3334     else
3335     {
3336 	cmd = tv_get_string_chk(&argvars[0]);
3337 	if (cmd == NULL)
3338 	    return;
3339     }
3340 
3341     if (argvars[1].v_type != VAR_UNKNOWN)
3342     {
3343 	char_u	buf[NUMBUFLEN];
3344 	char_u  *s = tv_get_string_buf_chk(&argvars[1], buf);
3345 
3346 	if (s == NULL)
3347 	    return;
3348 	if (*s == NUL)
3349 	    echo_output = TRUE;
3350 	if (STRNCMP(s, "silent", 6) == 0)
3351 	    ++msg_silent;
3352 	if (STRCMP(s, "silent!") == 0)
3353 	{
3354 	    emsg_silent = TRUE;
3355 	    emsg_noredir = TRUE;
3356 	}
3357     }
3358     else
3359 	++msg_silent;
3360 
3361     if (redir_execute)
3362 	save_ga = redir_execute_ga;
3363     ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3364     redir_execute = TRUE;
3365     redir_off = FALSE;
3366     if (!echo_output)
3367 	msg_col = 0;  // prevent leading spaces
3368 
3369     if (cmd != NULL)
3370 	do_cmdline_cmd(cmd);
3371     else
3372     {
3373 	listitem_T	*item = list->lv_first;
3374 
3375 	do_cmdline(NULL, get_list_line, (void *)&item,
3376 		      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3377 	--list->lv_refcount;
3378     }
3379 
3380     /* Need to append a NUL to the result. */
3381     if (ga_grow(&redir_execute_ga, 1) == OK)
3382     {
3383 	((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3384 	rettv->vval.v_string = redir_execute_ga.ga_data;
3385     }
3386     else
3387     {
3388 	ga_clear(&redir_execute_ga);
3389 	rettv->vval.v_string = NULL;
3390     }
3391     msg_silent = save_msg_silent;
3392     emsg_silent = save_emsg_silent;
3393     emsg_noredir = save_emsg_noredir;
3394 
3395     redir_execute = save_redir_execute;
3396     if (redir_execute)
3397 	redir_execute_ga = save_ga;
3398     redir_off = save_redir_off;
3399 
3400     // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
3401     if (echo_output)
3402 	// When not working silently: put it in column zero.  A following
3403 	// "echon" will overwrite the message, unavoidably.
3404 	msg_col = 0;
3405     else
3406 	// When working silently: Put it back where it was, since nothing
3407 	// should have been written.
3408 	msg_col = save_msg_col;
3409 }
3410 
3411 /*
3412  * "exepath()" function
3413  */
3414     static void
3415 f_exepath(typval_T *argvars, typval_T *rettv)
3416 {
3417     char_u *p = NULL;
3418 
3419     (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
3420     rettv->v_type = VAR_STRING;
3421     rettv->vval.v_string = p;
3422 }
3423 
3424 /*
3425  * "exists()" function
3426  */
3427     static void
3428 f_exists(typval_T *argvars, typval_T *rettv)
3429 {
3430     char_u	*p;
3431     int		n = FALSE;
3432 
3433     p = tv_get_string(&argvars[0]);
3434     if (*p == '$')			/* environment variable */
3435     {
3436 	/* first try "normal" environment variables (fast) */
3437 	if (mch_getenv(p + 1) != NULL)
3438 	    n = TRUE;
3439 	else
3440 	{
3441 	    /* try expanding things like $VIM and ${HOME} */
3442 	    p = expand_env_save(p);
3443 	    if (p != NULL && *p != '$')
3444 		n = TRUE;
3445 	    vim_free(p);
3446 	}
3447     }
3448     else if (*p == '&' || *p == '+')			/* option */
3449     {
3450 	n = (get_option_tv(&p, NULL, TRUE) == OK);
3451 	if (*skipwhite(p) != NUL)
3452 	    n = FALSE;			/* trailing garbage */
3453     }
3454     else if (*p == '*')			/* internal or user defined function */
3455     {
3456 	n = function_exists(p + 1, FALSE);
3457     }
3458     else if (*p == ':')
3459     {
3460 	n = cmd_exists(p + 1);
3461     }
3462     else if (*p == '#')
3463     {
3464 	if (p[1] == '#')
3465 	    n = autocmd_supported(p + 2);
3466 	else
3467 	    n = au_exists(p + 1);
3468     }
3469     else				/* internal variable */
3470     {
3471 	n = var_exists(p);
3472     }
3473 
3474     rettv->vval.v_number = n;
3475 }
3476 
3477 #ifdef FEAT_FLOAT
3478 /*
3479  * "exp()" function
3480  */
3481     static void
3482 f_exp(typval_T *argvars, typval_T *rettv)
3483 {
3484     float_T	f = 0.0;
3485 
3486     rettv->v_type = VAR_FLOAT;
3487     if (get_float_arg(argvars, &f) == OK)
3488 	rettv->vval.v_float = exp(f);
3489     else
3490 	rettv->vval.v_float = 0.0;
3491 }
3492 #endif
3493 
3494 /*
3495  * "expand()" function
3496  */
3497     static void
3498 f_expand(typval_T *argvars, typval_T *rettv)
3499 {
3500     char_u	*s;
3501     int		len;
3502     char	*errormsg;
3503     int		options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3504     expand_T	xpc;
3505     int		error = FALSE;
3506     char_u	*result;
3507 
3508     rettv->v_type = VAR_STRING;
3509     if (argvars[1].v_type != VAR_UNKNOWN
3510 	    && argvars[2].v_type != VAR_UNKNOWN
3511 	    && tv_get_number_chk(&argvars[2], &error)
3512 	    && !error)
3513     {
3514 	rettv_list_set(rettv, NULL);
3515     }
3516 
3517     s = tv_get_string(&argvars[0]);
3518     if (*s == '%' || *s == '#' || *s == '<')
3519     {
3520 	++emsg_off;
3521 	result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3522 	--emsg_off;
3523 	if (rettv->v_type == VAR_LIST)
3524 	{
3525 	    if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3526 		list_append_string(rettv->vval.v_list, result, -1);
3527 	    else
3528 		vim_free(result);
3529 	}
3530 	else
3531 	    rettv->vval.v_string = result;
3532     }
3533     else
3534     {
3535 	/* When the optional second argument is non-zero, don't remove matches
3536 	 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3537 	if (argvars[1].v_type != VAR_UNKNOWN
3538 				    && tv_get_number_chk(&argvars[1], &error))
3539 	    options |= WILD_KEEP_ALL;
3540 	if (!error)
3541 	{
3542 	    ExpandInit(&xpc);
3543 	    xpc.xp_context = EXPAND_FILES;
3544 	    if (p_wic)
3545 		options += WILD_ICASE;
3546 	    if (rettv->v_type == VAR_STRING)
3547 		rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3548 							   options, WILD_ALL);
3549 	    else if (rettv_list_alloc(rettv) != FAIL)
3550 	    {
3551 		int i;
3552 
3553 		ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3554 		for (i = 0; i < xpc.xp_numfiles; i++)
3555 		    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3556 		ExpandCleanup(&xpc);
3557 	    }
3558 	}
3559 	else
3560 	    rettv->vval.v_string = NULL;
3561     }
3562 }
3563 
3564 /*
3565  * "extend(list, list [, idx])" function
3566  * "extend(dict, dict [, action])" function
3567  */
3568     static void
3569 f_extend(typval_T *argvars, typval_T *rettv)
3570 {
3571     char_u      *arg_errmsg = (char_u *)N_("extend() argument");
3572 
3573     if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3574     {
3575 	list_T		*l1, *l2;
3576 	listitem_T	*item;
3577 	long		before;
3578 	int		error = FALSE;
3579 
3580 	l1 = argvars[0].vval.v_list;
3581 	l2 = argvars[1].vval.v_list;
3582 	if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3583 		&& l2 != NULL)
3584 	{
3585 	    if (argvars[2].v_type != VAR_UNKNOWN)
3586 	    {
3587 		before = (long)tv_get_number_chk(&argvars[2], &error);
3588 		if (error)
3589 		    return;		/* type error; errmsg already given */
3590 
3591 		if (before == l1->lv_len)
3592 		    item = NULL;
3593 		else
3594 		{
3595 		    item = list_find(l1, before);
3596 		    if (item == NULL)
3597 		    {
3598 			semsg(_(e_listidx), before);
3599 			return;
3600 		    }
3601 		}
3602 	    }
3603 	    else
3604 		item = NULL;
3605 	    list_extend(l1, l2, item);
3606 
3607 	    copy_tv(&argvars[0], rettv);
3608 	}
3609     }
3610     else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3611     {
3612 	dict_T	*d1, *d2;
3613 	char_u	*action;
3614 	int	i;
3615 
3616 	d1 = argvars[0].vval.v_dict;
3617 	d2 = argvars[1].vval.v_dict;
3618 	if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3619 		&& d2 != NULL)
3620 	{
3621 	    /* Check the third argument. */
3622 	    if (argvars[2].v_type != VAR_UNKNOWN)
3623 	    {
3624 		static char *(av[]) = {"keep", "force", "error"};
3625 
3626 		action = tv_get_string_chk(&argvars[2]);
3627 		if (action == NULL)
3628 		    return;		/* type error; errmsg already given */
3629 		for (i = 0; i < 3; ++i)
3630 		    if (STRCMP(action, av[i]) == 0)
3631 			break;
3632 		if (i == 3)
3633 		{
3634 		    semsg(_(e_invarg2), action);
3635 		    return;
3636 		}
3637 	    }
3638 	    else
3639 		action = (char_u *)"force";
3640 
3641 	    dict_extend(d1, d2, action);
3642 
3643 	    copy_tv(&argvars[0], rettv);
3644 	}
3645     }
3646     else
3647 	semsg(_(e_listdictarg), "extend()");
3648 }
3649 
3650 /*
3651  * "feedkeys()" function
3652  */
3653     static void
3654 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3655 {
3656     int		remap = TRUE;
3657     int		insert = FALSE;
3658     char_u	*keys, *flags;
3659     char_u	nbuf[NUMBUFLEN];
3660     int		typed = FALSE;
3661     int		execute = FALSE;
3662     int		dangerous = FALSE;
3663     int		lowlevel = FALSE;
3664     char_u	*keys_esc;
3665 
3666     /* This is not allowed in the sandbox.  If the commands would still be
3667      * executed in the sandbox it would be OK, but it probably happens later,
3668      * when "sandbox" is no longer set. */
3669     if (check_secure())
3670 	return;
3671 
3672     keys = tv_get_string(&argvars[0]);
3673 
3674     if (argvars[1].v_type != VAR_UNKNOWN)
3675     {
3676 	flags = tv_get_string_buf(&argvars[1], nbuf);
3677 	for ( ; *flags != NUL; ++flags)
3678 	{
3679 	    switch (*flags)
3680 	    {
3681 		case 'n': remap = FALSE; break;
3682 		case 'm': remap = TRUE; break;
3683 		case 't': typed = TRUE; break;
3684 		case 'i': insert = TRUE; break;
3685 		case 'x': execute = TRUE; break;
3686 		case '!': dangerous = TRUE; break;
3687 		case 'L': lowlevel = TRUE; break;
3688 	    }
3689 	}
3690     }
3691 
3692     if (*keys != NUL || execute)
3693     {
3694 	/* Need to escape K_SPECIAL and CSI before putting the string in the
3695 	 * typeahead buffer. */
3696 	keys_esc = vim_strsave_escape_csi(keys);
3697 	if (keys_esc != NULL)
3698 	{
3699 	    if (lowlevel)
3700 	    {
3701 #ifdef USE_INPUT_BUF
3702 		add_to_input_buf(keys, (int)STRLEN(keys));
3703 #else
3704 		emsg(_("E980: lowlevel input not supported"));
3705 #endif
3706 	    }
3707 	    else
3708 	    {
3709 		ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3710 				  insert ? 0 : typebuf.tb_len, !typed, FALSE);
3711 		if (vgetc_busy
3712 #ifdef FEAT_TIMERS
3713 			|| timer_busy
3714 #endif
3715 			)
3716 		    typebuf_was_filled = TRUE;
3717 	    }
3718 	    vim_free(keys_esc);
3719 
3720 	    if (execute)
3721 	    {
3722 		int save_msg_scroll = msg_scroll;
3723 
3724 		/* Avoid a 1 second delay when the keys start Insert mode. */
3725 		msg_scroll = FALSE;
3726 
3727 		if (!dangerous)
3728 		    ++ex_normal_busy;
3729 		exec_normal(TRUE, FALSE, TRUE);
3730 		if (!dangerous)
3731 		    --ex_normal_busy;
3732 
3733 		msg_scroll |= save_msg_scroll;
3734 	    }
3735 	}
3736     }
3737 }
3738 
3739 /*
3740  * "filereadable()" function
3741  */
3742     static void
3743 f_filereadable(typval_T *argvars, typval_T *rettv)
3744 {
3745     int		fd;
3746     char_u	*p;
3747     int		n;
3748 
3749 #ifndef O_NONBLOCK
3750 # define O_NONBLOCK 0
3751 #endif
3752     p = tv_get_string(&argvars[0]);
3753     if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3754 					      O_RDONLY | O_NONBLOCK, 0)) >= 0)
3755     {
3756 	n = TRUE;
3757 	close(fd);
3758     }
3759     else
3760 	n = FALSE;
3761 
3762     rettv->vval.v_number = n;
3763 }
3764 
3765 /*
3766  * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3767  * rights to write into.
3768  */
3769     static void
3770 f_filewritable(typval_T *argvars, typval_T *rettv)
3771 {
3772     rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
3773 }
3774 
3775     static void
3776 findfilendir(
3777     typval_T	*argvars UNUSED,
3778     typval_T	*rettv,
3779     int		find_what UNUSED)
3780 {
3781 #ifdef FEAT_SEARCHPATH
3782     char_u	*fname;
3783     char_u	*fresult = NULL;
3784     char_u	*path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3785     char_u	*p;
3786     char_u	pathbuf[NUMBUFLEN];
3787     int		count = 1;
3788     int		first = TRUE;
3789     int		error = FALSE;
3790 #endif
3791 
3792     rettv->vval.v_string = NULL;
3793     rettv->v_type = VAR_STRING;
3794 
3795 #ifdef FEAT_SEARCHPATH
3796     fname = tv_get_string(&argvars[0]);
3797 
3798     if (argvars[1].v_type != VAR_UNKNOWN)
3799     {
3800 	p = tv_get_string_buf_chk(&argvars[1], pathbuf);
3801 	if (p == NULL)
3802 	    error = TRUE;
3803 	else
3804 	{
3805 	    if (*p != NUL)
3806 		path = p;
3807 
3808 	    if (argvars[2].v_type != VAR_UNKNOWN)
3809 		count = (int)tv_get_number_chk(&argvars[2], &error);
3810 	}
3811     }
3812 
3813     if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3814 	error = TRUE;
3815 
3816     if (*fname != NUL && !error)
3817     {
3818 	do
3819 	{
3820 	    if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3821 		vim_free(fresult);
3822 	    fresult = find_file_in_path_option(first ? fname : NULL,
3823 					       first ? (int)STRLEN(fname) : 0,
3824 					0, first, path,
3825 					find_what,
3826 					curbuf->b_ffname,
3827 					find_what == FINDFILE_DIR
3828 					    ? (char_u *)"" : curbuf->b_p_sua);
3829 	    first = FALSE;
3830 
3831 	    if (fresult != NULL && rettv->v_type == VAR_LIST)
3832 		list_append_string(rettv->vval.v_list, fresult, -1);
3833 
3834 	} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3835     }
3836 
3837     if (rettv->v_type == VAR_STRING)
3838 	rettv->vval.v_string = fresult;
3839 #endif
3840 }
3841 
3842 /*
3843  * "filter()" function
3844  */
3845     static void
3846 f_filter(typval_T *argvars, typval_T *rettv)
3847 {
3848     filter_map(argvars, rettv, FALSE);
3849 }
3850 
3851 /*
3852  * "finddir({fname}[, {path}[, {count}]])" function
3853  */
3854     static void
3855 f_finddir(typval_T *argvars, typval_T *rettv)
3856 {
3857     findfilendir(argvars, rettv, FINDFILE_DIR);
3858 }
3859 
3860 /*
3861  * "findfile({fname}[, {path}[, {count}]])" function
3862  */
3863     static void
3864 f_findfile(typval_T *argvars, typval_T *rettv)
3865 {
3866     findfilendir(argvars, rettv, FINDFILE_FILE);
3867 }
3868 
3869 #ifdef FEAT_FLOAT
3870 /*
3871  * "float2nr({float})" function
3872  */
3873     static void
3874 f_float2nr(typval_T *argvars, typval_T *rettv)
3875 {
3876     float_T	f = 0.0;
3877 
3878     if (get_float_arg(argvars, &f) == OK)
3879     {
3880 	if (f <= -VARNUM_MAX + DBL_EPSILON)
3881 	    rettv->vval.v_number = -VARNUM_MAX;
3882 	else if (f >= VARNUM_MAX - DBL_EPSILON)
3883 	    rettv->vval.v_number = VARNUM_MAX;
3884 	else
3885 	    rettv->vval.v_number = (varnumber_T)f;
3886     }
3887 }
3888 
3889 /*
3890  * "floor({float})" function
3891  */
3892     static void
3893 f_floor(typval_T *argvars, typval_T *rettv)
3894 {
3895     float_T	f = 0.0;
3896 
3897     rettv->v_type = VAR_FLOAT;
3898     if (get_float_arg(argvars, &f) == OK)
3899 	rettv->vval.v_float = floor(f);
3900     else
3901 	rettv->vval.v_float = 0.0;
3902 }
3903 
3904 /*
3905  * "fmod()" function
3906  */
3907     static void
3908 f_fmod(typval_T *argvars, typval_T *rettv)
3909 {
3910     float_T	fx = 0.0, fy = 0.0;
3911 
3912     rettv->v_type = VAR_FLOAT;
3913     if (get_float_arg(argvars, &fx) == OK
3914 				     && get_float_arg(&argvars[1], &fy) == OK)
3915 	rettv->vval.v_float = fmod(fx, fy);
3916     else
3917 	rettv->vval.v_float = 0.0;
3918 }
3919 #endif
3920 
3921 /*
3922  * "fnameescape({string})" function
3923  */
3924     static void
3925 f_fnameescape(typval_T *argvars, typval_T *rettv)
3926 {
3927     rettv->vval.v_string = vim_strsave_fnameescape(
3928 					   tv_get_string(&argvars[0]), FALSE);
3929     rettv->v_type = VAR_STRING;
3930 }
3931 
3932 /*
3933  * "fnamemodify({fname}, {mods})" function
3934  */
3935     static void
3936 f_fnamemodify(typval_T *argvars, typval_T *rettv)
3937 {
3938     char_u	*fname;
3939     char_u	*mods;
3940     int		usedlen = 0;
3941     int		len;
3942     char_u	*fbuf = NULL;
3943     char_u	buf[NUMBUFLEN];
3944 
3945     fname = tv_get_string_chk(&argvars[0]);
3946     mods = tv_get_string_buf_chk(&argvars[1], buf);
3947     if (fname == NULL || mods == NULL)
3948 	fname = NULL;
3949     else
3950     {
3951 	len = (int)STRLEN(fname);
3952 	(void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
3953     }
3954 
3955     rettv->v_type = VAR_STRING;
3956     if (fname == NULL)
3957 	rettv->vval.v_string = NULL;
3958     else
3959 	rettv->vval.v_string = vim_strnsave(fname, len);
3960     vim_free(fbuf);
3961 }
3962 
3963 /*
3964  * "foldclosed()" function
3965  */
3966     static void
3967 foldclosed_both(
3968     typval_T	*argvars UNUSED,
3969     typval_T	*rettv,
3970     int		end UNUSED)
3971 {
3972 #ifdef FEAT_FOLDING
3973     linenr_T	lnum;
3974     linenr_T	first, last;
3975 
3976     lnum = tv_get_lnum(argvars);
3977     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3978     {
3979 	if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3980 	{
3981 	    if (end)
3982 		rettv->vval.v_number = (varnumber_T)last;
3983 	    else
3984 		rettv->vval.v_number = (varnumber_T)first;
3985 	    return;
3986 	}
3987     }
3988 #endif
3989     rettv->vval.v_number = -1;
3990 }
3991 
3992 /*
3993  * "foldclosed()" function
3994  */
3995     static void
3996 f_foldclosed(typval_T *argvars, typval_T *rettv)
3997 {
3998     foldclosed_both(argvars, rettv, FALSE);
3999 }
4000 
4001 /*
4002  * "foldclosedend()" function
4003  */
4004     static void
4005 f_foldclosedend(typval_T *argvars, typval_T *rettv)
4006 {
4007     foldclosed_both(argvars, rettv, TRUE);
4008 }
4009 
4010 /*
4011  * "foldlevel()" function
4012  */
4013     static void
4014 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4015 {
4016 #ifdef FEAT_FOLDING
4017     linenr_T	lnum;
4018 
4019     lnum = tv_get_lnum(argvars);
4020     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4021 	rettv->vval.v_number = foldLevel(lnum);
4022 #endif
4023 }
4024 
4025 /*
4026  * "foldtext()" function
4027  */
4028     static void
4029 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4030 {
4031 #ifdef FEAT_FOLDING
4032     linenr_T	foldstart;
4033     linenr_T	foldend;
4034     char_u	*dashes;
4035     linenr_T	lnum;
4036     char_u	*s;
4037     char_u	*r;
4038     int		len;
4039     char	*txt;
4040     long	count;
4041 #endif
4042 
4043     rettv->v_type = VAR_STRING;
4044     rettv->vval.v_string = NULL;
4045 #ifdef FEAT_FOLDING
4046     foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4047     foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4048     dashes = get_vim_var_str(VV_FOLDDASHES);
4049     if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4050 	    && dashes != NULL)
4051     {
4052 	/* Find first non-empty line in the fold. */
4053 	for (lnum = foldstart; lnum < foldend; ++lnum)
4054 	    if (!linewhite(lnum))
4055 		break;
4056 
4057 	/* Find interesting text in this line. */
4058 	s = skipwhite(ml_get(lnum));
4059 	/* skip C comment-start */
4060 	if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4061 	{
4062 	    s = skipwhite(s + 2);
4063 	    if (*skipwhite(s) == NUL
4064 			    && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4065 	    {
4066 		s = skipwhite(ml_get(lnum + 1));
4067 		if (*s == '*')
4068 		    s = skipwhite(s + 1);
4069 	    }
4070 	}
4071 	count = (long)(foldend - foldstart + 1);
4072 	txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
4073 	r = alloc((unsigned)(STRLEN(txt)
4074 		    + STRLEN(dashes)	    /* for %s */
4075 		    + 20		    /* for %3ld */
4076 		    + STRLEN(s)));	    /* concatenated */
4077 	if (r != NULL)
4078 	{
4079 	    sprintf((char *)r, txt, dashes, count);
4080 	    len = (int)STRLEN(r);
4081 	    STRCAT(r, s);
4082 	    /* remove 'foldmarker' and 'commentstring' */
4083 	    foldtext_cleanup(r + len);
4084 	    rettv->vval.v_string = r;
4085 	}
4086     }
4087 #endif
4088 }
4089 
4090 /*
4091  * "foldtextresult(lnum)" function
4092  */
4093     static void
4094 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4095 {
4096 #ifdef FEAT_FOLDING
4097     linenr_T	lnum;
4098     char_u	*text;
4099     char_u	buf[FOLD_TEXT_LEN];
4100     foldinfo_T  foldinfo;
4101     int		fold_count;
4102     static int	entered = FALSE;
4103 #endif
4104 
4105     rettv->v_type = VAR_STRING;
4106     rettv->vval.v_string = NULL;
4107 #ifdef FEAT_FOLDING
4108     if (entered)
4109 	return; /* reject recursive use */
4110     entered = TRUE;
4111 
4112     lnum = tv_get_lnum(argvars);
4113     /* treat illegal types and illegal string values for {lnum} the same */
4114     if (lnum < 0)
4115 	lnum = 0;
4116     fold_count = foldedCount(curwin, lnum, &foldinfo);
4117     if (fold_count > 0)
4118     {
4119 	text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4120 							       &foldinfo, buf);
4121 	if (text == buf)
4122 	    text = vim_strsave(text);
4123 	rettv->vval.v_string = text;
4124     }
4125 
4126     entered = FALSE;
4127 #endif
4128 }
4129 
4130 /*
4131  * "foreground()" function
4132  */
4133     static void
4134 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4135 {
4136 #ifdef FEAT_GUI
4137     if (gui.in_use)
4138 	gui_mch_set_foreground();
4139 #else
4140 # ifdef WIN32
4141     win32_set_foreground();
4142 # endif
4143 #endif
4144 }
4145 
4146     static void
4147 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
4148 {
4149     char_u	*s;
4150     char_u	*name;
4151     int		use_string = FALSE;
4152     partial_T   *arg_pt = NULL;
4153     char_u	*trans_name = NULL;
4154 
4155     if (argvars[0].v_type == VAR_FUNC)
4156     {
4157 	/* function(MyFunc, [arg], dict) */
4158 	s = argvars[0].vval.v_string;
4159     }
4160     else if (argvars[0].v_type == VAR_PARTIAL
4161 					 && argvars[0].vval.v_partial != NULL)
4162     {
4163 	/* function(dict.MyFunc, [arg]) */
4164 	arg_pt = argvars[0].vval.v_partial;
4165 	s = partial_name(arg_pt);
4166     }
4167     else
4168     {
4169 	/* function('MyFunc', [arg], dict) */
4170 	s = tv_get_string(&argvars[0]);
4171 	use_string = TRUE;
4172     }
4173 
4174     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
4175     {
4176 	name = s;
4177 	trans_name = trans_function_name(&name, FALSE,
4178 	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4179 	if (*name != NUL)
4180 	    s = NULL;
4181     }
4182 
4183     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4184 					 || (is_funcref && trans_name == NULL))
4185 	semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
4186     /* Don't check an autoload name for existence here. */
4187     else if (trans_name != NULL && (is_funcref
4188 				? find_func(trans_name) == NULL
4189 				: !translated_function_exists(trans_name)))
4190 	semsg(_("E700: Unknown function: %s"), s);
4191     else
4192     {
4193 	int	dict_idx = 0;
4194 	int	arg_idx = 0;
4195 	list_T	*list = NULL;
4196 
4197 	if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4198 	{
4199 	    char	sid_buf[25];
4200 	    int		off = *s == 's' ? 2 : 5;
4201 
4202 	    /* Expand s: and <SID> into <SNR>nr_, so that the function can
4203 	     * also be called from another script. Using trans_function_name()
4204 	     * would also work, but some plugins depend on the name being
4205 	     * printable text. */
4206 	    sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
4207 	    name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4208 	    if (name != NULL)
4209 	    {
4210 		STRCPY(name, sid_buf);
4211 		STRCAT(name, s + off);
4212 	    }
4213 	}
4214 	else
4215 	    name = vim_strsave(s);
4216 
4217 	if (argvars[1].v_type != VAR_UNKNOWN)
4218 	{
4219 	    if (argvars[2].v_type != VAR_UNKNOWN)
4220 	    {
4221 		/* function(name, [args], dict) */
4222 		arg_idx = 1;
4223 		dict_idx = 2;
4224 	    }
4225 	    else if (argvars[1].v_type == VAR_DICT)
4226 		/* function(name, dict) */
4227 		dict_idx = 1;
4228 	    else
4229 		/* function(name, [args]) */
4230 		arg_idx = 1;
4231 	    if (dict_idx > 0)
4232 	    {
4233 		if (argvars[dict_idx].v_type != VAR_DICT)
4234 		{
4235 		    emsg(_("E922: expected a dict"));
4236 		    vim_free(name);
4237 		    goto theend;
4238 		}
4239 		if (argvars[dict_idx].vval.v_dict == NULL)
4240 		    dict_idx = 0;
4241 	    }
4242 	    if (arg_idx > 0)
4243 	    {
4244 		if (argvars[arg_idx].v_type != VAR_LIST)
4245 		{
4246 		    emsg(_("E923: Second argument of function() must be a list or a dict"));
4247 		    vim_free(name);
4248 		    goto theend;
4249 		}
4250 		list = argvars[arg_idx].vval.v_list;
4251 		if (list == NULL || list->lv_len == 0)
4252 		    arg_idx = 0;
4253 	    }
4254 	}
4255 	if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
4256 	{
4257 	    partial_T	*pt = (partial_T *)alloc_clear(sizeof(partial_T));
4258 
4259 	    /* result is a VAR_PARTIAL */
4260 	    if (pt == NULL)
4261 		vim_free(name);
4262 	    else
4263 	    {
4264 		if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4265 		{
4266 		    listitem_T	*li;
4267 		    int		i = 0;
4268 		    int		arg_len = 0;
4269 		    int		lv_len = 0;
4270 
4271 		    if (arg_pt != NULL)
4272 			arg_len = arg_pt->pt_argc;
4273 		    if (list != NULL)
4274 			lv_len = list->lv_len;
4275 		    pt->pt_argc = arg_len + lv_len;
4276 		    pt->pt_argv = (typval_T *)alloc(
4277 					      sizeof(typval_T) * pt->pt_argc);
4278 		    if (pt->pt_argv == NULL)
4279 		    {
4280 			vim_free(pt);
4281 			vim_free(name);
4282 			goto theend;
4283 		    }
4284 		    for (i = 0; i < arg_len; i++)
4285 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4286 		    if (lv_len > 0)
4287 			for (li = list->lv_first; li != NULL;
4288 							 li = li->li_next)
4289 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
4290 		}
4291 
4292 		/* For "function(dict.func, [], dict)" and "func" is a partial
4293 		 * use "dict".  That is backwards compatible. */
4294 		if (dict_idx > 0)
4295 		{
4296 		    /* The dict is bound explicitly, pt_auto is FALSE. */
4297 		    pt->pt_dict = argvars[dict_idx].vval.v_dict;
4298 		    ++pt->pt_dict->dv_refcount;
4299 		}
4300 		else if (arg_pt != NULL)
4301 		{
4302 		    /* If the dict was bound automatically the result is also
4303 		     * bound automatically. */
4304 		    pt->pt_dict = arg_pt->pt_dict;
4305 		    pt->pt_auto = arg_pt->pt_auto;
4306 		    if (pt->pt_dict != NULL)
4307 			++pt->pt_dict->dv_refcount;
4308 		}
4309 
4310 		pt->pt_refcount = 1;
4311 		if (arg_pt != NULL && arg_pt->pt_func != NULL)
4312 		{
4313 		    pt->pt_func = arg_pt->pt_func;
4314 		    func_ptr_ref(pt->pt_func);
4315 		    vim_free(name);
4316 		}
4317 		else if (is_funcref)
4318 		{
4319 		    pt->pt_func = find_func(trans_name);
4320 		    func_ptr_ref(pt->pt_func);
4321 		    vim_free(name);
4322 		}
4323 		else
4324 		{
4325 		    pt->pt_name = name;
4326 		    func_ref(name);
4327 		}
4328 	    }
4329 	    rettv->v_type = VAR_PARTIAL;
4330 	    rettv->vval.v_partial = pt;
4331 	}
4332 	else
4333 	{
4334 	    /* result is a VAR_FUNC */
4335 	    rettv->v_type = VAR_FUNC;
4336 	    rettv->vval.v_string = name;
4337 	    func_ref(name);
4338 	}
4339     }
4340 theend:
4341     vim_free(trans_name);
4342 }
4343 
4344 /*
4345  * "funcref()" function
4346  */
4347     static void
4348 f_funcref(typval_T *argvars, typval_T *rettv)
4349 {
4350     common_function(argvars, rettv, TRUE);
4351 }
4352 
4353 /*
4354  * "function()" function
4355  */
4356     static void
4357 f_function(typval_T *argvars, typval_T *rettv)
4358 {
4359     common_function(argvars, rettv, FALSE);
4360 }
4361 
4362 /*
4363  * "garbagecollect()" function
4364  */
4365     static void
4366 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4367 {
4368     /* This is postponed until we are back at the toplevel, because we may be
4369      * using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]". */
4370     want_garbage_collect = TRUE;
4371 
4372     if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
4373 	garbage_collect_at_exit = TRUE;
4374 }
4375 
4376 /*
4377  * "get()" function
4378  */
4379     static void
4380 f_get(typval_T *argvars, typval_T *rettv)
4381 {
4382     listitem_T	*li;
4383     list_T	*l;
4384     dictitem_T	*di;
4385     dict_T	*d;
4386     typval_T	*tv = NULL;
4387 
4388     if (argvars[0].v_type == VAR_BLOB)
4389     {
4390 	int error = FALSE;
4391 	int idx = tv_get_number_chk(&argvars[1], &error);
4392 
4393 	if (!error)
4394 	{
4395 	    rettv->v_type = VAR_NUMBER;
4396 	    if (idx < 0)
4397 		idx = blob_len(argvars[0].vval.v_blob) + idx;
4398 	    if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4399 		rettv->vval.v_number = -1;
4400 	    else
4401 	    {
4402 		rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
4403 		tv = rettv;
4404 	    }
4405 	}
4406     }
4407     else if (argvars[0].v_type == VAR_LIST)
4408     {
4409 	if ((l = argvars[0].vval.v_list) != NULL)
4410 	{
4411 	    int		error = FALSE;
4412 
4413 	    li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
4414 	    if (!error && li != NULL)
4415 		tv = &li->li_tv;
4416 	}
4417     }
4418     else if (argvars[0].v_type == VAR_DICT)
4419     {
4420 	if ((d = argvars[0].vval.v_dict) != NULL)
4421 	{
4422 	    di = dict_find(d, tv_get_string(&argvars[1]), -1);
4423 	    if (di != NULL)
4424 		tv = &di->di_tv;
4425 	}
4426     }
4427     else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4428     {
4429 	partial_T	*pt;
4430 	partial_T	fref_pt;
4431 
4432 	if (argvars[0].v_type == VAR_PARTIAL)
4433 	    pt = argvars[0].vval.v_partial;
4434 	else
4435 	{
4436 	    vim_memset(&fref_pt, 0, sizeof(fref_pt));
4437 	    fref_pt.pt_name = argvars[0].vval.v_string;
4438 	    pt = &fref_pt;
4439 	}
4440 
4441 	if (pt != NULL)
4442 	{
4443 	    char_u *what = tv_get_string(&argvars[1]);
4444 	    char_u *n;
4445 
4446 	    if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4447 	    {
4448 		rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
4449 		n = partial_name(pt);
4450 		if (n == NULL)
4451 		    rettv->vval.v_string = NULL;
4452 		else
4453 		{
4454 		    rettv->vval.v_string = vim_strsave(n);
4455 		    if (rettv->v_type == VAR_FUNC)
4456 			func_ref(rettv->vval.v_string);
4457 		}
4458 	    }
4459 	    else if (STRCMP(what, "dict") == 0)
4460 		rettv_dict_set(rettv, pt->pt_dict);
4461 	    else if (STRCMP(what, "args") == 0)
4462 	    {
4463 		rettv->v_type = VAR_LIST;
4464 		if (rettv_list_alloc(rettv) == OK)
4465 		{
4466 		    int i;
4467 
4468 		    for (i = 0; i < pt->pt_argc; ++i)
4469 			list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4470 		}
4471 	    }
4472 	    else
4473 		semsg(_(e_invarg2), what);
4474 	    return;
4475 	}
4476     }
4477     else
4478 	semsg(_(e_listdictblobarg), "get()");
4479 
4480     if (tv == NULL)
4481     {
4482 	if (argvars[2].v_type != VAR_UNKNOWN)
4483 	    copy_tv(&argvars[2], rettv);
4484     }
4485     else
4486 	copy_tv(tv, rettv);
4487 }
4488 
4489 /*
4490  * Returns buffer options, variables and other attributes in a dictionary.
4491  */
4492     static dict_T *
4493 get_buffer_info(buf_T *buf)
4494 {
4495     dict_T	*dict;
4496     tabpage_T	*tp;
4497     win_T	*wp;
4498     list_T	*windows;
4499 
4500     dict = dict_alloc();
4501     if (dict == NULL)
4502 	return NULL;
4503 
4504     dict_add_number(dict, "bufnr", buf->b_fnum);
4505     dict_add_string(dict, "name", buf->b_ffname);
4506     dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4507 						     : buflist_findlnum(buf));
4508     dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4509     dict_add_number(dict, "listed", buf->b_p_bl);
4510     dict_add_number(dict, "changed", bufIsChanged(buf));
4511     dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4512     dict_add_number(dict, "hidden",
4513 			    buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
4514 
4515     /* Get a reference to buffer variables */
4516     dict_add_dict(dict, "variables", buf->b_vars);
4517 
4518     /* List of windows displaying this buffer */
4519     windows = list_alloc();
4520     if (windows != NULL)
4521     {
4522 	FOR_ALL_TAB_WINDOWS(tp, wp)
4523 	    if (wp->w_buffer == buf)
4524 		list_append_number(windows, (varnumber_T)wp->w_id);
4525 	dict_add_list(dict, "windows", windows);
4526     }
4527 
4528 #ifdef FEAT_SIGNS
4529     if (buf->b_signlist != NULL)
4530     {
4531 	/* List of signs placed in this buffer */
4532 	list_T	*signs = list_alloc();
4533 	if (signs != NULL)
4534 	{
4535 	    get_buffer_signs(buf, signs);
4536 	    dict_add_list(dict, "signs", signs);
4537 	}
4538     }
4539 #endif
4540 
4541     return dict;
4542 }
4543 
4544 /*
4545  * "getbufinfo()" function
4546  */
4547     static void
4548 f_getbufinfo(typval_T *argvars, typval_T *rettv)
4549 {
4550     buf_T	*buf = NULL;
4551     buf_T	*argbuf = NULL;
4552     dict_T	*d;
4553     int		filtered = FALSE;
4554     int		sel_buflisted = FALSE;
4555     int		sel_bufloaded = FALSE;
4556     int		sel_bufmodified = FALSE;
4557 
4558     if (rettv_list_alloc(rettv) != OK)
4559 	return;
4560 
4561     /* List of all the buffers or selected buffers */
4562     if (argvars[0].v_type == VAR_DICT)
4563     {
4564 	dict_T	*sel_d = argvars[0].vval.v_dict;
4565 
4566 	if (sel_d != NULL)
4567 	{
4568 	    dictitem_T	*di;
4569 
4570 	    filtered = TRUE;
4571 
4572 	    di = dict_find(sel_d, (char_u *)"buflisted", -1);
4573 	    if (di != NULL && tv_get_number(&di->di_tv))
4574 		sel_buflisted = TRUE;
4575 
4576 	    di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4577 	    if (di != NULL && tv_get_number(&di->di_tv))
4578 		sel_bufloaded = TRUE;
4579 
4580 	    di = dict_find(sel_d, (char_u *)"bufmodified", -1);
4581 	    if (di != NULL && tv_get_number(&di->di_tv))
4582 		sel_bufmodified = TRUE;
4583 	}
4584     }
4585     else if (argvars[0].v_type != VAR_UNKNOWN)
4586     {
4587 	/* Information about one buffer.  Argument specifies the buffer */
4588 	(void)tv_get_number(&argvars[0]);   /* issue errmsg if type error */
4589 	++emsg_off;
4590 	argbuf = tv_get_buf(&argvars[0], FALSE);
4591 	--emsg_off;
4592 	if (argbuf == NULL)
4593 	    return;
4594     }
4595 
4596     /* Return information about all the buffers or a specified buffer */
4597     FOR_ALL_BUFFERS(buf)
4598     {
4599 	if (argbuf != NULL && argbuf != buf)
4600 	    continue;
4601 	if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
4602 			|| (sel_buflisted && !buf->b_p_bl)
4603 			|| (sel_bufmodified && !buf->b_changed)))
4604 	    continue;
4605 
4606 	d = get_buffer_info(buf);
4607 	if (d != NULL)
4608 	    list_append_dict(rettv->vval.v_list, d);
4609 	if (argbuf != NULL)
4610 	    return;
4611     }
4612 }
4613 
4614 /*
4615  * Get line or list of lines from buffer "buf" into "rettv".
4616  * Return a range (from start to end) of lines in rettv from the specified
4617  * buffer.
4618  * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4619  */
4620     static void
4621 get_buffer_lines(
4622     buf_T	*buf,
4623     linenr_T	start,
4624     linenr_T	end,
4625     int		retlist,
4626     typval_T	*rettv)
4627 {
4628     char_u	*p;
4629 
4630     rettv->v_type = VAR_STRING;
4631     rettv->vval.v_string = NULL;
4632     if (retlist && rettv_list_alloc(rettv) == FAIL)
4633 	return;
4634 
4635     if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4636 	return;
4637 
4638     if (!retlist)
4639     {
4640 	if (start >= 1 && start <= buf->b_ml.ml_line_count)
4641 	    p = ml_get_buf(buf, start, FALSE);
4642 	else
4643 	    p = (char_u *)"";
4644 	rettv->vval.v_string = vim_strsave(p);
4645     }
4646     else
4647     {
4648 	if (end < start)
4649 	    return;
4650 
4651 	if (start < 1)
4652 	    start = 1;
4653 	if (end > buf->b_ml.ml_line_count)
4654 	    end = buf->b_ml.ml_line_count;
4655 	while (start <= end)
4656 	    if (list_append_string(rettv->vval.v_list,
4657 				 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4658 		break;
4659     }
4660 }
4661 
4662 /*
4663  * "getbufline()" function
4664  */
4665     static void
4666 f_getbufline(typval_T *argvars, typval_T *rettv)
4667 {
4668     linenr_T	lnum;
4669     linenr_T	end;
4670     buf_T	*buf;
4671 
4672     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4673     ++emsg_off;
4674     buf = tv_get_buf(&argvars[0], FALSE);
4675     --emsg_off;
4676 
4677     lnum = tv_get_lnum_buf(&argvars[1], buf);
4678     if (argvars[2].v_type == VAR_UNKNOWN)
4679 	end = lnum;
4680     else
4681 	end = tv_get_lnum_buf(&argvars[2], buf);
4682 
4683     get_buffer_lines(buf, lnum, end, TRUE, rettv);
4684 }
4685 
4686 /*
4687  * "getbufvar()" function
4688  */
4689     static void
4690 f_getbufvar(typval_T *argvars, typval_T *rettv)
4691 {
4692     buf_T	*buf;
4693     buf_T	*save_curbuf;
4694     char_u	*varname;
4695     dictitem_T	*v;
4696     int		done = FALSE;
4697 
4698     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4699     varname = tv_get_string_chk(&argvars[1]);
4700     ++emsg_off;
4701     buf = tv_get_buf(&argvars[0], FALSE);
4702 
4703     rettv->v_type = VAR_STRING;
4704     rettv->vval.v_string = NULL;
4705 
4706     if (buf != NULL && varname != NULL)
4707     {
4708 	/* set curbuf to be our buf, temporarily */
4709 	save_curbuf = curbuf;
4710 	curbuf = buf;
4711 
4712 	if (*varname == '&')
4713 	{
4714 	    if (varname[1] == NUL)
4715 	    {
4716 		/* get all buffer-local options in a dict */
4717 		dict_T	*opts = get_winbuf_options(TRUE);
4718 
4719 		if (opts != NULL)
4720 		{
4721 		    rettv_dict_set(rettv, opts);
4722 		    done = TRUE;
4723 		}
4724 	    }
4725 	    else if (get_option_tv(&varname, rettv, TRUE) == OK)
4726 		/* buffer-local-option */
4727 		done = TRUE;
4728 	}
4729 	else
4730 	{
4731 	    /* Look up the variable. */
4732 	    /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4733 	    v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4734 							 'b', varname, FALSE);
4735 	    if (v != NULL)
4736 	    {
4737 		copy_tv(&v->di_tv, rettv);
4738 		done = TRUE;
4739 	    }
4740 	}
4741 
4742 	/* restore previous notion of curbuf */
4743 	curbuf = save_curbuf;
4744     }
4745 
4746     if (!done && argvars[2].v_type != VAR_UNKNOWN)
4747 	/* use the default value */
4748 	copy_tv(&argvars[2], rettv);
4749 
4750     --emsg_off;
4751 }
4752 
4753 /*
4754  * "getchangelist()" function
4755  */
4756     static void
4757 f_getchangelist(typval_T *argvars, typval_T *rettv)
4758 {
4759 #ifdef FEAT_JUMPLIST
4760     buf_T	*buf;
4761     int		i;
4762     list_T	*l;
4763     dict_T	*d;
4764 #endif
4765 
4766     if (rettv_list_alloc(rettv) != OK)
4767 	return;
4768 
4769 #ifdef FEAT_JUMPLIST
4770     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
4771     ++emsg_off;
4772     buf = tv_get_buf(&argvars[0], FALSE);
4773     --emsg_off;
4774     if (buf == NULL)
4775 	return;
4776 
4777     l = list_alloc();
4778     if (l == NULL)
4779 	return;
4780 
4781     if (list_append_list(rettv->vval.v_list, l) == FAIL)
4782 	return;
4783     /*
4784      * The current window change list index tracks only the position in the
4785      * current buffer change list. For other buffers, use the change list
4786      * length as the current index.
4787      */
4788     list_append_number(rettv->vval.v_list,
4789 	    (varnumber_T)((buf == curwin->w_buffer)
4790 		? curwin->w_changelistidx : buf->b_changelistlen));
4791 
4792     for (i = 0; i < buf->b_changelistlen; ++i)
4793     {
4794 	if (buf->b_changelist[i].lnum == 0)
4795 	    continue;
4796 	if ((d = dict_alloc()) == NULL)
4797 	    return;
4798 	if (list_append_dict(l, d) == FAIL)
4799 	    return;
4800 	dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4801 	dict_add_number(d, "col", (long)buf->b_changelist[i].col);
4802 	dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
4803     }
4804 #endif
4805 }
4806 /*
4807  * "getchar()" function
4808  */
4809     static void
4810 f_getchar(typval_T *argvars, typval_T *rettv)
4811 {
4812     varnumber_T		n;
4813     int			error = FALSE;
4814 
4815 #ifdef MESSAGE_QUEUE
4816     // vpeekc() used to check for messages, but that caused problems, invoking
4817     // a callback where it was not expected.  Some plugins use getchar(1) in a
4818     // loop to await a message, therefore make sure we check for messages here.
4819     parse_queued_messages();
4820 #endif
4821 
4822     /* Position the cursor.  Needed after a message that ends in a space. */
4823     windgoto(msg_row, msg_col);
4824 
4825     ++no_mapping;
4826     ++allow_keys;
4827     for (;;)
4828     {
4829 	if (argvars[0].v_type == VAR_UNKNOWN)
4830 	    /* getchar(): blocking wait. */
4831 	    n = plain_vgetc();
4832 	else if (tv_get_number_chk(&argvars[0], &error) == 1)
4833 	    /* getchar(1): only check if char avail */
4834 	    n = vpeekc_any();
4835 	else if (error || vpeekc_any() == NUL)
4836 	    /* illegal argument or getchar(0) and no char avail: return zero */
4837 	    n = 0;
4838 	else
4839 	    /* getchar(0) and char avail: return char */
4840 	    n = plain_vgetc();
4841 
4842 	if (n == K_IGNORE)
4843 	    continue;
4844 	break;
4845     }
4846     --no_mapping;
4847     --allow_keys;
4848 
4849     set_vim_var_nr(VV_MOUSE_WIN, 0);
4850     set_vim_var_nr(VV_MOUSE_WINID, 0);
4851     set_vim_var_nr(VV_MOUSE_LNUM, 0);
4852     set_vim_var_nr(VV_MOUSE_COL, 0);
4853 
4854     rettv->vval.v_number = n;
4855     if (IS_SPECIAL(n) || mod_mask != 0)
4856     {
4857 	char_u		temp[10];   /* modifier: 3, mbyte-char: 6, NUL: 1 */
4858 	int		i = 0;
4859 
4860 	/* Turn a special key into three bytes, plus modifier. */
4861 	if (mod_mask != 0)
4862 	{
4863 	    temp[i++] = K_SPECIAL;
4864 	    temp[i++] = KS_MODIFIER;
4865 	    temp[i++] = mod_mask;
4866 	}
4867 	if (IS_SPECIAL(n))
4868 	{
4869 	    temp[i++] = K_SPECIAL;
4870 	    temp[i++] = K_SECOND(n);
4871 	    temp[i++] = K_THIRD(n);
4872 	}
4873 	else if (has_mbyte)
4874 	    i += (*mb_char2bytes)(n, temp + i);
4875 	else
4876 	    temp[i++] = n;
4877 	temp[i++] = NUL;
4878 	rettv->v_type = VAR_STRING;
4879 	rettv->vval.v_string = vim_strsave(temp);
4880 
4881 #ifdef FEAT_MOUSE
4882 	if (is_mouse_key(n))
4883 	{
4884 	    int		row = mouse_row;
4885 	    int		col = mouse_col;
4886 	    win_T	*win;
4887 	    linenr_T	lnum;
4888 	    win_T	*wp;
4889 	    int		winnr = 1;
4890 
4891 	    if (row >= 0 && col >= 0)
4892 	    {
4893 		/* Find the window at the mouse coordinates and compute the
4894 		 * text position. */
4895 		win = mouse_find_win(&row, &col);
4896 		if (win == NULL)
4897 		    return;
4898 		(void)mouse_comp_pos(win, &row, &col, &lnum);
4899 		for (wp = firstwin; wp != win; wp = wp->w_next)
4900 		    ++winnr;
4901 		set_vim_var_nr(VV_MOUSE_WIN, winnr);
4902 		set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4903 		set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4904 		set_vim_var_nr(VV_MOUSE_COL, col + 1);
4905 	    }
4906 	}
4907 #endif
4908     }
4909 }
4910 
4911 /*
4912  * "getcharmod()" function
4913  */
4914     static void
4915 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4916 {
4917     rettv->vval.v_number = mod_mask;
4918 }
4919 
4920 /*
4921  * "getcharsearch()" function
4922  */
4923     static void
4924 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4925 {
4926     if (rettv_dict_alloc(rettv) != FAIL)
4927     {
4928 	dict_T *dict = rettv->vval.v_dict;
4929 
4930 	dict_add_string(dict, "char", last_csearch());
4931 	dict_add_number(dict, "forward", last_csearch_forward());
4932 	dict_add_number(dict, "until", last_csearch_until());
4933     }
4934 }
4935 
4936 /*
4937  * "getcmdline()" function
4938  */
4939     static void
4940 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4941 {
4942     rettv->v_type = VAR_STRING;
4943     rettv->vval.v_string = get_cmdline_str();
4944 }
4945 
4946 /*
4947  * "getcmdpos()" function
4948  */
4949     static void
4950 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4951 {
4952     rettv->vval.v_number = get_cmdline_pos() + 1;
4953 }
4954 
4955 /*
4956  * "getcmdtype()" function
4957  */
4958     static void
4959 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4960 {
4961     rettv->v_type = VAR_STRING;
4962     rettv->vval.v_string = alloc(2);
4963     if (rettv->vval.v_string != NULL)
4964     {
4965 	rettv->vval.v_string[0] = get_cmdline_type();
4966 	rettv->vval.v_string[1] = NUL;
4967     }
4968 }
4969 
4970 /*
4971  * "getcmdwintype()" function
4972  */
4973     static void
4974 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4975 {
4976     rettv->v_type = VAR_STRING;
4977     rettv->vval.v_string = NULL;
4978 #ifdef FEAT_CMDWIN
4979     rettv->vval.v_string = alloc(2);
4980     if (rettv->vval.v_string != NULL)
4981     {
4982 	rettv->vval.v_string[0] = cmdwin_type;
4983 	rettv->vval.v_string[1] = NUL;
4984     }
4985 #endif
4986 }
4987 
4988 #if defined(FEAT_CMDL_COMPL)
4989 /*
4990  * "getcompletion()" function
4991  */
4992     static void
4993 f_getcompletion(typval_T *argvars, typval_T *rettv)
4994 {
4995     char_u	*pat;
4996     expand_T	xpc;
4997     int		filtered = FALSE;
4998     int		options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4999 					| WILD_NO_BEEP;
5000 
5001     if (argvars[2].v_type != VAR_UNKNOWN)
5002 	filtered = tv_get_number_chk(&argvars[2], NULL);
5003 
5004     if (p_wic)
5005 	options |= WILD_ICASE;
5006 
5007     /* For filtered results, 'wildignore' is used */
5008     if (!filtered)
5009 	options |= WILD_KEEP_ALL;
5010 
5011     ExpandInit(&xpc);
5012     xpc.xp_pattern = tv_get_string(&argvars[0]);
5013     xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5014     xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
5015     if (xpc.xp_context == EXPAND_NOTHING)
5016     {
5017 	if (argvars[1].v_type == VAR_STRING)
5018 	    semsg(_(e_invarg2), argvars[1].vval.v_string);
5019 	else
5020 	    emsg(_(e_invarg));
5021 	return;
5022     }
5023 
5024 # if defined(FEAT_MENU)
5025     if (xpc.xp_context == EXPAND_MENUS)
5026     {
5027 	set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5028 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5029     }
5030 # endif
5031 #ifdef FEAT_CSCOPE
5032     if (xpc.xp_context == EXPAND_CSCOPE)
5033     {
5034 	set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5035 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5036     }
5037 #endif
5038 #ifdef FEAT_SIGNS
5039     if (xpc.xp_context == EXPAND_SIGN)
5040     {
5041 	set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5042 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5043     }
5044 #endif
5045 
5046     pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5047     if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5048     {
5049 	int	i;
5050 
5051 	ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5052 
5053 	for (i = 0; i < xpc.xp_numfiles; i++)
5054 	    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5055     }
5056     vim_free(pat);
5057     ExpandCleanup(&xpc);
5058 }
5059 #endif
5060 
5061 /*
5062  * "getcwd()" function
5063  */
5064     static void
5065 f_getcwd(typval_T *argvars, typval_T *rettv)
5066 {
5067     win_T	*wp = NULL;
5068     char_u	*cwd;
5069     int		global = FALSE;
5070 
5071     rettv->v_type = VAR_STRING;
5072     rettv->vval.v_string = NULL;
5073 
5074     if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5075 	global = TRUE;
5076     else
5077 	wp = find_tabwin(&argvars[0], &argvars[1]);
5078 
5079     if (wp != NULL && wp->w_localdir != NULL)
5080 	rettv->vval.v_string = vim_strsave(wp->w_localdir);
5081     else if (wp != NULL || global)
5082     {
5083 	if (globaldir != NULL)
5084 	    rettv->vval.v_string = vim_strsave(globaldir);
5085 	else
5086 	{
5087 	    cwd = alloc(MAXPATHL);
5088 	    if (cwd != NULL)
5089 	    {
5090 		if (mch_dirname(cwd, MAXPATHL) != FAIL)
5091 		    rettv->vval.v_string = vim_strsave(cwd);
5092 		vim_free(cwd);
5093 	    }
5094 	}
5095     }
5096 #ifdef BACKSLASH_IN_FILENAME
5097     if (rettv->vval.v_string != NULL)
5098 	slash_adjust(rettv->vval.v_string);
5099 #endif
5100 }
5101 
5102 /*
5103  * "getfontname()" function
5104  */
5105     static void
5106 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5107 {
5108     rettv->v_type = VAR_STRING;
5109     rettv->vval.v_string = NULL;
5110 #ifdef FEAT_GUI
5111     if (gui.in_use)
5112     {
5113 	GuiFont font;
5114 	char_u	*name = NULL;
5115 
5116 	if (argvars[0].v_type == VAR_UNKNOWN)
5117 	{
5118 	    /* Get the "Normal" font.  Either the name saved by
5119 	     * hl_set_font_name() or from the font ID. */
5120 	    font = gui.norm_font;
5121 	    name = hl_get_font_name();
5122 	}
5123 	else
5124 	{
5125 	    name = tv_get_string(&argvars[0]);
5126 	    if (STRCMP(name, "*") == 0)	    /* don't use font dialog */
5127 		return;
5128 	    font = gui_mch_get_font(name, FALSE);
5129 	    if (font == NOFONT)
5130 		return;	    /* Invalid font name, return empty string. */
5131 	}
5132 	rettv->vval.v_string = gui_mch_get_fontname(font, name);
5133 	if (argvars[0].v_type != VAR_UNKNOWN)
5134 	    gui_mch_free_font(font);
5135     }
5136 #endif
5137 }
5138 
5139 /*
5140  * "getfperm({fname})" function
5141  */
5142     static void
5143 f_getfperm(typval_T *argvars, typval_T *rettv)
5144 {
5145     char_u	*fname;
5146     stat_T	st;
5147     char_u	*perm = NULL;
5148     char_u	flags[] = "rwx";
5149     int		i;
5150 
5151     fname = tv_get_string(&argvars[0]);
5152 
5153     rettv->v_type = VAR_STRING;
5154     if (mch_stat((char *)fname, &st) >= 0)
5155     {
5156 	perm = vim_strsave((char_u *)"---------");
5157 	if (perm != NULL)
5158 	{
5159 	    for (i = 0; i < 9; i++)
5160 	    {
5161 		if (st.st_mode & (1 << (8 - i)))
5162 		    perm[i] = flags[i % 3];
5163 	    }
5164 	}
5165     }
5166     rettv->vval.v_string = perm;
5167 }
5168 
5169 /*
5170  * "getfsize({fname})" function
5171  */
5172     static void
5173 f_getfsize(typval_T *argvars, typval_T *rettv)
5174 {
5175     char_u	*fname;
5176     stat_T	st;
5177 
5178     fname = tv_get_string(&argvars[0]);
5179 
5180     rettv->v_type = VAR_NUMBER;
5181 
5182     if (mch_stat((char *)fname, &st) >= 0)
5183     {
5184 	if (mch_isdir(fname))
5185 	    rettv->vval.v_number = 0;
5186 	else
5187 	{
5188 	    rettv->vval.v_number = (varnumber_T)st.st_size;
5189 
5190 	    /* non-perfect check for overflow */
5191 	    if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5192 		rettv->vval.v_number = -2;
5193 	}
5194     }
5195     else
5196 	  rettv->vval.v_number = -1;
5197 }
5198 
5199 /*
5200  * "getftime({fname})" function
5201  */
5202     static void
5203 f_getftime(typval_T *argvars, typval_T *rettv)
5204 {
5205     char_u	*fname;
5206     stat_T	st;
5207 
5208     fname = tv_get_string(&argvars[0]);
5209 
5210     if (mch_stat((char *)fname, &st) >= 0)
5211 	rettv->vval.v_number = (varnumber_T)st.st_mtime;
5212     else
5213 	rettv->vval.v_number = -1;
5214 }
5215 
5216 /*
5217  * "getftype({fname})" function
5218  */
5219     static void
5220 f_getftype(typval_T *argvars, typval_T *rettv)
5221 {
5222     char_u	*fname;
5223     stat_T	st;
5224     char_u	*type = NULL;
5225     char	*t;
5226 
5227     fname = tv_get_string(&argvars[0]);
5228 
5229     rettv->v_type = VAR_STRING;
5230     if (mch_lstat((char *)fname, &st) >= 0)
5231     {
5232 	if (S_ISREG(st.st_mode))
5233 	    t = "file";
5234 	else if (S_ISDIR(st.st_mode))
5235 	    t = "dir";
5236 	else if (S_ISLNK(st.st_mode))
5237 	    t = "link";
5238 	else if (S_ISBLK(st.st_mode))
5239 	    t = "bdev";
5240 	else if (S_ISCHR(st.st_mode))
5241 	    t = "cdev";
5242 	else if (S_ISFIFO(st.st_mode))
5243 	    t = "fifo";
5244 	else if (S_ISSOCK(st.st_mode))
5245 	    t = "socket";
5246 	else
5247 	    t = "other";
5248 	type = vim_strsave((char_u *)t);
5249     }
5250     rettv->vval.v_string = type;
5251 }
5252 
5253 /*
5254  * "getjumplist()" function
5255  */
5256     static void
5257 f_getjumplist(typval_T *argvars, typval_T *rettv)
5258 {
5259 #ifdef FEAT_JUMPLIST
5260     win_T	*wp;
5261     int		i;
5262     list_T	*l;
5263     dict_T	*d;
5264 #endif
5265 
5266     if (rettv_list_alloc(rettv) != OK)
5267 	return;
5268 
5269 #ifdef FEAT_JUMPLIST
5270     wp = find_tabwin(&argvars[0], &argvars[1]);
5271     if (wp == NULL)
5272 	return;
5273 
5274     l = list_alloc();
5275     if (l == NULL)
5276 	return;
5277 
5278     if (list_append_list(rettv->vval.v_list, l) == FAIL)
5279 	return;
5280     list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5281 
5282     cleanup_jumplist(wp, TRUE);
5283 
5284     for (i = 0; i < wp->w_jumplistlen; ++i)
5285     {
5286 	if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5287 	    continue;
5288 	if ((d = dict_alloc()) == NULL)
5289 	    return;
5290 	if (list_append_dict(l, d) == FAIL)
5291 	    return;
5292 	dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5293 	dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
5294 	dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
5295 	dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
5296 	if (wp->w_jumplist[i].fname != NULL)
5297 	    dict_add_string(d, "filename", wp->w_jumplist[i].fname);
5298     }
5299 #endif
5300 }
5301 
5302 /*
5303  * "getline(lnum, [end])" function
5304  */
5305     static void
5306 f_getline(typval_T *argvars, typval_T *rettv)
5307 {
5308     linenr_T	lnum;
5309     linenr_T	end;
5310     int		retlist;
5311 
5312     lnum = tv_get_lnum(argvars);
5313     if (argvars[1].v_type == VAR_UNKNOWN)
5314     {
5315 	end = 0;
5316 	retlist = FALSE;
5317     }
5318     else
5319     {
5320 	end = tv_get_lnum(&argvars[1]);
5321 	retlist = TRUE;
5322     }
5323 
5324     get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5325 }
5326 
5327 #ifdef FEAT_QUICKFIX
5328     static void
5329 get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5330 {
5331     if (what_arg->v_type == VAR_UNKNOWN)
5332     {
5333 	if (rettv_list_alloc(rettv) == OK)
5334 	    if (is_qf || wp != NULL)
5335 		(void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
5336     }
5337     else
5338     {
5339 	if (rettv_dict_alloc(rettv) == OK)
5340 	    if (is_qf || (wp != NULL))
5341 	    {
5342 		if (what_arg->v_type == VAR_DICT)
5343 		{
5344 		    dict_T	*d = what_arg->vval.v_dict;
5345 
5346 		    if (d != NULL)
5347 			qf_get_properties(wp, d, rettv->vval.v_dict);
5348 		}
5349 		else
5350 		    emsg(_(e_dictreq));
5351 	    }
5352     }
5353 }
5354 #endif
5355 
5356 /*
5357  * "getloclist()" function
5358  */
5359     static void
5360 f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5361 {
5362 #ifdef FEAT_QUICKFIX
5363     win_T	*wp;
5364 
5365     wp = find_win_by_nr_or_id(&argvars[0]);
5366     get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5367 #endif
5368 }
5369 
5370 /*
5371  * "getmatches()" function
5372  */
5373     static void
5374 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5375 {
5376 #ifdef FEAT_SEARCH_EXTRA
5377     dict_T	*dict;
5378     matchitem_T	*cur = curwin->w_match_head;
5379     int		i;
5380 
5381     if (rettv_list_alloc(rettv) == OK)
5382     {
5383 	while (cur != NULL)
5384 	{
5385 	    dict = dict_alloc();
5386 	    if (dict == NULL)
5387 		return;
5388 	    if (cur->match.regprog == NULL)
5389 	    {
5390 		/* match added with matchaddpos() */
5391 		for (i = 0; i < MAXPOSMATCH; ++i)
5392 		{
5393 		    llpos_T	*llpos;
5394 		    char	buf[6];
5395 		    list_T	*l;
5396 
5397 		    llpos = &cur->pos.pos[i];
5398 		    if (llpos->lnum == 0)
5399 			break;
5400 		    l = list_alloc();
5401 		    if (l == NULL)
5402 			break;
5403 		    list_append_number(l, (varnumber_T)llpos->lnum);
5404 		    if (llpos->col > 0)
5405 		    {
5406 			list_append_number(l, (varnumber_T)llpos->col);
5407 			list_append_number(l, (varnumber_T)llpos->len);
5408 		    }
5409 		    sprintf(buf, "pos%d", i + 1);
5410 		    dict_add_list(dict, buf, l);
5411 		}
5412 	    }
5413 	    else
5414 	    {
5415 		dict_add_string(dict, "pattern", cur->pattern);
5416 	    }
5417 	    dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5418 	    dict_add_number(dict, "priority", (long)cur->priority);
5419 	    dict_add_number(dict, "id", (long)cur->id);
5420 # if defined(FEAT_CONCEAL)
5421 	    if (cur->conceal_char)
5422 	    {
5423 		char_u buf[MB_MAXBYTES + 1];
5424 
5425 		buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5426 		dict_add_string(dict, "conceal", (char_u *)&buf);
5427 	    }
5428 # endif
5429 	    list_append_dict(rettv->vval.v_list, dict);
5430 	    cur = cur->next;
5431 	}
5432     }
5433 #endif
5434 }
5435 
5436 /*
5437  * "getpid()" function
5438  */
5439     static void
5440 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5441 {
5442     rettv->vval.v_number = mch_get_pid();
5443 }
5444 
5445     static void
5446 getpos_both(
5447     typval_T	*argvars,
5448     typval_T	*rettv,
5449     int		getcurpos)
5450 {
5451     pos_T	*fp;
5452     list_T	*l;
5453     int		fnum = -1;
5454 
5455     if (rettv_list_alloc(rettv) == OK)
5456     {
5457 	l = rettv->vval.v_list;
5458 	if (getcurpos)
5459 	    fp = &curwin->w_cursor;
5460 	else
5461 	    fp = var2fpos(&argvars[0], TRUE, &fnum);
5462 	if (fnum != -1)
5463 	    list_append_number(l, (varnumber_T)fnum);
5464 	else
5465 	    list_append_number(l, (varnumber_T)0);
5466 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5467 							    : (varnumber_T)0);
5468 	list_append_number(l, (fp != NULL)
5469 		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5470 							    : (varnumber_T)0);
5471 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
5472 							      (varnumber_T)0);
5473 	if (getcurpos)
5474 	{
5475 	    update_curswant();
5476 	    list_append_number(l, curwin->w_curswant == MAXCOL ?
5477 		    (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
5478 	}
5479     }
5480     else
5481 	rettv->vval.v_number = FALSE;
5482 }
5483 
5484 /*
5485  * "getcurpos()" function
5486  */
5487     static void
5488 f_getcurpos(typval_T *argvars, typval_T *rettv)
5489 {
5490     getpos_both(argvars, rettv, TRUE);
5491 }
5492 
5493 /*
5494  * "getpos(string)" function
5495  */
5496     static void
5497 f_getpos(typval_T *argvars, typval_T *rettv)
5498 {
5499     getpos_both(argvars, rettv, FALSE);
5500 }
5501 
5502 /*
5503  * "getqflist()" function
5504  */
5505     static void
5506 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5507 {
5508 #ifdef FEAT_QUICKFIX
5509     get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
5510 #endif
5511 }
5512 
5513 /*
5514  * "getreg()" function
5515  */
5516     static void
5517 f_getreg(typval_T *argvars, typval_T *rettv)
5518 {
5519     char_u	*strregname;
5520     int		regname;
5521     int		arg2 = FALSE;
5522     int		return_list = FALSE;
5523     int		error = FALSE;
5524 
5525     if (argvars[0].v_type != VAR_UNKNOWN)
5526     {
5527 	strregname = tv_get_string_chk(&argvars[0]);
5528 	error = strregname == NULL;
5529 	if (argvars[1].v_type != VAR_UNKNOWN)
5530 	{
5531 	    arg2 = (int)tv_get_number_chk(&argvars[1], &error);
5532 	    if (!error && argvars[2].v_type != VAR_UNKNOWN)
5533 		return_list = (int)tv_get_number_chk(&argvars[2], &error);
5534 	}
5535     }
5536     else
5537 	strregname = get_vim_var_str(VV_REG);
5538 
5539     if (error)
5540 	return;
5541 
5542     regname = (strregname == NULL ? '"' : *strregname);
5543     if (regname == 0)
5544 	regname = '"';
5545 
5546     if (return_list)
5547     {
5548 	rettv->v_type = VAR_LIST;
5549 	rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5550 				      (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5551 	if (rettv->vval.v_list == NULL)
5552 	    (void)rettv_list_alloc(rettv);
5553 	else
5554 	    ++rettv->vval.v_list->lv_refcount;
5555     }
5556     else
5557     {
5558 	rettv->v_type = VAR_STRING;
5559 	rettv->vval.v_string = get_reg_contents(regname,
5560 						    arg2 ? GREG_EXPR_SRC : 0);
5561     }
5562 }
5563 
5564 /*
5565  * "getregtype()" function
5566  */
5567     static void
5568 f_getregtype(typval_T *argvars, typval_T *rettv)
5569 {
5570     char_u	*strregname;
5571     int		regname;
5572     char_u	buf[NUMBUFLEN + 2];
5573     long	reglen = 0;
5574 
5575     if (argvars[0].v_type != VAR_UNKNOWN)
5576     {
5577 	strregname = tv_get_string_chk(&argvars[0]);
5578 	if (strregname == NULL)	    /* type error; errmsg already given */
5579 	{
5580 	    rettv->v_type = VAR_STRING;
5581 	    rettv->vval.v_string = NULL;
5582 	    return;
5583 	}
5584     }
5585     else
5586 	/* Default to v:register */
5587 	strregname = get_vim_var_str(VV_REG);
5588 
5589     regname = (strregname == NULL ? '"' : *strregname);
5590     if (regname == 0)
5591 	regname = '"';
5592 
5593     buf[0] = NUL;
5594     buf[1] = NUL;
5595     switch (get_reg_type(regname, &reglen))
5596     {
5597 	case MLINE: buf[0] = 'V'; break;
5598 	case MCHAR: buf[0] = 'v'; break;
5599 	case MBLOCK:
5600 		buf[0] = Ctrl_V;
5601 		sprintf((char *)buf + 1, "%ld", reglen + 1);
5602 		break;
5603     }
5604     rettv->v_type = VAR_STRING;
5605     rettv->vval.v_string = vim_strsave(buf);
5606 }
5607 
5608 /*
5609  * Returns information (variables, options, etc.) about a tab page
5610  * as a dictionary.
5611  */
5612     static dict_T *
5613 get_tabpage_info(tabpage_T *tp, int tp_idx)
5614 {
5615     win_T	*wp;
5616     dict_T	*dict;
5617     list_T	*l;
5618 
5619     dict = dict_alloc();
5620     if (dict == NULL)
5621 	return NULL;
5622 
5623     dict_add_number(dict, "tabnr", tp_idx);
5624 
5625     l = list_alloc();
5626     if (l != NULL)
5627     {
5628 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5629 		wp; wp = wp->w_next)
5630 	    list_append_number(l, (varnumber_T)wp->w_id);
5631 	dict_add_list(dict, "windows", l);
5632     }
5633 
5634     /* Make a reference to tabpage variables */
5635     dict_add_dict(dict, "variables", tp->tp_vars);
5636 
5637     return dict;
5638 }
5639 
5640 /*
5641  * "gettabinfo()" function
5642  */
5643     static void
5644 f_gettabinfo(typval_T *argvars, typval_T *rettv)
5645 {
5646     tabpage_T	*tp, *tparg = NULL;
5647     dict_T	*d;
5648     int		tpnr = 0;
5649 
5650     if (rettv_list_alloc(rettv) != OK)
5651 	return;
5652 
5653     if (argvars[0].v_type != VAR_UNKNOWN)
5654     {
5655 	/* Information about one tab page */
5656 	tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
5657 	if (tparg == NULL)
5658 	    return;
5659     }
5660 
5661     /* Get information about a specific tab page or all tab pages */
5662     FOR_ALL_TABPAGES(tp)
5663     {
5664 	tpnr++;
5665 	if (tparg != NULL && tp != tparg)
5666 	    continue;
5667 	d = get_tabpage_info(tp, tpnr);
5668 	if (d != NULL)
5669 	    list_append_dict(rettv->vval.v_list, d);
5670 	if (tparg != NULL)
5671 	    return;
5672     }
5673 }
5674 
5675 /*
5676  * "gettabvar()" function
5677  */
5678     static void
5679 f_gettabvar(typval_T *argvars, typval_T *rettv)
5680 {
5681     win_T	*oldcurwin;
5682     tabpage_T	*tp, *oldtabpage;
5683     dictitem_T	*v;
5684     char_u	*varname;
5685     int		done = FALSE;
5686 
5687     rettv->v_type = VAR_STRING;
5688     rettv->vval.v_string = NULL;
5689 
5690     varname = tv_get_string_chk(&argvars[1]);
5691     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
5692     if (tp != NULL && varname != NULL)
5693     {
5694 	/* Set tp to be our tabpage, temporarily.  Also set the window to the
5695 	 * first window in the tabpage, otherwise the window is not valid. */
5696 	if (switch_win(&oldcurwin, &oldtabpage,
5697 		tp == curtab || tp->tp_firstwin == NULL ? firstwin
5698 					    : tp->tp_firstwin, tp, TRUE) == OK)
5699 	{
5700 	    /* look up the variable */
5701 	    /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5702 	    v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5703 	    if (v != NULL)
5704 	    {
5705 		copy_tv(&v->di_tv, rettv);
5706 		done = TRUE;
5707 	    }
5708 	}
5709 
5710 	/* restore previous notion of curwin */
5711 	restore_win(oldcurwin, oldtabpage, TRUE);
5712     }
5713 
5714     if (!done && argvars[2].v_type != VAR_UNKNOWN)
5715 	copy_tv(&argvars[2], rettv);
5716 }
5717 
5718 /*
5719  * "gettabwinvar()" function
5720  */
5721     static void
5722 f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5723 {
5724     getwinvar(argvars, rettv, 1);
5725 }
5726 
5727 /*
5728  * "gettagstack()" function
5729  */
5730     static void
5731 f_gettagstack(typval_T *argvars, typval_T *rettv)
5732 {
5733     win_T	*wp = curwin;			// default is current window
5734 
5735     if (rettv_dict_alloc(rettv) != OK)
5736 	return;
5737 
5738     if (argvars[0].v_type != VAR_UNKNOWN)
5739     {
5740 	wp = find_win_by_nr_or_id(&argvars[0]);
5741 	if (wp == NULL)
5742 	    return;
5743     }
5744 
5745     get_tagstack(wp, rettv->vval.v_dict);
5746 }
5747 
5748 /*
5749  * Returns information about a window as a dictionary.
5750  */
5751     static dict_T *
5752 get_win_info(win_T *wp, short tpnr, short winnr)
5753 {
5754     dict_T	*dict;
5755 
5756     dict = dict_alloc();
5757     if (dict == NULL)
5758 	return NULL;
5759 
5760     dict_add_number(dict, "tabnr", tpnr);
5761     dict_add_number(dict, "winnr", winnr);
5762     dict_add_number(dict, "winid", wp->w_id);
5763     dict_add_number(dict, "height", wp->w_height);
5764     dict_add_number(dict, "winrow", wp->w_winrow + 1);
5765 #ifdef FEAT_MENU
5766     dict_add_number(dict, "winbar", wp->w_winbar_height);
5767 #endif
5768     dict_add_number(dict, "width", wp->w_width);
5769     dict_add_number(dict, "wincol", wp->w_wincol + 1);
5770     dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
5771 
5772 #ifdef FEAT_TERMINAL
5773     dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
5774 #endif
5775 #ifdef FEAT_QUICKFIX
5776     dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5777     dict_add_number(dict, "loclist",
5778 		      (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
5779 #endif
5780 
5781     /* Add a reference to window variables */
5782     dict_add_dict(dict, "variables", wp->w_vars);
5783 
5784     return dict;
5785 }
5786 
5787 /*
5788  * "getwininfo()" function
5789  */
5790     static void
5791 f_getwininfo(typval_T *argvars, typval_T *rettv)
5792 {
5793     tabpage_T	*tp;
5794     win_T	*wp = NULL, *wparg = NULL;
5795     dict_T	*d;
5796     short	tabnr = 0, winnr;
5797 
5798     if (rettv_list_alloc(rettv) != OK)
5799 	return;
5800 
5801     if (argvars[0].v_type != VAR_UNKNOWN)
5802     {
5803 	wparg = win_id2wp(argvars);
5804 	if (wparg == NULL)
5805 	    return;
5806     }
5807 
5808     /* Collect information about either all the windows across all the tab
5809      * pages or one particular window.
5810      */
5811     FOR_ALL_TABPAGES(tp)
5812     {
5813 	tabnr++;
5814 	winnr = 0;
5815 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
5816 	{
5817 	    winnr++;
5818 	    if (wparg != NULL && wp != wparg)
5819 		continue;
5820 	    d = get_win_info(wp, tabnr, winnr);
5821 	    if (d != NULL)
5822 		list_append_dict(rettv->vval.v_list, d);
5823 	    if (wparg != NULL)
5824 		/* found information about a specific window */
5825 		return;
5826 	}
5827     }
5828 }
5829 
5830 /*
5831  * "win_findbuf()" function
5832  */
5833     static void
5834 f_win_findbuf(typval_T *argvars, typval_T *rettv)
5835 {
5836     if (rettv_list_alloc(rettv) != FAIL)
5837 	win_findbuf(argvars, rettv->vval.v_list);
5838 }
5839 
5840 /*
5841  * "win_getid()" function
5842  */
5843     static void
5844 f_win_getid(typval_T *argvars, typval_T *rettv)
5845 {
5846     rettv->vval.v_number = win_getid(argvars);
5847 }
5848 
5849 /*
5850  * "win_gotoid()" function
5851  */
5852     static void
5853 f_win_gotoid(typval_T *argvars, typval_T *rettv)
5854 {
5855     rettv->vval.v_number = win_gotoid(argvars);
5856 }
5857 
5858 /*
5859  * "win_id2tabwin()" function
5860  */
5861     static void
5862 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5863 {
5864     if (rettv_list_alloc(rettv) != FAIL)
5865 	win_id2tabwin(argvars, rettv->vval.v_list);
5866 }
5867 
5868 /*
5869  * "win_id2win()" function
5870  */
5871     static void
5872 f_win_id2win(typval_T *argvars, typval_T *rettv)
5873 {
5874     rettv->vval.v_number = win_id2win(argvars);
5875 }
5876 
5877 /*
5878  * "win_screenpos()" function
5879  */
5880     static void
5881 f_win_screenpos(typval_T *argvars, typval_T *rettv)
5882 {
5883     win_T	*wp;
5884 
5885     if (rettv_list_alloc(rettv) == FAIL)
5886 	return;
5887 
5888     wp = find_win_by_nr_or_id(&argvars[0]);
5889     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5890     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5891 }
5892 
5893 /*
5894  * "getwinpos({timeout})" function
5895  */
5896     static void
5897 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5898 {
5899     int x = -1;
5900     int y = -1;
5901 
5902     if (rettv_list_alloc(rettv) == FAIL)
5903 	return;
5904 #ifdef FEAT_GUI
5905     if (gui.in_use)
5906 	(void)gui_mch_get_winpos(&x, &y);
5907 # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5908     else
5909 # endif
5910 #endif
5911 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5912     {
5913 	varnumber_T timeout = 100;
5914 
5915 	if (argvars[0].v_type != VAR_UNKNOWN)
5916 	    timeout = tv_get_number(&argvars[0]);
5917 	term_get_winpos(&x, &y, timeout);
5918     }
5919 #endif
5920     list_append_number(rettv->vval.v_list, (varnumber_T)x);
5921     list_append_number(rettv->vval.v_list, (varnumber_T)y);
5922 }
5923 
5924 
5925 /*
5926  * "getwinposx()" function
5927  */
5928     static void
5929 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5930 {
5931     rettv->vval.v_number = -1;
5932 #ifdef FEAT_GUI
5933     if (gui.in_use)
5934     {
5935 	int	    x, y;
5936 
5937 	if (gui_mch_get_winpos(&x, &y) == OK)
5938 	    rettv->vval.v_number = x;
5939 	return;
5940     }
5941 #endif
5942 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5943     {
5944 	int	    x, y;
5945 
5946 	if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
5947 	    rettv->vval.v_number = x;
5948     }
5949 #endif
5950 }
5951 
5952 /*
5953  * "getwinposy()" function
5954  */
5955     static void
5956 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5957 {
5958     rettv->vval.v_number = -1;
5959 #ifdef FEAT_GUI
5960     if (gui.in_use)
5961     {
5962 	int	    x, y;
5963 
5964 	if (gui_mch_get_winpos(&x, &y) == OK)
5965 	    rettv->vval.v_number = y;
5966 	return;
5967     }
5968 #endif
5969 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5970     {
5971 	int	    x, y;
5972 
5973 	if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
5974 	    rettv->vval.v_number = y;
5975     }
5976 #endif
5977 }
5978 
5979 /*
5980  * "getwinvar()" function
5981  */
5982     static void
5983 f_getwinvar(typval_T *argvars, typval_T *rettv)
5984 {
5985     getwinvar(argvars, rettv, 0);
5986 }
5987 
5988 /*
5989  * "glob()" function
5990  */
5991     static void
5992 f_glob(typval_T *argvars, typval_T *rettv)
5993 {
5994     int		options = WILD_SILENT|WILD_USE_NL;
5995     expand_T	xpc;
5996     int		error = FALSE;
5997 
5998     /* When the optional second argument is non-zero, don't remove matches
5999      * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6000     rettv->v_type = VAR_STRING;
6001     if (argvars[1].v_type != VAR_UNKNOWN)
6002     {
6003 	if (tv_get_number_chk(&argvars[1], &error))
6004 	    options |= WILD_KEEP_ALL;
6005 	if (argvars[2].v_type != VAR_UNKNOWN)
6006 	{
6007 	    if (tv_get_number_chk(&argvars[2], &error))
6008 	    {
6009 		rettv_list_set(rettv, NULL);
6010 	    }
6011 	    if (argvars[3].v_type != VAR_UNKNOWN
6012 				    && tv_get_number_chk(&argvars[3], &error))
6013 		options |= WILD_ALLLINKS;
6014 	}
6015     }
6016     if (!error)
6017     {
6018 	ExpandInit(&xpc);
6019 	xpc.xp_context = EXPAND_FILES;
6020 	if (p_wic)
6021 	    options += WILD_ICASE;
6022 	if (rettv->v_type == VAR_STRING)
6023 	    rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
6024 						     NULL, options, WILD_ALL);
6025 	else if (rettv_list_alloc(rettv) != FAIL)
6026 	{
6027 	  int i;
6028 
6029 	  ExpandOne(&xpc, tv_get_string(&argvars[0]),
6030 						NULL, options, WILD_ALL_KEEP);
6031 	  for (i = 0; i < xpc.xp_numfiles; i++)
6032 	      list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6033 
6034 	  ExpandCleanup(&xpc);
6035 	}
6036     }
6037     else
6038 	rettv->vval.v_string = NULL;
6039 }
6040 
6041 /*
6042  * "globpath()" function
6043  */
6044     static void
6045 f_globpath(typval_T *argvars, typval_T *rettv)
6046 {
6047     int		flags = 0;
6048     char_u	buf1[NUMBUFLEN];
6049     char_u	*file = tv_get_string_buf_chk(&argvars[1], buf1);
6050     int		error = FALSE;
6051     garray_T	ga;
6052     int		i;
6053 
6054     /* When the optional second argument is non-zero, don't remove matches
6055     * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6056     rettv->v_type = VAR_STRING;
6057     if (argvars[2].v_type != VAR_UNKNOWN)
6058     {
6059 	if (tv_get_number_chk(&argvars[2], &error))
6060 	    flags |= WILD_KEEP_ALL;
6061 	if (argvars[3].v_type != VAR_UNKNOWN)
6062 	{
6063 	    if (tv_get_number_chk(&argvars[3], &error))
6064 	    {
6065 		rettv_list_set(rettv, NULL);
6066 	    }
6067 	    if (argvars[4].v_type != VAR_UNKNOWN
6068 				    && tv_get_number_chk(&argvars[4], &error))
6069 		flags |= WILD_ALLLINKS;
6070 	}
6071     }
6072     if (file != NULL && !error)
6073     {
6074 	ga_init2(&ga, (int)sizeof(char_u *), 10);
6075 	globpath(tv_get_string(&argvars[0]), file, &ga, flags);
6076 	if (rettv->v_type == VAR_STRING)
6077 	    rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6078 	else if (rettv_list_alloc(rettv) != FAIL)
6079 	    for (i = 0; i < ga.ga_len; ++i)
6080 		list_append_string(rettv->vval.v_list,
6081 					    ((char_u **)(ga.ga_data))[i], -1);
6082 	ga_clear_strings(&ga);
6083     }
6084     else
6085 	rettv->vval.v_string = NULL;
6086 }
6087 
6088 /*
6089  * "glob2regpat()" function
6090  */
6091     static void
6092 f_glob2regpat(typval_T *argvars, typval_T *rettv)
6093 {
6094     char_u	*pat = tv_get_string_chk(&argvars[0]);
6095 
6096     rettv->v_type = VAR_STRING;
6097     rettv->vval.v_string = (pat == NULL)
6098 			 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6099 }
6100 
6101 /* for VIM_VERSION_ defines */
6102 #include "version.h"
6103 
6104 /*
6105  * "has()" function
6106  */
6107     static void
6108 f_has(typval_T *argvars, typval_T *rettv)
6109 {
6110     int		i;
6111     char_u	*name;
6112     int		n = FALSE;
6113     static char	*(has_list[]) =
6114     {
6115 #ifdef AMIGA
6116 	"amiga",
6117 # ifdef FEAT_ARP
6118 	"arp",
6119 # endif
6120 #endif
6121 #ifdef __BEOS__
6122 	"beos",
6123 #endif
6124 #if defined(BSD) && !defined(MACOS_X)
6125 	"bsd",
6126 #endif
6127 #ifdef hpux
6128 	"hpux",
6129 #endif
6130 #ifdef __linux__
6131 	"linux",
6132 #endif
6133 #ifdef MACOS_X
6134 	"mac",		/* Mac OS X (and, once, Mac OS Classic) */
6135 	"osx",		/* Mac OS X */
6136 # ifdef MACOS_X_DARWIN
6137 	"macunix",	/* Mac OS X, with the darwin feature */
6138 	"osxdarwin",	/* synonym for macunix */
6139 # endif
6140 #endif
6141 #ifdef __QNX__
6142 	"qnx",
6143 #endif
6144 #ifdef SUN_SYSTEM
6145 	"sun",
6146 #else
6147 	"moon",
6148 #endif
6149 #ifdef UNIX
6150 	"unix",
6151 #endif
6152 #ifdef VMS
6153 	"vms",
6154 #endif
6155 #ifdef WIN32
6156 	"win32",
6157 #endif
6158 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
6159 	"win32unix",
6160 #endif
6161 #if defined(WIN64) || defined(_WIN64)
6162 	"win64",
6163 #endif
6164 #ifdef EBCDIC
6165 	"ebcdic",
6166 #endif
6167 #ifndef CASE_INSENSITIVE_FILENAME
6168 	"fname_case",
6169 #endif
6170 #ifdef HAVE_ACL
6171 	"acl",
6172 #endif
6173 #ifdef FEAT_ARABIC
6174 	"arabic",
6175 #endif
6176 	"autocmd",
6177 #ifdef FEAT_AUTOCHDIR
6178 	"autochdir",
6179 #endif
6180 #ifdef FEAT_AUTOSERVERNAME
6181 	"autoservername",
6182 #endif
6183 #ifdef FEAT_BEVAL_GUI
6184 	"balloon_eval",
6185 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
6186 	"balloon_multiline",
6187 # endif
6188 #endif
6189 #ifdef FEAT_BEVAL_TERM
6190 	"balloon_eval_term",
6191 #endif
6192 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6193 	"builtin_terms",
6194 # ifdef ALL_BUILTIN_TCAPS
6195 	"all_builtin_terms",
6196 # endif
6197 #endif
6198 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
6199 	|| defined(FEAT_GUI_W32) \
6200 	|| defined(FEAT_GUI_MOTIF))
6201 	"browsefilter",
6202 #endif
6203 #ifdef FEAT_BYTEOFF
6204 	"byte_offset",
6205 #endif
6206 #ifdef FEAT_JOB_CHANNEL
6207 	"channel",
6208 #endif
6209 #ifdef FEAT_CINDENT
6210 	"cindent",
6211 #endif
6212 #ifdef FEAT_CLIENTSERVER
6213 	"clientserver",
6214 #endif
6215 #ifdef FEAT_CLIPBOARD
6216 	"clipboard",
6217 #endif
6218 #ifdef FEAT_CMDL_COMPL
6219 	"cmdline_compl",
6220 #endif
6221 #ifdef FEAT_CMDHIST
6222 	"cmdline_hist",
6223 #endif
6224 #ifdef FEAT_COMMENTS
6225 	"comments",
6226 #endif
6227 #ifdef FEAT_CONCEAL
6228 	"conceal",
6229 #endif
6230 #ifdef FEAT_CRYPT
6231 	"cryptv",
6232 	"crypt-blowfish",
6233 	"crypt-blowfish2",
6234 #endif
6235 #ifdef FEAT_CSCOPE
6236 	"cscope",
6237 #endif
6238 	"cursorbind",
6239 #ifdef CURSOR_SHAPE
6240 	"cursorshape",
6241 #endif
6242 #ifdef DEBUG
6243 	"debug",
6244 #endif
6245 #ifdef FEAT_CON_DIALOG
6246 	"dialog_con",
6247 #endif
6248 #ifdef FEAT_GUI_DIALOG
6249 	"dialog_gui",
6250 #endif
6251 #ifdef FEAT_DIFF
6252 	"diff",
6253 #endif
6254 #ifdef FEAT_DIGRAPHS
6255 	"digraphs",
6256 #endif
6257 #ifdef FEAT_DIRECTX
6258 	"directx",
6259 #endif
6260 #ifdef FEAT_DND
6261 	"dnd",
6262 #endif
6263 #ifdef FEAT_EMACS_TAGS
6264 	"emacs_tags",
6265 #endif
6266 	"eval",	    /* always present, of course! */
6267 	"ex_extra", /* graduated feature */
6268 #ifdef FEAT_SEARCH_EXTRA
6269 	"extra_search",
6270 #endif
6271 #ifdef FEAT_FKMAP
6272 	"farsi",
6273 #endif
6274 #ifdef FEAT_SEARCHPATH
6275 	"file_in_path",
6276 #endif
6277 #ifdef FEAT_FILTERPIPE
6278 	"filterpipe",
6279 #endif
6280 #ifdef FEAT_FIND_ID
6281 	"find_in_path",
6282 #endif
6283 #ifdef FEAT_FLOAT
6284 	"float",
6285 #endif
6286 #ifdef FEAT_FOLDING
6287 	"folding",
6288 #endif
6289 #ifdef FEAT_FOOTER
6290 	"footer",
6291 #endif
6292 #if !defined(USE_SYSTEM) && defined(UNIX)
6293 	"fork",
6294 #endif
6295 #ifdef FEAT_GETTEXT
6296 	"gettext",
6297 #endif
6298 #ifdef FEAT_GUI
6299 	"gui",
6300 #endif
6301 #ifdef FEAT_GUI_ATHENA
6302 # ifdef FEAT_GUI_NEXTAW
6303 	"gui_neXtaw",
6304 # else
6305 	"gui_athena",
6306 # endif
6307 #endif
6308 #ifdef FEAT_GUI_GTK
6309 	"gui_gtk",
6310 # ifdef USE_GTK3
6311 	"gui_gtk3",
6312 # else
6313 	"gui_gtk2",
6314 # endif
6315 #endif
6316 #ifdef FEAT_GUI_GNOME
6317 	"gui_gnome",
6318 #endif
6319 #ifdef FEAT_GUI_MAC
6320 	"gui_mac",
6321 #endif
6322 #ifdef FEAT_GUI_MOTIF
6323 	"gui_motif",
6324 #endif
6325 #ifdef FEAT_GUI_PHOTON
6326 	"gui_photon",
6327 #endif
6328 #ifdef FEAT_GUI_W32
6329 	"gui_win32",
6330 #endif
6331 #ifdef FEAT_HANGULIN
6332 	"hangul_input",
6333 #endif
6334 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6335 	"iconv",
6336 #endif
6337 #ifdef FEAT_INS_EXPAND
6338 	"insert_expand",
6339 #endif
6340 #ifdef FEAT_JOB_CHANNEL
6341 	"job",
6342 #endif
6343 #ifdef FEAT_JUMPLIST
6344 	"jumplist",
6345 #endif
6346 #ifdef FEAT_KEYMAP
6347 	"keymap",
6348 #endif
6349 	"lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
6350 #ifdef FEAT_LANGMAP
6351 	"langmap",
6352 #endif
6353 #ifdef FEAT_LIBCALL
6354 	"libcall",
6355 #endif
6356 #ifdef FEAT_LINEBREAK
6357 	"linebreak",
6358 #endif
6359 #ifdef FEAT_LISP
6360 	"lispindent",
6361 #endif
6362 	"listcmds",
6363 #ifdef FEAT_LOCALMAP
6364 	"localmap",
6365 #endif
6366 #ifdef FEAT_LUA
6367 # ifndef DYNAMIC_LUA
6368 	"lua",
6369 # endif
6370 #endif
6371 #ifdef FEAT_MENU
6372 	"menu",
6373 #endif
6374 #ifdef FEAT_SESSION
6375 	"mksession",
6376 #endif
6377 #ifdef FEAT_MODIFY_FNAME
6378 	"modify_fname",
6379 #endif
6380 #ifdef FEAT_MOUSE
6381 	"mouse",
6382 #endif
6383 #ifdef FEAT_MOUSESHAPE
6384 	"mouseshape",
6385 #endif
6386 #if defined(UNIX) || defined(VMS)
6387 # ifdef FEAT_MOUSE_DEC
6388 	"mouse_dec",
6389 # endif
6390 # ifdef FEAT_MOUSE_GPM
6391 	"mouse_gpm",
6392 # endif
6393 # ifdef FEAT_MOUSE_JSB
6394 	"mouse_jsbterm",
6395 # endif
6396 # ifdef FEAT_MOUSE_NET
6397 	"mouse_netterm",
6398 # endif
6399 # ifdef FEAT_MOUSE_PTERM
6400 	"mouse_pterm",
6401 # endif
6402 # ifdef FEAT_MOUSE_SGR
6403 	"mouse_sgr",
6404 # endif
6405 # ifdef FEAT_SYSMOUSE
6406 	"mouse_sysmouse",
6407 # endif
6408 # ifdef FEAT_MOUSE_URXVT
6409 	"mouse_urxvt",
6410 # endif
6411 # ifdef FEAT_MOUSE_XTERM
6412 	"mouse_xterm",
6413 # endif
6414 #endif
6415 	"multi_byte",
6416 #ifdef FEAT_MBYTE_IME
6417 	"multi_byte_ime",
6418 #endif
6419 #ifdef FEAT_MULTI_LANG
6420 	"multi_lang",
6421 #endif
6422 #ifdef FEAT_MZSCHEME
6423 #ifndef DYNAMIC_MZSCHEME
6424 	"mzscheme",
6425 #endif
6426 #endif
6427 #ifdef FEAT_NUM64
6428 	"num64",
6429 #endif
6430 #ifdef FEAT_OLE
6431 	"ole",
6432 #endif
6433 #ifdef FEAT_EVAL
6434 	"packages",
6435 #endif
6436 #ifdef FEAT_PATH_EXTRA
6437 	"path_extra",
6438 #endif
6439 #ifdef FEAT_PERL
6440 #ifndef DYNAMIC_PERL
6441 	"perl",
6442 #endif
6443 #endif
6444 #ifdef FEAT_PERSISTENT_UNDO
6445 	"persistent_undo",
6446 #endif
6447 #if defined(FEAT_PYTHON)
6448 	"python_compiled",
6449 # if defined(DYNAMIC_PYTHON)
6450 	"python_dynamic",
6451 # else
6452 	"python",
6453 	"pythonx",
6454 # endif
6455 #endif
6456 #if defined(FEAT_PYTHON3)
6457 	"python3_compiled",
6458 # if defined(DYNAMIC_PYTHON3)
6459 	"python3_dynamic",
6460 # else
6461 	"python3",
6462 	"pythonx",
6463 # endif
6464 #endif
6465 #ifdef FEAT_POSTSCRIPT
6466 	"postscript",
6467 #endif
6468 #ifdef FEAT_PRINTER
6469 	"printer",
6470 #endif
6471 #ifdef FEAT_PROFILE
6472 	"profile",
6473 #endif
6474 #ifdef FEAT_RELTIME
6475 	"reltime",
6476 #endif
6477 #ifdef FEAT_QUICKFIX
6478 	"quickfix",
6479 #endif
6480 #ifdef FEAT_RIGHTLEFT
6481 	"rightleft",
6482 #endif
6483 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6484 	"ruby",
6485 #endif
6486 	"scrollbind",
6487 #ifdef FEAT_CMDL_INFO
6488 	"showcmd",
6489 	"cmdline_info",
6490 #endif
6491 #ifdef FEAT_SIGNS
6492 	"signs",
6493 #endif
6494 #ifdef FEAT_SMARTINDENT
6495 	"smartindent",
6496 #endif
6497 #ifdef STARTUPTIME
6498 	"startuptime",
6499 #endif
6500 #ifdef FEAT_STL_OPT
6501 	"statusline",
6502 #endif
6503 #ifdef FEAT_NETBEANS_INTG
6504 	"netbeans_intg",
6505 #endif
6506 #ifdef FEAT_SPELL
6507 	"spell",
6508 #endif
6509 #ifdef FEAT_SYN_HL
6510 	"syntax",
6511 #endif
6512 #if defined(USE_SYSTEM) || !defined(UNIX)
6513 	"system",
6514 #endif
6515 #ifdef FEAT_TAG_BINS
6516 	"tag_binary",
6517 #endif
6518 #ifdef FEAT_TAG_OLDSTATIC
6519 	"tag_old_static",
6520 #endif
6521 #ifdef FEAT_TAG_ANYWHITE
6522 	"tag_any_white",
6523 #endif
6524 #ifdef FEAT_TCL
6525 # ifndef DYNAMIC_TCL
6526 	"tcl",
6527 # endif
6528 #endif
6529 #ifdef FEAT_TERMGUICOLORS
6530 	"termguicolors",
6531 #endif
6532 #if defined(FEAT_TERMINAL) && !defined(WIN3264)
6533 	"terminal",
6534 #endif
6535 #ifdef TERMINFO
6536 	"terminfo",
6537 #endif
6538 #ifdef FEAT_TERMRESPONSE
6539 	"termresponse",
6540 #endif
6541 #ifdef FEAT_TEXTOBJ
6542 	"textobjects",
6543 #endif
6544 #ifdef FEAT_TEXT_PROP
6545 	"textprop",
6546 #endif
6547 #ifdef HAVE_TGETENT
6548 	"tgetent",
6549 #endif
6550 #ifdef FEAT_TIMERS
6551 	"timers",
6552 #endif
6553 #ifdef FEAT_TITLE
6554 	"title",
6555 #endif
6556 #ifdef FEAT_TOOLBAR
6557 	"toolbar",
6558 #endif
6559 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6560 	"unnamedplus",
6561 #endif
6562 #ifdef FEAT_USR_CMDS
6563 	"user-commands",    /* was accidentally included in 5.4 */
6564 	"user_commands",
6565 #endif
6566 #ifdef FEAT_VARTABS
6567 	"vartabs",
6568 #endif
6569 #ifdef FEAT_VIMINFO
6570 	"viminfo",
6571 #endif
6572 	"vertsplit",
6573 	"virtualedit",
6574 	"visual",
6575 	"visualextra",
6576 	"vreplace",
6577 #ifdef FEAT_VTP
6578 	"vtp",
6579 #endif
6580 #ifdef FEAT_WILDIGN
6581 	"wildignore",
6582 #endif
6583 #ifdef FEAT_WILDMENU
6584 	"wildmenu",
6585 #endif
6586 	"windows",
6587 #ifdef FEAT_WAK
6588 	"winaltkeys",
6589 #endif
6590 #ifdef FEAT_WRITEBACKUP
6591 	"writebackup",
6592 #endif
6593 #ifdef FEAT_XIM
6594 	"xim",
6595 #endif
6596 #ifdef FEAT_XFONTSET
6597 	"xfontset",
6598 #endif
6599 #ifdef FEAT_XPM_W32
6600 	"xpm",
6601 	"xpm_w32",	/* for backward compatibility */
6602 #else
6603 # if defined(HAVE_XPM)
6604 	"xpm",
6605 # endif
6606 #endif
6607 #ifdef USE_XSMP
6608 	"xsmp",
6609 #endif
6610 #ifdef USE_XSMP_INTERACT
6611 	"xsmp_interact",
6612 #endif
6613 #ifdef FEAT_XCLIPBOARD
6614 	"xterm_clipboard",
6615 #endif
6616 #ifdef FEAT_XTERM_SAVE
6617 	"xterm_save",
6618 #endif
6619 #if defined(UNIX) && defined(FEAT_X11)
6620 	"X11",
6621 #endif
6622 	NULL
6623     };
6624 
6625     name = tv_get_string(&argvars[0]);
6626     for (i = 0; has_list[i] != NULL; ++i)
6627 	if (STRICMP(name, has_list[i]) == 0)
6628 	{
6629 	    n = TRUE;
6630 	    break;
6631 	}
6632 
6633     if (n == FALSE)
6634     {
6635 	if (STRNICMP(name, "patch", 5) == 0)
6636 	{
6637 	    if (name[5] == '-'
6638 		    && STRLEN(name) >= 11
6639 		    && vim_isdigit(name[6])
6640 		    && vim_isdigit(name[8])
6641 		    && vim_isdigit(name[10]))
6642 	    {
6643 		int major = atoi((char *)name + 6);
6644 		int minor = atoi((char *)name + 8);
6645 
6646 		/* Expect "patch-9.9.01234". */
6647 		n = (major < VIM_VERSION_MAJOR
6648 		     || (major == VIM_VERSION_MAJOR
6649 			 && (minor < VIM_VERSION_MINOR
6650 			     || (minor == VIM_VERSION_MINOR
6651 				 && has_patch(atoi((char *)name + 10))))));
6652 	    }
6653 	    else
6654 		n = has_patch(atoi((char *)name + 5));
6655 	}
6656 	else if (STRICMP(name, "vim_starting") == 0)
6657 	    n = (starting != 0);
6658 	else if (STRICMP(name, "ttyin") == 0)
6659 	    n = mch_input_isatty();
6660 	else if (STRICMP(name, "ttyout") == 0)
6661 	    n = stdout_isatty;
6662 	else if (STRICMP(name, "multi_byte_encoding") == 0)
6663 	    n = has_mbyte;
6664 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6665 	else if (STRICMP(name, "balloon_multiline") == 0)
6666 	    n = multiline_balloon_available();
6667 #endif
6668 #ifdef DYNAMIC_TCL
6669 	else if (STRICMP(name, "tcl") == 0)
6670 	    n = tcl_enabled(FALSE);
6671 #endif
6672 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6673 	else if (STRICMP(name, "iconv") == 0)
6674 	    n = iconv_enabled(FALSE);
6675 #endif
6676 #ifdef DYNAMIC_LUA
6677 	else if (STRICMP(name, "lua") == 0)
6678 	    n = lua_enabled(FALSE);
6679 #endif
6680 #ifdef DYNAMIC_MZSCHEME
6681 	else if (STRICMP(name, "mzscheme") == 0)
6682 	    n = mzscheme_enabled(FALSE);
6683 #endif
6684 #ifdef DYNAMIC_RUBY
6685 	else if (STRICMP(name, "ruby") == 0)
6686 	    n = ruby_enabled(FALSE);
6687 #endif
6688 #ifdef DYNAMIC_PYTHON
6689 	else if (STRICMP(name, "python") == 0)
6690 	    n = python_enabled(FALSE);
6691 #endif
6692 #ifdef DYNAMIC_PYTHON3
6693 	else if (STRICMP(name, "python3") == 0)
6694 	    n = python3_enabled(FALSE);
6695 #endif
6696 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6697 	else if (STRICMP(name, "pythonx") == 0)
6698 	{
6699 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6700 	    if (p_pyx == 0)
6701 		n = python3_enabled(FALSE) || python_enabled(FALSE);
6702 	    else if (p_pyx == 3)
6703 		n = python3_enabled(FALSE);
6704 	    else if (p_pyx == 2)
6705 		n = python_enabled(FALSE);
6706 # elif defined(DYNAMIC_PYTHON)
6707 	    n = python_enabled(FALSE);
6708 # elif defined(DYNAMIC_PYTHON3)
6709 	    n = python3_enabled(FALSE);
6710 # endif
6711 	}
6712 #endif
6713 #ifdef DYNAMIC_PERL
6714 	else if (STRICMP(name, "perl") == 0)
6715 	    n = perl_enabled(FALSE);
6716 #endif
6717 #ifdef FEAT_GUI
6718 	else if (STRICMP(name, "gui_running") == 0)
6719 	    n = (gui.in_use || gui.starting);
6720 # ifdef FEAT_BROWSE
6721 	else if (STRICMP(name, "browse") == 0)
6722 	    n = gui.in_use;	/* gui_mch_browse() works when GUI is running */
6723 # endif
6724 #endif
6725 #ifdef FEAT_SYN_HL
6726 	else if (STRICMP(name, "syntax_items") == 0)
6727 	    n = syntax_present(curwin);
6728 #endif
6729 #ifdef FEAT_VTP
6730 	else if (STRICMP(name, "vcon") == 0)
6731 	    n = is_term_win32() && has_vtp_working();
6732 #endif
6733 #ifdef FEAT_NETBEANS_INTG
6734 	else if (STRICMP(name, "netbeans_enabled") == 0)
6735 	    n = netbeans_active();
6736 #endif
6737 #if defined(FEAT_TERMINAL) && defined(WIN3264)
6738 	else if (STRICMP(name, "terminal") == 0)
6739 	    n = terminal_enabled();
6740 #endif
6741 #if defined(FEAT_TERMINAL) && defined(WIN3264)
6742 	else if (STRICMP(name, "conpty") == 0)
6743 	    n = use_conpty();
6744 #endif
6745     }
6746 
6747     rettv->vval.v_number = n;
6748 }
6749 
6750 /*
6751  * "has_key()" function
6752  */
6753     static void
6754 f_has_key(typval_T *argvars, typval_T *rettv)
6755 {
6756     if (argvars[0].v_type != VAR_DICT)
6757     {
6758 	emsg(_(e_dictreq));
6759 	return;
6760     }
6761     if (argvars[0].vval.v_dict == NULL)
6762 	return;
6763 
6764     rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6765 				      tv_get_string(&argvars[1]), -1) != NULL;
6766 }
6767 
6768 /*
6769  * "haslocaldir()" function
6770  */
6771     static void
6772 f_haslocaldir(typval_T *argvars, typval_T *rettv)
6773 {
6774     win_T	*wp = NULL;
6775 
6776     wp = find_tabwin(&argvars[0], &argvars[1]);
6777     rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6778 }
6779 
6780 /*
6781  * "hasmapto()" function
6782  */
6783     static void
6784 f_hasmapto(typval_T *argvars, typval_T *rettv)
6785 {
6786     char_u	*name;
6787     char_u	*mode;
6788     char_u	buf[NUMBUFLEN];
6789     int		abbr = FALSE;
6790 
6791     name = tv_get_string(&argvars[0]);
6792     if (argvars[1].v_type == VAR_UNKNOWN)
6793 	mode = (char_u *)"nvo";
6794     else
6795     {
6796 	mode = tv_get_string_buf(&argvars[1], buf);
6797 	if (argvars[2].v_type != VAR_UNKNOWN)
6798 	    abbr = (int)tv_get_number(&argvars[2]);
6799     }
6800 
6801     if (map_to_exists(name, mode, abbr))
6802 	rettv->vval.v_number = TRUE;
6803     else
6804 	rettv->vval.v_number = FALSE;
6805 }
6806 
6807 /*
6808  * "histadd()" function
6809  */
6810     static void
6811 f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6812 {
6813 #ifdef FEAT_CMDHIST
6814     int		histype;
6815     char_u	*str;
6816     char_u	buf[NUMBUFLEN];
6817 #endif
6818 
6819     rettv->vval.v_number = FALSE;
6820     if (check_restricted() || check_secure())
6821 	return;
6822 #ifdef FEAT_CMDHIST
6823     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6824     histype = str != NULL ? get_histtype(str) : -1;
6825     if (histype >= 0)
6826     {
6827 	str = tv_get_string_buf(&argvars[1], buf);
6828 	if (*str != NUL)
6829 	{
6830 	    init_history();
6831 	    add_to_history(histype, str, FALSE, NUL);
6832 	    rettv->vval.v_number = TRUE;
6833 	    return;
6834 	}
6835     }
6836 #endif
6837 }
6838 
6839 /*
6840  * "histdel()" function
6841  */
6842     static void
6843 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6844 {
6845 #ifdef FEAT_CMDHIST
6846     int		n;
6847     char_u	buf[NUMBUFLEN];
6848     char_u	*str;
6849 
6850     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6851     if (str == NULL)
6852 	n = 0;
6853     else if (argvars[1].v_type == VAR_UNKNOWN)
6854 	/* only one argument: clear entire history */
6855 	n = clr_history(get_histtype(str));
6856     else if (argvars[1].v_type == VAR_NUMBER)
6857 	/* index given: remove that entry */
6858 	n = del_history_idx(get_histtype(str),
6859 					  (int)tv_get_number(&argvars[1]));
6860     else
6861 	/* string given: remove all matching entries */
6862 	n = del_history_entry(get_histtype(str),
6863 				      tv_get_string_buf(&argvars[1], buf));
6864     rettv->vval.v_number = n;
6865 #endif
6866 }
6867 
6868 /*
6869  * "histget()" function
6870  */
6871     static void
6872 f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6873 {
6874 #ifdef FEAT_CMDHIST
6875     int		type;
6876     int		idx;
6877     char_u	*str;
6878 
6879     str = tv_get_string_chk(&argvars[0]);	/* NULL on type error */
6880     if (str == NULL)
6881 	rettv->vval.v_string = NULL;
6882     else
6883     {
6884 	type = get_histtype(str);
6885 	if (argvars[1].v_type == VAR_UNKNOWN)
6886 	    idx = get_history_idx(type);
6887 	else
6888 	    idx = (int)tv_get_number_chk(&argvars[1], NULL);
6889 						    /* -1 on type error */
6890 	rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6891     }
6892 #else
6893     rettv->vval.v_string = NULL;
6894 #endif
6895     rettv->v_type = VAR_STRING;
6896 }
6897 
6898 /*
6899  * "histnr()" function
6900  */
6901     static void
6902 f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6903 {
6904     int		i;
6905 
6906 #ifdef FEAT_CMDHIST
6907     char_u	*history = tv_get_string_chk(&argvars[0]);
6908 
6909     i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6910     if (i >= HIST_CMD && i < HIST_COUNT)
6911 	i = get_history_idx(i);
6912     else
6913 #endif
6914 	i = -1;
6915     rettv->vval.v_number = i;
6916 }
6917 
6918 /*
6919  * "highlightID(name)" function
6920  */
6921     static void
6922 f_hlID(typval_T *argvars, typval_T *rettv)
6923 {
6924     rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
6925 }
6926 
6927 /*
6928  * "highlight_exists()" function
6929  */
6930     static void
6931 f_hlexists(typval_T *argvars, typval_T *rettv)
6932 {
6933     rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
6934 }
6935 
6936 /*
6937  * "hostname()" function
6938  */
6939     static void
6940 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6941 {
6942     char_u hostname[256];
6943 
6944     mch_get_host_name(hostname, 256);
6945     rettv->v_type = VAR_STRING;
6946     rettv->vval.v_string = vim_strsave(hostname);
6947 }
6948 
6949 /*
6950  * iconv() function
6951  */
6952     static void
6953 f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6954 {
6955     char_u	buf1[NUMBUFLEN];
6956     char_u	buf2[NUMBUFLEN];
6957     char_u	*from, *to, *str;
6958     vimconv_T	vimconv;
6959 
6960     rettv->v_type = VAR_STRING;
6961     rettv->vval.v_string = NULL;
6962 
6963     str = tv_get_string(&argvars[0]);
6964     from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6965     to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
6966     vimconv.vc_type = CONV_NONE;
6967     convert_setup(&vimconv, from, to);
6968 
6969     /* If the encodings are equal, no conversion needed. */
6970     if (vimconv.vc_type == CONV_NONE)
6971 	rettv->vval.v_string = vim_strsave(str);
6972     else
6973 	rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6974 
6975     convert_setup(&vimconv, NULL, NULL);
6976     vim_free(from);
6977     vim_free(to);
6978 }
6979 
6980 /*
6981  * "indent()" function
6982  */
6983     static void
6984 f_indent(typval_T *argvars, typval_T *rettv)
6985 {
6986     linenr_T	lnum;
6987 
6988     lnum = tv_get_lnum(argvars);
6989     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6990 	rettv->vval.v_number = get_indent_lnum(lnum);
6991     else
6992 	rettv->vval.v_number = -1;
6993 }
6994 
6995 /*
6996  * "index()" function
6997  */
6998     static void
6999 f_index(typval_T *argvars, typval_T *rettv)
7000 {
7001     list_T	*l;
7002     listitem_T	*item;
7003     blob_T	*b;
7004     long	idx = 0;
7005     int		ic = FALSE;
7006     int		error = FALSE;
7007 
7008     rettv->vval.v_number = -1;
7009     if (argvars[0].v_type == VAR_BLOB)
7010     {
7011 	typval_T	tv;
7012 	int		start = 0;
7013 
7014 	if (argvars[2].v_type != VAR_UNKNOWN)
7015 	{
7016 	    start = tv_get_number_chk(&argvars[2], &error);
7017 	    if (error)
7018 		return;
7019 	}
7020 	b = argvars[0].vval.v_blob;
7021 	if (b == NULL)
7022 	    return;
7023 	if (start < 0)
7024 	{
7025 	    start = blob_len(b) + start;
7026 	    if (start < 0)
7027 		start = 0;
7028 	}
7029 
7030 	for (idx = start; idx < blob_len(b); ++idx)
7031 	{
7032 	    tv.v_type = VAR_NUMBER;
7033 	    tv.vval.v_number = blob_get(b, idx);
7034 	    if (tv_equal(&tv, &argvars[1], ic, FALSE))
7035 	    {
7036 		rettv->vval.v_number = idx;
7037 		return;
7038 	    }
7039 	}
7040 	return;
7041     }
7042     else if (argvars[0].v_type != VAR_LIST)
7043     {
7044 	emsg(_(e_listblobreq));
7045 	return;
7046     }
7047 
7048     l = argvars[0].vval.v_list;
7049     if (l != NULL)
7050     {
7051 	item = l->lv_first;
7052 	if (argvars[2].v_type != VAR_UNKNOWN)
7053 	{
7054 	    /* Start at specified item.  Use the cached index that list_find()
7055 	     * sets, so that a negative number also works. */
7056 	    item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
7057 	    idx = l->lv_idx;
7058 	    if (argvars[3].v_type != VAR_UNKNOWN)
7059 		ic = (int)tv_get_number_chk(&argvars[3], &error);
7060 	    if (error)
7061 		item = NULL;
7062 	}
7063 
7064 	for ( ; item != NULL; item = item->li_next, ++idx)
7065 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7066 	    {
7067 		rettv->vval.v_number = idx;
7068 		break;
7069 	    }
7070     }
7071 }
7072 
7073 static int inputsecret_flag = 0;
7074 
7075 /*
7076  * "input()" function
7077  *     Also handles inputsecret() when inputsecret is set.
7078  */
7079     static void
7080 f_input(typval_T *argvars, typval_T *rettv)
7081 {
7082     get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7083 }
7084 
7085 /*
7086  * "inputdialog()" function
7087  */
7088     static void
7089 f_inputdialog(typval_T *argvars, typval_T *rettv)
7090 {
7091 #if defined(FEAT_GUI_TEXTDIALOG)
7092     /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7093     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7094     {
7095 	char_u	*message;
7096 	char_u	buf[NUMBUFLEN];
7097 	char_u	*defstr = (char_u *)"";
7098 
7099 	message = tv_get_string_chk(&argvars[0]);
7100 	if (argvars[1].v_type != VAR_UNKNOWN
7101 		&& (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
7102 	    vim_strncpy(IObuff, defstr, IOSIZE - 1);
7103 	else
7104 	    IObuff[0] = NUL;
7105 	if (message != NULL && defstr != NULL
7106 		&& do_dialog(VIM_QUESTION, NULL, message,
7107 			  (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7108 	    rettv->vval.v_string = vim_strsave(IObuff);
7109 	else
7110 	{
7111 	    if (message != NULL && defstr != NULL
7112 					&& argvars[1].v_type != VAR_UNKNOWN
7113 					&& argvars[2].v_type != VAR_UNKNOWN)
7114 		rettv->vval.v_string = vim_strsave(
7115 				      tv_get_string_buf(&argvars[2], buf));
7116 	    else
7117 		rettv->vval.v_string = NULL;
7118 	}
7119 	rettv->v_type = VAR_STRING;
7120     }
7121     else
7122 #endif
7123 	get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7124 }
7125 
7126 /*
7127  * "inputlist()" function
7128  */
7129     static void
7130 f_inputlist(typval_T *argvars, typval_T *rettv)
7131 {
7132     listitem_T	*li;
7133     int		selected;
7134     int		mouse_used;
7135 
7136 #ifdef NO_CONSOLE_INPUT
7137     /* While starting up, there is no place to enter text. When running tests
7138      * with --not-a-term we assume feedkeys() will be used. */
7139     if (no_console_input() && !is_not_a_term())
7140 	return;
7141 #endif
7142     if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7143     {
7144 	semsg(_(e_listarg), "inputlist()");
7145 	return;
7146     }
7147 
7148     msg_start();
7149     msg_row = Rows - 1;	/* for when 'cmdheight' > 1 */
7150     lines_left = Rows;	/* avoid more prompt */
7151     msg_scroll = TRUE;
7152     msg_clr_eos();
7153 
7154     for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7155     {
7156 	msg_puts((char *)tv_get_string(&li->li_tv));
7157 	msg_putchar('\n');
7158     }
7159 
7160     /* Ask for choice. */
7161     selected = prompt_for_number(&mouse_used);
7162     if (mouse_used)
7163 	selected -= lines_left;
7164 
7165     rettv->vval.v_number = selected;
7166 }
7167 
7168 static garray_T	    ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7169 
7170 /*
7171  * "inputrestore()" function
7172  */
7173     static void
7174 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7175 {
7176     if (ga_userinput.ga_len > 0)
7177     {
7178 	--ga_userinput.ga_len;
7179 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7180 						       + ga_userinput.ga_len);
7181 	/* default return is zero == OK */
7182     }
7183     else if (p_verbose > 1)
7184     {
7185 	verb_msg(_("called inputrestore() more often than inputsave()"));
7186 	rettv->vval.v_number = 1; /* Failed */
7187     }
7188 }
7189 
7190 /*
7191  * "inputsave()" function
7192  */
7193     static void
7194 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7195 {
7196     /* Add an entry to the stack of typeahead storage. */
7197     if (ga_grow(&ga_userinput, 1) == OK)
7198     {
7199 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
7200 						       + ga_userinput.ga_len);
7201 	++ga_userinput.ga_len;
7202 	/* default return is zero == OK */
7203     }
7204     else
7205 	rettv->vval.v_number = 1; /* Failed */
7206 }
7207 
7208 /*
7209  * "inputsecret()" function
7210  */
7211     static void
7212 f_inputsecret(typval_T *argvars, typval_T *rettv)
7213 {
7214     ++cmdline_star;
7215     ++inputsecret_flag;
7216     f_input(argvars, rettv);
7217     --cmdline_star;
7218     --inputsecret_flag;
7219 }
7220 
7221 /*
7222  * "insert()" function
7223  */
7224     static void
7225 f_insert(typval_T *argvars, typval_T *rettv)
7226 {
7227     long	before = 0;
7228     listitem_T	*item;
7229     list_T	*l;
7230     int		error = FALSE;
7231 
7232     if (argvars[0].v_type == VAR_BLOB)
7233     {
7234 	int	    val, len;
7235 	char_u	    *p;
7236 
7237 	len = blob_len(argvars[0].vval.v_blob);
7238 	if (argvars[2].v_type != VAR_UNKNOWN)
7239 	{
7240 	    before = (long)tv_get_number_chk(&argvars[2], &error);
7241 	    if (error)
7242 		return;		// type error; errmsg already given
7243 	    if (before < 0 || before > len)
7244 	    {
7245 		semsg(_(e_invarg2), tv_get_string(&argvars[2]));
7246 		return;
7247 	    }
7248 	}
7249 	val = tv_get_number_chk(&argvars[1], &error);
7250 	if (error)
7251 	    return;
7252 	if (val < 0 || val > 255)
7253 	{
7254 	    semsg(_(e_invarg2), tv_get_string(&argvars[1]));
7255 	    return;
7256 	}
7257 
7258 	if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7259 	    return;
7260 	p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7261 	mch_memmove(p + before + 1, p + before, (size_t)len - before);
7262 	*(p + before) = val;
7263 	++argvars[0].vval.v_blob->bv_ga.ga_len;
7264 
7265 	copy_tv(&argvars[0], rettv);
7266     }
7267     else if (argvars[0].v_type != VAR_LIST)
7268 	semsg(_(e_listblobarg), "insert()");
7269     else if ((l = argvars[0].vval.v_list) != NULL && !tv_check_lock(l->lv_lock,
7270 				      (char_u *)N_("insert() argument"), TRUE))
7271     {
7272 	if (argvars[2].v_type != VAR_UNKNOWN)
7273 	    before = (long)tv_get_number_chk(&argvars[2], &error);
7274 	if (error)
7275 	    return;		/* type error; errmsg already given */
7276 
7277 	if (before == l->lv_len)
7278 	    item = NULL;
7279 	else
7280 	{
7281 	    item = list_find(l, before);
7282 	    if (item == NULL)
7283 	    {
7284 		semsg(_(e_listidx), before);
7285 		l = NULL;
7286 	    }
7287 	}
7288 	if (l != NULL)
7289 	{
7290 	    list_insert_tv(l, &argvars[1], item);
7291 	    copy_tv(&argvars[0], rettv);
7292 	}
7293     }
7294 }
7295 
7296 /*
7297  * "invert(expr)" function
7298  */
7299     static void
7300 f_invert(typval_T *argvars, typval_T *rettv)
7301 {
7302     rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
7303 }
7304 
7305 /*
7306  * "isdirectory()" function
7307  */
7308     static void
7309 f_isdirectory(typval_T *argvars, typval_T *rettv)
7310 {
7311     rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
7312 }
7313 
7314 /*
7315  * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7316  * or it refers to a List or Dictionary that is locked.
7317  */
7318     static int
7319 tv_islocked(typval_T *tv)
7320 {
7321     return (tv->v_lock & VAR_LOCKED)
7322 	|| (tv->v_type == VAR_LIST
7323 		&& tv->vval.v_list != NULL
7324 		&& (tv->vval.v_list->lv_lock & VAR_LOCKED))
7325 	|| (tv->v_type == VAR_DICT
7326 		&& tv->vval.v_dict != NULL
7327 		&& (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7328 }
7329 
7330 /*
7331  * "islocked()" function
7332  */
7333     static void
7334 f_islocked(typval_T *argvars, typval_T *rettv)
7335 {
7336     lval_T	lv;
7337     char_u	*end;
7338     dictitem_T	*di;
7339 
7340     rettv->vval.v_number = -1;
7341     end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
7342 			     GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
7343     if (end != NULL && lv.ll_name != NULL)
7344     {
7345 	if (*end != NUL)
7346 	    emsg(_(e_trailing));
7347 	else
7348 	{
7349 	    if (lv.ll_tv == NULL)
7350 	    {
7351 		di = find_var(lv.ll_name, NULL, TRUE);
7352 		if (di != NULL)
7353 		{
7354 		    /* Consider a variable locked when:
7355 		     * 1. the variable itself is locked
7356 		     * 2. the value of the variable is locked.
7357 		     * 3. the List or Dict value is locked.
7358 		     */
7359 		    rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7360 						   || tv_islocked(&di->di_tv));
7361 		}
7362 	    }
7363 	    else if (lv.ll_range)
7364 		emsg(_("E786: Range not allowed"));
7365 	    else if (lv.ll_newkey != NULL)
7366 		semsg(_(e_dictkey), lv.ll_newkey);
7367 	    else if (lv.ll_list != NULL)
7368 		/* List item. */
7369 		rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7370 	    else
7371 		/* Dictionary item. */
7372 		rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7373 	}
7374     }
7375 
7376     clear_lval(&lv);
7377 }
7378 
7379 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7380 /*
7381  * "isnan()" function
7382  */
7383     static void
7384 f_isnan(typval_T *argvars, typval_T *rettv)
7385 {
7386     rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7387 					    && isnan(argvars[0].vval.v_float);
7388 }
7389 #endif
7390 
7391 /*
7392  * "items(dict)" function
7393  */
7394     static void
7395 f_items(typval_T *argvars, typval_T *rettv)
7396 {
7397     dict_list(argvars, rettv, 2);
7398 }
7399 
7400 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7401 /*
7402  * Get the job from the argument.
7403  * Returns NULL if the job is invalid.
7404  */
7405     static job_T *
7406 get_job_arg(typval_T *tv)
7407 {
7408     job_T *job;
7409 
7410     if (tv->v_type != VAR_JOB)
7411     {
7412 	semsg(_(e_invarg2), tv_get_string(tv));
7413 	return NULL;
7414     }
7415     job = tv->vval.v_job;
7416 
7417     if (job == NULL)
7418 	emsg(_("E916: not a valid job"));
7419     return job;
7420 }
7421 
7422 /*
7423  * "job_getchannel()" function
7424  */
7425     static void
7426 f_job_getchannel(typval_T *argvars, typval_T *rettv)
7427 {
7428     job_T	*job = get_job_arg(&argvars[0]);
7429 
7430     if (job != NULL)
7431     {
7432 	rettv->v_type = VAR_CHANNEL;
7433 	rettv->vval.v_channel = job->jv_channel;
7434 	if (job->jv_channel != NULL)
7435 	    ++job->jv_channel->ch_refcount;
7436     }
7437 }
7438 
7439 /*
7440  * "job_info()" function
7441  */
7442     static void
7443 f_job_info(typval_T *argvars, typval_T *rettv)
7444 {
7445     if (argvars[0].v_type != VAR_UNKNOWN)
7446     {
7447 	job_T	*job = get_job_arg(&argvars[0]);
7448 
7449 	if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7450 	    job_info(job, rettv->vval.v_dict);
7451     }
7452     else if (rettv_list_alloc(rettv) == OK)
7453 	job_info_all(rettv->vval.v_list);
7454 }
7455 
7456 /*
7457  * "job_setoptions()" function
7458  */
7459     static void
7460 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7461 {
7462     job_T	*job = get_job_arg(&argvars[0]);
7463     jobopt_T	opt;
7464 
7465     if (job == NULL)
7466 	return;
7467     clear_job_options(&opt);
7468     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
7469 	job_set_options(job, &opt);
7470     free_job_options(&opt);
7471 }
7472 
7473 /*
7474  * "job_start()" function
7475  */
7476     static void
7477 f_job_start(typval_T *argvars, typval_T *rettv)
7478 {
7479     rettv->v_type = VAR_JOB;
7480     if (check_restricted() || check_secure())
7481 	return;
7482     rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
7483 }
7484 
7485 /*
7486  * "job_status()" function
7487  */
7488     static void
7489 f_job_status(typval_T *argvars, typval_T *rettv)
7490 {
7491     job_T	*job = get_job_arg(&argvars[0]);
7492 
7493     if (job != NULL)
7494     {
7495 	rettv->v_type = VAR_STRING;
7496 	rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7497     }
7498 }
7499 
7500 /*
7501  * "job_stop()" function
7502  */
7503     static void
7504 f_job_stop(typval_T *argvars, typval_T *rettv)
7505 {
7506     job_T	*job = get_job_arg(&argvars[0]);
7507 
7508     if (job != NULL)
7509 	rettv->vval.v_number = job_stop(job, argvars, NULL);
7510 }
7511 #endif
7512 
7513 /*
7514  * "join()" function
7515  */
7516     static void
7517 f_join(typval_T *argvars, typval_T *rettv)
7518 {
7519     garray_T	ga;
7520     char_u	*sep;
7521 
7522     if (argvars[0].v_type != VAR_LIST)
7523     {
7524 	emsg(_(e_listreq));
7525 	return;
7526     }
7527     if (argvars[0].vval.v_list == NULL)
7528 	return;
7529     if (argvars[1].v_type == VAR_UNKNOWN)
7530 	sep = (char_u *)" ";
7531     else
7532 	sep = tv_get_string_chk(&argvars[1]);
7533 
7534     rettv->v_type = VAR_STRING;
7535 
7536     if (sep != NULL)
7537     {
7538 	ga_init2(&ga, (int)sizeof(char), 80);
7539 	list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7540 	ga_append(&ga, NUL);
7541 	rettv->vval.v_string = (char_u *)ga.ga_data;
7542     }
7543     else
7544 	rettv->vval.v_string = NULL;
7545 }
7546 
7547 /*
7548  * "js_decode()" function
7549  */
7550     static void
7551 f_js_decode(typval_T *argvars, typval_T *rettv)
7552 {
7553     js_read_T	reader;
7554 
7555     reader.js_buf = tv_get_string(&argvars[0]);
7556     reader.js_fill = NULL;
7557     reader.js_used = 0;
7558     if (json_decode_all(&reader, rettv, JSON_JS) != OK)
7559 	emsg(_(e_invarg));
7560 }
7561 
7562 /*
7563  * "js_encode()" function
7564  */
7565     static void
7566 f_js_encode(typval_T *argvars, typval_T *rettv)
7567 {
7568     rettv->v_type = VAR_STRING;
7569     rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7570 }
7571 
7572 /*
7573  * "json_decode()" function
7574  */
7575     static void
7576 f_json_decode(typval_T *argvars, typval_T *rettv)
7577 {
7578     js_read_T	reader;
7579 
7580     reader.js_buf = tv_get_string(&argvars[0]);
7581     reader.js_fill = NULL;
7582     reader.js_used = 0;
7583     json_decode_all(&reader, rettv, 0);
7584 }
7585 
7586 /*
7587  * "json_encode()" function
7588  */
7589     static void
7590 f_json_encode(typval_T *argvars, typval_T *rettv)
7591 {
7592     rettv->v_type = VAR_STRING;
7593     rettv->vval.v_string = json_encode(&argvars[0], 0);
7594 }
7595 
7596 /*
7597  * "keys()" function
7598  */
7599     static void
7600 f_keys(typval_T *argvars, typval_T *rettv)
7601 {
7602     dict_list(argvars, rettv, 0);
7603 }
7604 
7605 /*
7606  * "last_buffer_nr()" function.
7607  */
7608     static void
7609 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7610 {
7611     int		n = 0;
7612     buf_T	*buf;
7613 
7614     FOR_ALL_BUFFERS(buf)
7615 	if (n < buf->b_fnum)
7616 	    n = buf->b_fnum;
7617 
7618     rettv->vval.v_number = n;
7619 }
7620 
7621 /*
7622  * "len()" function
7623  */
7624     static void
7625 f_len(typval_T *argvars, typval_T *rettv)
7626 {
7627     switch (argvars[0].v_type)
7628     {
7629 	case VAR_STRING:
7630 	case VAR_NUMBER:
7631 	    rettv->vval.v_number = (varnumber_T)STRLEN(
7632 					       tv_get_string(&argvars[0]));
7633 	    break;
7634 	case VAR_BLOB:
7635 	    rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7636 	    break;
7637 	case VAR_LIST:
7638 	    rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7639 	    break;
7640 	case VAR_DICT:
7641 	    rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7642 	    break;
7643 	case VAR_UNKNOWN:
7644 	case VAR_SPECIAL:
7645 	case VAR_FLOAT:
7646 	case VAR_FUNC:
7647 	case VAR_PARTIAL:
7648 	case VAR_JOB:
7649 	case VAR_CHANNEL:
7650 	    emsg(_("E701: Invalid type for len()"));
7651 	    break;
7652     }
7653 }
7654 
7655     static void
7656 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
7657 {
7658 #ifdef FEAT_LIBCALL
7659     char_u		*string_in;
7660     char_u		**string_result;
7661     int			nr_result;
7662 #endif
7663 
7664     rettv->v_type = type;
7665     if (type != VAR_NUMBER)
7666 	rettv->vval.v_string = NULL;
7667 
7668     if (check_restricted() || check_secure())
7669 	return;
7670 
7671 #ifdef FEAT_LIBCALL
7672     /* The first two args must be strings, otherwise it's meaningless */
7673     if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7674     {
7675 	string_in = NULL;
7676 	if (argvars[2].v_type == VAR_STRING)
7677 	    string_in = argvars[2].vval.v_string;
7678 	if (type == VAR_NUMBER)
7679 	    string_result = NULL;
7680 	else
7681 	    string_result = &rettv->vval.v_string;
7682 	if (mch_libcall(argvars[0].vval.v_string,
7683 			     argvars[1].vval.v_string,
7684 			     string_in,
7685 			     argvars[2].vval.v_number,
7686 			     string_result,
7687 			     &nr_result) == OK
7688 		&& type == VAR_NUMBER)
7689 	    rettv->vval.v_number = nr_result;
7690     }
7691 #endif
7692 }
7693 
7694 /*
7695  * "libcall()" function
7696  */
7697     static void
7698 f_libcall(typval_T *argvars, typval_T *rettv)
7699 {
7700     libcall_common(argvars, rettv, VAR_STRING);
7701 }
7702 
7703 /*
7704  * "libcallnr()" function
7705  */
7706     static void
7707 f_libcallnr(typval_T *argvars, typval_T *rettv)
7708 {
7709     libcall_common(argvars, rettv, VAR_NUMBER);
7710 }
7711 
7712 /*
7713  * "line(string)" function
7714  */
7715     static void
7716 f_line(typval_T *argvars, typval_T *rettv)
7717 {
7718     linenr_T	lnum = 0;
7719     pos_T	*fp;
7720     int		fnum;
7721 
7722     fp = var2fpos(&argvars[0], TRUE, &fnum);
7723     if (fp != NULL)
7724 	lnum = fp->lnum;
7725     rettv->vval.v_number = lnum;
7726 }
7727 
7728 /*
7729  * "line2byte(lnum)" function
7730  */
7731     static void
7732 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7733 {
7734 #ifndef FEAT_BYTEOFF
7735     rettv->vval.v_number = -1;
7736 #else
7737     linenr_T	lnum;
7738 
7739     lnum = tv_get_lnum(argvars);
7740     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7741 	rettv->vval.v_number = -1;
7742     else
7743 	rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7744     if (rettv->vval.v_number >= 0)
7745 	++rettv->vval.v_number;
7746 #endif
7747 }
7748 
7749 /*
7750  * "lispindent(lnum)" function
7751  */
7752     static void
7753 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7754 {
7755 #ifdef FEAT_LISP
7756     pos_T	pos;
7757     linenr_T	lnum;
7758 
7759     pos = curwin->w_cursor;
7760     lnum = tv_get_lnum(argvars);
7761     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7762     {
7763 	curwin->w_cursor.lnum = lnum;
7764 	rettv->vval.v_number = get_lisp_indent();
7765 	curwin->w_cursor = pos;
7766     }
7767     else
7768 #endif
7769 	rettv->vval.v_number = -1;
7770 }
7771 
7772 /*
7773  * "localtime()" function
7774  */
7775     static void
7776 f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7777 {
7778     rettv->vval.v_number = (varnumber_T)time(NULL);
7779 }
7780 
7781     static void
7782 get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7783 {
7784     char_u	*keys;
7785     char_u	*which;
7786     char_u	buf[NUMBUFLEN];
7787     char_u	*keys_buf = NULL;
7788     char_u	*rhs;
7789     int		mode;
7790     int		abbr = FALSE;
7791     int		get_dict = FALSE;
7792     mapblock_T	*mp;
7793     int		buffer_local;
7794 
7795     /* return empty string for failure */
7796     rettv->v_type = VAR_STRING;
7797     rettv->vval.v_string = NULL;
7798 
7799     keys = tv_get_string(&argvars[0]);
7800     if (*keys == NUL)
7801 	return;
7802 
7803     if (argvars[1].v_type != VAR_UNKNOWN)
7804     {
7805 	which = tv_get_string_buf_chk(&argvars[1], buf);
7806 	if (argvars[2].v_type != VAR_UNKNOWN)
7807 	{
7808 	    abbr = (int)tv_get_number(&argvars[2]);
7809 	    if (argvars[3].v_type != VAR_UNKNOWN)
7810 		get_dict = (int)tv_get_number(&argvars[3]);
7811 	}
7812     }
7813     else
7814 	which = (char_u *)"";
7815     if (which == NULL)
7816 	return;
7817 
7818     mode = get_map_mode(&which, 0);
7819 
7820     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7821     rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7822     vim_free(keys_buf);
7823 
7824     if (!get_dict)
7825     {
7826 	/* Return a string. */
7827 	if (rhs != NULL)
7828 	{
7829 	    if (*rhs == NUL)
7830 		rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7831 	    else
7832 		rettv->vval.v_string = str2special_save(rhs, FALSE);
7833 	}
7834 
7835     }
7836     else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7837     {
7838 	/* Return a dictionary. */
7839 	char_u	    *lhs = str2special_save(mp->m_keys, TRUE);
7840 	char_u	    *mapmode = map_mode_to_chars(mp->m_mode);
7841 	dict_T	    *dict = rettv->vval.v_dict;
7842 
7843 	dict_add_string(dict, "lhs", lhs);
7844 	dict_add_string(dict, "rhs", mp->m_orig_str);
7845 	dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7846 	dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7847 	dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
7848 	dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7849 	dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
7850 	dict_add_number(dict, "buffer", (long)buffer_local);
7851 	dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7852 	dict_add_string(dict, "mode", mapmode);
7853 
7854 	vim_free(lhs);
7855 	vim_free(mapmode);
7856     }
7857 }
7858 
7859 #ifdef FEAT_FLOAT
7860 /*
7861  * "log()" function
7862  */
7863     static void
7864 f_log(typval_T *argvars, typval_T *rettv)
7865 {
7866     float_T	f = 0.0;
7867 
7868     rettv->v_type = VAR_FLOAT;
7869     if (get_float_arg(argvars, &f) == OK)
7870 	rettv->vval.v_float = log(f);
7871     else
7872 	rettv->vval.v_float = 0.0;
7873 }
7874 
7875 /*
7876  * "log10()" function
7877  */
7878     static void
7879 f_log10(typval_T *argvars, typval_T *rettv)
7880 {
7881     float_T	f = 0.0;
7882 
7883     rettv->v_type = VAR_FLOAT;
7884     if (get_float_arg(argvars, &f) == OK)
7885 	rettv->vval.v_float = log10(f);
7886     else
7887 	rettv->vval.v_float = 0.0;
7888 }
7889 #endif
7890 
7891 #ifdef FEAT_LUA
7892 /*
7893  * "luaeval()" function
7894  */
7895     static void
7896 f_luaeval(typval_T *argvars, typval_T *rettv)
7897 {
7898     char_u	*str;
7899     char_u	buf[NUMBUFLEN];
7900 
7901     str = tv_get_string_buf(&argvars[0], buf);
7902     do_luaeval(str, argvars + 1, rettv);
7903 }
7904 #endif
7905 
7906 /*
7907  * "map()" function
7908  */
7909     static void
7910 f_map(typval_T *argvars, typval_T *rettv)
7911 {
7912     filter_map(argvars, rettv, TRUE);
7913 }
7914 
7915 /*
7916  * "maparg()" function
7917  */
7918     static void
7919 f_maparg(typval_T *argvars, typval_T *rettv)
7920 {
7921     get_maparg(argvars, rettv, TRUE);
7922 }
7923 
7924 /*
7925  * "mapcheck()" function
7926  */
7927     static void
7928 f_mapcheck(typval_T *argvars, typval_T *rettv)
7929 {
7930     get_maparg(argvars, rettv, FALSE);
7931 }
7932 
7933 typedef enum
7934 {
7935     MATCH_END,	    /* matchend() */
7936     MATCH_MATCH,    /* match() */
7937     MATCH_STR,	    /* matchstr() */
7938     MATCH_LIST,	    /* matchlist() */
7939     MATCH_POS	    /* matchstrpos() */
7940 } matchtype_T;
7941 
7942     static void
7943 find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
7944 {
7945     char_u	*str = NULL;
7946     long	len = 0;
7947     char_u	*expr = NULL;
7948     char_u	*pat;
7949     regmatch_T	regmatch;
7950     char_u	patbuf[NUMBUFLEN];
7951     char_u	strbuf[NUMBUFLEN];
7952     char_u	*save_cpo;
7953     long	start = 0;
7954     long	nth = 1;
7955     colnr_T	startcol = 0;
7956     int		match = 0;
7957     list_T	*l = NULL;
7958     listitem_T	*li = NULL;
7959     long	idx = 0;
7960     char_u	*tofree = NULL;
7961 
7962     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7963     save_cpo = p_cpo;
7964     p_cpo = (char_u *)"";
7965 
7966     rettv->vval.v_number = -1;
7967     if (type == MATCH_LIST || type == MATCH_POS)
7968     {
7969 	/* type MATCH_LIST: return empty list when there are no matches.
7970 	 * type MATCH_POS: return ["", -1, -1, -1] */
7971 	if (rettv_list_alloc(rettv) == FAIL)
7972 	    goto theend;
7973 	if (type == MATCH_POS
7974 		&& (list_append_string(rettv->vval.v_list,
7975 					    (char_u *)"", 0) == FAIL
7976 		    || list_append_number(rettv->vval.v_list,
7977 					    (varnumber_T)-1) == FAIL
7978 		    || list_append_number(rettv->vval.v_list,
7979 					    (varnumber_T)-1) == FAIL
7980 		    || list_append_number(rettv->vval.v_list,
7981 					    (varnumber_T)-1) == FAIL))
7982 	{
7983 		list_free(rettv->vval.v_list);
7984 		rettv->vval.v_list = NULL;
7985 		goto theend;
7986 	}
7987     }
7988     else if (type == MATCH_STR)
7989     {
7990 	rettv->v_type = VAR_STRING;
7991 	rettv->vval.v_string = NULL;
7992     }
7993 
7994     if (argvars[0].v_type == VAR_LIST)
7995     {
7996 	if ((l = argvars[0].vval.v_list) == NULL)
7997 	    goto theend;
7998 	li = l->lv_first;
7999     }
8000     else
8001     {
8002 	expr = str = tv_get_string(&argvars[0]);
8003 	len = (long)STRLEN(str);
8004     }
8005 
8006     pat = tv_get_string_buf_chk(&argvars[1], patbuf);
8007     if (pat == NULL)
8008 	goto theend;
8009 
8010     if (argvars[2].v_type != VAR_UNKNOWN)
8011     {
8012 	int	    error = FALSE;
8013 
8014 	start = (long)tv_get_number_chk(&argvars[2], &error);
8015 	if (error)
8016 	    goto theend;
8017 	if (l != NULL)
8018 	{
8019 	    li = list_find(l, start);
8020 	    if (li == NULL)
8021 		goto theend;
8022 	    idx = l->lv_idx;	/* use the cached index */
8023 	}
8024 	else
8025 	{
8026 	    if (start < 0)
8027 		start = 0;
8028 	    if (start > len)
8029 		goto theend;
8030 	    /* When "count" argument is there ignore matches before "start",
8031 	     * otherwise skip part of the string.  Differs when pattern is "^"
8032 	     * or "\<". */
8033 	    if (argvars[3].v_type != VAR_UNKNOWN)
8034 		startcol = start;
8035 	    else
8036 	    {
8037 		str += start;
8038 		len -= start;
8039 	    }
8040 	}
8041 
8042 	if (argvars[3].v_type != VAR_UNKNOWN)
8043 	    nth = (long)tv_get_number_chk(&argvars[3], &error);
8044 	if (error)
8045 	    goto theend;
8046     }
8047 
8048     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8049     if (regmatch.regprog != NULL)
8050     {
8051 	regmatch.rm_ic = p_ic;
8052 
8053 	for (;;)
8054 	{
8055 	    if (l != NULL)
8056 	    {
8057 		if (li == NULL)
8058 		{
8059 		    match = FALSE;
8060 		    break;
8061 		}
8062 		vim_free(tofree);
8063 		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8064 		if (str == NULL)
8065 		    break;
8066 	    }
8067 
8068 	    match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8069 
8070 	    if (match && --nth <= 0)
8071 		break;
8072 	    if (l == NULL && !match)
8073 		break;
8074 
8075 	    /* Advance to just after the match. */
8076 	    if (l != NULL)
8077 	    {
8078 		li = li->li_next;
8079 		++idx;
8080 	    }
8081 	    else
8082 	    {
8083 		startcol = (colnr_T)(regmatch.startp[0]
8084 				    + (*mb_ptr2len)(regmatch.startp[0]) - str);
8085 		if (startcol > (colnr_T)len
8086 				      || str + startcol <= regmatch.startp[0])
8087 		{
8088 		    match = FALSE;
8089 		    break;
8090 		}
8091 	    }
8092 	}
8093 
8094 	if (match)
8095 	{
8096 	    if (type == MATCH_POS)
8097 	    {
8098 		listitem_T *li1 = rettv->vval.v_list->lv_first;
8099 		listitem_T *li2 = li1->li_next;
8100 		listitem_T *li3 = li2->li_next;
8101 		listitem_T *li4 = li3->li_next;
8102 
8103 		vim_free(li1->li_tv.vval.v_string);
8104 		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8105 				(int)(regmatch.endp[0] - regmatch.startp[0]));
8106 		li3->li_tv.vval.v_number =
8107 				      (varnumber_T)(regmatch.startp[0] - expr);
8108 		li4->li_tv.vval.v_number =
8109 					(varnumber_T)(regmatch.endp[0] - expr);
8110 		if (l != NULL)
8111 		    li2->li_tv.vval.v_number = (varnumber_T)idx;
8112 	    }
8113 	    else if (type == MATCH_LIST)
8114 	    {
8115 		int i;
8116 
8117 		/* return list with matched string and submatches */
8118 		for (i = 0; i < NSUBEXP; ++i)
8119 		{
8120 		    if (regmatch.endp[i] == NULL)
8121 		    {
8122 			if (list_append_string(rettv->vval.v_list,
8123 						     (char_u *)"", 0) == FAIL)
8124 			    break;
8125 		    }
8126 		    else if (list_append_string(rettv->vval.v_list,
8127 				regmatch.startp[i],
8128 				(int)(regmatch.endp[i] - regmatch.startp[i]))
8129 			    == FAIL)
8130 			break;
8131 		}
8132 	    }
8133 	    else if (type == MATCH_STR)
8134 	    {
8135 		/* return matched string */
8136 		if (l != NULL)
8137 		    copy_tv(&li->li_tv, rettv);
8138 		else
8139 		    rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8140 				(int)(regmatch.endp[0] - regmatch.startp[0]));
8141 	    }
8142 	    else if (l != NULL)
8143 		rettv->vval.v_number = idx;
8144 	    else
8145 	    {
8146 		if (type != MATCH_END)
8147 		    rettv->vval.v_number =
8148 				      (varnumber_T)(regmatch.startp[0] - str);
8149 		else
8150 		    rettv->vval.v_number =
8151 					(varnumber_T)(regmatch.endp[0] - str);
8152 		rettv->vval.v_number += (varnumber_T)(str - expr);
8153 	    }
8154 	}
8155 	vim_regfree(regmatch.regprog);
8156     }
8157 
8158 theend:
8159     if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
8160 	/* matchstrpos() without a list: drop the second item. */
8161 	listitem_remove(rettv->vval.v_list,
8162 				       rettv->vval.v_list->lv_first->li_next);
8163     vim_free(tofree);
8164     p_cpo = save_cpo;
8165 }
8166 
8167 /*
8168  * "match()" function
8169  */
8170     static void
8171 f_match(typval_T *argvars, typval_T *rettv)
8172 {
8173     find_some_match(argvars, rettv, MATCH_MATCH);
8174 }
8175 
8176 #ifdef FEAT_SEARCH_EXTRA
8177     static int
8178 matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8179 {
8180     dictitem_T *di;
8181 
8182     if (tv->v_type != VAR_DICT)
8183     {
8184 	emsg(_(e_dictreq));
8185 	return FAIL;
8186     }
8187 
8188     if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
8189 	*conceal_char = dict_get_string(tv->vval.v_dict,
8190 						   (char_u *)"conceal", FALSE);
8191 
8192     if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8193     {
8194 	*win = find_win_by_nr_or_id(&di->di_tv);
8195 	if (*win == NULL)
8196 	{
8197 	    emsg(_("E957: Invalid window number"));
8198 	    return FAIL;
8199 	}
8200     }
8201 
8202     return OK;
8203 }
8204 #endif
8205 
8206 /*
8207  * "matchadd()" function
8208  */
8209     static void
8210 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8211 {
8212 #ifdef FEAT_SEARCH_EXTRA
8213     char_u	buf[NUMBUFLEN];
8214     char_u	*grp = tv_get_string_buf_chk(&argvars[0], buf);	/* group */
8215     char_u	*pat = tv_get_string_buf_chk(&argvars[1], buf);	/* pattern */
8216     int		prio = 10;	/* default priority */
8217     int		id = -1;
8218     int		error = FALSE;
8219     char_u	*conceal_char = NULL;
8220     win_T	*win = curwin;
8221 
8222     rettv->vval.v_number = -1;
8223 
8224     if (grp == NULL || pat == NULL)
8225 	return;
8226     if (argvars[2].v_type != VAR_UNKNOWN)
8227     {
8228 	prio = (int)tv_get_number_chk(&argvars[2], &error);
8229 	if (argvars[3].v_type != VAR_UNKNOWN)
8230 	{
8231 	    id = (int)tv_get_number_chk(&argvars[3], &error);
8232 	    if (argvars[4].v_type != VAR_UNKNOWN
8233 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8234 		return;
8235 	}
8236     }
8237     if (error == TRUE)
8238 	return;
8239     if (id >= 1 && id <= 3)
8240     {
8241 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
8242 	return;
8243     }
8244 
8245     rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
8246 								conceal_char);
8247 #endif
8248 }
8249 
8250 /*
8251  * "matchaddpos()" function
8252  */
8253     static void
8254 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8255 {
8256 #ifdef FEAT_SEARCH_EXTRA
8257     char_u	buf[NUMBUFLEN];
8258     char_u	*group;
8259     int		prio = 10;
8260     int		id = -1;
8261     int		error = FALSE;
8262     list_T	*l;
8263     char_u	*conceal_char = NULL;
8264     win_T	*win = curwin;
8265 
8266     rettv->vval.v_number = -1;
8267 
8268     group = tv_get_string_buf_chk(&argvars[0], buf);
8269     if (group == NULL)
8270 	return;
8271 
8272     if (argvars[1].v_type != VAR_LIST)
8273     {
8274 	semsg(_(e_listarg), "matchaddpos()");
8275 	return;
8276     }
8277     l = argvars[1].vval.v_list;
8278     if (l == NULL)
8279 	return;
8280 
8281     if (argvars[2].v_type != VAR_UNKNOWN)
8282     {
8283 	prio = (int)tv_get_number_chk(&argvars[2], &error);
8284 	if (argvars[3].v_type != VAR_UNKNOWN)
8285 	{
8286 	    id = (int)tv_get_number_chk(&argvars[3], &error);
8287 
8288 	    if (argvars[4].v_type != VAR_UNKNOWN
8289 		&& matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8290 		return;
8291 	}
8292     }
8293     if (error == TRUE)
8294 	return;
8295 
8296     /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8297     if (id == 1 || id == 2)
8298     {
8299 	semsg(_("E798: ID is reserved for \":match\": %d"), id);
8300 	return;
8301     }
8302 
8303     rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
8304 								conceal_char);
8305 #endif
8306 }
8307 
8308 /*
8309  * "matcharg()" function
8310  */
8311     static void
8312 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8313 {
8314     if (rettv_list_alloc(rettv) == OK)
8315     {
8316 #ifdef FEAT_SEARCH_EXTRA
8317 	int	    id = (int)tv_get_number(&argvars[0]);
8318 	matchitem_T *m;
8319 
8320 	if (id >= 1 && id <= 3)
8321 	{
8322 	    if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8323 	    {
8324 		list_append_string(rettv->vval.v_list,
8325 						syn_id2name(m->hlg_id), -1);
8326 		list_append_string(rettv->vval.v_list, m->pattern, -1);
8327 	    }
8328 	    else
8329 	    {
8330 		list_append_string(rettv->vval.v_list, NULL, -1);
8331 		list_append_string(rettv->vval.v_list, NULL, -1);
8332 	    }
8333 	}
8334 #endif
8335     }
8336 }
8337 
8338 /*
8339  * "matchdelete()" function
8340  */
8341     static void
8342 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8343 {
8344 #ifdef FEAT_SEARCH_EXTRA
8345     rettv->vval.v_number = match_delete(curwin,
8346 				       (int)tv_get_number(&argvars[0]), TRUE);
8347 #endif
8348 }
8349 
8350 /*
8351  * "matchend()" function
8352  */
8353     static void
8354 f_matchend(typval_T *argvars, typval_T *rettv)
8355 {
8356     find_some_match(argvars, rettv, MATCH_END);
8357 }
8358 
8359 /*
8360  * "matchlist()" function
8361  */
8362     static void
8363 f_matchlist(typval_T *argvars, typval_T *rettv)
8364 {
8365     find_some_match(argvars, rettv, MATCH_LIST);
8366 }
8367 
8368 /*
8369  * "matchstr()" function
8370  */
8371     static void
8372 f_matchstr(typval_T *argvars, typval_T *rettv)
8373 {
8374     find_some_match(argvars, rettv, MATCH_STR);
8375 }
8376 
8377 /*
8378  * "matchstrpos()" function
8379  */
8380     static void
8381 f_matchstrpos(typval_T *argvars, typval_T *rettv)
8382 {
8383     find_some_match(argvars, rettv, MATCH_POS);
8384 }
8385 
8386     static void
8387 max_min(typval_T *argvars, typval_T *rettv, int domax)
8388 {
8389     varnumber_T	n = 0;
8390     varnumber_T	i;
8391     int		error = FALSE;
8392 
8393     if (argvars[0].v_type == VAR_LIST)
8394     {
8395 	list_T		*l;
8396 	listitem_T	*li;
8397 
8398 	l = argvars[0].vval.v_list;
8399 	if (l != NULL)
8400 	{
8401 	    li = l->lv_first;
8402 	    if (li != NULL)
8403 	    {
8404 		n = tv_get_number_chk(&li->li_tv, &error);
8405 		for (;;)
8406 		{
8407 		    li = li->li_next;
8408 		    if (li == NULL)
8409 			break;
8410 		    i = tv_get_number_chk(&li->li_tv, &error);
8411 		    if (domax ? i > n : i < n)
8412 			n = i;
8413 		}
8414 	    }
8415 	}
8416     }
8417     else if (argvars[0].v_type == VAR_DICT)
8418     {
8419 	dict_T		*d;
8420 	int		first = TRUE;
8421 	hashitem_T	*hi;
8422 	int		todo;
8423 
8424 	d = argvars[0].vval.v_dict;
8425 	if (d != NULL)
8426 	{
8427 	    todo = (int)d->dv_hashtab.ht_used;
8428 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8429 	    {
8430 		if (!HASHITEM_EMPTY(hi))
8431 		{
8432 		    --todo;
8433 		    i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
8434 		    if (first)
8435 		    {
8436 			n = i;
8437 			first = FALSE;
8438 		    }
8439 		    else if (domax ? i > n : i < n)
8440 			n = i;
8441 		}
8442 	    }
8443 	}
8444     }
8445     else
8446 	semsg(_(e_listdictarg), domax ? "max()" : "min()");
8447     rettv->vval.v_number = error ? 0 : n;
8448 }
8449 
8450 /*
8451  * "max()" function
8452  */
8453     static void
8454 f_max(typval_T *argvars, typval_T *rettv)
8455 {
8456     max_min(argvars, rettv, TRUE);
8457 }
8458 
8459 /*
8460  * "min()" function
8461  */
8462     static void
8463 f_min(typval_T *argvars, typval_T *rettv)
8464 {
8465     max_min(argvars, rettv, FALSE);
8466 }
8467 
8468 /*
8469  * Create the directory in which "dir" is located, and higher levels when
8470  * needed.
8471  * Return OK or FAIL.
8472  */
8473     static int
8474 mkdir_recurse(char_u *dir, int prot)
8475 {
8476     char_u	*p;
8477     char_u	*updir;
8478     int		r = FAIL;
8479 
8480     /* Get end of directory name in "dir".
8481      * We're done when it's "/" or "c:/". */
8482     p = gettail_sep(dir);
8483     if (p <= get_past_head(dir))
8484 	return OK;
8485 
8486     /* If the directory exists we're done.  Otherwise: create it.*/
8487     updir = vim_strnsave(dir, (int)(p - dir));
8488     if (updir == NULL)
8489 	return FAIL;
8490     if (mch_isdir(updir))
8491 	r = OK;
8492     else if (mkdir_recurse(updir, prot) == OK)
8493 	r = vim_mkdir_emsg(updir, prot);
8494     vim_free(updir);
8495     return r;
8496 }
8497 
8498 #ifdef vim_mkdir
8499 /*
8500  * "mkdir()" function
8501  */
8502     static void
8503 f_mkdir(typval_T *argvars, typval_T *rettv)
8504 {
8505     char_u	*dir;
8506     char_u	buf[NUMBUFLEN];
8507     int		prot = 0755;
8508 
8509     rettv->vval.v_number = FAIL;
8510     if (check_restricted() || check_secure())
8511 	return;
8512 
8513     dir = tv_get_string_buf(&argvars[0], buf);
8514     if (*dir == NUL)
8515 	return;
8516 
8517     if (*gettail(dir) == NUL)
8518 	/* remove trailing slashes */
8519 	*gettail_sep(dir) = NUL;
8520 
8521     if (argvars[1].v_type != VAR_UNKNOWN)
8522     {
8523 	if (argvars[2].v_type != VAR_UNKNOWN)
8524 	{
8525 	    prot = (int)tv_get_number_chk(&argvars[2], NULL);
8526 	    if (prot == -1)
8527 		return;
8528 	}
8529 	if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
8530 	{
8531 	    if (mch_isdir(dir))
8532 	    {
8533 		/* With the "p" flag it's OK if the dir already exists. */
8534 		rettv->vval.v_number = OK;
8535 		return;
8536 	    }
8537 	    mkdir_recurse(dir, prot);
8538 	}
8539     }
8540     rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
8541 }
8542 #endif
8543 
8544 /*
8545  * "mode()" function
8546  */
8547     static void
8548 f_mode(typval_T *argvars, typval_T *rettv)
8549 {
8550     char_u	buf[4];
8551 
8552     vim_memset(buf, 0, sizeof(buf));
8553 
8554     if (time_for_testing == 93784)
8555     {
8556 	/* Testing the two-character code. */
8557 	buf[0] = 'x';
8558 	buf[1] = '!';
8559     }
8560 #ifdef FEAT_TERMINAL
8561     else if (term_use_loop())
8562 	buf[0] = 't';
8563 #endif
8564     else if (VIsual_active)
8565     {
8566 	if (VIsual_select)
8567 	    buf[0] = VIsual_mode + 's' - 'v';
8568 	else
8569 	    buf[0] = VIsual_mode;
8570     }
8571     else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8572 		|| State == CONFIRM)
8573     {
8574 	buf[0] = 'r';
8575 	if (State == ASKMORE)
8576 	    buf[1] = 'm';
8577 	else if (State == CONFIRM)
8578 	    buf[1] = '?';
8579     }
8580     else if (State == EXTERNCMD)
8581 	buf[0] = '!';
8582     else if (State & INSERT)
8583     {
8584 	if (State & VREPLACE_FLAG)
8585 	{
8586 	    buf[0] = 'R';
8587 	    buf[1] = 'v';
8588 	}
8589 	else
8590 	{
8591 	    if (State & REPLACE_FLAG)
8592 		buf[0] = 'R';
8593 	    else
8594 		buf[0] = 'i';
8595 #ifdef FEAT_INS_EXPAND
8596 	    if (ins_compl_active())
8597 		buf[1] = 'c';
8598 	    else if (ctrl_x_mode_not_defined_yet())
8599 		buf[1] = 'x';
8600 #endif
8601 	}
8602     }
8603     else if ((State & CMDLINE) || exmode_active)
8604     {
8605 	buf[0] = 'c';
8606 	if (exmode_active == EXMODE_VIM)
8607 	    buf[1] = 'v';
8608 	else if (exmode_active == EXMODE_NORMAL)
8609 	    buf[1] = 'e';
8610     }
8611     else
8612     {
8613 	buf[0] = 'n';
8614 	if (finish_op)
8615 	{
8616 	    buf[1] = 'o';
8617 	    // to be able to detect force-linewise/blockwise/characterwise operations
8618 	    buf[2] = motion_force;
8619 	}
8620 	else if (restart_edit == 'I' || restart_edit == 'R'
8621 							|| restart_edit == 'V')
8622 	{
8623 	    buf[1] = 'i';
8624 	    buf[2] = restart_edit;
8625 	}
8626     }
8627 
8628     /* Clear out the minor mode when the argument is not a non-zero number or
8629      * non-empty string.  */
8630     if (!non_zero_arg(&argvars[0]))
8631 	buf[1] = NUL;
8632 
8633     rettv->vval.v_string = vim_strsave(buf);
8634     rettv->v_type = VAR_STRING;
8635 }
8636 
8637 #if defined(FEAT_MZSCHEME) || defined(PROTO)
8638 /*
8639  * "mzeval()" function
8640  */
8641     static void
8642 f_mzeval(typval_T *argvars, typval_T *rettv)
8643 {
8644     char_u	*str;
8645     char_u	buf[NUMBUFLEN];
8646 
8647     str = tv_get_string_buf(&argvars[0], buf);
8648     do_mzeval(str, rettv);
8649 }
8650 
8651     void
8652 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8653 {
8654     typval_T argvars[3];
8655 
8656     argvars[0].v_type = VAR_STRING;
8657     argvars[0].vval.v_string = name;
8658     copy_tv(args, &argvars[1]);
8659     argvars[2].v_type = VAR_UNKNOWN;
8660     f_call(argvars, rettv);
8661     clear_tv(&argvars[1]);
8662 }
8663 #endif
8664 
8665 /*
8666  * "nextnonblank()" function
8667  */
8668     static void
8669 f_nextnonblank(typval_T *argvars, typval_T *rettv)
8670 {
8671     linenr_T	lnum;
8672 
8673     for (lnum = tv_get_lnum(argvars); ; ++lnum)
8674     {
8675 	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8676 	{
8677 	    lnum = 0;
8678 	    break;
8679 	}
8680 	if (*skipwhite(ml_get(lnum)) != NUL)
8681 	    break;
8682     }
8683     rettv->vval.v_number = lnum;
8684 }
8685 
8686 /*
8687  * "nr2char()" function
8688  */
8689     static void
8690 f_nr2char(typval_T *argvars, typval_T *rettv)
8691 {
8692     char_u	buf[NUMBUFLEN];
8693 
8694     if (has_mbyte)
8695     {
8696 	int	utf8 = 0;
8697 
8698 	if (argvars[1].v_type != VAR_UNKNOWN)
8699 	    utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8700 	if (utf8)
8701 	    buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
8702 	else
8703 	    buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
8704     }
8705     else
8706     {
8707 	buf[0] = (char_u)tv_get_number(&argvars[0]);
8708 	buf[1] = NUL;
8709     }
8710     rettv->v_type = VAR_STRING;
8711     rettv->vval.v_string = vim_strsave(buf);
8712 }
8713 
8714 /*
8715  * "or(expr, expr)" function
8716  */
8717     static void
8718 f_or(typval_T *argvars, typval_T *rettv)
8719 {
8720     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8721 					| tv_get_number_chk(&argvars[1], NULL);
8722 }
8723 
8724 /*
8725  * "pathshorten()" function
8726  */
8727     static void
8728 f_pathshorten(typval_T *argvars, typval_T *rettv)
8729 {
8730     char_u	*p;
8731 
8732     rettv->v_type = VAR_STRING;
8733     p = tv_get_string_chk(&argvars[0]);
8734     if (p == NULL)
8735 	rettv->vval.v_string = NULL;
8736     else
8737     {
8738 	p = vim_strsave(p);
8739 	rettv->vval.v_string = p;
8740 	if (p != NULL)
8741 	    shorten_dir(p);
8742     }
8743 }
8744 
8745 #ifdef FEAT_PERL
8746 /*
8747  * "perleval()" function
8748  */
8749     static void
8750 f_perleval(typval_T *argvars, typval_T *rettv)
8751 {
8752     char_u	*str;
8753     char_u	buf[NUMBUFLEN];
8754 
8755     str = tv_get_string_buf(&argvars[0], buf);
8756     do_perleval(str, rettv);
8757 }
8758 #endif
8759 
8760 #ifdef FEAT_FLOAT
8761 /*
8762  * "pow()" function
8763  */
8764     static void
8765 f_pow(typval_T *argvars, typval_T *rettv)
8766 {
8767     float_T	fx = 0.0, fy = 0.0;
8768 
8769     rettv->v_type = VAR_FLOAT;
8770     if (get_float_arg(argvars, &fx) == OK
8771 				     && get_float_arg(&argvars[1], &fy) == OK)
8772 	rettv->vval.v_float = pow(fx, fy);
8773     else
8774 	rettv->vval.v_float = 0.0;
8775 }
8776 #endif
8777 
8778 /*
8779  * "prevnonblank()" function
8780  */
8781     static void
8782 f_prevnonblank(typval_T *argvars, typval_T *rettv)
8783 {
8784     linenr_T	lnum;
8785 
8786     lnum = tv_get_lnum(argvars);
8787     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8788 	lnum = 0;
8789     else
8790 	while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8791 	    --lnum;
8792     rettv->vval.v_number = lnum;
8793 }
8794 
8795 /* This dummy va_list is here because:
8796  * - passing a NULL pointer doesn't work when va_list isn't a pointer
8797  * - locally in the function results in a "used before set" warning
8798  * - using va_start() to initialize it gives "function with fixed args" error */
8799 static va_list	ap;
8800 
8801 /*
8802  * "printf()" function
8803  */
8804     static void
8805 f_printf(typval_T *argvars, typval_T *rettv)
8806 {
8807     char_u	buf[NUMBUFLEN];
8808     int		len;
8809     char_u	*s;
8810     int		saved_did_emsg = did_emsg;
8811     char	*fmt;
8812 
8813     rettv->v_type = VAR_STRING;
8814     rettv->vval.v_string = NULL;
8815 
8816     /* Get the required length, allocate the buffer and do it for real. */
8817     did_emsg = FALSE;
8818     fmt = (char *)tv_get_string_buf(&argvars[0], buf);
8819     len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
8820     if (!did_emsg)
8821     {
8822 	s = alloc(len + 1);
8823 	if (s != NULL)
8824 	{
8825 	    rettv->vval.v_string = s;
8826 	    (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8827 							      ap, argvars + 1);
8828 	}
8829     }
8830     did_emsg |= saved_did_emsg;
8831 }
8832 
8833 #ifdef FEAT_JOB_CHANNEL
8834 /*
8835  * "prompt_setcallback({buffer}, {callback})" function
8836  */
8837     static void
8838 f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8839 {
8840     buf_T	*buf;
8841     char_u	*callback;
8842     partial_T	*partial;
8843 
8844     if (check_secure())
8845 	return;
8846     buf = tv_get_buf(&argvars[0], FALSE);
8847     if (buf == NULL)
8848 	return;
8849 
8850     callback = get_callback(&argvars[1], &partial);
8851     if (callback == NULL)
8852 	return;
8853 
8854     free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8855     if (partial == NULL)
8856 	buf->b_prompt_callback = vim_strsave(callback);
8857     else
8858 	/* pointer into the partial */
8859 	buf->b_prompt_callback = callback;
8860     buf->b_prompt_partial = partial;
8861 }
8862 
8863 /*
8864  * "prompt_setinterrupt({buffer}, {callback})" function
8865  */
8866     static void
8867 f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8868 {
8869     buf_T	*buf;
8870     char_u	*callback;
8871     partial_T	*partial;
8872 
8873     if (check_secure())
8874 	return;
8875     buf = tv_get_buf(&argvars[0], FALSE);
8876     if (buf == NULL)
8877 	return;
8878 
8879     callback = get_callback(&argvars[1], &partial);
8880     if (callback == NULL)
8881 	return;
8882 
8883     free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8884     if (partial == NULL)
8885 	buf->b_prompt_interrupt = vim_strsave(callback);
8886     else
8887 	/* pointer into the partial */
8888 	buf->b_prompt_interrupt = callback;
8889     buf->b_prompt_int_partial = partial;
8890 }
8891 
8892 /*
8893  * "prompt_setprompt({buffer}, {text})" function
8894  */
8895     static void
8896 f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8897 {
8898     buf_T	*buf;
8899     char_u	*text;
8900 
8901     if (check_secure())
8902 	return;
8903     buf = tv_get_buf(&argvars[0], FALSE);
8904     if (buf == NULL)
8905 	return;
8906 
8907     text = tv_get_string(&argvars[1]);
8908     vim_free(buf->b_prompt_text);
8909     buf->b_prompt_text = vim_strsave(text);
8910 }
8911 #endif
8912 
8913 /*
8914  * "pumvisible()" function
8915  */
8916     static void
8917 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8918 {
8919 #ifdef FEAT_INS_EXPAND
8920     if (pum_visible())
8921 	rettv->vval.v_number = 1;
8922 #endif
8923 }
8924 
8925 #ifdef FEAT_PYTHON3
8926 /*
8927  * "py3eval()" function
8928  */
8929     static void
8930 f_py3eval(typval_T *argvars, typval_T *rettv)
8931 {
8932     char_u	*str;
8933     char_u	buf[NUMBUFLEN];
8934 
8935     if (p_pyx == 0)
8936 	p_pyx = 3;
8937 
8938     str = tv_get_string_buf(&argvars[0], buf);
8939     do_py3eval(str, rettv);
8940 }
8941 #endif
8942 
8943 #ifdef FEAT_PYTHON
8944 /*
8945  * "pyeval()" function
8946  */
8947     static void
8948 f_pyeval(typval_T *argvars, typval_T *rettv)
8949 {
8950     char_u	*str;
8951     char_u	buf[NUMBUFLEN];
8952 
8953     if (p_pyx == 0)
8954 	p_pyx = 2;
8955 
8956     str = tv_get_string_buf(&argvars[0], buf);
8957     do_pyeval(str, rettv);
8958 }
8959 #endif
8960 
8961 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8962 /*
8963  * "pyxeval()" function
8964  */
8965     static void
8966 f_pyxeval(typval_T *argvars, typval_T *rettv)
8967 {
8968 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8969     init_pyxversion();
8970     if (p_pyx == 2)
8971 	f_pyeval(argvars, rettv);
8972     else
8973 	f_py3eval(argvars, rettv);
8974 # elif defined(FEAT_PYTHON)
8975     f_pyeval(argvars, rettv);
8976 # elif defined(FEAT_PYTHON3)
8977     f_py3eval(argvars, rettv);
8978 # endif
8979 }
8980 #endif
8981 
8982 /*
8983  * "range()" function
8984  */
8985     static void
8986 f_range(typval_T *argvars, typval_T *rettv)
8987 {
8988     varnumber_T	start;
8989     varnumber_T	end;
8990     varnumber_T	stride = 1;
8991     varnumber_T	i;
8992     int		error = FALSE;
8993 
8994     start = tv_get_number_chk(&argvars[0], &error);
8995     if (argvars[1].v_type == VAR_UNKNOWN)
8996     {
8997 	end = start - 1;
8998 	start = 0;
8999     }
9000     else
9001     {
9002 	end = tv_get_number_chk(&argvars[1], &error);
9003 	if (argvars[2].v_type != VAR_UNKNOWN)
9004 	    stride = tv_get_number_chk(&argvars[2], &error);
9005     }
9006 
9007     if (error)
9008 	return;		/* type error; errmsg already given */
9009     if (stride == 0)
9010 	emsg(_("E726: Stride is zero"));
9011     else if (stride > 0 ? end + 1 < start : end - 1 > start)
9012 	emsg(_("E727: Start past end"));
9013     else
9014     {
9015 	if (rettv_list_alloc(rettv) == OK)
9016 	    for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9017 		if (list_append_number(rettv->vval.v_list,
9018 						      (varnumber_T)i) == FAIL)
9019 		    break;
9020     }
9021 }
9022 
9023 /*
9024  * "readfile()" function
9025  */
9026     static void
9027 f_readfile(typval_T *argvars, typval_T *rettv)
9028 {
9029     int		binary = FALSE;
9030     int		blob = FALSE;
9031     int		failed = FALSE;
9032     char_u	*fname;
9033     FILE	*fd;
9034     char_u	buf[(IOSIZE/256)*256];	/* rounded to avoid odd + 1 */
9035     int		io_size = sizeof(buf);
9036     int		readlen;		/* size of last fread() */
9037     char_u	*prev	 = NULL;	/* previously read bytes, if any */
9038     long	prevlen  = 0;		/* length of data in prev */
9039     long	prevsize = 0;		/* size of prev buffer */
9040     long	maxline  = MAXLNUM;
9041     long	cnt	 = 0;
9042     char_u	*p;			/* position in buf */
9043     char_u	*start;			/* start of current line */
9044 
9045     if (argvars[1].v_type != VAR_UNKNOWN)
9046     {
9047 	if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
9048 	    binary = TRUE;
9049 	if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9050 	    blob = TRUE;
9051 
9052 	if (argvars[2].v_type != VAR_UNKNOWN)
9053 	    maxline = (long)tv_get_number(&argvars[2]);
9054     }
9055 
9056     if (blob)
9057     {
9058 	if (rettv_blob_alloc(rettv) == FAIL)
9059 	    return;
9060     }
9061     else
9062     {
9063 	if (rettv_list_alloc(rettv) == FAIL)
9064 	    return;
9065     }
9066 
9067     /* Always open the file in binary mode, library functions have a mind of
9068      * their own about CR-LF conversion. */
9069     fname = tv_get_string(&argvars[0]);
9070     if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9071     {
9072 	semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
9073 	return;
9074     }
9075 
9076     if (blob)
9077     {
9078 	if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9079 	{
9080 	    emsg("cannot read file");
9081 	    blob_free(rettv->vval.v_blob);
9082 	}
9083 	fclose(fd);
9084 	return;
9085     }
9086 
9087     while (cnt < maxline || maxline < 0)
9088     {
9089 	readlen = (int)fread(buf, 1, io_size, fd);
9090 
9091 	/* This for loop processes what was read, but is also entered at end
9092 	 * of file so that either:
9093 	 * - an incomplete line gets written
9094 	 * - a "binary" file gets an empty line at the end if it ends in a
9095 	 *   newline.  */
9096 	for (p = buf, start = buf;
9097 		p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9098 		++p)
9099 	{
9100 	    if (*p == '\n' || readlen <= 0)
9101 	    {
9102 		listitem_T  *li;
9103 		char_u	    *s	= NULL;
9104 		long_u	    len = p - start;
9105 
9106 		/* Finished a line.  Remove CRs before NL. */
9107 		if (readlen > 0 && !binary)
9108 		{
9109 		    while (len > 0 && start[len - 1] == '\r')
9110 			--len;
9111 		    /* removal may cross back to the "prev" string */
9112 		    if (len == 0)
9113 			while (prevlen > 0 && prev[prevlen - 1] == '\r')
9114 			    --prevlen;
9115 		}
9116 		if (prevlen == 0)
9117 		    s = vim_strnsave(start, (int)len);
9118 		else
9119 		{
9120 		    /* Change "prev" buffer to be the right size.  This way
9121 		     * the bytes are only copied once, and very long lines are
9122 		     * allocated only once.  */
9123 		    if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9124 		    {
9125 			mch_memmove(s + prevlen, start, len);
9126 			s[prevlen + len] = NUL;
9127 			prev = NULL; /* the list will own the string */
9128 			prevlen = prevsize = 0;
9129 		    }
9130 		}
9131 		if (s == NULL)
9132 		{
9133 		    do_outofmem_msg((long_u) prevlen + len + 1);
9134 		    failed = TRUE;
9135 		    break;
9136 		}
9137 
9138 		if ((li = listitem_alloc()) == NULL)
9139 		{
9140 		    vim_free(s);
9141 		    failed = TRUE;
9142 		    break;
9143 		}
9144 		li->li_tv.v_type = VAR_STRING;
9145 		li->li_tv.v_lock = 0;
9146 		li->li_tv.vval.v_string = s;
9147 		list_append(rettv->vval.v_list, li);
9148 
9149 		start = p + 1; /* step over newline */
9150 		if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9151 		    break;
9152 	    }
9153 	    else if (*p == NUL)
9154 		*p = '\n';
9155 	    /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF.  Do this
9156 	     * when finding the BF and check the previous two bytes. */
9157 	    else if (*p == 0xbf && enc_utf8 && !binary)
9158 	    {
9159 		/* Find the two bytes before the 0xbf.	If p is at buf, or buf
9160 		 * + 1, these may be in the "prev" string. */
9161 		char_u back1 = p >= buf + 1 ? p[-1]
9162 				     : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9163 		char_u back2 = p >= buf + 2 ? p[-2]
9164 			  : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9165 			  : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9166 
9167 		if (back2 == 0xef && back1 == 0xbb)
9168 		{
9169 		    char_u *dest = p - 2;
9170 
9171 		    /* Usually a BOM is at the beginning of a file, and so at
9172 		     * the beginning of a line; then we can just step over it.
9173 		     */
9174 		    if (start == dest)
9175 			start = p + 1;
9176 		    else
9177 		    {
9178 			/* have to shuffle buf to close gap */
9179 			int adjust_prevlen = 0;
9180 
9181 			if (dest < buf)
9182 			{
9183 			    adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9184 			    dest = buf;
9185 			}
9186 			if (readlen > p - buf + 1)
9187 			    mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9188 			readlen -= 3 - adjust_prevlen;
9189 			prevlen -= adjust_prevlen;
9190 			p = dest - 1;
9191 		    }
9192 		}
9193 	    }
9194 	} /* for */
9195 
9196 	if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9197 	    break;
9198 	if (start < p)
9199 	{
9200 	    /* There's part of a line in buf, store it in "prev". */
9201 	    if (p - start + prevlen >= prevsize)
9202 	    {
9203 		/* need bigger "prev" buffer */
9204 		char_u *newprev;
9205 
9206 		/* A common use case is ordinary text files and "prev" gets a
9207 		 * fragment of a line, so the first allocation is made
9208 		 * small, to avoid repeatedly 'allocing' large and
9209 		 * 'reallocing' small. */
9210 		if (prevsize == 0)
9211 		    prevsize = (long)(p - start);
9212 		else
9213 		{
9214 		    long grow50pc = (prevsize * 3) / 2;
9215 		    long growmin  = (long)((p - start) * 2 + prevlen);
9216 		    prevsize = grow50pc > growmin ? grow50pc : growmin;
9217 		}
9218 		newprev = prev == NULL ? alloc(prevsize)
9219 						: vim_realloc(prev, prevsize);
9220 		if (newprev == NULL)
9221 		{
9222 		    do_outofmem_msg((long_u)prevsize);
9223 		    failed = TRUE;
9224 		    break;
9225 		}
9226 		prev = newprev;
9227 	    }
9228 	    /* Add the line part to end of "prev". */
9229 	    mch_memmove(prev + prevlen, start, p - start);
9230 	    prevlen += (long)(p - start);
9231 	}
9232     } /* while */
9233 
9234     /*
9235      * For a negative line count use only the lines at the end of the file,
9236      * free the rest.
9237      */
9238     if (!failed && maxline < 0)
9239 	while (cnt > -maxline)
9240 	{
9241 	    listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9242 	    --cnt;
9243 	}
9244 
9245     if (failed)
9246     {
9247 	list_free(rettv->vval.v_list);
9248 	/* readfile doc says an empty list is returned on error */
9249 	rettv->vval.v_list = list_alloc();
9250     }
9251 
9252     vim_free(prev);
9253     fclose(fd);
9254 }
9255 
9256     static void
9257 return_register(int regname, typval_T *rettv)
9258 {
9259     char_u buf[2] = {0, 0};
9260 
9261     buf[0] = (char_u)regname;
9262     rettv->v_type = VAR_STRING;
9263     rettv->vval.v_string = vim_strsave(buf);
9264 }
9265 
9266 /*
9267  * "reg_executing()" function
9268  */
9269     static void
9270 f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9271 {
9272     return_register(reg_executing, rettv);
9273 }
9274 
9275 /*
9276  * "reg_recording()" function
9277  */
9278     static void
9279 f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9280 {
9281     return_register(reg_recording, rettv);
9282 }
9283 
9284 #if defined(FEAT_RELTIME)
9285 /*
9286  * Convert a List to proftime_T.
9287  * Return FAIL when there is something wrong.
9288  */
9289     static int
9290 list2proftime(typval_T *arg, proftime_T *tm)
9291 {
9292     long	n1, n2;
9293     int	error = FALSE;
9294 
9295     if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9296 					     || arg->vval.v_list->lv_len != 2)
9297 	return FAIL;
9298     n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9299     n2 = list_find_nr(arg->vval.v_list, 1L, &error);
9300 # ifdef WIN3264
9301     tm->HighPart = n1;
9302     tm->LowPart = n2;
9303 # else
9304     tm->tv_sec = n1;
9305     tm->tv_usec = n2;
9306 # endif
9307     return error ? FAIL : OK;
9308 }
9309 #endif /* FEAT_RELTIME */
9310 
9311 /*
9312  * "reltime()" function
9313  */
9314     static void
9315 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9316 {
9317 #ifdef FEAT_RELTIME
9318     proftime_T	res;
9319     proftime_T	start;
9320 
9321     if (argvars[0].v_type == VAR_UNKNOWN)
9322     {
9323 	/* No arguments: get current time. */
9324 	profile_start(&res);
9325     }
9326     else if (argvars[1].v_type == VAR_UNKNOWN)
9327     {
9328 	if (list2proftime(&argvars[0], &res) == FAIL)
9329 	    return;
9330 	profile_end(&res);
9331     }
9332     else
9333     {
9334 	/* Two arguments: compute the difference. */
9335 	if (list2proftime(&argvars[0], &start) == FAIL
9336 		|| list2proftime(&argvars[1], &res) == FAIL)
9337 	    return;
9338 	profile_sub(&res, &start);
9339     }
9340 
9341     if (rettv_list_alloc(rettv) == OK)
9342     {
9343 	long	n1, n2;
9344 
9345 # ifdef WIN3264
9346 	n1 = res.HighPart;
9347 	n2 = res.LowPart;
9348 # else
9349 	n1 = res.tv_sec;
9350 	n2 = res.tv_usec;
9351 # endif
9352 	list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9353 	list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9354     }
9355 #endif
9356 }
9357 
9358 #ifdef FEAT_FLOAT
9359 /*
9360  * "reltimefloat()" function
9361  */
9362     static void
9363 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9364 {
9365 # ifdef FEAT_RELTIME
9366     proftime_T	tm;
9367 # endif
9368 
9369     rettv->v_type = VAR_FLOAT;
9370     rettv->vval.v_float = 0;
9371 # ifdef FEAT_RELTIME
9372     if (list2proftime(&argvars[0], &tm) == OK)
9373 	rettv->vval.v_float = profile_float(&tm);
9374 # endif
9375 }
9376 #endif
9377 
9378 /*
9379  * "reltimestr()" function
9380  */
9381     static void
9382 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9383 {
9384 #ifdef FEAT_RELTIME
9385     proftime_T	tm;
9386 #endif
9387 
9388     rettv->v_type = VAR_STRING;
9389     rettv->vval.v_string = NULL;
9390 #ifdef FEAT_RELTIME
9391     if (list2proftime(&argvars[0], &tm) == OK)
9392 	rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9393 #endif
9394 }
9395 
9396 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
9397     static void
9398 make_connection(void)
9399 {
9400     if (X_DISPLAY == NULL
9401 # ifdef FEAT_GUI
9402 	    && !gui.in_use
9403 # endif
9404 	    )
9405     {
9406 	x_force_connect = TRUE;
9407 	setup_term_clip();
9408 	x_force_connect = FALSE;
9409     }
9410 }
9411 
9412     static int
9413 check_connection(void)
9414 {
9415     make_connection();
9416     if (X_DISPLAY == NULL)
9417     {
9418 	emsg(_("E240: No connection to the X server"));
9419 	return FAIL;
9420     }
9421     return OK;
9422 }
9423 #endif
9424 
9425 #ifdef FEAT_CLIENTSERVER
9426     static void
9427 remote_common(typval_T *argvars, typval_T *rettv, int expr)
9428 {
9429     char_u	*server_name;
9430     char_u	*keys;
9431     char_u	*r = NULL;
9432     char_u	buf[NUMBUFLEN];
9433     int		timeout = 0;
9434 # ifdef WIN32
9435     HWND	w;
9436 # else
9437     Window	w;
9438 # endif
9439 
9440     if (check_restricted() || check_secure())
9441 	return;
9442 
9443 # ifdef FEAT_X11
9444     if (check_connection() == FAIL)
9445 	return;
9446 # endif
9447     if (argvars[2].v_type != VAR_UNKNOWN
9448 	    && argvars[3].v_type != VAR_UNKNOWN)
9449 	timeout = tv_get_number(&argvars[3]);
9450 
9451     server_name = tv_get_string_chk(&argvars[0]);
9452     if (server_name == NULL)
9453 	return;		/* type error; errmsg already given */
9454     keys = tv_get_string_buf(&argvars[1], buf);
9455 # ifdef WIN32
9456     if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
9457 # else
9458     if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9459 								  0, TRUE) < 0)
9460 # endif
9461     {
9462 	if (r != NULL)
9463 	{
9464 	    emsg((char *)r);	// sending worked but evaluation failed
9465 	    vim_free(r);
9466 	}
9467 	else
9468 	    semsg(_("E241: Unable to send to %s"), server_name);
9469 	return;
9470     }
9471 
9472     rettv->vval.v_string = r;
9473 
9474     if (argvars[2].v_type != VAR_UNKNOWN)
9475     {
9476 	dictitem_T	v;
9477 	char_u		str[30];
9478 	char_u		*idvar;
9479 
9480 	idvar = tv_get_string_chk(&argvars[2]);
9481 	if (idvar != NULL && *idvar != NUL)
9482 	{
9483 	    sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9484 	    v.di_tv.v_type = VAR_STRING;
9485 	    v.di_tv.vval.v_string = vim_strsave(str);
9486 	    set_var(idvar, &v.di_tv, FALSE);
9487 	    vim_free(v.di_tv.vval.v_string);
9488 	}
9489     }
9490 }
9491 #endif
9492 
9493 /*
9494  * "remote_expr()" function
9495  */
9496     static void
9497 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9498 {
9499     rettv->v_type = VAR_STRING;
9500     rettv->vval.v_string = NULL;
9501 #ifdef FEAT_CLIENTSERVER
9502     remote_common(argvars, rettv, TRUE);
9503 #endif
9504 }
9505 
9506 /*
9507  * "remote_foreground()" function
9508  */
9509     static void
9510 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9511 {
9512 #ifdef FEAT_CLIENTSERVER
9513 # ifdef WIN32
9514     /* On Win32 it's done in this application. */
9515     {
9516 	char_u	*server_name = tv_get_string_chk(&argvars[0]);
9517 
9518 	if (server_name != NULL)
9519 	    serverForeground(server_name);
9520     }
9521 # else
9522     /* Send a foreground() expression to the server. */
9523     argvars[1].v_type = VAR_STRING;
9524     argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9525     argvars[2].v_type = VAR_UNKNOWN;
9526     rettv->v_type = VAR_STRING;
9527     rettv->vval.v_string = NULL;
9528     remote_common(argvars, rettv, TRUE);
9529     vim_free(argvars[1].vval.v_string);
9530 # endif
9531 #endif
9532 }
9533 
9534     static void
9535 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9536 {
9537 #ifdef FEAT_CLIENTSERVER
9538     dictitem_T	v;
9539     char_u	*s = NULL;
9540 # ifdef WIN32
9541     long_u	n = 0;
9542 # endif
9543     char_u	*serverid;
9544 
9545     if (check_restricted() || check_secure())
9546     {
9547 	rettv->vval.v_number = -1;
9548 	return;
9549     }
9550     serverid = tv_get_string_chk(&argvars[0]);
9551     if (serverid == NULL)
9552     {
9553 	rettv->vval.v_number = -1;
9554 	return;		/* type error; errmsg already given */
9555     }
9556 # ifdef WIN32
9557     sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9558     if (n == 0)
9559 	rettv->vval.v_number = -1;
9560     else
9561     {
9562 	s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
9563 	rettv->vval.v_number = (s != NULL);
9564     }
9565 # else
9566     if (check_connection() == FAIL)
9567 	return;
9568 
9569     rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9570 						serverStrToWin(serverid), &s);
9571 # endif
9572 
9573     if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9574     {
9575 	char_u		*retvar;
9576 
9577 	v.di_tv.v_type = VAR_STRING;
9578 	v.di_tv.vval.v_string = vim_strsave(s);
9579 	retvar = tv_get_string_chk(&argvars[1]);
9580 	if (retvar != NULL)
9581 	    set_var(retvar, &v.di_tv, FALSE);
9582 	vim_free(v.di_tv.vval.v_string);
9583     }
9584 #else
9585     rettv->vval.v_number = -1;
9586 #endif
9587 }
9588 
9589     static void
9590 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9591 {
9592     char_u	*r = NULL;
9593 
9594 #ifdef FEAT_CLIENTSERVER
9595     char_u	*serverid = tv_get_string_chk(&argvars[0]);
9596 
9597     if (serverid != NULL && !check_restricted() && !check_secure())
9598     {
9599 	int timeout = 0;
9600 # ifdef WIN32
9601 	/* The server's HWND is encoded in the 'id' parameter */
9602 	long_u		n = 0;
9603 # endif
9604 
9605 	if (argvars[1].v_type != VAR_UNKNOWN)
9606 	    timeout = tv_get_number(&argvars[1]);
9607 
9608 # ifdef WIN32
9609 	sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9610 	if (n != 0)
9611 	    r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
9612 	if (r == NULL)
9613 # else
9614 	if (check_connection() == FAIL
9615 		|| serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9616 						       &r, FALSE, timeout) < 0)
9617 # endif
9618 	    emsg(_("E277: Unable to read a server reply"));
9619     }
9620 #endif
9621     rettv->v_type = VAR_STRING;
9622     rettv->vval.v_string = r;
9623 }
9624 
9625 /*
9626  * "remote_send()" function
9627  */
9628     static void
9629 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9630 {
9631     rettv->v_type = VAR_STRING;
9632     rettv->vval.v_string = NULL;
9633 #ifdef FEAT_CLIENTSERVER
9634     remote_common(argvars, rettv, FALSE);
9635 #endif
9636 }
9637 
9638 /*
9639  * "remote_startserver()" function
9640  */
9641     static void
9642 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9643 {
9644 #ifdef FEAT_CLIENTSERVER
9645     char_u	*server = tv_get_string_chk(&argvars[0]);
9646 
9647     if (server == NULL)
9648 	return;		/* type error; errmsg already given */
9649     if (serverName != NULL)
9650 	emsg(_("E941: already started a server"));
9651     else
9652     {
9653 # ifdef FEAT_X11
9654 	if (check_connection() == OK)
9655 	    serverRegisterName(X_DISPLAY, server);
9656 # else
9657 	serverSetName(server);
9658 # endif
9659     }
9660 #else
9661     emsg(_("E942: +clientserver feature not available"));
9662 #endif
9663 }
9664 
9665 /*
9666  * "remove()" function
9667  */
9668     static void
9669 f_remove(typval_T *argvars, typval_T *rettv)
9670 {
9671     list_T	*l;
9672     listitem_T	*item, *item2;
9673     listitem_T	*li;
9674     long	idx;
9675     long	end;
9676     char_u	*key;
9677     dict_T	*d;
9678     dictitem_T	*di;
9679     char_u	*arg_errmsg = (char_u *)N_("remove() argument");
9680     int		error = FALSE;
9681 
9682     if (argvars[0].v_type == VAR_DICT)
9683     {
9684 	if (argvars[2].v_type != VAR_UNKNOWN)
9685 	    semsg(_(e_toomanyarg), "remove()");
9686 	else if ((d = argvars[0].vval.v_dict) != NULL
9687 		&& !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
9688 	{
9689 	    key = tv_get_string_chk(&argvars[1]);
9690 	    if (key != NULL)
9691 	    {
9692 		di = dict_find(d, key, -1);
9693 		if (di == NULL)
9694 		    semsg(_(e_dictkey), key);
9695 		else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9696 			    && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9697 		{
9698 		    *rettv = di->di_tv;
9699 		    init_tv(&di->di_tv);
9700 		    dictitem_remove(d, di);
9701 		}
9702 	    }
9703 	}
9704     }
9705     else if (argvars[0].v_type == VAR_BLOB)
9706     {
9707 	idx = (long)tv_get_number_chk(&argvars[1], &error);
9708 	if (!error)
9709 	{
9710 	    blob_T  *b = argvars[0].vval.v_blob;
9711 	    int	    len = blob_len(b);
9712 	    char_u  *p;
9713 
9714 	    if (idx < 0)
9715 		// count from the end
9716 		idx = len + idx;
9717 	    if (idx < 0 || idx >= len)
9718 	    {
9719 		semsg(_(e_blobidx), idx);
9720 		return;
9721 	    }
9722 	    if (argvars[2].v_type == VAR_UNKNOWN)
9723 	    {
9724 		// Remove one item, return its value.
9725 		p = (char_u *)b->bv_ga.ga_data;
9726 		rettv->vval.v_number = (varnumber_T) *(p + idx);
9727 		mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9728 		--b->bv_ga.ga_len;
9729 	    }
9730 	    else
9731 	    {
9732 		blob_T  *blob;
9733 
9734 		// Remove range of items, return list with values.
9735 		end = (long)tv_get_number_chk(&argvars[2], &error);
9736 		if (error)
9737 		    return;
9738 		if (end < 0)
9739 		    // count from the end
9740 		    end = len + end;
9741 		if (end >= len || idx > end)
9742 		{
9743 		    semsg(_(e_blobidx), end);
9744 		    return;
9745 		}
9746 		blob = blob_alloc();
9747 		if (blob == NULL)
9748 		    return;
9749 		blob->bv_ga.ga_len = end - idx + 1;
9750 		if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9751 		{
9752 		    vim_free(blob);
9753 		    return;
9754 		}
9755 		p = (char_u *)b->bv_ga.ga_data;
9756 		mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9757 						      (size_t)(end - idx + 1));
9758 		++blob->bv_refcount;
9759 		rettv->v_type = VAR_BLOB;
9760 		rettv->vval.v_blob = blob;
9761 
9762 		mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9763 		b->bv_ga.ga_len -= end - idx + 1;
9764 	    }
9765 	}
9766     }
9767     else if (argvars[0].v_type != VAR_LIST)
9768 	semsg(_(e_listdictblobarg), "remove()");
9769     else if ((l = argvars[0].vval.v_list) != NULL
9770 			       && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
9771     {
9772 	idx = (long)tv_get_number_chk(&argvars[1], &error);
9773 	if (error)
9774 	    ;		// type error: do nothing, errmsg already given
9775 	else if ((item = list_find(l, idx)) == NULL)
9776 	    semsg(_(e_listidx), idx);
9777 	else
9778 	{
9779 	    if (argvars[2].v_type == VAR_UNKNOWN)
9780 	    {
9781 		/* Remove one item, return its value. */
9782 		vimlist_remove(l, item, item);
9783 		*rettv = item->li_tv;
9784 		vim_free(item);
9785 	    }
9786 	    else
9787 	    {
9788 		// Remove range of items, return list with values.
9789 		end = (long)tv_get_number_chk(&argvars[2], &error);
9790 		if (error)
9791 		    ;		// type error: do nothing
9792 		else if ((item2 = list_find(l, end)) == NULL)
9793 		    semsg(_(e_listidx), end);
9794 		else
9795 		{
9796 		    int	    cnt = 0;
9797 
9798 		    for (li = item; li != NULL; li = li->li_next)
9799 		    {
9800 			++cnt;
9801 			if (li == item2)
9802 			    break;
9803 		    }
9804 		    if (li == NULL)  /* didn't find "item2" after "item" */
9805 			emsg(_(e_invrange));
9806 		    else
9807 		    {
9808 			vimlist_remove(l, item, item2);
9809 			if (rettv_list_alloc(rettv) == OK)
9810 			{
9811 			    l = rettv->vval.v_list;
9812 			    l->lv_first = item;
9813 			    l->lv_last = item2;
9814 			    item->li_prev = NULL;
9815 			    item2->li_next = NULL;
9816 			    l->lv_len = cnt;
9817 			}
9818 		    }
9819 		}
9820 	    }
9821 	}
9822     }
9823 }
9824 
9825 /*
9826  * "rename({from}, {to})" function
9827  */
9828     static void
9829 f_rename(typval_T *argvars, typval_T *rettv)
9830 {
9831     char_u	buf[NUMBUFLEN];
9832 
9833     if (check_restricted() || check_secure())
9834 	rettv->vval.v_number = -1;
9835     else
9836 	rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9837 				      tv_get_string_buf(&argvars[1], buf));
9838 }
9839 
9840 /*
9841  * "repeat()" function
9842  */
9843     static void
9844 f_repeat(typval_T *argvars, typval_T *rettv)
9845 {
9846     char_u	*p;
9847     int		n;
9848     int		slen;
9849     int		len;
9850     char_u	*r;
9851     int		i;
9852 
9853     n = (int)tv_get_number(&argvars[1]);
9854     if (argvars[0].v_type == VAR_LIST)
9855     {
9856 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9857 	    while (n-- > 0)
9858 		if (list_extend(rettv->vval.v_list,
9859 					argvars[0].vval.v_list, NULL) == FAIL)
9860 		    break;
9861     }
9862     else
9863     {
9864 	p = tv_get_string(&argvars[0]);
9865 	rettv->v_type = VAR_STRING;
9866 	rettv->vval.v_string = NULL;
9867 
9868 	slen = (int)STRLEN(p);
9869 	len = slen * n;
9870 	if (len <= 0)
9871 	    return;
9872 
9873 	r = alloc(len + 1);
9874 	if (r != NULL)
9875 	{
9876 	    for (i = 0; i < n; i++)
9877 		mch_memmove(r + i * slen, p, (size_t)slen);
9878 	    r[len] = NUL;
9879 	}
9880 
9881 	rettv->vval.v_string = r;
9882     }
9883 }
9884 
9885 /*
9886  * "resolve()" function
9887  */
9888     static void
9889 f_resolve(typval_T *argvars, typval_T *rettv)
9890 {
9891     char_u	*p;
9892 #ifdef HAVE_READLINK
9893     char_u	*buf = NULL;
9894 #endif
9895 
9896     p = tv_get_string(&argvars[0]);
9897 #ifdef FEAT_SHORTCUT
9898     {
9899 	char_u	*v = NULL;
9900 
9901 	v = mch_resolve_shortcut(p);
9902 	if (v != NULL)
9903 	    rettv->vval.v_string = v;
9904 	else
9905 	    rettv->vval.v_string = vim_strsave(p);
9906     }
9907 #else
9908 # ifdef HAVE_READLINK
9909     {
9910 	char_u	*cpy;
9911 	int	len;
9912 	char_u	*remain = NULL;
9913 	char_u	*q;
9914 	int	is_relative_to_current = FALSE;
9915 	int	has_trailing_pathsep = FALSE;
9916 	int	limit = 100;
9917 
9918 	p = vim_strsave(p);
9919 
9920 	if (p[0] == '.' && (vim_ispathsep(p[1])
9921 				   || (p[1] == '.' && (vim_ispathsep(p[2])))))
9922 	    is_relative_to_current = TRUE;
9923 
9924 	len = STRLEN(p);
9925 	if (len > 0 && after_pathsep(p, p + len))
9926 	{
9927 	    has_trailing_pathsep = TRUE;
9928 	    p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9929 	}
9930 
9931 	q = getnextcomp(p);
9932 	if (*q != NUL)
9933 	{
9934 	    /* Separate the first path component in "p", and keep the
9935 	     * remainder (beginning with the path separator). */
9936 	    remain = vim_strsave(q - 1);
9937 	    q[-1] = NUL;
9938 	}
9939 
9940 	buf = alloc(MAXPATHL + 1);
9941 	if (buf == NULL)
9942 	    goto fail;
9943 
9944 	for (;;)
9945 	{
9946 	    for (;;)
9947 	    {
9948 		len = readlink((char *)p, (char *)buf, MAXPATHL);
9949 		if (len <= 0)
9950 		    break;
9951 		buf[len] = NUL;
9952 
9953 		if (limit-- == 0)
9954 		{
9955 		    vim_free(p);
9956 		    vim_free(remain);
9957 		    emsg(_("E655: Too many symbolic links (cycle?)"));
9958 		    rettv->vval.v_string = NULL;
9959 		    goto fail;
9960 		}
9961 
9962 		/* Ensure that the result will have a trailing path separator
9963 		 * if the argument has one. */
9964 		if (remain == NULL && has_trailing_pathsep)
9965 		    add_pathsep(buf);
9966 
9967 		/* Separate the first path component in the link value and
9968 		 * concatenate the remainders. */
9969 		q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9970 		if (*q != NUL)
9971 		{
9972 		    if (remain == NULL)
9973 			remain = vim_strsave(q - 1);
9974 		    else
9975 		    {
9976 			cpy = concat_str(q - 1, remain);
9977 			if (cpy != NULL)
9978 			{
9979 			    vim_free(remain);
9980 			    remain = cpy;
9981 			}
9982 		    }
9983 		    q[-1] = NUL;
9984 		}
9985 
9986 		q = gettail(p);
9987 		if (q > p && *q == NUL)
9988 		{
9989 		    /* Ignore trailing path separator. */
9990 		    q[-1] = NUL;
9991 		    q = gettail(p);
9992 		}
9993 		if (q > p && !mch_isFullName(buf))
9994 		{
9995 		    /* symlink is relative to directory of argument */
9996 		    cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9997 		    if (cpy != NULL)
9998 		    {
9999 			STRCPY(cpy, p);
10000 			STRCPY(gettail(cpy), buf);
10001 			vim_free(p);
10002 			p = cpy;
10003 		    }
10004 		}
10005 		else
10006 		{
10007 		    vim_free(p);
10008 		    p = vim_strsave(buf);
10009 		}
10010 	    }
10011 
10012 	    if (remain == NULL)
10013 		break;
10014 
10015 	    /* Append the first path component of "remain" to "p". */
10016 	    q = getnextcomp(remain + 1);
10017 	    len = q - remain - (*q != NUL);
10018 	    cpy = vim_strnsave(p, STRLEN(p) + len);
10019 	    if (cpy != NULL)
10020 	    {
10021 		STRNCAT(cpy, remain, len);
10022 		vim_free(p);
10023 		p = cpy;
10024 	    }
10025 	    /* Shorten "remain". */
10026 	    if (*q != NUL)
10027 		STRMOVE(remain, q - 1);
10028 	    else
10029 		VIM_CLEAR(remain);
10030 	}
10031 
10032 	/* If the result is a relative path name, make it explicitly relative to
10033 	 * the current directory if and only if the argument had this form. */
10034 	if (!vim_ispathsep(*p))
10035 	{
10036 	    if (is_relative_to_current
10037 		    && *p != NUL
10038 		    && !(p[0] == '.'
10039 			&& (p[1] == NUL
10040 			    || vim_ispathsep(p[1])
10041 			    || (p[1] == '.'
10042 				&& (p[2] == NUL
10043 				    || vim_ispathsep(p[2]))))))
10044 	    {
10045 		/* Prepend "./". */
10046 		cpy = concat_str((char_u *)"./", p);
10047 		if (cpy != NULL)
10048 		{
10049 		    vim_free(p);
10050 		    p = cpy;
10051 		}
10052 	    }
10053 	    else if (!is_relative_to_current)
10054 	    {
10055 		/* Strip leading "./". */
10056 		q = p;
10057 		while (q[0] == '.' && vim_ispathsep(q[1]))
10058 		    q += 2;
10059 		if (q > p)
10060 		    STRMOVE(p, p + 2);
10061 	    }
10062 	}
10063 
10064 	/* Ensure that the result will have no trailing path separator
10065 	 * if the argument had none.  But keep "/" or "//". */
10066 	if (!has_trailing_pathsep)
10067 	{
10068 	    q = p + STRLEN(p);
10069 	    if (after_pathsep(p, q))
10070 		*gettail_sep(p) = NUL;
10071 	}
10072 
10073 	rettv->vval.v_string = p;
10074     }
10075 # else
10076     rettv->vval.v_string = vim_strsave(p);
10077 # endif
10078 #endif
10079 
10080     simplify_filename(rettv->vval.v_string);
10081 
10082 #ifdef HAVE_READLINK
10083 fail:
10084     vim_free(buf);
10085 #endif
10086     rettv->v_type = VAR_STRING;
10087 }
10088 
10089 /*
10090  * "reverse({list})" function
10091  */
10092     static void
10093 f_reverse(typval_T *argvars, typval_T *rettv)
10094 {
10095     list_T	*l;
10096     listitem_T	*li, *ni;
10097 
10098     if (argvars[0].v_type == VAR_BLOB)
10099     {
10100 	blob_T	*b = argvars[0].vval.v_blob;
10101 	int	i, len = blob_len(b);
10102 
10103 	for (i = 0; i < len / 2; i++)
10104 	{
10105 	    int tmp = blob_get(b, i);
10106 
10107 	    blob_set(b, i, blob_get(b, len - i - 1));
10108 	    blob_set(b, len - i - 1, tmp);
10109 	}
10110 	rettv_blob_set(rettv, b);
10111 	return;
10112     }
10113 
10114     if (argvars[0].v_type != VAR_LIST)
10115 	semsg(_(e_listblobarg), "reverse()");
10116     else if ((l = argvars[0].vval.v_list) != NULL
10117 	    && !tv_check_lock(l->lv_lock,
10118 				    (char_u *)N_("reverse() argument"), TRUE))
10119     {
10120 	li = l->lv_last;
10121 	l->lv_first = l->lv_last = NULL;
10122 	l->lv_len = 0;
10123 	while (li != NULL)
10124 	{
10125 	    ni = li->li_prev;
10126 	    list_append(l, li);
10127 	    li = ni;
10128 	}
10129 	rettv_list_set(rettv, l);
10130 	l->lv_idx = l->lv_len - l->lv_idx - 1;
10131     }
10132 }
10133 
10134 #define SP_NOMOVE	0x01	    /* don't move cursor */
10135 #define SP_REPEAT	0x02	    /* repeat to find outer pair */
10136 #define SP_RETCOUNT	0x04	    /* return matchcount */
10137 #define SP_SETPCMARK	0x08	    /* set previous context mark */
10138 #define SP_START	0x10	    /* accept match at start position */
10139 #define SP_SUBPAT	0x20	    /* return nr of matching sub-pattern */
10140 #define SP_END		0x40	    /* leave cursor at end of match */
10141 #define SP_COLUMN	0x80	    /* start at cursor column */
10142 
10143 /*
10144  * Get flags for a search function.
10145  * Possibly sets "p_ws".
10146  * Returns BACKWARD, FORWARD or zero (for an error).
10147  */
10148     static int
10149 get_search_arg(typval_T *varp, int *flagsp)
10150 {
10151     int		dir = FORWARD;
10152     char_u	*flags;
10153     char_u	nbuf[NUMBUFLEN];
10154     int		mask;
10155 
10156     if (varp->v_type != VAR_UNKNOWN)
10157     {
10158 	flags = tv_get_string_buf_chk(varp, nbuf);
10159 	if (flags == NULL)
10160 	    return 0;		/* type error; errmsg already given */
10161 	while (*flags != NUL)
10162 	{
10163 	    switch (*flags)
10164 	    {
10165 		case 'b': dir = BACKWARD; break;
10166 		case 'w': p_ws = TRUE; break;
10167 		case 'W': p_ws = FALSE; break;
10168 		default:  mask = 0;
10169 			  if (flagsp != NULL)
10170 			     switch (*flags)
10171 			     {
10172 				 case 'c': mask = SP_START; break;
10173 				 case 'e': mask = SP_END; break;
10174 				 case 'm': mask = SP_RETCOUNT; break;
10175 				 case 'n': mask = SP_NOMOVE; break;
10176 				 case 'p': mask = SP_SUBPAT; break;
10177 				 case 'r': mask = SP_REPEAT; break;
10178 				 case 's': mask = SP_SETPCMARK; break;
10179 				 case 'z': mask = SP_COLUMN; break;
10180 			     }
10181 			  if (mask == 0)
10182 			  {
10183 			      semsg(_(e_invarg2), flags);
10184 			      dir = 0;
10185 			  }
10186 			  else
10187 			      *flagsp |= mask;
10188 	    }
10189 	    if (dir == 0)
10190 		break;
10191 	    ++flags;
10192 	}
10193     }
10194     return dir;
10195 }
10196 
10197 /*
10198  * Shared by search() and searchpos() functions.
10199  */
10200     static int
10201 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10202 {
10203     int		flags;
10204     char_u	*pat;
10205     pos_T	pos;
10206     pos_T	save_cursor;
10207     int		save_p_ws = p_ws;
10208     int		dir;
10209     int		retval = 0;	/* default: FAIL */
10210     long	lnum_stop = 0;
10211     proftime_T	tm;
10212 #ifdef FEAT_RELTIME
10213     long	time_limit = 0;
10214 #endif
10215     int		options = SEARCH_KEEP;
10216     int		subpatnum;
10217 
10218     pat = tv_get_string(&argvars[0]);
10219     dir = get_search_arg(&argvars[1], flagsp);	/* may set p_ws */
10220     if (dir == 0)
10221 	goto theend;
10222     flags = *flagsp;
10223     if (flags & SP_START)
10224 	options |= SEARCH_START;
10225     if (flags & SP_END)
10226 	options |= SEARCH_END;
10227     if (flags & SP_COLUMN)
10228 	options |= SEARCH_COL;
10229 
10230     /* Optional arguments: line number to stop searching and timeout. */
10231     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10232     {
10233 	lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
10234 	if (lnum_stop < 0)
10235 	    goto theend;
10236 #ifdef FEAT_RELTIME
10237 	if (argvars[3].v_type != VAR_UNKNOWN)
10238 	{
10239 	    time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
10240 	    if (time_limit < 0)
10241 		goto theend;
10242 	}
10243 #endif
10244     }
10245 
10246 #ifdef FEAT_RELTIME
10247     /* Set the time limit, if there is one. */
10248     profile_setlimit(time_limit, &tm);
10249 #endif
10250 
10251     /*
10252      * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10253      * Check to make sure only those flags are set.
10254      * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10255      * flags cannot be set. Check for that condition also.
10256      */
10257     if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10258 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10259     {
10260 	semsg(_(e_invarg2), tv_get_string(&argvars[1]));
10261 	goto theend;
10262     }
10263 
10264     pos = save_cursor = curwin->w_cursor;
10265     subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
10266 			   options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
10267     if (subpatnum != FAIL)
10268     {
10269 	if (flags & SP_SUBPAT)
10270 	    retval = subpatnum;
10271 	else
10272 	    retval = pos.lnum;
10273 	if (flags & SP_SETPCMARK)
10274 	    setpcmark();
10275 	curwin->w_cursor = pos;
10276 	if (match_pos != NULL)
10277 	{
10278 	    /* Store the match cursor position */
10279 	    match_pos->lnum = pos.lnum;
10280 	    match_pos->col = pos.col + 1;
10281 	}
10282 	/* "/$" will put the cursor after the end of the line, may need to
10283 	 * correct that here */
10284 	check_cursor();
10285     }
10286 
10287     /* If 'n' flag is used: restore cursor position. */
10288     if (flags & SP_NOMOVE)
10289 	curwin->w_cursor = save_cursor;
10290     else
10291 	curwin->w_set_curswant = TRUE;
10292 theend:
10293     p_ws = save_p_ws;
10294 
10295     return retval;
10296 }
10297 
10298 #ifdef FEAT_FLOAT
10299 
10300 /*
10301  * round() is not in C90, use ceil() or floor() instead.
10302  */
10303     float_T
10304 vim_round(float_T f)
10305 {
10306     return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10307 }
10308 
10309 /*
10310  * "round({float})" function
10311  */
10312     static void
10313 f_round(typval_T *argvars, typval_T *rettv)
10314 {
10315     float_T	f = 0.0;
10316 
10317     rettv->v_type = VAR_FLOAT;
10318     if (get_float_arg(argvars, &f) == OK)
10319 	rettv->vval.v_float = vim_round(f);
10320     else
10321 	rettv->vval.v_float = 0.0;
10322 }
10323 #endif
10324 
10325 /*
10326  * "screenattr()" function
10327  */
10328     static void
10329 f_screenattr(typval_T *argvars, typval_T *rettv)
10330 {
10331     int		row;
10332     int		col;
10333     int		c;
10334 
10335     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10336     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10337     if (row < 0 || row >= screen_Rows
10338 	    || col < 0 || col >= screen_Columns)
10339 	c = -1;
10340     else
10341 	c = ScreenAttrs[LineOffset[row] + col];
10342     rettv->vval.v_number = c;
10343 }
10344 
10345 /*
10346  * "screenchar()" function
10347  */
10348     static void
10349 f_screenchar(typval_T *argvars, typval_T *rettv)
10350 {
10351     int		row;
10352     int		col;
10353     int		off;
10354     int		c;
10355 
10356     row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10357     col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10358     if (row < 0 || row >= screen_Rows
10359 	    || col < 0 || col >= screen_Columns)
10360 	c = -1;
10361     else
10362     {
10363 	off = LineOffset[row] + col;
10364 	if (enc_utf8 && ScreenLinesUC[off] != 0)
10365 	    c = ScreenLinesUC[off];
10366 	else
10367 	    c = ScreenLines[off];
10368     }
10369     rettv->vval.v_number = c;
10370 }
10371 
10372 /*
10373  * "screencol()" function
10374  *
10375  * First column is 1 to be consistent with virtcol().
10376  */
10377     static void
10378 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10379 {
10380     rettv->vval.v_number = screen_screencol() + 1;
10381 }
10382 
10383 /*
10384  * "screenrow()" function
10385  */
10386     static void
10387 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10388 {
10389     rettv->vval.v_number = screen_screenrow() + 1;
10390 }
10391 
10392 /*
10393  * "search()" function
10394  */
10395     static void
10396 f_search(typval_T *argvars, typval_T *rettv)
10397 {
10398     int		flags = 0;
10399 
10400     rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10401 }
10402 
10403 /*
10404  * "searchdecl()" function
10405  */
10406     static void
10407 f_searchdecl(typval_T *argvars, typval_T *rettv)
10408 {
10409     int		locally = 1;
10410     int		thisblock = 0;
10411     int		error = FALSE;
10412     char_u	*name;
10413 
10414     rettv->vval.v_number = 1;	/* default: FAIL */
10415 
10416     name = tv_get_string_chk(&argvars[0]);
10417     if (argvars[1].v_type != VAR_UNKNOWN)
10418     {
10419 	locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
10420 	if (!error && argvars[2].v_type != VAR_UNKNOWN)
10421 	    thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
10422     }
10423     if (!error && name != NULL)
10424 	rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10425 				     locally, thisblock, SEARCH_KEEP) == FAIL;
10426 }
10427 
10428 /*
10429  * Used by searchpair() and searchpairpos()
10430  */
10431     static int
10432 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10433 {
10434     char_u	*spat, *mpat, *epat;
10435     typval_T	*skip;
10436     int		save_p_ws = p_ws;
10437     int		dir;
10438     int		flags = 0;
10439     char_u	nbuf1[NUMBUFLEN];
10440     char_u	nbuf2[NUMBUFLEN];
10441     int		retval = 0;		/* default: FAIL */
10442     long	lnum_stop = 0;
10443     long	time_limit = 0;
10444 
10445     /* Get the three pattern arguments: start, middle, end. Will result in an
10446      * error if not a valid argument. */
10447     spat = tv_get_string_chk(&argvars[0]);
10448     mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10449     epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
10450     if (spat == NULL || mpat == NULL || epat == NULL)
10451 	goto theend;	    /* type error */
10452 
10453     /* Handle the optional fourth argument: flags */
10454     dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10455     if (dir == 0)
10456 	goto theend;
10457 
10458     /* Don't accept SP_END or SP_SUBPAT.
10459      * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10460      */
10461     if ((flags & (SP_END | SP_SUBPAT)) != 0
10462 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10463     {
10464 	semsg(_(e_invarg2), tv_get_string(&argvars[3]));
10465 	goto theend;
10466     }
10467 
10468     /* Using 'r' implies 'W', otherwise it doesn't work. */
10469     if (flags & SP_REPEAT)
10470 	p_ws = FALSE;
10471 
10472     /* Optional fifth argument: skip expression */
10473     if (argvars[3].v_type == VAR_UNKNOWN
10474 	    || argvars[4].v_type == VAR_UNKNOWN)
10475 	skip = NULL;
10476     else
10477     {
10478 	skip = &argvars[4];
10479 	if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10480 	    && skip->v_type != VAR_STRING)
10481 	{
10482 	    /* Type error */
10483 	    semsg(_(e_invarg2), tv_get_string(&argvars[4]));
10484 	    goto theend;
10485 	}
10486 	if (argvars[5].v_type != VAR_UNKNOWN)
10487 	{
10488 	    lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
10489 	    if (lnum_stop < 0)
10490 	    {
10491 		semsg(_(e_invarg2), tv_get_string(&argvars[5]));
10492 		goto theend;
10493 	    }
10494 #ifdef FEAT_RELTIME
10495 	    if (argvars[6].v_type != VAR_UNKNOWN)
10496 	    {
10497 		time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
10498 		if (time_limit < 0)
10499 		{
10500 		    semsg(_(e_invarg2), tv_get_string(&argvars[6]));
10501 		    goto theend;
10502 		}
10503 	    }
10504 #endif
10505 	}
10506     }
10507 
10508     retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10509 					    match_pos, lnum_stop, time_limit);
10510 
10511 theend:
10512     p_ws = save_p_ws;
10513 
10514     return retval;
10515 }
10516 
10517 /*
10518  * "searchpair()" function
10519  */
10520     static void
10521 f_searchpair(typval_T *argvars, typval_T *rettv)
10522 {
10523     rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10524 }
10525 
10526 /*
10527  * "searchpairpos()" function
10528  */
10529     static void
10530 f_searchpairpos(typval_T *argvars, typval_T *rettv)
10531 {
10532     pos_T	match_pos;
10533     int		lnum = 0;
10534     int		col = 0;
10535 
10536     if (rettv_list_alloc(rettv) == FAIL)
10537 	return;
10538 
10539     if (searchpair_cmn(argvars, &match_pos) > 0)
10540     {
10541 	lnum = match_pos.lnum;
10542 	col = match_pos.col;
10543     }
10544 
10545     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10546     list_append_number(rettv->vval.v_list, (varnumber_T)col);
10547 }
10548 
10549 /*
10550  * Search for a start/middle/end thing.
10551  * Used by searchpair(), see its documentation for the details.
10552  * Returns 0 or -1 for no match,
10553  */
10554     long
10555 do_searchpair(
10556     char_u	*spat,	    /* start pattern */
10557     char_u	*mpat,	    /* middle pattern */
10558     char_u	*epat,	    /* end pattern */
10559     int		dir,	    /* BACKWARD or FORWARD */
10560     typval_T	*skip,	    /* skip expression */
10561     int		flags,	    /* SP_SETPCMARK and other SP_ values */
10562     pos_T	*match_pos,
10563     linenr_T	lnum_stop,  /* stop at this line if not zero */
10564     long	time_limit UNUSED) /* stop after this many msec */
10565 {
10566     char_u	*save_cpo;
10567     char_u	*pat, *pat2 = NULL, *pat3 = NULL;
10568     long	retval = 0;
10569     pos_T	pos;
10570     pos_T	firstpos;
10571     pos_T	foundpos;
10572     pos_T	save_cursor;
10573     pos_T	save_pos;
10574     int		n;
10575     int		r;
10576     int		nest = 1;
10577     int		use_skip = FALSE;
10578     int		err;
10579     int		options = SEARCH_KEEP;
10580     proftime_T	tm;
10581 
10582     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10583     save_cpo = p_cpo;
10584     p_cpo = empty_option;
10585 
10586 #ifdef FEAT_RELTIME
10587     /* Set the time limit, if there is one. */
10588     profile_setlimit(time_limit, &tm);
10589 #endif
10590 
10591     /* Make two search patterns: start/end (pat2, for in nested pairs) and
10592      * start/middle/end (pat3, for the top pair). */
10593     pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10594     pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
10595     if (pat2 == NULL || pat3 == NULL)
10596 	goto theend;
10597     sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
10598     if (*mpat == NUL)
10599 	STRCPY(pat3, pat2);
10600     else
10601 	sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
10602 							    spat, epat, mpat);
10603     if (flags & SP_START)
10604 	options |= SEARCH_START;
10605 
10606     if (skip != NULL)
10607     {
10608 	/* Empty string means to not use the skip expression. */
10609 	if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10610 	    use_skip = skip->vval.v_string != NULL
10611 						&& *skip->vval.v_string != NUL;
10612     }
10613 
10614     save_cursor = curwin->w_cursor;
10615     pos = curwin->w_cursor;
10616     CLEAR_POS(&firstpos);
10617     CLEAR_POS(&foundpos);
10618     pat = pat3;
10619     for (;;)
10620     {
10621 	n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
10622 				     options, RE_SEARCH, lnum_stop, &tm, NULL);
10623 	if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
10624 	    /* didn't find it or found the first match again: FAIL */
10625 	    break;
10626 
10627 	if (firstpos.lnum == 0)
10628 	    firstpos = pos;
10629 	if (EQUAL_POS(pos, foundpos))
10630 	{
10631 	    /* Found the same position again.  Can happen with a pattern that
10632 	     * has "\zs" at the end and searching backwards.  Advance one
10633 	     * character and try again. */
10634 	    if (dir == BACKWARD)
10635 		decl(&pos);
10636 	    else
10637 		incl(&pos);
10638 	}
10639 	foundpos = pos;
10640 
10641 	/* clear the start flag to avoid getting stuck here */
10642 	options &= ~SEARCH_START;
10643 
10644 	/* If the skip pattern matches, ignore this match. */
10645 	if (use_skip)
10646 	{
10647 	    save_pos = curwin->w_cursor;
10648 	    curwin->w_cursor = pos;
10649 	    err = FALSE;
10650 	    r = eval_expr_to_bool(skip, &err);
10651 	    curwin->w_cursor = save_pos;
10652 	    if (err)
10653 	    {
10654 		/* Evaluating {skip} caused an error, break here. */
10655 		curwin->w_cursor = save_cursor;
10656 		retval = -1;
10657 		break;
10658 	    }
10659 	    if (r)
10660 		continue;
10661 	}
10662 
10663 	if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10664 	{
10665 	    /* Found end when searching backwards or start when searching
10666 	     * forward: nested pair. */
10667 	    ++nest;
10668 	    pat = pat2;		/* nested, don't search for middle */
10669 	}
10670 	else
10671 	{
10672 	    /* Found end when searching forward or start when searching
10673 	     * backward: end of (nested) pair; or found middle in outer pair. */
10674 	    if (--nest == 1)
10675 		pat = pat3;	/* outer level, search for middle */
10676 	}
10677 
10678 	if (nest == 0)
10679 	{
10680 	    /* Found the match: return matchcount or line number. */
10681 	    if (flags & SP_RETCOUNT)
10682 		++retval;
10683 	    else
10684 		retval = pos.lnum;
10685 	    if (flags & SP_SETPCMARK)
10686 		setpcmark();
10687 	    curwin->w_cursor = pos;
10688 	    if (!(flags & SP_REPEAT))
10689 		break;
10690 	    nest = 1;	    /* search for next unmatched */
10691 	}
10692     }
10693 
10694     if (match_pos != NULL)
10695     {
10696 	/* Store the match cursor position */
10697 	match_pos->lnum = curwin->w_cursor.lnum;
10698 	match_pos->col = curwin->w_cursor.col + 1;
10699     }
10700 
10701     /* If 'n' flag is used or search failed: restore cursor position. */
10702     if ((flags & SP_NOMOVE) || retval == 0)
10703 	curwin->w_cursor = save_cursor;
10704 
10705 theend:
10706     vim_free(pat2);
10707     vim_free(pat3);
10708     if (p_cpo == empty_option)
10709 	p_cpo = save_cpo;
10710     else
10711 	/* Darn, evaluating the {skip} expression changed the value. */
10712 	free_string_option(save_cpo);
10713 
10714     return retval;
10715 }
10716 
10717 /*
10718  * "searchpos()" function
10719  */
10720     static void
10721 f_searchpos(typval_T *argvars, typval_T *rettv)
10722 {
10723     pos_T	match_pos;
10724     int		lnum = 0;
10725     int		col = 0;
10726     int		n;
10727     int		flags = 0;
10728 
10729     if (rettv_list_alloc(rettv) == FAIL)
10730 	return;
10731 
10732     n = search_cmn(argvars, &match_pos, &flags);
10733     if (n > 0)
10734     {
10735 	lnum = match_pos.lnum;
10736 	col = match_pos.col;
10737     }
10738 
10739     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10740     list_append_number(rettv->vval.v_list, (varnumber_T)col);
10741     if (flags & SP_SUBPAT)
10742 	list_append_number(rettv->vval.v_list, (varnumber_T)n);
10743 }
10744 
10745     static void
10746 f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10747 {
10748 #ifdef FEAT_CLIENTSERVER
10749     char_u	buf[NUMBUFLEN];
10750     char_u	*server = tv_get_string_chk(&argvars[0]);
10751     char_u	*reply = tv_get_string_buf_chk(&argvars[1], buf);
10752 
10753     rettv->vval.v_number = -1;
10754     if (server == NULL || reply == NULL)
10755 	return;
10756     if (check_restricted() || check_secure())
10757 	return;
10758 # ifdef FEAT_X11
10759     if (check_connection() == FAIL)
10760 	return;
10761 # endif
10762 
10763     if (serverSendReply(server, reply) < 0)
10764     {
10765 	emsg(_("E258: Unable to send to client"));
10766 	return;
10767     }
10768     rettv->vval.v_number = 0;
10769 #else
10770     rettv->vval.v_number = -1;
10771 #endif
10772 }
10773 
10774     static void
10775 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10776 {
10777     char_u	*r = NULL;
10778 
10779 #ifdef FEAT_CLIENTSERVER
10780 # ifdef WIN32
10781     r = serverGetVimNames();
10782 # else
10783     make_connection();
10784     if (X_DISPLAY != NULL)
10785 	r = serverGetVimNames(X_DISPLAY);
10786 # endif
10787 #endif
10788     rettv->v_type = VAR_STRING;
10789     rettv->vval.v_string = r;
10790 }
10791 
10792 /*
10793  * "setbufline()" function
10794  */
10795     static void
10796 f_setbufline(typval_T *argvars, typval_T *rettv)
10797 {
10798     linenr_T	lnum;
10799     buf_T	*buf;
10800 
10801     buf = tv_get_buf(&argvars[0], FALSE);
10802     if (buf == NULL)
10803 	rettv->vval.v_number = 1; /* FAIL */
10804     else
10805     {
10806 	lnum = tv_get_lnum_buf(&argvars[1], buf);
10807 	set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
10808     }
10809 }
10810 
10811 /*
10812  * "setbufvar()" function
10813  */
10814     static void
10815 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10816 {
10817     buf_T	*buf;
10818     char_u	*varname, *bufvarname;
10819     typval_T	*varp;
10820     char_u	nbuf[NUMBUFLEN];
10821 
10822     if (check_restricted() || check_secure())
10823 	return;
10824     (void)tv_get_number(&argvars[0]);	    /* issue errmsg if type error */
10825     varname = tv_get_string_chk(&argvars[1]);
10826     buf = tv_get_buf(&argvars[0], FALSE);
10827     varp = &argvars[2];
10828 
10829     if (buf != NULL && varname != NULL && varp != NULL)
10830     {
10831 	if (*varname == '&')
10832 	{
10833 	    long	numval;
10834 	    char_u	*strval;
10835 	    int		error = FALSE;
10836 	    aco_save_T	aco;
10837 
10838 	    /* set curbuf to be our buf, temporarily */
10839 	    aucmd_prepbuf(&aco, buf);
10840 
10841 	    ++varname;
10842 	    numval = (long)tv_get_number_chk(varp, &error);
10843 	    strval = tv_get_string_buf_chk(varp, nbuf);
10844 	    if (!error && strval != NULL)
10845 		set_option_value(varname, numval, strval, OPT_LOCAL);
10846 
10847 	    /* reset notion of buffer */
10848 	    aucmd_restbuf(&aco);
10849 	}
10850 	else
10851 	{
10852 	    buf_T *save_curbuf = curbuf;
10853 
10854 	    bufvarname = alloc((unsigned)STRLEN(varname) + 3);
10855 	    if (bufvarname != NULL)
10856 	    {
10857 		curbuf = buf;
10858 		STRCPY(bufvarname, "b:");
10859 		STRCPY(bufvarname + 2, varname);
10860 		set_var(bufvarname, varp, TRUE);
10861 		vim_free(bufvarname);
10862 		curbuf = save_curbuf;
10863 	    }
10864 	}
10865     }
10866 }
10867 
10868     static void
10869 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10870 {
10871     dict_T	*d;
10872     dictitem_T	*di;
10873     char_u	*csearch;
10874 
10875     if (argvars[0].v_type != VAR_DICT)
10876     {
10877 	emsg(_(e_dictreq));
10878 	return;
10879     }
10880 
10881     if ((d = argvars[0].vval.v_dict) != NULL)
10882     {
10883 	csearch = dict_get_string(d, (char_u *)"char", FALSE);
10884 	if (csearch != NULL)
10885 	{
10886 	    if (enc_utf8)
10887 	    {
10888 		int pcc[MAX_MCO];
10889 		int c = utfc_ptr2char(csearch, pcc);
10890 
10891 		set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10892 	    }
10893 	    else
10894 		set_last_csearch(PTR2CHAR(csearch),
10895 						csearch, MB_PTR2LEN(csearch));
10896 	}
10897 
10898 	di = dict_find(d, (char_u *)"forward", -1);
10899 	if (di != NULL)
10900 	    set_csearch_direction((int)tv_get_number(&di->di_tv)
10901 							? FORWARD : BACKWARD);
10902 
10903 	di = dict_find(d, (char_u *)"until", -1);
10904 	if (di != NULL)
10905 	    set_csearch_until(!!tv_get_number(&di->di_tv));
10906     }
10907 }
10908 
10909 /*
10910  * "setcmdpos()" function
10911  */
10912     static void
10913 f_setcmdpos(typval_T *argvars, typval_T *rettv)
10914 {
10915     int		pos = (int)tv_get_number(&argvars[0]) - 1;
10916 
10917     if (pos >= 0)
10918 	rettv->vval.v_number = set_cmdline_pos(pos);
10919 }
10920 
10921 /*
10922  * "setfperm({fname}, {mode})" function
10923  */
10924     static void
10925 f_setfperm(typval_T *argvars, typval_T *rettv)
10926 {
10927     char_u	*fname;
10928     char_u	modebuf[NUMBUFLEN];
10929     char_u	*mode_str;
10930     int		i;
10931     int		mask;
10932     int		mode = 0;
10933 
10934     rettv->vval.v_number = 0;
10935     fname = tv_get_string_chk(&argvars[0]);
10936     if (fname == NULL)
10937 	return;
10938     mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
10939     if (mode_str == NULL)
10940 	return;
10941     if (STRLEN(mode_str) != 9)
10942     {
10943 	semsg(_(e_invarg2), mode_str);
10944 	return;
10945     }
10946 
10947     mask = 1;
10948     for (i = 8; i >= 0; --i)
10949     {
10950 	if (mode_str[i] != '-')
10951 	    mode |= mask;
10952 	mask = mask << 1;
10953     }
10954     rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10955 }
10956 
10957 /*
10958  * "setline()" function
10959  */
10960     static void
10961 f_setline(typval_T *argvars, typval_T *rettv)
10962 {
10963     linenr_T	lnum = tv_get_lnum(&argvars[0]);
10964 
10965     set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
10966 }
10967 
10968 /*
10969  * Used by "setqflist()" and "setloclist()" functions
10970  */
10971     static void
10972 set_qf_ll_list(
10973     win_T	*wp UNUSED,
10974     typval_T	*list_arg UNUSED,
10975     typval_T	*action_arg UNUSED,
10976     typval_T	*what_arg UNUSED,
10977     typval_T	*rettv)
10978 {
10979 #ifdef FEAT_QUICKFIX
10980     static char *e_invact = N_("E927: Invalid action: '%s'");
10981     char_u	*act;
10982     int		action = 0;
10983     static int	recursive = 0;
10984 #endif
10985 
10986     rettv->vval.v_number = -1;
10987 
10988 #ifdef FEAT_QUICKFIX
10989     if (list_arg->v_type != VAR_LIST)
10990 	emsg(_(e_listreq));
10991     else if (recursive != 0)
10992 	emsg(_(e_au_recursive));
10993     else
10994     {
10995 	list_T  *l = list_arg->vval.v_list;
10996 	dict_T	*d = NULL;
10997 	int	valid_dict = TRUE;
10998 
10999 	if (action_arg->v_type == VAR_STRING)
11000 	{
11001 	    act = tv_get_string_chk(action_arg);
11002 	    if (act == NULL)
11003 		return;		/* type error; errmsg already given */
11004 	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11005 		    act[1] == NUL)
11006 		action = *act;
11007 	    else
11008 		semsg(_(e_invact), act);
11009 	}
11010 	else if (action_arg->v_type == VAR_UNKNOWN)
11011 	    action = ' ';
11012 	else
11013 	    emsg(_(e_stringreq));
11014 
11015 	if (action_arg->v_type != VAR_UNKNOWN
11016 		&& what_arg->v_type != VAR_UNKNOWN)
11017 	{
11018 	    if (what_arg->v_type == VAR_DICT)
11019 		d = what_arg->vval.v_dict;
11020 	    else
11021 	    {
11022 		emsg(_(e_dictreq));
11023 		valid_dict = FALSE;
11024 	    }
11025 	}
11026 
11027 	++recursive;
11028 	if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
11029 		     (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11030 		     d) == OK)
11031 	    rettv->vval.v_number = 0;
11032 	--recursive;
11033     }
11034 #endif
11035 }
11036 
11037 /*
11038  * "setloclist()" function
11039  */
11040     static void
11041 f_setloclist(typval_T *argvars, typval_T *rettv)
11042 {
11043     win_T	*win;
11044 
11045     rettv->vval.v_number = -1;
11046 
11047     win = find_win_by_nr_or_id(&argvars[0]);
11048     if (win != NULL)
11049 	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
11050 }
11051 
11052 /*
11053  * "setmatches()" function
11054  */
11055     static void
11056 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11057 {
11058 #ifdef FEAT_SEARCH_EXTRA
11059     list_T	*l;
11060     listitem_T	*li;
11061     dict_T	*d;
11062     list_T	*s = NULL;
11063 
11064     rettv->vval.v_number = -1;
11065     if (argvars[0].v_type != VAR_LIST)
11066     {
11067 	emsg(_(e_listreq));
11068 	return;
11069     }
11070     if ((l = argvars[0].vval.v_list) != NULL)
11071     {
11072 
11073 	/* To some extent make sure that we are dealing with a list from
11074 	 * "getmatches()". */
11075 	li = l->lv_first;
11076 	while (li != NULL)
11077 	{
11078 	    if (li->li_tv.v_type != VAR_DICT
11079 		    || (d = li->li_tv.vval.v_dict) == NULL)
11080 	    {
11081 		emsg(_(e_invarg));
11082 		return;
11083 	    }
11084 	    if (!(dict_find(d, (char_u *)"group", -1) != NULL
11085 			&& (dict_find(d, (char_u *)"pattern", -1) != NULL
11086 			    || dict_find(d, (char_u *)"pos1", -1) != NULL)
11087 			&& dict_find(d, (char_u *)"priority", -1) != NULL
11088 			&& dict_find(d, (char_u *)"id", -1) != NULL))
11089 	    {
11090 		emsg(_(e_invarg));
11091 		return;
11092 	    }
11093 	    li = li->li_next;
11094 	}
11095 
11096 	clear_matches(curwin);
11097 	li = l->lv_first;
11098 	while (li != NULL)
11099 	{
11100 	    int		i = 0;
11101 	    char_u	buf[5];
11102 	    dictitem_T  *di;
11103 	    char_u	*group;
11104 	    int		priority;
11105 	    int		id;
11106 	    char_u	*conceal;
11107 
11108 	    d = li->li_tv.vval.v_dict;
11109 	    if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11110 	    {
11111 		if (s == NULL)
11112 		{
11113 		    s = list_alloc();
11114 		    if (s == NULL)
11115 			return;
11116 		}
11117 
11118 		/* match from matchaddpos() */
11119 		for (i = 1; i < 9; i++)
11120 		{
11121 		    sprintf((char *)buf, (char *)"pos%d", i);
11122 		    if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11123 		    {
11124 			if (di->di_tv.v_type != VAR_LIST)
11125 			    return;
11126 
11127 			list_append_tv(s, &di->di_tv);
11128 			s->lv_refcount++;
11129 		    }
11130 		    else
11131 			break;
11132 		}
11133 	    }
11134 
11135 	    group = dict_get_string(d, (char_u *)"group", TRUE);
11136 	    priority = (int)dict_get_number(d, (char_u *)"priority");
11137 	    id = (int)dict_get_number(d, (char_u *)"id");
11138 	    conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
11139 			      ? dict_get_string(d, (char_u *)"conceal", TRUE)
11140 			      : NULL;
11141 	    if (i == 0)
11142 	    {
11143 		match_add(curwin, group,
11144 		    dict_get_string(d, (char_u *)"pattern", FALSE),
11145 		    priority, id, NULL, conceal);
11146 	    }
11147 	    else
11148 	    {
11149 		match_add(curwin, group, NULL, priority, id, s, conceal);
11150 		list_unref(s);
11151 		s = NULL;
11152 	    }
11153 	    vim_free(group);
11154 	    vim_free(conceal);
11155 
11156 	    li = li->li_next;
11157 	}
11158 	rettv->vval.v_number = 0;
11159     }
11160 #endif
11161 }
11162 
11163 /*
11164  * "setpos()" function
11165  */
11166     static void
11167 f_setpos(typval_T *argvars, typval_T *rettv)
11168 {
11169     pos_T	pos;
11170     int		fnum;
11171     char_u	*name;
11172     colnr_T	curswant = -1;
11173 
11174     rettv->vval.v_number = -1;
11175     name = tv_get_string_chk(argvars);
11176     if (name != NULL)
11177     {
11178 	if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11179 	{
11180 	    if (--pos.col < 0)
11181 		pos.col = 0;
11182 	    if (name[0] == '.' && name[1] == NUL)
11183 	    {
11184 		/* set cursor; "fnum" is ignored */
11185 		curwin->w_cursor = pos;
11186 		if (curswant >= 0)
11187 		{
11188 		    curwin->w_curswant = curswant - 1;
11189 		    curwin->w_set_curswant = FALSE;
11190 		}
11191 		check_cursor();
11192 		rettv->vval.v_number = 0;
11193 	    }
11194 	    else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11195 	    {
11196 		/* set mark */
11197 		if (setmark_pos(name[1], &pos, fnum) == OK)
11198 		    rettv->vval.v_number = 0;
11199 	    }
11200 	    else
11201 		emsg(_(e_invarg));
11202 	}
11203     }
11204 }
11205 
11206 /*
11207  * "setqflist()" function
11208  */
11209     static void
11210 f_setqflist(typval_T *argvars, typval_T *rettv)
11211 {
11212     set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
11213 }
11214 
11215 /*
11216  * "setreg()" function
11217  */
11218     static void
11219 f_setreg(typval_T *argvars, typval_T *rettv)
11220 {
11221     int		regname;
11222     char_u	*strregname;
11223     char_u	*stropt;
11224     char_u	*strval;
11225     int		append;
11226     char_u	yank_type;
11227     long	block_len;
11228 
11229     block_len = -1;
11230     yank_type = MAUTO;
11231     append = FALSE;
11232 
11233     strregname = tv_get_string_chk(argvars);
11234     rettv->vval.v_number = 1;		/* FAIL is default */
11235 
11236     if (strregname == NULL)
11237 	return;		/* type error; errmsg already given */
11238     regname = *strregname;
11239     if (regname == 0 || regname == '@')
11240 	regname = '"';
11241 
11242     if (argvars[2].v_type != VAR_UNKNOWN)
11243     {
11244 	stropt = tv_get_string_chk(&argvars[2]);
11245 	if (stropt == NULL)
11246 	    return;		/* type error */
11247 	for (; *stropt != NUL; ++stropt)
11248 	    switch (*stropt)
11249 	    {
11250 		case 'a': case 'A':	/* append */
11251 		    append = TRUE;
11252 		    break;
11253 		case 'v': case 'c':	/* character-wise selection */
11254 		    yank_type = MCHAR;
11255 		    break;
11256 		case 'V': case 'l':	/* line-wise selection */
11257 		    yank_type = MLINE;
11258 		    break;
11259 		case 'b': case Ctrl_V:	/* block-wise selection */
11260 		    yank_type = MBLOCK;
11261 		    if (VIM_ISDIGIT(stropt[1]))
11262 		    {
11263 			++stropt;
11264 			block_len = getdigits(&stropt) - 1;
11265 			--stropt;
11266 		    }
11267 		    break;
11268 	    }
11269     }
11270 
11271     if (argvars[1].v_type == VAR_LIST)
11272     {
11273 	char_u		**lstval;
11274 	char_u		**allocval;
11275 	char_u		buf[NUMBUFLEN];
11276 	char_u		**curval;
11277 	char_u		**curallocval;
11278 	list_T		*ll = argvars[1].vval.v_list;
11279 	listitem_T	*li;
11280 	int		len;
11281 
11282 	/* If the list is NULL handle like an empty list. */
11283 	len = ll == NULL ? 0 : ll->lv_len;
11284 
11285 	/* First half: use for pointers to result lines; second half: use for
11286 	 * pointers to allocated copies. */
11287 	lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11288 	if (lstval == NULL)
11289 	    return;
11290 	curval = lstval;
11291 	allocval = lstval + len + 2;
11292 	curallocval = allocval;
11293 
11294 	for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11295 							     li = li->li_next)
11296 	{
11297 	    strval = tv_get_string_buf_chk(&li->li_tv, buf);
11298 	    if (strval == NULL)
11299 		goto free_lstval;
11300 	    if (strval == buf)
11301 	    {
11302 		/* Need to make a copy, next tv_get_string_buf_chk() will
11303 		 * overwrite the string. */
11304 		strval = vim_strsave(buf);
11305 		if (strval == NULL)
11306 		    goto free_lstval;
11307 		*curallocval++ = strval;
11308 	    }
11309 	    *curval++ = strval;
11310 	}
11311 	*curval++ = NULL;
11312 
11313 	write_reg_contents_lst(regname, lstval, -1,
11314 						append, yank_type, block_len);
11315 free_lstval:
11316 	while (curallocval > allocval)
11317 	    vim_free(*--curallocval);
11318 	vim_free(lstval);
11319     }
11320     else
11321     {
11322 	strval = tv_get_string_chk(&argvars[1]);
11323 	if (strval == NULL)
11324 	    return;
11325 	write_reg_contents_ex(regname, strval, -1,
11326 						append, yank_type, block_len);
11327     }
11328     rettv->vval.v_number = 0;
11329 }
11330 
11331 /*
11332  * "settabvar()" function
11333  */
11334     static void
11335 f_settabvar(typval_T *argvars, typval_T *rettv)
11336 {
11337     tabpage_T	*save_curtab;
11338     tabpage_T	*tp;
11339     char_u	*varname, *tabvarname;
11340     typval_T	*varp;
11341 
11342     rettv->vval.v_number = 0;
11343 
11344     if (check_restricted() || check_secure())
11345 	return;
11346 
11347     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11348     varname = tv_get_string_chk(&argvars[1]);
11349     varp = &argvars[2];
11350 
11351     if (varname != NULL && varp != NULL && tp != NULL)
11352     {
11353 	save_curtab = curtab;
11354 	goto_tabpage_tp(tp, FALSE, FALSE);
11355 
11356 	tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11357 	if (tabvarname != NULL)
11358 	{
11359 	    STRCPY(tabvarname, "t:");
11360 	    STRCPY(tabvarname + 2, varname);
11361 	    set_var(tabvarname, varp, TRUE);
11362 	    vim_free(tabvarname);
11363 	}
11364 
11365 	/* Restore current tabpage */
11366 	if (valid_tabpage(save_curtab))
11367 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
11368     }
11369 }
11370 
11371 /*
11372  * "settabwinvar()" function
11373  */
11374     static void
11375 f_settabwinvar(typval_T *argvars, typval_T *rettv)
11376 {
11377     setwinvar(argvars, rettv, 1);
11378 }
11379 
11380 /*
11381  * "settagstack()" function
11382  */
11383     static void
11384 f_settagstack(typval_T *argvars, typval_T *rettv)
11385 {
11386     static char *e_invact2 = N_("E962: Invalid action: '%s'");
11387     win_T	*wp;
11388     dict_T	*d;
11389     int		action = 'r';
11390 
11391     rettv->vval.v_number = -1;
11392 
11393     // first argument: window number or id
11394     wp = find_win_by_nr_or_id(&argvars[0]);
11395     if (wp == NULL)
11396 	return;
11397 
11398     // second argument: dict with items to set in the tag stack
11399     if (argvars[1].v_type != VAR_DICT)
11400     {
11401 	emsg(_(e_dictreq));
11402 	return;
11403     }
11404     d = argvars[1].vval.v_dict;
11405     if (d == NULL)
11406 	return;
11407 
11408     // third argument: action - 'a' for append and 'r' for replace.
11409     // default is to replace the stack.
11410     if (argvars[2].v_type == VAR_UNKNOWN)
11411 	action = 'r';
11412     else if (argvars[2].v_type == VAR_STRING)
11413     {
11414 	char_u	*actstr;
11415 	actstr = tv_get_string_chk(&argvars[2]);
11416 	if (actstr == NULL)
11417 	    return;
11418 	if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11419 	    action = *actstr;
11420 	else
11421 	{
11422 	    semsg(_(e_invact2), actstr);
11423 	    return;
11424 	}
11425     }
11426     else
11427     {
11428 	emsg(_(e_stringreq));
11429 	return;
11430     }
11431 
11432     if (set_tagstack(wp, d, action) == OK)
11433 	rettv->vval.v_number = 0;
11434 }
11435 
11436 /*
11437  * "setwinvar()" function
11438  */
11439     static void
11440 f_setwinvar(typval_T *argvars, typval_T *rettv)
11441 {
11442     setwinvar(argvars, rettv, 0);
11443 }
11444 
11445 #ifdef FEAT_CRYPT
11446 /*
11447  * "sha256({string})" function
11448  */
11449     static void
11450 f_sha256(typval_T *argvars, typval_T *rettv)
11451 {
11452     char_u	*p;
11453 
11454     p = tv_get_string(&argvars[0]);
11455     rettv->vval.v_string = vim_strsave(
11456 				    sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11457     rettv->v_type = VAR_STRING;
11458 }
11459 #endif /* FEAT_CRYPT */
11460 
11461 /*
11462  * "shellescape({string})" function
11463  */
11464     static void
11465 f_shellescape(typval_T *argvars, typval_T *rettv)
11466 {
11467     int do_special = non_zero_arg(&argvars[1]);
11468 
11469     rettv->vval.v_string = vim_strsave_shellescape(
11470 			   tv_get_string(&argvars[0]), do_special, do_special);
11471     rettv->v_type = VAR_STRING;
11472 }
11473 
11474 /*
11475  * shiftwidth() function
11476  */
11477     static void
11478 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11479 {
11480     rettv->vval.v_number = 0;
11481 
11482     if (argvars[0].v_type != VAR_UNKNOWN)
11483     {
11484 	long	col;
11485 
11486 	col = (long)tv_get_number_chk(argvars, NULL);
11487 	if (col < 0)
11488 	    return;	// type error; errmsg already given
11489 #ifdef FEAT_VARTABS
11490 	rettv->vval.v_number = get_sw_value_col(curbuf, col);
11491 	return;
11492 #endif
11493     }
11494 
11495     rettv->vval.v_number = get_sw_value(curbuf);
11496 }
11497 
11498 #ifdef FEAT_SIGNS
11499 /*
11500  * "sign_define()" function
11501  */
11502     static void
11503 f_sign_define(typval_T *argvars, typval_T *rettv)
11504 {
11505     char_u	*name;
11506     dict_T	*dict;
11507     char_u	*icon = NULL;
11508     char_u	*linehl = NULL;
11509     char_u	*text = NULL;
11510     char_u	*texthl = NULL;
11511 
11512     rettv->vval.v_number = -1;
11513 
11514     name = tv_get_string_chk(&argvars[0]);
11515     if (name == NULL)
11516 	return;
11517 
11518     if (argvars[1].v_type != VAR_UNKNOWN)
11519     {
11520 	if (argvars[1].v_type != VAR_DICT)
11521 	{
11522 	    emsg(_(e_dictreq));
11523 	    return;
11524 	}
11525 
11526 	// sign attributes
11527 	dict = argvars[1].vval.v_dict;
11528 	if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11529 	    icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11530 	if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11531 	    linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11532 	if (dict_find(dict, (char_u *)"text", -1) != NULL)
11533 	    text = dict_get_string(dict, (char_u *)"text", TRUE);
11534 	if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11535 	    texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11536     }
11537 
11538     if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11539 	rettv->vval.v_number = 0;
11540 
11541     vim_free(icon);
11542     vim_free(linehl);
11543     vim_free(text);
11544     vim_free(texthl);
11545 }
11546 
11547 /*
11548  * "sign_getdefined()" function
11549  */
11550     static void
11551 f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11552 {
11553     char_u	*name = NULL;
11554 
11555     if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11556 	return;
11557 
11558     if (argvars[0].v_type != VAR_UNKNOWN)
11559 	name = tv_get_string(&argvars[0]);
11560 
11561     sign_getlist(name, rettv->vval.v_list);
11562 }
11563 
11564 /*
11565  * "sign_getplaced()" function
11566  */
11567     static void
11568 f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11569 {
11570     buf_T	*buf = NULL;
11571     dict_T	*dict;
11572     dictitem_T	*di;
11573     linenr_T	lnum = 0;
11574     int		sign_id = 0;
11575     char_u	*group = NULL;
11576     int		notanum = FALSE;
11577 
11578     if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11579 	return;
11580 
11581     if (argvars[0].v_type != VAR_UNKNOWN)
11582     {
11583 	// get signs placed in the specified buffer
11584 	buf = get_buf_arg(&argvars[0]);
11585 	if (buf == NULL)
11586 	    return;
11587 
11588 	if (argvars[1].v_type != VAR_UNKNOWN)
11589 	{
11590 	    if (argvars[1].v_type != VAR_DICT ||
11591 				((dict = argvars[1].vval.v_dict) == NULL))
11592 	    {
11593 		emsg(_(e_dictreq));
11594 		return;
11595 	    }
11596 	    if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11597 	    {
11598 		// get signs placed at this line
11599 		(void)tv_get_number_chk(&di->di_tv, &notanum);
11600 		if (notanum)
11601 		    return;
11602 		lnum = tv_get_lnum(&di->di_tv);
11603 	    }
11604 	    if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11605 	    {
11606 		// get sign placed with this identifier
11607 		sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
11608 		if (notanum)
11609 		    return;
11610 	    }
11611 	    if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11612 	    {
11613 		group = tv_get_string_chk(&di->di_tv);
11614 		if (group == NULL)
11615 		    return;
11616 		if (*group == '\0')	// empty string means global group
11617 		    group = NULL;
11618 	    }
11619 	}
11620     }
11621 
11622     sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11623 }
11624 
11625 /*
11626  * "sign_jump()" function
11627  */
11628     static void
11629 f_sign_jump(typval_T *argvars, typval_T *rettv)
11630 {
11631     int		sign_id;
11632     char_u	*sign_group = NULL;
11633     buf_T	*buf;
11634     int		notanum = FALSE;
11635 
11636     rettv->vval.v_number = -1;
11637 
11638     // Sign identifer
11639     sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11640     if (notanum)
11641 	return;
11642     if (sign_id <= 0)
11643     {
11644 	emsg(_(e_invarg));
11645 	return;
11646     }
11647 
11648     // Sign group
11649     sign_group = tv_get_string_chk(&argvars[1]);
11650     if (sign_group == NULL)
11651 	return;
11652     if (sign_group[0] == '\0')
11653 	sign_group = NULL;			// global sign group
11654     else
11655     {
11656 	sign_group = vim_strsave(sign_group);
11657 	if (sign_group == NULL)
11658 	    return;
11659     }
11660 
11661     // Buffer to place the sign
11662     buf = get_buf_arg(&argvars[2]);
11663     if (buf == NULL)
11664 	goto cleanup;
11665 
11666     rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11667 
11668 cleanup:
11669     vim_free(sign_group);
11670 }
11671 
11672 /*
11673  * "sign_place()" function
11674  */
11675     static void
11676 f_sign_place(typval_T *argvars, typval_T *rettv)
11677 {
11678     int		sign_id;
11679     char_u	*group = NULL;
11680     char_u	*sign_name;
11681     buf_T	*buf;
11682     dict_T	*dict;
11683     dictitem_T	*di;
11684     linenr_T	lnum = 0;
11685     int		prio = SIGN_DEF_PRIO;
11686     int		notanum = FALSE;
11687 
11688     rettv->vval.v_number = -1;
11689 
11690     // Sign identifer
11691     sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11692     if (notanum)
11693 	return;
11694     if (sign_id < 0)
11695     {
11696 	emsg(_(e_invarg));
11697 	return;
11698     }
11699 
11700     // Sign group
11701     group = tv_get_string_chk(&argvars[1]);
11702     if (group == NULL)
11703 	return;
11704     if (group[0] == '\0')
11705 	group = NULL;			// global sign group
11706     else
11707     {
11708 	group = vim_strsave(group);
11709 	if (group == NULL)
11710 	    return;
11711     }
11712 
11713     // Sign name
11714     sign_name = tv_get_string_chk(&argvars[2]);
11715     if (sign_name == NULL)
11716 	goto cleanup;
11717 
11718     // Buffer to place the sign
11719     buf = get_buf_arg(&argvars[3]);
11720     if (buf == NULL)
11721 	goto cleanup;
11722 
11723     if (argvars[4].v_type != VAR_UNKNOWN)
11724     {
11725 	if (argvars[4].v_type != VAR_DICT ||
11726 				((dict = argvars[4].vval.v_dict) == NULL))
11727 	{
11728 	    emsg(_(e_dictreq));
11729 	    goto cleanup;
11730 	}
11731 
11732 	// Line number where the sign is to be placed
11733 	if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11734 	{
11735 	    (void)tv_get_number_chk(&di->di_tv, &notanum);
11736 	    if (notanum)
11737 		goto cleanup;
11738 	    lnum = tv_get_lnum(&di->di_tv);
11739 	}
11740 	if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11741 	{
11742 	    // Sign priority
11743 	    prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
11744 	    if (notanum)
11745 		goto cleanup;
11746 	}
11747     }
11748 
11749     if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11750 	rettv->vval.v_number = sign_id;
11751 
11752 cleanup:
11753     vim_free(group);
11754 }
11755 
11756 /*
11757  * "sign_undefine()" function
11758  */
11759     static void
11760 f_sign_undefine(typval_T *argvars, typval_T *rettv)
11761 {
11762     char_u *name;
11763 
11764     rettv->vval.v_number = -1;
11765 
11766     if (argvars[0].v_type == VAR_UNKNOWN)
11767     {
11768 	// Free all the signs
11769 	free_signs();
11770 	rettv->vval.v_number = 0;
11771     }
11772     else
11773     {
11774 	// Free only the specified sign
11775 	name = tv_get_string_chk(&argvars[0]);
11776 	if (name == NULL)
11777 	    return;
11778 
11779 	if (sign_undefine_by_name(name) == OK)
11780 	    rettv->vval.v_number = 0;
11781     }
11782 }
11783 
11784 /*
11785  * "sign_unplace()" function
11786  */
11787     static void
11788 f_sign_unplace(typval_T *argvars, typval_T *rettv)
11789 {
11790     dict_T	*dict;
11791     dictitem_T	*di;
11792     int		sign_id = 0;
11793     buf_T	*buf = NULL;
11794     char_u	*group = NULL;
11795 
11796     rettv->vval.v_number = -1;
11797 
11798     if (argvars[0].v_type != VAR_STRING)
11799     {
11800 	emsg(_(e_invarg));
11801 	return;
11802     }
11803 
11804     group = tv_get_string(&argvars[0]);
11805     if (group[0] == '\0')
11806 	group = NULL;			// global sign group
11807     else
11808     {
11809 	group = vim_strsave(group);
11810 	if (group == NULL)
11811 	    return;
11812     }
11813 
11814     if (argvars[1].v_type != VAR_UNKNOWN)
11815     {
11816 	if (argvars[1].v_type != VAR_DICT)
11817 	{
11818 	    emsg(_(e_dictreq));
11819 	    goto cleanup;
11820 	}
11821 	dict = argvars[1].vval.v_dict;
11822 
11823 	if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11824 	{
11825 	    buf = get_buf_arg(&di->di_tv);
11826 	    if (buf == NULL)
11827 		goto cleanup;
11828 	}
11829 	if (dict_find(dict, (char_u *)"id", -1) != NULL)
11830 	    sign_id = dict_get_number(dict, (char_u *)"id");
11831     }
11832 
11833     if (buf == NULL)
11834     {
11835 	// Delete the sign in all the buffers
11836 	FOR_ALL_BUFFERS(buf)
11837 	    if (sign_unplace(sign_id, group, buf, 0) == OK)
11838 		rettv->vval.v_number = 0;
11839     }
11840     else
11841     {
11842 	if (sign_unplace(sign_id, group, buf, 0) == OK)
11843 	    rettv->vval.v_number = 0;
11844     }
11845 
11846 cleanup:
11847     vim_free(group);
11848 }
11849 #endif
11850 
11851 /*
11852  * "simplify()" function
11853  */
11854     static void
11855 f_simplify(typval_T *argvars, typval_T *rettv)
11856 {
11857     char_u	*p;
11858 
11859     p = tv_get_string(&argvars[0]);
11860     rettv->vval.v_string = vim_strsave(p);
11861     simplify_filename(rettv->vval.v_string);	/* simplify in place */
11862     rettv->v_type = VAR_STRING;
11863 }
11864 
11865 #ifdef FEAT_FLOAT
11866 /*
11867  * "sin()" function
11868  */
11869     static void
11870 f_sin(typval_T *argvars, typval_T *rettv)
11871 {
11872     float_T	f = 0.0;
11873 
11874     rettv->v_type = VAR_FLOAT;
11875     if (get_float_arg(argvars, &f) == OK)
11876 	rettv->vval.v_float = sin(f);
11877     else
11878 	rettv->vval.v_float = 0.0;
11879 }
11880 
11881 /*
11882  * "sinh()" function
11883  */
11884     static void
11885 f_sinh(typval_T *argvars, typval_T *rettv)
11886 {
11887     float_T	f = 0.0;
11888 
11889     rettv->v_type = VAR_FLOAT;
11890     if (get_float_arg(argvars, &f) == OK)
11891 	rettv->vval.v_float = sinh(f);
11892     else
11893 	rettv->vval.v_float = 0.0;
11894 }
11895 #endif
11896 
11897 static int
11898 #ifdef __BORLANDC__
11899     _RTLENTRYF
11900 #endif
11901 	item_compare(const void *s1, const void *s2);
11902 static int
11903 #ifdef __BORLANDC__
11904     _RTLENTRYF
11905 #endif
11906 	item_compare2(const void *s1, const void *s2);
11907 
11908 /* struct used in the array that's given to qsort() */
11909 typedef struct
11910 {
11911     listitem_T	*item;
11912     int		idx;
11913 } sortItem_T;
11914 
11915 /* struct storing information about current sort */
11916 typedef struct
11917 {
11918     int		item_compare_ic;
11919     int		item_compare_numeric;
11920     int		item_compare_numbers;
11921 #ifdef FEAT_FLOAT
11922     int		item_compare_float;
11923 #endif
11924     char_u	*item_compare_func;
11925     partial_T	*item_compare_partial;
11926     dict_T	*item_compare_selfdict;
11927     int		item_compare_func_err;
11928     int		item_compare_keep_zero;
11929 } sortinfo_T;
11930 static sortinfo_T	*sortinfo = NULL;
11931 #define ITEM_COMPARE_FAIL 999
11932 
11933 /*
11934  * Compare functions for f_sort() and f_uniq() below.
11935  */
11936     static int
11937 #ifdef __BORLANDC__
11938 _RTLENTRYF
11939 #endif
11940 item_compare(const void *s1, const void *s2)
11941 {
11942     sortItem_T  *si1, *si2;
11943     typval_T	*tv1, *tv2;
11944     char_u	*p1, *p2;
11945     char_u	*tofree1 = NULL, *tofree2 = NULL;
11946     int		res;
11947     char_u	numbuf1[NUMBUFLEN];
11948     char_u	numbuf2[NUMBUFLEN];
11949 
11950     si1 = (sortItem_T *)s1;
11951     si2 = (sortItem_T *)s2;
11952     tv1 = &si1->item->li_tv;
11953     tv2 = &si2->item->li_tv;
11954 
11955     if (sortinfo->item_compare_numbers)
11956     {
11957 	varnumber_T	v1 = tv_get_number(tv1);
11958 	varnumber_T	v2 = tv_get_number(tv2);
11959 
11960 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11961     }
11962 
11963 #ifdef FEAT_FLOAT
11964     if (sortinfo->item_compare_float)
11965     {
11966 	float_T	v1 = tv_get_float(tv1);
11967 	float_T	v2 = tv_get_float(tv2);
11968 
11969 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11970     }
11971 #endif
11972 
11973     /* tv2string() puts quotes around a string and allocates memory.  Don't do
11974      * that for string variables. Use a single quote when comparing with a
11975      * non-string to do what the docs promise. */
11976     if (tv1->v_type == VAR_STRING)
11977     {
11978 	if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11979 	    p1 = (char_u *)"'";
11980 	else
11981 	    p1 = tv1->vval.v_string;
11982     }
11983     else
11984 	p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11985     if (tv2->v_type == VAR_STRING)
11986     {
11987 	if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11988 	    p2 = (char_u *)"'";
11989 	else
11990 	    p2 = tv2->vval.v_string;
11991     }
11992     else
11993 	p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11994     if (p1 == NULL)
11995 	p1 = (char_u *)"";
11996     if (p2 == NULL)
11997 	p2 = (char_u *)"";
11998     if (!sortinfo->item_compare_numeric)
11999     {
12000 	if (sortinfo->item_compare_ic)
12001 	    res = STRICMP(p1, p2);
12002 	else
12003 	    res = STRCMP(p1, p2);
12004     }
12005     else
12006     {
12007 	double n1, n2;
12008 	n1 = strtod((char *)p1, (char **)&p1);
12009 	n2 = strtod((char *)p2, (char **)&p2);
12010 	res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12011     }
12012 
12013     /* When the result would be zero, compare the item indexes.  Makes the
12014      * sort stable. */
12015     if (res == 0 && !sortinfo->item_compare_keep_zero)
12016 	res = si1->idx > si2->idx ? 1 : -1;
12017 
12018     vim_free(tofree1);
12019     vim_free(tofree2);
12020     return res;
12021 }
12022 
12023     static int
12024 #ifdef __BORLANDC__
12025 _RTLENTRYF
12026 #endif
12027 item_compare2(const void *s1, const void *s2)
12028 {
12029     sortItem_T  *si1, *si2;
12030     int		res;
12031     typval_T	rettv;
12032     typval_T	argv[3];
12033     int		dummy;
12034     char_u	*func_name;
12035     partial_T	*partial = sortinfo->item_compare_partial;
12036 
12037     /* shortcut after failure in previous call; compare all items equal */
12038     if (sortinfo->item_compare_func_err)
12039 	return 0;
12040 
12041     si1 = (sortItem_T *)s1;
12042     si2 = (sortItem_T *)s2;
12043 
12044     if (partial == NULL)
12045 	func_name = sortinfo->item_compare_func;
12046     else
12047 	func_name = partial_name(partial);
12048 
12049     /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
12050      * in the copy without changing the original list items. */
12051     copy_tv(&si1->item->li_tv, &argv[0]);
12052     copy_tv(&si2->item->li_tv, &argv[1]);
12053 
12054     rettv.v_type = VAR_UNKNOWN;		/* clear_tv() uses this */
12055     res = call_func(func_name, (int)STRLEN(func_name),
12056 				 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
12057 				 partial, sortinfo->item_compare_selfdict);
12058     clear_tv(&argv[0]);
12059     clear_tv(&argv[1]);
12060 
12061     if (res == FAIL)
12062 	res = ITEM_COMPARE_FAIL;
12063     else
12064 	res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
12065     if (sortinfo->item_compare_func_err)
12066 	res = ITEM_COMPARE_FAIL;  /* return value has wrong type */
12067     clear_tv(&rettv);
12068 
12069     /* When the result would be zero, compare the pointers themselves.  Makes
12070      * the sort stable. */
12071     if (res == 0 && !sortinfo->item_compare_keep_zero)
12072 	res = si1->idx > si2->idx ? 1 : -1;
12073 
12074     return res;
12075 }
12076 
12077 /*
12078  * "sort({list})" function
12079  */
12080     static void
12081 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12082 {
12083     list_T	*l;
12084     listitem_T	*li;
12085     sortItem_T	*ptrs;
12086     sortinfo_T	*old_sortinfo;
12087     sortinfo_T	info;
12088     long	len;
12089     long	i;
12090 
12091     /* Pointer to current info struct used in compare function. Save and
12092      * restore the current one for nested calls. */
12093     old_sortinfo = sortinfo;
12094     sortinfo = &info;
12095 
12096     if (argvars[0].v_type != VAR_LIST)
12097 	semsg(_(e_listarg), sort ? "sort()" : "uniq()");
12098     else
12099     {
12100 	l = argvars[0].vval.v_list;
12101 	if (l == NULL || tv_check_lock(l->lv_lock,
12102 	     (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12103 									TRUE))
12104 	    goto theend;
12105 	rettv_list_set(rettv, l);
12106 
12107 	len = list_len(l);
12108 	if (len <= 1)
12109 	    goto theend;	/* short list sorts pretty quickly */
12110 
12111 	info.item_compare_ic = FALSE;
12112 	info.item_compare_numeric = FALSE;
12113 	info.item_compare_numbers = FALSE;
12114 #ifdef FEAT_FLOAT
12115 	info.item_compare_float = FALSE;
12116 #endif
12117 	info.item_compare_func = NULL;
12118 	info.item_compare_partial = NULL;
12119 	info.item_compare_selfdict = NULL;
12120 	if (argvars[1].v_type != VAR_UNKNOWN)
12121 	{
12122 	    /* optional second argument: {func} */
12123 	    if (argvars[1].v_type == VAR_FUNC)
12124 		info.item_compare_func = argvars[1].vval.v_string;
12125 	    else if (argvars[1].v_type == VAR_PARTIAL)
12126 		info.item_compare_partial = argvars[1].vval.v_partial;
12127 	    else
12128 	    {
12129 		int	    error = FALSE;
12130 
12131 		i = (long)tv_get_number_chk(&argvars[1], &error);
12132 		if (error)
12133 		    goto theend;	/* type error; errmsg already given */
12134 		if (i == 1)
12135 		    info.item_compare_ic = TRUE;
12136 		else if (argvars[1].v_type != VAR_NUMBER)
12137 		    info.item_compare_func = tv_get_string(&argvars[1]);
12138 		else if (i != 0)
12139 		{
12140 		    emsg(_(e_invarg));
12141 		    goto theend;
12142 		}
12143 		if (info.item_compare_func != NULL)
12144 		{
12145 		    if (*info.item_compare_func == NUL)
12146 		    {
12147 			/* empty string means default sort */
12148 			info.item_compare_func = NULL;
12149 		    }
12150 		    else if (STRCMP(info.item_compare_func, "n") == 0)
12151 		    {
12152 			info.item_compare_func = NULL;
12153 			info.item_compare_numeric = TRUE;
12154 		    }
12155 		    else if (STRCMP(info.item_compare_func, "N") == 0)
12156 		    {
12157 			info.item_compare_func = NULL;
12158 			info.item_compare_numbers = TRUE;
12159 		    }
12160 #ifdef FEAT_FLOAT
12161 		    else if (STRCMP(info.item_compare_func, "f") == 0)
12162 		    {
12163 			info.item_compare_func = NULL;
12164 			info.item_compare_float = TRUE;
12165 		    }
12166 #endif
12167 		    else if (STRCMP(info.item_compare_func, "i") == 0)
12168 		    {
12169 			info.item_compare_func = NULL;
12170 			info.item_compare_ic = TRUE;
12171 		    }
12172 		}
12173 	    }
12174 
12175 	    if (argvars[2].v_type != VAR_UNKNOWN)
12176 	    {
12177 		/* optional third argument: {dict} */
12178 		if (argvars[2].v_type != VAR_DICT)
12179 		{
12180 		    emsg(_(e_dictreq));
12181 		    goto theend;
12182 		}
12183 		info.item_compare_selfdict = argvars[2].vval.v_dict;
12184 	    }
12185 	}
12186 
12187 	/* Make an array with each entry pointing to an item in the List. */
12188 	ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12189 	if (ptrs == NULL)
12190 	    goto theend;
12191 
12192 	i = 0;
12193 	if (sort)
12194 	{
12195 	    /* sort(): ptrs will be the list to sort */
12196 	    for (li = l->lv_first; li != NULL; li = li->li_next)
12197 	    {
12198 		ptrs[i].item = li;
12199 		ptrs[i].idx = i;
12200 		++i;
12201 	    }
12202 
12203 	    info.item_compare_func_err = FALSE;
12204 	    info.item_compare_keep_zero = FALSE;
12205 	    /* test the compare function */
12206 	    if ((info.item_compare_func != NULL
12207 					 || info.item_compare_partial != NULL)
12208 		    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12209 							 == ITEM_COMPARE_FAIL)
12210 		emsg(_("E702: Sort compare function failed"));
12211 	    else
12212 	    {
12213 		/* Sort the array with item pointers. */
12214 		qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12215 		    info.item_compare_func == NULL
12216 					  && info.item_compare_partial == NULL
12217 					       ? item_compare : item_compare2);
12218 
12219 		if (!info.item_compare_func_err)
12220 		{
12221 		    /* Clear the List and append the items in sorted order. */
12222 		    l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12223 		    l->lv_len = 0;
12224 		    for (i = 0; i < len; ++i)
12225 			list_append(l, ptrs[i].item);
12226 		}
12227 	    }
12228 	}
12229 	else
12230 	{
12231 	    int	(*item_compare_func_ptr)(const void *, const void *);
12232 
12233 	    /* f_uniq(): ptrs will be a stack of items to remove */
12234 	    info.item_compare_func_err = FALSE;
12235 	    info.item_compare_keep_zero = TRUE;
12236 	    item_compare_func_ptr = info.item_compare_func != NULL
12237 					  || info.item_compare_partial != NULL
12238 					       ? item_compare2 : item_compare;
12239 
12240 	    for (li = l->lv_first; li != NULL && li->li_next != NULL;
12241 							     li = li->li_next)
12242 	    {
12243 		if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12244 									 == 0)
12245 		    ptrs[i++].item = li;
12246 		if (info.item_compare_func_err)
12247 		{
12248 		    emsg(_("E882: Uniq compare function failed"));
12249 		    break;
12250 		}
12251 	    }
12252 
12253 	    if (!info.item_compare_func_err)
12254 	    {
12255 		while (--i >= 0)
12256 		{
12257 		    li = ptrs[i].item->li_next;
12258 		    ptrs[i].item->li_next = li->li_next;
12259 		    if (li->li_next != NULL)
12260 			li->li_next->li_prev = ptrs[i].item;
12261 		    else
12262 			l->lv_last = ptrs[i].item;
12263 		    list_fix_watch(l, li);
12264 		    listitem_free(li);
12265 		    l->lv_len--;
12266 		}
12267 	    }
12268 	}
12269 
12270 	vim_free(ptrs);
12271     }
12272 theend:
12273     sortinfo = old_sortinfo;
12274 }
12275 
12276 /*
12277  * "sort({list})" function
12278  */
12279     static void
12280 f_sort(typval_T *argvars, typval_T *rettv)
12281 {
12282     do_sort_uniq(argvars, rettv, TRUE);
12283 }
12284 
12285 /*
12286  * "uniq({list})" function
12287  */
12288     static void
12289 f_uniq(typval_T *argvars, typval_T *rettv)
12290 {
12291     do_sort_uniq(argvars, rettv, FALSE);
12292 }
12293 
12294 /*
12295  * "soundfold({word})" function
12296  */
12297     static void
12298 f_soundfold(typval_T *argvars, typval_T *rettv)
12299 {
12300     char_u	*s;
12301 
12302     rettv->v_type = VAR_STRING;
12303     s = tv_get_string(&argvars[0]);
12304 #ifdef FEAT_SPELL
12305     rettv->vval.v_string = eval_soundfold(s);
12306 #else
12307     rettv->vval.v_string = vim_strsave(s);
12308 #endif
12309 }
12310 
12311 /*
12312  * "spellbadword()" function
12313  */
12314     static void
12315 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12316 {
12317     char_u	*word = (char_u *)"";
12318     hlf_T	attr = HLF_COUNT;
12319     int		len = 0;
12320 
12321     if (rettv_list_alloc(rettv) == FAIL)
12322 	return;
12323 
12324 #ifdef FEAT_SPELL
12325     if (argvars[0].v_type == VAR_UNKNOWN)
12326     {
12327 	/* Find the start and length of the badly spelled word. */
12328 	len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12329 	if (len != 0)
12330 	{
12331 	    word = ml_get_cursor();
12332 	    curwin->w_set_curswant = TRUE;
12333 	}
12334     }
12335     else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12336     {
12337 	char_u	*str = tv_get_string_chk(&argvars[0]);
12338 	int	capcol = -1;
12339 
12340 	if (str != NULL)
12341 	{
12342 	    /* Check the argument for spelling. */
12343 	    while (*str != NUL)
12344 	    {
12345 		len = spell_check(curwin, str, &attr, &capcol, FALSE);
12346 		if (attr != HLF_COUNT)
12347 		{
12348 		    word = str;
12349 		    break;
12350 		}
12351 		str += len;
12352 		capcol -= len;
12353 	    }
12354 	}
12355     }
12356 #endif
12357 
12358     list_append_string(rettv->vval.v_list, word, len);
12359     list_append_string(rettv->vval.v_list, (char_u *)(
12360 			attr == HLF_SPB ? "bad" :
12361 			attr == HLF_SPR ? "rare" :
12362 			attr == HLF_SPL ? "local" :
12363 			attr == HLF_SPC ? "caps" :
12364 			""), -1);
12365 }
12366 
12367 /*
12368  * "spellsuggest()" function
12369  */
12370     static void
12371 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12372 {
12373 #ifdef FEAT_SPELL
12374     char_u	*str;
12375     int		typeerr = FALSE;
12376     int		maxcount;
12377     garray_T	ga;
12378     int		i;
12379     listitem_T	*li;
12380     int		need_capital = FALSE;
12381 #endif
12382 
12383     if (rettv_list_alloc(rettv) == FAIL)
12384 	return;
12385 
12386 #ifdef FEAT_SPELL
12387     if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12388     {
12389 	str = tv_get_string(&argvars[0]);
12390 	if (argvars[1].v_type != VAR_UNKNOWN)
12391 	{
12392 	    maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
12393 	    if (maxcount <= 0)
12394 		return;
12395 	    if (argvars[2].v_type != VAR_UNKNOWN)
12396 	    {
12397 		need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
12398 		if (typeerr)
12399 		    return;
12400 	    }
12401 	}
12402 	else
12403 	    maxcount = 25;
12404 
12405 	spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12406 
12407 	for (i = 0; i < ga.ga_len; ++i)
12408 	{
12409 	    str = ((char_u **)ga.ga_data)[i];
12410 
12411 	    li = listitem_alloc();
12412 	    if (li == NULL)
12413 		vim_free(str);
12414 	    else
12415 	    {
12416 		li->li_tv.v_type = VAR_STRING;
12417 		li->li_tv.v_lock = 0;
12418 		li->li_tv.vval.v_string = str;
12419 		list_append(rettv->vval.v_list, li);
12420 	    }
12421 	}
12422 	ga_clear(&ga);
12423     }
12424 #endif
12425 }
12426 
12427     static void
12428 f_split(typval_T *argvars, typval_T *rettv)
12429 {
12430     char_u	*str;
12431     char_u	*end;
12432     char_u	*pat = NULL;
12433     regmatch_T	regmatch;
12434     char_u	patbuf[NUMBUFLEN];
12435     char_u	*save_cpo;
12436     int		match;
12437     colnr_T	col = 0;
12438     int		keepempty = FALSE;
12439     int		typeerr = FALSE;
12440 
12441     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12442     save_cpo = p_cpo;
12443     p_cpo = (char_u *)"";
12444 
12445     str = tv_get_string(&argvars[0]);
12446     if (argvars[1].v_type != VAR_UNKNOWN)
12447     {
12448 	pat = tv_get_string_buf_chk(&argvars[1], patbuf);
12449 	if (pat == NULL)
12450 	    typeerr = TRUE;
12451 	if (argvars[2].v_type != VAR_UNKNOWN)
12452 	    keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
12453     }
12454     if (pat == NULL || *pat == NUL)
12455 	pat = (char_u *)"[\\x01- ]\\+";
12456 
12457     if (rettv_list_alloc(rettv) == FAIL)
12458 	return;
12459     if (typeerr)
12460 	return;
12461 
12462     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12463     if (regmatch.regprog != NULL)
12464     {
12465 	regmatch.rm_ic = FALSE;
12466 	while (*str != NUL || keepempty)
12467 	{
12468 	    if (*str == NUL)
12469 		match = FALSE;	/* empty item at the end */
12470 	    else
12471 		match = vim_regexec_nl(&regmatch, str, col);
12472 	    if (match)
12473 		end = regmatch.startp[0];
12474 	    else
12475 		end = str + STRLEN(str);
12476 	    if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12477 			   && *str != NUL && match && end < regmatch.endp[0]))
12478 	    {
12479 		if (list_append_string(rettv->vval.v_list, str,
12480 						    (int)(end - str)) == FAIL)
12481 		    break;
12482 	    }
12483 	    if (!match)
12484 		break;
12485 	    // Advance to just after the match.
12486 	    if (regmatch.endp[0] > str)
12487 		col = 0;
12488 	    else
12489 		// Don't get stuck at the same match.
12490 		col = (*mb_ptr2len)(regmatch.endp[0]);
12491 	    str = regmatch.endp[0];
12492 	}
12493 
12494 	vim_regfree(regmatch.regprog);
12495     }
12496 
12497     p_cpo = save_cpo;
12498 }
12499 
12500 #ifdef FEAT_FLOAT
12501 /*
12502  * "sqrt()" function
12503  */
12504     static void
12505 f_sqrt(typval_T *argvars, typval_T *rettv)
12506 {
12507     float_T	f = 0.0;
12508 
12509     rettv->v_type = VAR_FLOAT;
12510     if (get_float_arg(argvars, &f) == OK)
12511 	rettv->vval.v_float = sqrt(f);
12512     else
12513 	rettv->vval.v_float = 0.0;
12514 }
12515 
12516 /*
12517  * "str2float()" function
12518  */
12519     static void
12520 f_str2float(typval_T *argvars, typval_T *rettv)
12521 {
12522     char_u *p = skipwhite(tv_get_string(&argvars[0]));
12523     int     isneg = (*p == '-');
12524 
12525     if (*p == '+' || *p == '-')
12526 	p = skipwhite(p + 1);
12527     (void)string2float(p, &rettv->vval.v_float);
12528     if (isneg)
12529 	rettv->vval.v_float *= -1;
12530     rettv->v_type = VAR_FLOAT;
12531 }
12532 #endif
12533 
12534 /*
12535  * "str2nr()" function
12536  */
12537     static void
12538 f_str2nr(typval_T *argvars, typval_T *rettv)
12539 {
12540     int		base = 10;
12541     char_u	*p;
12542     varnumber_T	n;
12543     int		what;
12544     int		isneg;
12545 
12546     if (argvars[1].v_type != VAR_UNKNOWN)
12547     {
12548 	base = (int)tv_get_number(&argvars[1]);
12549 	if (base != 2 && base != 8 && base != 10 && base != 16)
12550 	{
12551 	    emsg(_(e_invarg));
12552 	    return;
12553 	}
12554     }
12555 
12556     p = skipwhite(tv_get_string(&argvars[0]));
12557     isneg = (*p == '-');
12558     if (*p == '+' || *p == '-')
12559 	p = skipwhite(p + 1);
12560     switch (base)
12561     {
12562 	case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12563 	case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12564 	case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12565 	default: what = 0;
12566     }
12567     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
12568     if (isneg)
12569 	rettv->vval.v_number = -n;
12570     else
12571 	rettv->vval.v_number = n;
12572 
12573 }
12574 
12575 #ifdef HAVE_STRFTIME
12576 /*
12577  * "strftime({format}[, {time}])" function
12578  */
12579     static void
12580 f_strftime(typval_T *argvars, typval_T *rettv)
12581 {
12582     char_u	result_buf[256];
12583     struct tm	*curtime;
12584     time_t	seconds;
12585     char_u	*p;
12586 
12587     rettv->v_type = VAR_STRING;
12588 
12589     p = tv_get_string(&argvars[0]);
12590     if (argvars[1].v_type == VAR_UNKNOWN)
12591 	seconds = time(NULL);
12592     else
12593 	seconds = (time_t)tv_get_number(&argvars[1]);
12594     curtime = localtime(&seconds);
12595     /* MSVC returns NULL for an invalid value of seconds. */
12596     if (curtime == NULL)
12597 	rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12598     else
12599     {
12600 	vimconv_T   conv;
12601 	char_u	    *enc;
12602 
12603 	conv.vc_type = CONV_NONE;
12604 	enc = enc_locale();
12605 	convert_setup(&conv, p_enc, enc);
12606 	if (conv.vc_type != CONV_NONE)
12607 	    p = string_convert(&conv, p, NULL);
12608 	if (p != NULL)
12609 	    (void)strftime((char *)result_buf, sizeof(result_buf),
12610 							  (char *)p, curtime);
12611 	else
12612 	    result_buf[0] = NUL;
12613 
12614 	if (conv.vc_type != CONV_NONE)
12615 	    vim_free(p);
12616 	convert_setup(&conv, enc, p_enc);
12617 	if (conv.vc_type != CONV_NONE)
12618 	    rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12619 	else
12620 	    rettv->vval.v_string = vim_strsave(result_buf);
12621 
12622 	/* Release conversion descriptors */
12623 	convert_setup(&conv, NULL, NULL);
12624 	vim_free(enc);
12625     }
12626 }
12627 #endif
12628 
12629 /*
12630  * "strgetchar()" function
12631  */
12632     static void
12633 f_strgetchar(typval_T *argvars, typval_T *rettv)
12634 {
12635     char_u	*str;
12636     int		len;
12637     int		error = FALSE;
12638     int		charidx;
12639     int		byteidx = 0;
12640 
12641     rettv->vval.v_number = -1;
12642     str = tv_get_string_chk(&argvars[0]);
12643     if (str == NULL)
12644 	return;
12645     len = (int)STRLEN(str);
12646     charidx = (int)tv_get_number_chk(&argvars[1], &error);
12647     if (error)
12648 	return;
12649 
12650     while (charidx >= 0 && byteidx < len)
12651     {
12652 	if (charidx == 0)
12653 	{
12654 	    rettv->vval.v_number = mb_ptr2char(str + byteidx);
12655 	    break;
12656 	}
12657 	--charidx;
12658 	byteidx += MB_CPTR2LEN(str + byteidx);
12659     }
12660 }
12661 
12662 /*
12663  * "stridx()" function
12664  */
12665     static void
12666 f_stridx(typval_T *argvars, typval_T *rettv)
12667 {
12668     char_u	buf[NUMBUFLEN];
12669     char_u	*needle;
12670     char_u	*haystack;
12671     char_u	*save_haystack;
12672     char_u	*pos;
12673     int		start_idx;
12674 
12675     needle = tv_get_string_chk(&argvars[1]);
12676     save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
12677     rettv->vval.v_number = -1;
12678     if (needle == NULL || haystack == NULL)
12679 	return;		/* type error; errmsg already given */
12680 
12681     if (argvars[2].v_type != VAR_UNKNOWN)
12682     {
12683 	int	    error = FALSE;
12684 
12685 	start_idx = (int)tv_get_number_chk(&argvars[2], &error);
12686 	if (error || start_idx >= (int)STRLEN(haystack))
12687 	    return;
12688 	if (start_idx >= 0)
12689 	    haystack += start_idx;
12690     }
12691 
12692     pos	= (char_u *)strstr((char *)haystack, (char *)needle);
12693     if (pos != NULL)
12694 	rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12695 }
12696 
12697 /*
12698  * "string()" function
12699  */
12700     void
12701 f_string(typval_T *argvars, typval_T *rettv)
12702 {
12703     char_u	*tofree;
12704     char_u	numbuf[NUMBUFLEN];
12705 
12706     rettv->v_type = VAR_STRING;
12707     rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12708 								get_copyID());
12709     /* Make a copy if we have a value but it's not in allocated memory. */
12710     if (rettv->vval.v_string != NULL && tofree == NULL)
12711 	rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12712 }
12713 
12714 /*
12715  * "strlen()" function
12716  */
12717     static void
12718 f_strlen(typval_T *argvars, typval_T *rettv)
12719 {
12720     rettv->vval.v_number = (varnumber_T)(STRLEN(
12721 					      tv_get_string(&argvars[0])));
12722 }
12723 
12724 /*
12725  * "strchars()" function
12726  */
12727     static void
12728 f_strchars(typval_T *argvars, typval_T *rettv)
12729 {
12730     char_u		*s = tv_get_string(&argvars[0]);
12731     int			skipcc = 0;
12732     varnumber_T		len = 0;
12733     int			(*func_mb_ptr2char_adv)(char_u **pp);
12734 
12735     if (argvars[1].v_type != VAR_UNKNOWN)
12736 	skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
12737     if (skipcc < 0 || skipcc > 1)
12738 	emsg(_(e_invarg));
12739     else
12740     {
12741 	func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12742 	while (*s != NUL)
12743 	{
12744 	    func_mb_ptr2char_adv(&s);
12745 	    ++len;
12746 	}
12747 	rettv->vval.v_number = len;
12748     }
12749 }
12750 
12751 /*
12752  * "strdisplaywidth()" function
12753  */
12754     static void
12755 f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12756 {
12757     char_u	*s = tv_get_string(&argvars[0]);
12758     int		col = 0;
12759 
12760     if (argvars[1].v_type != VAR_UNKNOWN)
12761 	col = (int)tv_get_number(&argvars[1]);
12762 
12763     rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12764 }
12765 
12766 /*
12767  * "strwidth()" function
12768  */
12769     static void
12770 f_strwidth(typval_T *argvars, typval_T *rettv)
12771 {
12772     char_u	*s = tv_get_string(&argvars[0]);
12773 
12774     rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
12775 }
12776 
12777 /*
12778  * "strcharpart()" function
12779  */
12780     static void
12781 f_strcharpart(typval_T *argvars, typval_T *rettv)
12782 {
12783     char_u	*p;
12784     int		nchar;
12785     int		nbyte = 0;
12786     int		charlen;
12787     int		len = 0;
12788     int		slen;
12789     int		error = FALSE;
12790 
12791     p = tv_get_string(&argvars[0]);
12792     slen = (int)STRLEN(p);
12793 
12794     nchar = (int)tv_get_number_chk(&argvars[1], &error);
12795     if (!error)
12796     {
12797 	if (nchar > 0)
12798 	    while (nchar > 0 && nbyte < slen)
12799 	    {
12800 		nbyte += MB_CPTR2LEN(p + nbyte);
12801 		--nchar;
12802 	    }
12803 	else
12804 	    nbyte = nchar;
12805 	if (argvars[2].v_type != VAR_UNKNOWN)
12806 	{
12807 	    charlen = (int)tv_get_number(&argvars[2]);
12808 	    while (charlen > 0 && nbyte + len < slen)
12809 	    {
12810 		int off = nbyte + len;
12811 
12812 		if (off < 0)
12813 		    len += 1;
12814 		else
12815 		    len += MB_CPTR2LEN(p + off);
12816 		--charlen;
12817 	    }
12818 	}
12819 	else
12820 	    len = slen - nbyte;    /* default: all bytes that are available. */
12821     }
12822 
12823     /*
12824      * Only return the overlap between the specified part and the actual
12825      * string.
12826      */
12827     if (nbyte < 0)
12828     {
12829 	len += nbyte;
12830 	nbyte = 0;
12831     }
12832     else if (nbyte > slen)
12833 	nbyte = slen;
12834     if (len < 0)
12835 	len = 0;
12836     else if (nbyte + len > slen)
12837 	len = slen - nbyte;
12838 
12839     rettv->v_type = VAR_STRING;
12840     rettv->vval.v_string = vim_strnsave(p + nbyte, len);
12841 }
12842 
12843 /*
12844  * "strpart()" function
12845  */
12846     static void
12847 f_strpart(typval_T *argvars, typval_T *rettv)
12848 {
12849     char_u	*p;
12850     int		n;
12851     int		len;
12852     int		slen;
12853     int		error = FALSE;
12854 
12855     p = tv_get_string(&argvars[0]);
12856     slen = (int)STRLEN(p);
12857 
12858     n = (int)tv_get_number_chk(&argvars[1], &error);
12859     if (error)
12860 	len = 0;
12861     else if (argvars[2].v_type != VAR_UNKNOWN)
12862 	len = (int)tv_get_number(&argvars[2]);
12863     else
12864 	len = slen - n;	    /* default len: all bytes that are available. */
12865 
12866     /*
12867      * Only return the overlap between the specified part and the actual
12868      * string.
12869      */
12870     if (n < 0)
12871     {
12872 	len += n;
12873 	n = 0;
12874     }
12875     else if (n > slen)
12876 	n = slen;
12877     if (len < 0)
12878 	len = 0;
12879     else if (n + len > slen)
12880 	len = slen - n;
12881 
12882     rettv->v_type = VAR_STRING;
12883     rettv->vval.v_string = vim_strnsave(p + n, len);
12884 }
12885 
12886 /*
12887  * "strridx()" function
12888  */
12889     static void
12890 f_strridx(typval_T *argvars, typval_T *rettv)
12891 {
12892     char_u	buf[NUMBUFLEN];
12893     char_u	*needle;
12894     char_u	*haystack;
12895     char_u	*rest;
12896     char_u	*lastmatch = NULL;
12897     int		haystack_len, end_idx;
12898 
12899     needle = tv_get_string_chk(&argvars[1]);
12900     haystack = tv_get_string_buf_chk(&argvars[0], buf);
12901 
12902     rettv->vval.v_number = -1;
12903     if (needle == NULL || haystack == NULL)
12904 	return;		/* type error; errmsg already given */
12905 
12906     haystack_len = (int)STRLEN(haystack);
12907     if (argvars[2].v_type != VAR_UNKNOWN)
12908     {
12909 	/* Third argument: upper limit for index */
12910 	end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
12911 	if (end_idx < 0)
12912 	    return;	/* can never find a match */
12913     }
12914     else
12915 	end_idx = haystack_len;
12916 
12917     if (*needle == NUL)
12918     {
12919 	/* Empty string matches past the end. */
12920 	lastmatch = haystack + end_idx;
12921     }
12922     else
12923     {
12924 	for (rest = haystack; *rest != '\0'; ++rest)
12925 	{
12926 	    rest = (char_u *)strstr((char *)rest, (char *)needle);
12927 	    if (rest == NULL || rest > haystack + end_idx)
12928 		break;
12929 	    lastmatch = rest;
12930 	}
12931     }
12932 
12933     if (lastmatch == NULL)
12934 	rettv->vval.v_number = -1;
12935     else
12936 	rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12937 }
12938 
12939 /*
12940  * "strtrans()" function
12941  */
12942     static void
12943 f_strtrans(typval_T *argvars, typval_T *rettv)
12944 {
12945     rettv->v_type = VAR_STRING;
12946     rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
12947 }
12948 
12949 /*
12950  * "submatch()" function
12951  */
12952     static void
12953 f_submatch(typval_T *argvars, typval_T *rettv)
12954 {
12955     int		error = FALSE;
12956     int		no;
12957     int		retList = 0;
12958 
12959     no = (int)tv_get_number_chk(&argvars[0], &error);
12960     if (error)
12961 	return;
12962     if (no < 0 || no >= NSUBEXP)
12963     {
12964 	semsg(_("E935: invalid submatch number: %d"), no);
12965 	return;
12966     }
12967     if (argvars[1].v_type != VAR_UNKNOWN)
12968 	retList = (int)tv_get_number_chk(&argvars[1], &error);
12969     if (error)
12970 	return;
12971 
12972     if (retList == 0)
12973     {
12974 	rettv->v_type = VAR_STRING;
12975 	rettv->vval.v_string = reg_submatch(no);
12976     }
12977     else
12978     {
12979 	rettv->v_type = VAR_LIST;
12980 	rettv->vval.v_list = reg_submatch_list(no);
12981     }
12982 }
12983 
12984 /*
12985  * "substitute()" function
12986  */
12987     static void
12988 f_substitute(typval_T *argvars, typval_T *rettv)
12989 {
12990     char_u	patbuf[NUMBUFLEN];
12991     char_u	subbuf[NUMBUFLEN];
12992     char_u	flagsbuf[NUMBUFLEN];
12993 
12994     char_u	*str = tv_get_string_chk(&argvars[0]);
12995     char_u	*pat = tv_get_string_buf_chk(&argvars[1], patbuf);
12996     char_u	*sub = NULL;
12997     typval_T	*expr = NULL;
12998     char_u	*flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
12999 
13000     if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13001 	expr = &argvars[2];
13002     else
13003 	sub = tv_get_string_buf_chk(&argvars[2], subbuf);
13004 
13005     rettv->v_type = VAR_STRING;
13006     if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13007 								|| flg == NULL)
13008 	rettv->vval.v_string = NULL;
13009     else
13010 	rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
13011 }
13012 
13013 /*
13014  * "swapinfo(swap_filename)" function
13015  */
13016     static void
13017 f_swapinfo(typval_T *argvars, typval_T *rettv)
13018 {
13019     if (rettv_dict_alloc(rettv) == OK)
13020 	get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
13021 }
13022 
13023 /*
13024  * "swapname(expr)" function
13025  */
13026     static void
13027 f_swapname(typval_T *argvars, typval_T *rettv)
13028 {
13029     buf_T	*buf;
13030 
13031     rettv->v_type = VAR_STRING;
13032     buf = tv_get_buf(&argvars[0], FALSE);
13033     if (buf == NULL || buf->b_ml.ml_mfp == NULL
13034 					|| buf->b_ml.ml_mfp->mf_fname == NULL)
13035 	rettv->vval.v_string = NULL;
13036     else
13037 	rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13038 }
13039 
13040 /*
13041  * "synID(lnum, col, trans)" function
13042  */
13043     static void
13044 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13045 {
13046     int		id = 0;
13047 #ifdef FEAT_SYN_HL
13048     linenr_T	lnum;
13049     colnr_T	col;
13050     int		trans;
13051     int		transerr = FALSE;
13052 
13053     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13054     col = (linenr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13055     trans = (int)tv_get_number_chk(&argvars[2], &transerr);
13056 
13057     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13058 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13059 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13060 #endif
13061 
13062     rettv->vval.v_number = id;
13063 }
13064 
13065 /*
13066  * "synIDattr(id, what [, mode])" function
13067  */
13068     static void
13069 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13070 {
13071     char_u	*p = NULL;
13072 #ifdef FEAT_SYN_HL
13073     int		id;
13074     char_u	*what;
13075     char_u	*mode;
13076     char_u	modebuf[NUMBUFLEN];
13077     int		modec;
13078 
13079     id = (int)tv_get_number(&argvars[0]);
13080     what = tv_get_string(&argvars[1]);
13081     if (argvars[2].v_type != VAR_UNKNOWN)
13082     {
13083 	mode = tv_get_string_buf(&argvars[2], modebuf);
13084 	modec = TOLOWER_ASC(mode[0]);
13085 	if (modec != 't' && modec != 'c' && modec != 'g')
13086 	    modec = 0;	/* replace invalid with current */
13087     }
13088     else
13089     {
13090 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13091 	if (USE_24BIT)
13092 	    modec = 'g';
13093 	else
13094 #endif
13095 	    if (t_colors > 1)
13096 	    modec = 'c';
13097 	else
13098 	    modec = 't';
13099     }
13100 
13101     switch (TOLOWER_ASC(what[0]))
13102     {
13103 	case 'b':
13104 		if (TOLOWER_ASC(what[1]) == 'g')	/* bg[#] */
13105 		    p = highlight_color(id, what, modec);
13106 		else					/* bold */
13107 		    p = highlight_has_attr(id, HL_BOLD, modec);
13108 		break;
13109 
13110 	case 'f':					/* fg[#] or font */
13111 		p = highlight_color(id, what, modec);
13112 		break;
13113 
13114 	case 'i':
13115 		if (TOLOWER_ASC(what[1]) == 'n')	/* inverse */
13116 		    p = highlight_has_attr(id, HL_INVERSE, modec);
13117 		else					/* italic */
13118 		    p = highlight_has_attr(id, HL_ITALIC, modec);
13119 		break;
13120 
13121 	case 'n':					/* name */
13122 		p = get_highlight_name_ext(NULL, id - 1, FALSE);
13123 		break;
13124 
13125 	case 'r':					/* reverse */
13126 		p = highlight_has_attr(id, HL_INVERSE, modec);
13127 		break;
13128 
13129 	case 's':
13130 		if (TOLOWER_ASC(what[1]) == 'p')	/* sp[#] */
13131 		    p = highlight_color(id, what, modec);
13132 							/* strikeout */
13133 		else if (TOLOWER_ASC(what[1]) == 't' &&
13134 			TOLOWER_ASC(what[2]) == 'r')
13135 		    p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
13136 		else					/* standout */
13137 		    p = highlight_has_attr(id, HL_STANDOUT, modec);
13138 		break;
13139 
13140 	case 'u':
13141 		if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13142 							/* underline */
13143 		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
13144 		else
13145 							/* undercurl */
13146 		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
13147 		break;
13148     }
13149 
13150     if (p != NULL)
13151 	p = vim_strsave(p);
13152 #endif
13153     rettv->v_type = VAR_STRING;
13154     rettv->vval.v_string = p;
13155 }
13156 
13157 /*
13158  * "synIDtrans(id)" function
13159  */
13160     static void
13161 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13162 {
13163     int		id;
13164 
13165 #ifdef FEAT_SYN_HL
13166     id = (int)tv_get_number(&argvars[0]);
13167 
13168     if (id > 0)
13169 	id = syn_get_final_id(id);
13170     else
13171 #endif
13172 	id = 0;
13173 
13174     rettv->vval.v_number = id;
13175 }
13176 
13177 /*
13178  * "synconcealed(lnum, col)" function
13179  */
13180     static void
13181 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13182 {
13183 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13184     linenr_T	lnum;
13185     colnr_T	col;
13186     int		syntax_flags = 0;
13187     int		cchar;
13188     int		matchid = 0;
13189     char_u	str[NUMBUFLEN];
13190 #endif
13191 
13192     rettv_list_set(rettv, NULL);
13193 
13194 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13195     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13196     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13197 
13198     vim_memset(str, NUL, sizeof(str));
13199 
13200     if (rettv_list_alloc(rettv) != FAIL)
13201     {
13202 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13203 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13204 	    && curwin->w_p_cole > 0)
13205 	{
13206 	    (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13207 	    syntax_flags = get_syntax_info(&matchid);
13208 
13209 	    /* get the conceal character */
13210 	    if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13211 	    {
13212 		cchar = syn_get_sub_char();
13213 		if (cchar == NUL && curwin->w_p_cole == 1)
13214 		    cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
13215 		if (cchar != NUL)
13216 		{
13217 		    if (has_mbyte)
13218 			(*mb_char2bytes)(cchar, str);
13219 		    else
13220 			str[0] = cchar;
13221 		}
13222 	    }
13223 	}
13224 
13225 	list_append_number(rettv->vval.v_list,
13226 					    (syntax_flags & HL_CONCEAL) != 0);
13227 	/* -1 to auto-determine strlen */
13228 	list_append_string(rettv->vval.v_list, str, -1);
13229 	list_append_number(rettv->vval.v_list, matchid);
13230     }
13231 #endif
13232 }
13233 
13234 /*
13235  * "synstack(lnum, col)" function
13236  */
13237     static void
13238 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13239 {
13240 #ifdef FEAT_SYN_HL
13241     linenr_T	lnum;
13242     colnr_T	col;
13243     int		i;
13244     int		id;
13245 #endif
13246 
13247     rettv_list_set(rettv, NULL);
13248 
13249 #ifdef FEAT_SYN_HL
13250     lnum = tv_get_lnum(argvars);		/* -1 on type error */
13251     col = (colnr_T)tv_get_number(&argvars[1]) - 1;	/* -1 on type error */
13252 
13253     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13254 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13255 	    && rettv_list_alloc(rettv) != FAIL)
13256     {
13257 	(void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13258 	for (i = 0; ; ++i)
13259 	{
13260 	    id = syn_get_stack_item(i);
13261 	    if (id < 0)
13262 		break;
13263 	    if (list_append_number(rettv->vval.v_list, id) == FAIL)
13264 		break;
13265 	}
13266     }
13267 #endif
13268 }
13269 
13270     static void
13271 get_cmd_output_as_rettv(
13272     typval_T	*argvars,
13273     typval_T	*rettv,
13274     int		retlist)
13275 {
13276     char_u	*res = NULL;
13277     char_u	*p;
13278     char_u	*infile = NULL;
13279     int		err = FALSE;
13280     FILE	*fd;
13281     list_T	*list = NULL;
13282     int		flags = SHELL_SILENT;
13283 
13284     rettv->v_type = VAR_STRING;
13285     rettv->vval.v_string = NULL;
13286     if (check_restricted() || check_secure())
13287 	goto errret;
13288 
13289     if (argvars[1].v_type != VAR_UNKNOWN)
13290     {
13291 	/*
13292 	 * Write the text to a temp file, to be used for input of the shell
13293 	 * command.
13294 	 */
13295 	if ((infile = vim_tempname('i', TRUE)) == NULL)
13296 	{
13297 	    emsg(_(e_notmp));
13298 	    goto errret;
13299 	}
13300 
13301 	fd = mch_fopen((char *)infile, WRITEBIN);
13302 	if (fd == NULL)
13303 	{
13304 	    semsg(_(e_notopen), infile);
13305 	    goto errret;
13306 	}
13307 	if (argvars[1].v_type == VAR_NUMBER)
13308 	{
13309 	    linenr_T	lnum;
13310 	    buf_T	*buf;
13311 
13312 	    buf = buflist_findnr(argvars[1].vval.v_number);
13313 	    if (buf == NULL)
13314 	    {
13315 		semsg(_(e_nobufnr), argvars[1].vval.v_number);
13316 		fclose(fd);
13317 		goto errret;
13318 	    }
13319 
13320 	    for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13321 	    {
13322 		for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13323 		    if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13324 		    {
13325 			err = TRUE;
13326 			break;
13327 		    }
13328 		if (putc(NL, fd) == EOF)
13329 		{
13330 		    err = TRUE;
13331 		    break;
13332 		}
13333 	    }
13334 	}
13335 	else if (argvars[1].v_type == VAR_LIST)
13336 	{
13337 	    if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13338 		err = TRUE;
13339 	}
13340 	else
13341 	{
13342 	    size_t	len;
13343 	    char_u	buf[NUMBUFLEN];
13344 
13345 	    p = tv_get_string_buf_chk(&argvars[1], buf);
13346 	    if (p == NULL)
13347 	    {
13348 		fclose(fd);
13349 		goto errret;		/* type error; errmsg already given */
13350 	    }
13351 	    len = STRLEN(p);
13352 	    if (len > 0 && fwrite(p, len, 1, fd) != 1)
13353 		err = TRUE;
13354 	}
13355 	if (fclose(fd) != 0)
13356 	    err = TRUE;
13357 	if (err)
13358 	{
13359 	    emsg(_("E677: Error writing temp file"));
13360 	    goto errret;
13361 	}
13362     }
13363 
13364     /* Omit SHELL_COOKED when invoked with ":silent".  Avoids that the shell
13365      * echoes typeahead, that messes up the display. */
13366     if (!msg_silent)
13367 	flags += SHELL_COOKED;
13368 
13369     if (retlist)
13370     {
13371 	int		len;
13372 	listitem_T	*li;
13373 	char_u		*s = NULL;
13374 	char_u		*start;
13375 	char_u		*end;
13376 	int		i;
13377 
13378 	res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
13379 	if (res == NULL)
13380 	    goto errret;
13381 
13382 	list = list_alloc();
13383 	if (list == NULL)
13384 	    goto errret;
13385 
13386 	for (i = 0; i < len; ++i)
13387 	{
13388 	    start = res + i;
13389 	    while (i < len && res[i] != NL)
13390 		++i;
13391 	    end = res + i;
13392 
13393 	    s = alloc((unsigned)(end - start + 1));
13394 	    if (s == NULL)
13395 		goto errret;
13396 
13397 	    for (p = s; start < end; ++p, ++start)
13398 		*p = *start == NUL ? NL : *start;
13399 	    *p = NUL;
13400 
13401 	    li = listitem_alloc();
13402 	    if (li == NULL)
13403 	    {
13404 		vim_free(s);
13405 		goto errret;
13406 	    }
13407 	    li->li_tv.v_type = VAR_STRING;
13408 	    li->li_tv.v_lock = 0;
13409 	    li->li_tv.vval.v_string = s;
13410 	    list_append(list, li);
13411 	}
13412 
13413 	rettv_list_set(rettv, list);
13414 	list = NULL;
13415     }
13416     else
13417     {
13418 	res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
13419 #ifdef USE_CR
13420 	/* translate <CR> into <NL> */
13421 	if (res != NULL)
13422 	{
13423 	    char_u	*s;
13424 
13425 	    for (s = res; *s; ++s)
13426 	    {
13427 		if (*s == CAR)
13428 		    *s = NL;
13429 	    }
13430 	}
13431 #else
13432 # ifdef USE_CRNL
13433 	/* translate <CR><NL> into <NL> */
13434 	if (res != NULL)
13435 	{
13436 	    char_u	*s, *d;
13437 
13438 	    d = res;
13439 	    for (s = res; *s; ++s)
13440 	    {
13441 		if (s[0] == CAR && s[1] == NL)
13442 		    ++s;
13443 		*d++ = *s;
13444 	    }
13445 	    *d = NUL;
13446 	}
13447 # endif
13448 #endif
13449 	rettv->vval.v_string = res;
13450 	res = NULL;
13451     }
13452 
13453 errret:
13454     if (infile != NULL)
13455     {
13456 	mch_remove(infile);
13457 	vim_free(infile);
13458     }
13459     if (res != NULL)
13460 	vim_free(res);
13461     if (list != NULL)
13462 	list_free(list);
13463 }
13464 
13465 /*
13466  * "system()" function
13467  */
13468     static void
13469 f_system(typval_T *argvars, typval_T *rettv)
13470 {
13471     get_cmd_output_as_rettv(argvars, rettv, FALSE);
13472 }
13473 
13474 /*
13475  * "systemlist()" function
13476  */
13477     static void
13478 f_systemlist(typval_T *argvars, typval_T *rettv)
13479 {
13480     get_cmd_output_as_rettv(argvars, rettv, TRUE);
13481 }
13482 
13483 /*
13484  * "tabpagebuflist()" function
13485  */
13486     static void
13487 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13488 {
13489     tabpage_T	*tp;
13490     win_T	*wp = NULL;
13491 
13492     if (argvars[0].v_type == VAR_UNKNOWN)
13493 	wp = firstwin;
13494     else
13495     {
13496 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
13497 	if (tp != NULL)
13498 	    wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13499     }
13500     if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13501     {
13502 	for (; wp != NULL; wp = wp->w_next)
13503 	    if (list_append_number(rettv->vval.v_list,
13504 						wp->w_buffer->b_fnum) == FAIL)
13505 		break;
13506     }
13507 }
13508 
13509 /*
13510  * "tabpagenr()" function
13511  */
13512     static void
13513 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13514 {
13515     int		nr = 1;
13516     char_u	*arg;
13517 
13518     if (argvars[0].v_type != VAR_UNKNOWN)
13519     {
13520 	arg = tv_get_string_chk(&argvars[0]);
13521 	nr = 0;
13522 	if (arg != NULL)
13523 	{
13524 	    if (STRCMP(arg, "$") == 0)
13525 		nr = tabpage_index(NULL) - 1;
13526 	    else
13527 		semsg(_(e_invexpr2), arg);
13528 	}
13529     }
13530     else
13531 	nr = tabpage_index(curtab);
13532     rettv->vval.v_number = nr;
13533 }
13534 
13535 
13536 /*
13537  * Common code for tabpagewinnr() and winnr().
13538  */
13539     static int
13540 get_winnr(tabpage_T *tp, typval_T *argvar)
13541 {
13542     win_T	*twin;
13543     int		nr = 1;
13544     win_T	*wp;
13545     char_u	*arg;
13546 
13547     twin = (tp == curtab) ? curwin : tp->tp_curwin;
13548     if (argvar->v_type != VAR_UNKNOWN)
13549     {
13550 	arg = tv_get_string_chk(argvar);
13551 	if (arg == NULL)
13552 	    nr = 0;		/* type error; errmsg already given */
13553 	else if (STRCMP(arg, "$") == 0)
13554 	    twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13555 	else if (STRCMP(arg, "#") == 0)
13556 	{
13557 	    twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13558 	    if (twin == NULL)
13559 		nr = 0;
13560 	}
13561 	else
13562 	{
13563 	    semsg(_(e_invexpr2), arg);
13564 	    nr = 0;
13565 	}
13566     }
13567 
13568     if (nr > 0)
13569 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13570 					      wp != twin; wp = wp->w_next)
13571 	{
13572 	    if (wp == NULL)
13573 	    {
13574 		/* didn't find it in this tabpage */
13575 		nr = 0;
13576 		break;
13577 	    }
13578 	    ++nr;
13579 	}
13580     return nr;
13581 }
13582 
13583 /*
13584  * "tabpagewinnr()" function
13585  */
13586     static void
13587 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13588 {
13589     int		nr = 1;
13590     tabpage_T	*tp;
13591 
13592     tp = find_tabpage((int)tv_get_number(&argvars[0]));
13593     if (tp == NULL)
13594 	nr = 0;
13595     else
13596 	nr = get_winnr(tp, &argvars[1]);
13597     rettv->vval.v_number = nr;
13598 }
13599 
13600 /*
13601  * "tagfiles()" function
13602  */
13603     static void
13604 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13605 {
13606     char_u	*fname;
13607     tagname_T	tn;
13608     int		first;
13609 
13610     if (rettv_list_alloc(rettv) == FAIL)
13611 	return;
13612     fname = alloc(MAXPATHL);
13613     if (fname == NULL)
13614 	return;
13615 
13616     for (first = TRUE; ; first = FALSE)
13617 	if (get_tagfname(&tn, first, fname) == FAIL
13618 		|| list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13619 	    break;
13620     tagname_free(&tn);
13621     vim_free(fname);
13622 }
13623 
13624 /*
13625  * "taglist()" function
13626  */
13627     static void
13628 f_taglist(typval_T *argvars, typval_T *rettv)
13629 {
13630     char_u  *fname = NULL;
13631     char_u  *tag_pattern;
13632 
13633     tag_pattern = tv_get_string(&argvars[0]);
13634 
13635     rettv->vval.v_number = FALSE;
13636     if (*tag_pattern == NUL)
13637 	return;
13638 
13639     if (argvars[1].v_type != VAR_UNKNOWN)
13640 	fname = tv_get_string(&argvars[1]);
13641     if (rettv_list_alloc(rettv) == OK)
13642 	(void)get_tags(rettv->vval.v_list, tag_pattern, fname);
13643 }
13644 
13645 /*
13646  * "tempname()" function
13647  */
13648     static void
13649 f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13650 {
13651     static int	x = 'A';
13652 
13653     rettv->v_type = VAR_STRING;
13654     rettv->vval.v_string = vim_tempname(x, FALSE);
13655 
13656     /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13657      * names.  Skip 'I' and 'O', they are used for shell redirection. */
13658     do
13659     {
13660 	if (x == 'Z')
13661 	    x = '0';
13662 	else if (x == '9')
13663 	    x = 'A';
13664 	else
13665 	{
13666 #ifdef EBCDIC
13667 	    if (x == 'I')
13668 		x = 'J';
13669 	    else if (x == 'R')
13670 		x = 'S';
13671 	    else
13672 #endif
13673 		++x;
13674 	}
13675     } while (x == 'I' || x == 'O');
13676 }
13677 
13678 #ifdef FEAT_FLOAT
13679 /*
13680  * "tan()" function
13681  */
13682     static void
13683 f_tan(typval_T *argvars, typval_T *rettv)
13684 {
13685     float_T	f = 0.0;
13686 
13687     rettv->v_type = VAR_FLOAT;
13688     if (get_float_arg(argvars, &f) == OK)
13689 	rettv->vval.v_float = tan(f);
13690     else
13691 	rettv->vval.v_float = 0.0;
13692 }
13693 
13694 /*
13695  * "tanh()" function
13696  */
13697     static void
13698 f_tanh(typval_T *argvars, typval_T *rettv)
13699 {
13700     float_T	f = 0.0;
13701 
13702     rettv->v_type = VAR_FLOAT;
13703     if (get_float_arg(argvars, &f) == OK)
13704 	rettv->vval.v_float = tanh(f);
13705     else
13706 	rettv->vval.v_float = 0.0;
13707 }
13708 #endif
13709 
13710 /*
13711  * "test_alloc_fail(id, countdown, repeat)" function
13712  */
13713     static void
13714 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13715 {
13716     if (argvars[0].v_type != VAR_NUMBER
13717 	    || argvars[0].vval.v_number <= 0
13718 	    || argvars[1].v_type != VAR_NUMBER
13719 	    || argvars[1].vval.v_number < 0
13720 	    || argvars[2].v_type != VAR_NUMBER)
13721 	emsg(_(e_invarg));
13722     else
13723     {
13724 	alloc_fail_id = argvars[0].vval.v_number;
13725 	if (alloc_fail_id >= aid_last)
13726 	    emsg(_(e_invarg));
13727 	alloc_fail_countdown = argvars[1].vval.v_number;
13728 	alloc_fail_repeat = argvars[2].vval.v_number;
13729 	did_outofmem_msg = FALSE;
13730     }
13731 }
13732 
13733 /*
13734  * "test_autochdir()"
13735  */
13736     static void
13737 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13738 {
13739 #if defined(FEAT_AUTOCHDIR)
13740     test_autochdir = TRUE;
13741 #endif
13742 }
13743 
13744 /*
13745  * "test_feedinput()"
13746  */
13747     static void
13748 f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13749 {
13750 #ifdef USE_INPUT_BUF
13751     char_u	*val = tv_get_string_chk(&argvars[0]);
13752 
13753     if (val != NULL)
13754     {
13755 	trash_input_buf();
13756 	add_to_input_buf_csi(val, (int)STRLEN(val));
13757     }
13758 #endif
13759 }
13760 
13761 /*
13762  * "test_option_not_set({name})" function
13763  */
13764     static void
13765 f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13766 {
13767     char_u *name = (char_u *)"";
13768 
13769     if (argvars[0].v_type != VAR_STRING)
13770 	emsg(_(e_invarg));
13771     else
13772     {
13773 	name = tv_get_string(&argvars[0]);
13774 	if (reset_option_was_set(name) == FAIL)
13775 	    semsg(_(e_invarg2), name);
13776     }
13777 }
13778 
13779 /*
13780  * "test_override({name}, {val})" function
13781  */
13782     static void
13783 f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
13784 {
13785     char_u *name = (char_u *)"";
13786     int     val;
13787     static int save_starting = -1;
13788 
13789     if (argvars[0].v_type != VAR_STRING
13790 	    || (argvars[1].v_type) != VAR_NUMBER)
13791 	emsg(_(e_invarg));
13792     else
13793     {
13794 	name = tv_get_string(&argvars[0]);
13795 	val = (int)tv_get_number(&argvars[1]);
13796 
13797 	if (STRCMP(name, (char_u *)"redraw") == 0)
13798 	    disable_redraw_for_testing = val;
13799 	else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13800 	    ignore_redraw_flag_for_testing = val;
13801 	else if (STRCMP(name, (char_u *)"char_avail") == 0)
13802 	    disable_char_avail_for_testing = val;
13803 	else if (STRCMP(name, (char_u *)"starting") == 0)
13804 	{
13805 	    if (val)
13806 	    {
13807 		if (save_starting < 0)
13808 		    save_starting = starting;
13809 		starting = 0;
13810 	    }
13811 	    else
13812 	    {
13813 		starting = save_starting;
13814 		save_starting = -1;
13815 	    }
13816 	}
13817 	else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13818 	    nfa_fail_for_testing = val;
13819 	else if (STRCMP(name, (char_u *)"ALL") == 0)
13820 	{
13821 	    disable_char_avail_for_testing = FALSE;
13822 	    disable_redraw_for_testing = FALSE;
13823 	    ignore_redraw_flag_for_testing = FALSE;
13824 	    nfa_fail_for_testing = FALSE;
13825 	    if (save_starting >= 0)
13826 	    {
13827 		starting = save_starting;
13828 		save_starting = -1;
13829 	    }
13830 	}
13831 	else
13832 	    semsg(_(e_invarg2), name);
13833     }
13834 }
13835 
13836 /*
13837  * "test_garbagecollect_now()" function
13838  */
13839     static void
13840 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13841 {
13842     /* This is dangerous, any Lists and Dicts used internally may be freed
13843      * while still in use. */
13844     garbage_collect(TRUE);
13845 }
13846 
13847 /*
13848  * "test_ignore_error()" function
13849  */
13850     static void
13851 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13852 {
13853      ignore_error_for_testing(tv_get_string(&argvars[0]));
13854 }
13855 
13856     static void
13857 f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13858 {
13859     rettv->v_type = VAR_BLOB;
13860     rettv->vval.v_blob = NULL;
13861 }
13862 
13863 #ifdef FEAT_JOB_CHANNEL
13864     static void
13865 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13866 {
13867     rettv->v_type = VAR_CHANNEL;
13868     rettv->vval.v_channel = NULL;
13869 }
13870 #endif
13871 
13872     static void
13873 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13874 {
13875     rettv_dict_set(rettv, NULL);
13876 }
13877 
13878 #ifdef FEAT_JOB_CHANNEL
13879     static void
13880 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13881 {
13882     rettv->v_type = VAR_JOB;
13883     rettv->vval.v_job = NULL;
13884 }
13885 #endif
13886 
13887     static void
13888 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13889 {
13890     rettv_list_set(rettv, NULL);
13891 }
13892 
13893     static void
13894 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13895 {
13896     rettv->v_type = VAR_PARTIAL;
13897     rettv->vval.v_partial = NULL;
13898 }
13899 
13900     static void
13901 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13902 {
13903     rettv->v_type = VAR_STRING;
13904     rettv->vval.v_string = NULL;
13905 }
13906 
13907 #ifdef FEAT_GUI
13908     static void
13909 f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13910 {
13911     char_u	*which;
13912     long	value;
13913     int		dragging;
13914     scrollbar_T *sb = NULL;
13915 
13916     if (argvars[0].v_type != VAR_STRING
13917 	    || (argvars[1].v_type) != VAR_NUMBER
13918 	    || (argvars[2].v_type) != VAR_NUMBER)
13919     {
13920 	emsg(_(e_invarg));
13921 	return;
13922     }
13923     which = tv_get_string(&argvars[0]);
13924     value = tv_get_number(&argvars[1]);
13925     dragging = tv_get_number(&argvars[2]);
13926 
13927     if (STRCMP(which, "left") == 0)
13928 	sb = &curwin->w_scrollbars[SBAR_LEFT];
13929     else if (STRCMP(which, "right") == 0)
13930 	sb = &curwin->w_scrollbars[SBAR_RIGHT];
13931     else if (STRCMP(which, "hor") == 0)
13932 	sb = &gui.bottom_sbar;
13933     if (sb == NULL)
13934     {
13935 	semsg(_(e_invarg2), which);
13936 	return;
13937     }
13938     gui_drag_scrollbar(sb, value, dragging);
13939 # ifndef USE_ON_FLY_SCROLL
13940     // need to loop through normal_cmd() to handle the scroll events
13941     exec_normal(FALSE, TRUE, FALSE);
13942 # endif
13943 }
13944 #endif
13945 
13946     static void
13947 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13948 {
13949     time_for_testing = (time_t)tv_get_number(&argvars[0]);
13950 }
13951 
13952 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
13953 /*
13954  * Get a callback from "arg".  It can be a Funcref or a function name.
13955  * When "arg" is zero return an empty string.
13956  * Return NULL for an invalid argument.
13957  */
13958     char_u *
13959 get_callback(typval_T *arg, partial_T **pp)
13960 {
13961     if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13962     {
13963 	*pp = arg->vval.v_partial;
13964 	++(*pp)->pt_refcount;
13965 	return partial_name(*pp);
13966     }
13967     *pp = NULL;
13968     if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
13969     {
13970 	func_ref(arg->vval.v_string);
13971 	return arg->vval.v_string;
13972     }
13973     if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13974 	return (char_u *)"";
13975     emsg(_("E921: Invalid callback argument"));
13976     return NULL;
13977 }
13978 
13979 /*
13980  * Unref/free "callback" and "partial" returned by get_callback().
13981  */
13982     void
13983 free_callback(char_u *callback, partial_T *partial)
13984 {
13985     if (partial != NULL)
13986 	partial_unref(partial);
13987     else if (callback != NULL)
13988     {
13989 	func_unref(callback);
13990 	vim_free(callback);
13991     }
13992 }
13993 #endif
13994 
13995 #ifdef FEAT_TIMERS
13996 /*
13997  * "timer_info([timer])" function
13998  */
13999     static void
14000 f_timer_info(typval_T *argvars, typval_T *rettv)
14001 {
14002     timer_T *timer = NULL;
14003 
14004     if (rettv_list_alloc(rettv) != OK)
14005 	return;
14006     if (argvars[0].v_type != VAR_UNKNOWN)
14007     {
14008 	if (argvars[0].v_type != VAR_NUMBER)
14009 	    emsg(_(e_number_exp));
14010 	else
14011 	{
14012 	    timer = find_timer((int)tv_get_number(&argvars[0]));
14013 	    if (timer != NULL)
14014 		add_timer_info(rettv, timer);
14015 	}
14016     }
14017     else
14018 	add_timer_info_all(rettv);
14019 }
14020 
14021 /*
14022  * "timer_pause(timer, paused)" function
14023  */
14024     static void
14025 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14026 {
14027     timer_T	*timer = NULL;
14028     int		paused = (int)tv_get_number(&argvars[1]);
14029 
14030     if (argvars[0].v_type != VAR_NUMBER)
14031 	emsg(_(e_number_exp));
14032     else
14033     {
14034 	timer = find_timer((int)tv_get_number(&argvars[0]));
14035 	if (timer != NULL)
14036 	    timer->tr_paused = paused;
14037     }
14038 }
14039 
14040 /*
14041  * "timer_start(time, callback [, options])" function
14042  */
14043     static void
14044 f_timer_start(typval_T *argvars, typval_T *rettv)
14045 {
14046     long	msec = (long)tv_get_number(&argvars[0]);
14047     timer_T	*timer;
14048     int		repeat = 0;
14049     char_u	*callback;
14050     dict_T	*dict;
14051     partial_T	*partial;
14052 
14053     rettv->vval.v_number = -1;
14054     if (check_secure())
14055 	return;
14056     if (argvars[2].v_type != VAR_UNKNOWN)
14057     {
14058 	if (argvars[2].v_type != VAR_DICT
14059 				   || (dict = argvars[2].vval.v_dict) == NULL)
14060 	{
14061 	    semsg(_(e_invarg2), tv_get_string(&argvars[2]));
14062 	    return;
14063 	}
14064 	if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
14065 	    repeat = dict_get_number(dict, (char_u *)"repeat");
14066     }
14067 
14068     callback = get_callback(&argvars[1], &partial);
14069     if (callback == NULL)
14070 	return;
14071 
14072     timer = create_timer(msec, repeat);
14073     if (timer == NULL)
14074 	free_callback(callback, partial);
14075     else
14076     {
14077 	if (partial == NULL)
14078 	    timer->tr_callback = vim_strsave(callback);
14079 	else
14080 	    /* pointer into the partial */
14081 	    timer->tr_callback = callback;
14082 	timer->tr_partial = partial;
14083 	rettv->vval.v_number = (varnumber_T)timer->tr_id;
14084     }
14085 }
14086 
14087 /*
14088  * "timer_stop(timer)" function
14089  */
14090     static void
14091 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14092 {
14093     timer_T *timer;
14094 
14095     if (argvars[0].v_type != VAR_NUMBER)
14096     {
14097 	emsg(_(e_number_exp));
14098 	return;
14099     }
14100     timer = find_timer((int)tv_get_number(&argvars[0]));
14101     if (timer != NULL)
14102 	stop_timer(timer);
14103 }
14104 
14105 /*
14106  * "timer_stopall()" function
14107  */
14108     static void
14109 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14110 {
14111     stop_all_timers();
14112 }
14113 #endif
14114 
14115 /*
14116  * "tolower(string)" function
14117  */
14118     static void
14119 f_tolower(typval_T *argvars, typval_T *rettv)
14120 {
14121     rettv->v_type = VAR_STRING;
14122     rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
14123 }
14124 
14125 /*
14126  * "toupper(string)" function
14127  */
14128     static void
14129 f_toupper(typval_T *argvars, typval_T *rettv)
14130 {
14131     rettv->v_type = VAR_STRING;
14132     rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
14133 }
14134 
14135 /*
14136  * "tr(string, fromstr, tostr)" function
14137  */
14138     static void
14139 f_tr(typval_T *argvars, typval_T *rettv)
14140 {
14141     char_u	*in_str;
14142     char_u	*fromstr;
14143     char_u	*tostr;
14144     char_u	*p;
14145     int		inlen;
14146     int		fromlen;
14147     int		tolen;
14148     int		idx;
14149     char_u	*cpstr;
14150     int		cplen;
14151     int		first = TRUE;
14152     char_u	buf[NUMBUFLEN];
14153     char_u	buf2[NUMBUFLEN];
14154     garray_T	ga;
14155 
14156     in_str = tv_get_string(&argvars[0]);
14157     fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14158     tostr = tv_get_string_buf_chk(&argvars[2], buf2);
14159 
14160     /* Default return value: empty string. */
14161     rettv->v_type = VAR_STRING;
14162     rettv->vval.v_string = NULL;
14163     if (fromstr == NULL || tostr == NULL)
14164 	    return;		/* type error; errmsg already given */
14165     ga_init2(&ga, (int)sizeof(char), 80);
14166 
14167     if (!has_mbyte)
14168 	/* not multi-byte: fromstr and tostr must be the same length */
14169 	if (STRLEN(fromstr) != STRLEN(tostr))
14170 	{
14171 error:
14172 	    semsg(_(e_invarg2), fromstr);
14173 	    ga_clear(&ga);
14174 	    return;
14175 	}
14176 
14177     /* fromstr and tostr have to contain the same number of chars */
14178     while (*in_str != NUL)
14179     {
14180 	if (has_mbyte)
14181 	{
14182 	    inlen = (*mb_ptr2len)(in_str);
14183 	    cpstr = in_str;
14184 	    cplen = inlen;
14185 	    idx = 0;
14186 	    for (p = fromstr; *p != NUL; p += fromlen)
14187 	    {
14188 		fromlen = (*mb_ptr2len)(p);
14189 		if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14190 		{
14191 		    for (p = tostr; *p != NUL; p += tolen)
14192 		    {
14193 			tolen = (*mb_ptr2len)(p);
14194 			if (idx-- == 0)
14195 			{
14196 			    cplen = tolen;
14197 			    cpstr = p;
14198 			    break;
14199 			}
14200 		    }
14201 		    if (*p == NUL)	/* tostr is shorter than fromstr */
14202 			goto error;
14203 		    break;
14204 		}
14205 		++idx;
14206 	    }
14207 
14208 	    if (first && cpstr == in_str)
14209 	    {
14210 		/* Check that fromstr and tostr have the same number of
14211 		 * (multi-byte) characters.  Done only once when a character
14212 		 * of in_str doesn't appear in fromstr. */
14213 		first = FALSE;
14214 		for (p = tostr; *p != NUL; p += tolen)
14215 		{
14216 		    tolen = (*mb_ptr2len)(p);
14217 		    --idx;
14218 		}
14219 		if (idx != 0)
14220 		    goto error;
14221 	    }
14222 
14223 	    (void)ga_grow(&ga, cplen);
14224 	    mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14225 	    ga.ga_len += cplen;
14226 
14227 	    in_str += inlen;
14228 	}
14229 	else
14230 	{
14231 	    /* When not using multi-byte chars we can do it faster. */
14232 	    p = vim_strchr(fromstr, *in_str);
14233 	    if (p != NULL)
14234 		ga_append(&ga, tostr[p - fromstr]);
14235 	    else
14236 		ga_append(&ga, *in_str);
14237 	    ++in_str;
14238 	}
14239     }
14240 
14241     /* add a terminating NUL */
14242     (void)ga_grow(&ga, 1);
14243     ga_append(&ga, NUL);
14244 
14245     rettv->vval.v_string = ga.ga_data;
14246 }
14247 
14248 /*
14249  * "trim({expr})" function
14250  */
14251     static void
14252 f_trim(typval_T *argvars, typval_T *rettv)
14253 {
14254     char_u	buf1[NUMBUFLEN];
14255     char_u	buf2[NUMBUFLEN];
14256     char_u	*head = tv_get_string_buf_chk(&argvars[0], buf1);
14257     char_u	*mask = NULL;
14258     char_u	*tail;
14259     char_u	*prev;
14260     char_u	*p;
14261     int		c1;
14262 
14263     rettv->v_type = VAR_STRING;
14264     if (head == NULL)
14265     {
14266 	rettv->vval.v_string = NULL;
14267 	return;
14268     }
14269 
14270     if (argvars[1].v_type == VAR_STRING)
14271 	mask = tv_get_string_buf_chk(&argvars[1], buf2);
14272 
14273     while (*head != NUL)
14274     {
14275 	c1 = PTR2CHAR(head);
14276 	if (mask == NULL)
14277 	{
14278 	    if (c1 > ' ' && c1 != 0xa0)
14279 		break;
14280 	}
14281 	else
14282 	{
14283 	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
14284 		if (c1 == PTR2CHAR(p))
14285 		    break;
14286 	    if (*p == NUL)
14287 		break;
14288 	}
14289 	MB_PTR_ADV(head);
14290     }
14291 
14292     for (tail = head + STRLEN(head); tail > head; tail = prev)
14293     {
14294 	prev = tail;
14295 	MB_PTR_BACK(head, prev);
14296 	c1 = PTR2CHAR(prev);
14297 	if (mask == NULL)
14298 	{
14299 	    if (c1 > ' ' && c1 != 0xa0)
14300 		break;
14301 	}
14302 	else
14303 	{
14304 	    for (p = mask; *p != NUL; MB_PTR_ADV(p))
14305 		if (c1 == PTR2CHAR(p))
14306 		    break;
14307 	    if (*p == NUL)
14308 		break;
14309 	}
14310     }
14311     rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14312 }
14313 
14314 #ifdef FEAT_FLOAT
14315 /*
14316  * "trunc({float})" function
14317  */
14318     static void
14319 f_trunc(typval_T *argvars, typval_T *rettv)
14320 {
14321     float_T	f = 0.0;
14322 
14323     rettv->v_type = VAR_FLOAT;
14324     if (get_float_arg(argvars, &f) == OK)
14325 	/* trunc() is not in C90, use floor() or ceil() instead. */
14326 	rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14327     else
14328 	rettv->vval.v_float = 0.0;
14329 }
14330 #endif
14331 
14332 /*
14333  * "type(expr)" function
14334  */
14335     static void
14336 f_type(typval_T *argvars, typval_T *rettv)
14337 {
14338     int n = -1;
14339 
14340     switch (argvars[0].v_type)
14341     {
14342 	case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14343 	case VAR_STRING: n = VAR_TYPE_STRING; break;
14344 	case VAR_PARTIAL:
14345 	case VAR_FUNC:   n = VAR_TYPE_FUNC; break;
14346 	case VAR_LIST:   n = VAR_TYPE_LIST; break;
14347 	case VAR_DICT:   n = VAR_TYPE_DICT; break;
14348 	case VAR_FLOAT:  n = VAR_TYPE_FLOAT; break;
14349 	case VAR_SPECIAL:
14350 	     if (argvars[0].vval.v_number == VVAL_FALSE
14351 		     || argvars[0].vval.v_number == VVAL_TRUE)
14352 		 n = VAR_TYPE_BOOL;
14353 	     else
14354 		 n = VAR_TYPE_NONE;
14355 	     break;
14356 	case VAR_JOB:     n = VAR_TYPE_JOB; break;
14357 	case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
14358 	case VAR_BLOB:    n = VAR_TYPE_BLOB; break;
14359 	case VAR_UNKNOWN:
14360 	     internal_error("f_type(UNKNOWN)");
14361 	     n = -1;
14362 	     break;
14363     }
14364     rettv->vval.v_number = n;
14365 }
14366 
14367 /*
14368  * "undofile(name)" function
14369  */
14370     static void
14371 f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14372 {
14373     rettv->v_type = VAR_STRING;
14374 #ifdef FEAT_PERSISTENT_UNDO
14375     {
14376 	char_u *fname = tv_get_string(&argvars[0]);
14377 
14378 	if (*fname == NUL)
14379 	{
14380 	    /* If there is no file name there will be no undo file. */
14381 	    rettv->vval.v_string = NULL;
14382 	}
14383 	else
14384 	{
14385 	    char_u *ffname = FullName_save(fname, FALSE);
14386 
14387 	    if (ffname != NULL)
14388 		rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14389 	    vim_free(ffname);
14390 	}
14391     }
14392 #else
14393     rettv->vval.v_string = NULL;
14394 #endif
14395 }
14396 
14397 /*
14398  * "undotree()" function
14399  */
14400     static void
14401 f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14402 {
14403     if (rettv_dict_alloc(rettv) == OK)
14404     {
14405 	dict_T *dict = rettv->vval.v_dict;
14406 	list_T *list;
14407 
14408 	dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14409 	dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14410 	dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14411 	dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14412 	dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14413 	dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
14414 
14415 	list = list_alloc();
14416 	if (list != NULL)
14417 	{
14418 	    u_eval_tree(curbuf->b_u_oldhead, list);
14419 	    dict_add_list(dict, "entries", list);
14420 	}
14421     }
14422 }
14423 
14424 /*
14425  * "values(dict)" function
14426  */
14427     static void
14428 f_values(typval_T *argvars, typval_T *rettv)
14429 {
14430     dict_list(argvars, rettv, 1);
14431 }
14432 
14433 /*
14434  * "virtcol(string)" function
14435  */
14436     static void
14437 f_virtcol(typval_T *argvars, typval_T *rettv)
14438 {
14439     colnr_T	vcol = 0;
14440     pos_T	*fp;
14441     int		fnum = curbuf->b_fnum;
14442 
14443     fp = var2fpos(&argvars[0], FALSE, &fnum);
14444     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14445 						    && fnum == curbuf->b_fnum)
14446     {
14447 	getvvcol(curwin, fp, NULL, NULL, &vcol);
14448 	++vcol;
14449     }
14450 
14451     rettv->vval.v_number = vcol;
14452 }
14453 
14454 /*
14455  * "visualmode()" function
14456  */
14457     static void
14458 f_visualmode(typval_T *argvars, typval_T *rettv)
14459 {
14460     char_u	str[2];
14461 
14462     rettv->v_type = VAR_STRING;
14463     str[0] = curbuf->b_visual_mode_eval;
14464     str[1] = NUL;
14465     rettv->vval.v_string = vim_strsave(str);
14466 
14467     /* A non-zero number or non-empty string argument: reset mode. */
14468     if (non_zero_arg(&argvars[0]))
14469 	curbuf->b_visual_mode_eval = NUL;
14470 }
14471 
14472 /*
14473  * "wildmenumode()" function
14474  */
14475     static void
14476 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14477 {
14478 #ifdef FEAT_WILDMENU
14479     if (wild_menu_showing)
14480 	rettv->vval.v_number = 1;
14481 #endif
14482 }
14483 
14484 /*
14485  * "winbufnr(nr)" function
14486  */
14487     static void
14488 f_winbufnr(typval_T *argvars, typval_T *rettv)
14489 {
14490     win_T	*wp;
14491 
14492     wp = find_win_by_nr_or_id(&argvars[0]);
14493     if (wp == NULL)
14494 	rettv->vval.v_number = -1;
14495     else
14496 	rettv->vval.v_number = wp->w_buffer->b_fnum;
14497 }
14498 
14499 /*
14500  * "wincol()" function
14501  */
14502     static void
14503 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14504 {
14505     validate_cursor();
14506     rettv->vval.v_number = curwin->w_wcol + 1;
14507 }
14508 
14509 /*
14510  * "winheight(nr)" function
14511  */
14512     static void
14513 f_winheight(typval_T *argvars, typval_T *rettv)
14514 {
14515     win_T	*wp;
14516 
14517     wp = find_win_by_nr_or_id(&argvars[0]);
14518     if (wp == NULL)
14519 	rettv->vval.v_number = -1;
14520     else
14521 	rettv->vval.v_number = wp->w_height;
14522 }
14523 
14524 /*
14525  * "winlayout()" function
14526  */
14527     static void
14528 f_winlayout(typval_T *argvars, typval_T *rettv)
14529 {
14530     tabpage_T	*tp;
14531 
14532     if (rettv_list_alloc(rettv) != OK)
14533 	return;
14534 
14535     if (argvars[0].v_type == VAR_UNKNOWN)
14536 	tp = curtab;
14537     else
14538     {
14539 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
14540 	if (tp == NULL)
14541 	    return;
14542     }
14543 
14544     get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14545 }
14546 
14547 /*
14548  * "winline()" function
14549  */
14550     static void
14551 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14552 {
14553     validate_cursor();
14554     rettv->vval.v_number = curwin->w_wrow + 1;
14555 }
14556 
14557 /*
14558  * "winnr()" function
14559  */
14560     static void
14561 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14562 {
14563     int		nr = 1;
14564 
14565     nr = get_winnr(curtab, &argvars[0]);
14566     rettv->vval.v_number = nr;
14567 }
14568 
14569 /*
14570  * "winrestcmd()" function
14571  */
14572     static void
14573 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14574 {
14575     win_T	*wp;
14576     int		winnr = 1;
14577     garray_T	ga;
14578     char_u	buf[50];
14579 
14580     ga_init2(&ga, (int)sizeof(char), 70);
14581     FOR_ALL_WINDOWS(wp)
14582     {
14583 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14584 	ga_concat(&ga, buf);
14585 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14586 	ga_concat(&ga, buf);
14587 	++winnr;
14588     }
14589     ga_append(&ga, NUL);
14590 
14591     rettv->vval.v_string = ga.ga_data;
14592     rettv->v_type = VAR_STRING;
14593 }
14594 
14595 /*
14596  * "winrestview()" function
14597  */
14598     static void
14599 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14600 {
14601     dict_T	*dict;
14602 
14603     if (argvars[0].v_type != VAR_DICT
14604 	    || (dict = argvars[0].vval.v_dict) == NULL)
14605 	emsg(_(e_invarg));
14606     else
14607     {
14608 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
14609 	    curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
14610 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
14611 	    curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
14612 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
14613 	    curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
14614 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14615 	{
14616 	    curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
14617 	    curwin->w_set_curswant = FALSE;
14618 	}
14619 
14620 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
14621 	    set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
14622 #ifdef FEAT_DIFF
14623 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
14624 	    curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
14625 #endif
14626 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
14627 	    curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
14628 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
14629 	    curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
14630 
14631 	check_cursor();
14632 	win_new_height(curwin, curwin->w_height);
14633 	win_new_width(curwin, curwin->w_width);
14634 	changed_window_setting();
14635 
14636 	if (curwin->w_topline <= 0)
14637 	    curwin->w_topline = 1;
14638 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14639 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
14640 #ifdef FEAT_DIFF
14641 	check_topfill(curwin, TRUE);
14642 #endif
14643     }
14644 }
14645 
14646 /*
14647  * "winsaveview()" function
14648  */
14649     static void
14650 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14651 {
14652     dict_T	*dict;
14653 
14654     if (rettv_dict_alloc(rettv) == FAIL)
14655 	return;
14656     dict = rettv->vval.v_dict;
14657 
14658     dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14659     dict_add_number(dict, "col", (long)curwin->w_cursor.col);
14660     dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
14661     update_curswant();
14662     dict_add_number(dict, "curswant", (long)curwin->w_curswant);
14663 
14664     dict_add_number(dict, "topline", (long)curwin->w_topline);
14665 #ifdef FEAT_DIFF
14666     dict_add_number(dict, "topfill", (long)curwin->w_topfill);
14667 #endif
14668     dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14669     dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
14670 }
14671 
14672 /*
14673  * "winwidth(nr)" function
14674  */
14675     static void
14676 f_winwidth(typval_T *argvars, typval_T *rettv)
14677 {
14678     win_T	*wp;
14679 
14680     wp = find_win_by_nr_or_id(&argvars[0]);
14681     if (wp == NULL)
14682 	rettv->vval.v_number = -1;
14683     else
14684 	rettv->vval.v_number = wp->w_width;
14685 }
14686 
14687 /*
14688  * "wordcount()" function
14689  */
14690     static void
14691 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14692 {
14693     if (rettv_dict_alloc(rettv) == FAIL)
14694 	return;
14695     cursor_pos_info(rettv->vval.v_dict);
14696 }
14697 
14698 /*
14699  * "writefile()" function
14700  */
14701     static void
14702 f_writefile(typval_T *argvars, typval_T *rettv)
14703 {
14704     int		binary = FALSE;
14705     int		append = FALSE;
14706 #ifdef HAVE_FSYNC
14707     int		do_fsync = p_fs;
14708 #endif
14709     char_u	*fname;
14710     FILE	*fd;
14711     int		ret = 0;
14712     listitem_T	*li;
14713     list_T	*list = NULL;
14714     blob_T	*blob = NULL;
14715 
14716     rettv->vval.v_number = -1;
14717     if (check_restricted() || check_secure())
14718 	return;
14719 
14720     if (argvars[0].v_type == VAR_LIST)
14721     {
14722 	list = argvars[0].vval.v_list;
14723 	if (list == NULL)
14724 	    return;
14725 	for (li = list->lv_first; li != NULL; li = li->li_next)
14726 	    if (tv_get_string_chk(&li->li_tv) == NULL)
14727 		return;
14728     }
14729     else if (argvars[0].v_type == VAR_BLOB)
14730     {
14731 	blob = argvars[0].vval.v_blob;
14732 	if (blob == NULL)
14733 	    return;
14734     }
14735     else
14736     {
14737 	semsg(_(e_invarg2), "writefile()");
14738 	return;
14739     }
14740 
14741     if (argvars[2].v_type != VAR_UNKNOWN)
14742     {
14743 	char_u *arg2 = tv_get_string_chk(&argvars[2]);
14744 
14745 	if (arg2 == NULL)
14746 	    return;
14747 	if (vim_strchr(arg2, 'b') != NULL)
14748 	    binary = TRUE;
14749 	if (vim_strchr(arg2, 'a') != NULL)
14750 	    append = TRUE;
14751 #ifdef HAVE_FSYNC
14752 	if (vim_strchr(arg2, 's') != NULL)
14753 	    do_fsync = TRUE;
14754 	else if (vim_strchr(arg2, 'S') != NULL)
14755 	    do_fsync = FALSE;
14756 #endif
14757     }
14758 
14759     fname = tv_get_string_chk(&argvars[1]);
14760     if (fname == NULL)
14761 	return;
14762 
14763     /* Always open the file in binary mode, library functions have a mind of
14764      * their own about CR-LF conversion. */
14765     if (*fname == NUL || (fd = mch_fopen((char *)fname,
14766 				      append ? APPENDBIN : WRITEBIN)) == NULL)
14767     {
14768 	semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
14769 	ret = -1;
14770     }
14771     else if (blob)
14772     {
14773 	if (write_blob(fd, blob) == FAIL)
14774 	    ret = -1;
14775 #ifdef HAVE_FSYNC
14776 	else if (do_fsync)
14777 	    // Ignore the error, the user wouldn't know what to do about it.
14778 	    // May happen for a device.
14779 	    vim_ignored = fsync(fileno(fd));
14780 #endif
14781 	fclose(fd);
14782     }
14783     else
14784     {
14785 	if (write_list(fd, list, binary) == FAIL)
14786 	    ret = -1;
14787 #ifdef HAVE_FSYNC
14788 	else if (do_fsync)
14789 	    /* Ignore the error, the user wouldn't know what to do about it.
14790 	     * May happen for a device. */
14791 	    vim_ignored = fsync(fileno(fd));
14792 #endif
14793 	fclose(fd);
14794     }
14795 
14796     rettv->vval.v_number = ret;
14797 }
14798 
14799 /*
14800  * "xor(expr, expr)" function
14801  */
14802     static void
14803 f_xor(typval_T *argvars, typval_T *rettv)
14804 {
14805     rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14806 					^ tv_get_number_chk(&argvars[1], NULL);
14807 }
14808 
14809 #endif /* FEAT_EVAL */
14810