xref: /vim-8.2.3635/src/evalfunc.c (revision e16b00a1)
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
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 #ifdef FEAT_QUICKFIX
33 static char *e_stringreq = N_("E928: String required");
34 #endif
35 
36 #ifdef FEAT_FLOAT
37 static void f_abs(typval_T *argvars, typval_T *rettv);
38 static void f_acos(typval_T *argvars, typval_T *rettv);
39 #endif
40 static void f_add(typval_T *argvars, typval_T *rettv);
41 static void f_and(typval_T *argvars, typval_T *rettv);
42 static void f_append(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_equal(typval_T *argvars, typval_T *rettv);
48 static void f_assert_exception(typval_T *argvars, typval_T *rettv);
49 static void f_assert_fails(typval_T *argvars, typval_T *rettv);
50 static void f_assert_false(typval_T *argvars, typval_T *rettv);
51 static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
52 static void f_assert_match(typval_T *argvars, typval_T *rettv);
53 static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
54 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
55 static void f_assert_report(typval_T *argvars, typval_T *rettv);
56 static void f_assert_true(typval_T *argvars, typval_T *rettv);
57 #ifdef FEAT_FLOAT
58 static void f_asin(typval_T *argvars, typval_T *rettv);
59 static void f_atan(typval_T *argvars, typval_T *rettv);
60 static void f_atan2(typval_T *argvars, typval_T *rettv);
61 #endif
62 #ifdef FEAT_BEVAL
63 static void f_balloon_show(typval_T *argvars, typval_T *rettv);
64 #endif
65 static void f_browse(typval_T *argvars, typval_T *rettv);
66 static void f_browsedir(typval_T *argvars, typval_T *rettv);
67 static void f_bufexists(typval_T *argvars, typval_T *rettv);
68 static void f_buflisted(typval_T *argvars, typval_T *rettv);
69 static void f_bufloaded(typval_T *argvars, typval_T *rettv);
70 static void f_bufname(typval_T *argvars, typval_T *rettv);
71 static void f_bufnr(typval_T *argvars, typval_T *rettv);
72 static void f_bufwinid(typval_T *argvars, typval_T *rettv);
73 static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
74 static void f_byte2line(typval_T *argvars, typval_T *rettv);
75 static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
76 static void f_byteidx(typval_T *argvars, typval_T *rettv);
77 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
78 static void f_call(typval_T *argvars, typval_T *rettv);
79 #ifdef FEAT_FLOAT
80 static void f_ceil(typval_T *argvars, typval_T *rettv);
81 #endif
82 #ifdef FEAT_JOB_CHANNEL
83 static void f_ch_canread(typval_T *argvars, typval_T *rettv);
84 static void f_ch_close(typval_T *argvars, typval_T *rettv);
85 static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
86 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
87 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
88 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
89 static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
90 static void f_ch_info(typval_T *argvars, typval_T *rettv);
91 static void f_ch_log(typval_T *argvars, typval_T *rettv);
92 static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
93 static void f_ch_open(typval_T *argvars, typval_T *rettv);
94 static void f_ch_read(typval_T *argvars, typval_T *rettv);
95 static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
96 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
97 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
98 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
99 static void f_ch_status(typval_T *argvars, typval_T *rettv);
100 #endif
101 static void f_changenr(typval_T *argvars, typval_T *rettv);
102 static void f_char2nr(typval_T *argvars, typval_T *rettv);
103 static void f_cindent(typval_T *argvars, typval_T *rettv);
104 static void f_clearmatches(typval_T *argvars, typval_T *rettv);
105 static void f_col(typval_T *argvars, typval_T *rettv);
106 #if defined(FEAT_INS_EXPAND)
107 static void f_complete(typval_T *argvars, typval_T *rettv);
108 static void f_complete_add(typval_T *argvars, typval_T *rettv);
109 static void f_complete_check(typval_T *argvars, typval_T *rettv);
110 #endif
111 static void f_confirm(typval_T *argvars, typval_T *rettv);
112 static void f_copy(typval_T *argvars, typval_T *rettv);
113 #ifdef FEAT_FLOAT
114 static void f_cos(typval_T *argvars, typval_T *rettv);
115 static void f_cosh(typval_T *argvars, typval_T *rettv);
116 #endif
117 static void f_count(typval_T *argvars, typval_T *rettv);
118 static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
119 static void f_cursor(typval_T *argsvars, typval_T *rettv);
120 static void f_deepcopy(typval_T *argvars, typval_T *rettv);
121 static void f_delete(typval_T *argvars, typval_T *rettv);
122 static void f_did_filetype(typval_T *argvars, typval_T *rettv);
123 static void f_diff_filler(typval_T *argvars, typval_T *rettv);
124 static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
125 static void f_empty(typval_T *argvars, typval_T *rettv);
126 static void f_escape(typval_T *argvars, typval_T *rettv);
127 static void f_eval(typval_T *argvars, typval_T *rettv);
128 static void f_eventhandler(typval_T *argvars, typval_T *rettv);
129 static void f_executable(typval_T *argvars, typval_T *rettv);
130 static void f_execute(typval_T *argvars, typval_T *rettv);
131 static void f_exepath(typval_T *argvars, typval_T *rettv);
132 static void f_exists(typval_T *argvars, typval_T *rettv);
133 #ifdef FEAT_FLOAT
134 static void f_exp(typval_T *argvars, typval_T *rettv);
135 #endif
136 static void f_expand(typval_T *argvars, typval_T *rettv);
137 static void f_extend(typval_T *argvars, typval_T *rettv);
138 static void f_feedkeys(typval_T *argvars, typval_T *rettv);
139 static void f_filereadable(typval_T *argvars, typval_T *rettv);
140 static void f_filewritable(typval_T *argvars, typval_T *rettv);
141 static void f_filter(typval_T *argvars, typval_T *rettv);
142 static void f_finddir(typval_T *argvars, typval_T *rettv);
143 static void f_findfile(typval_T *argvars, typval_T *rettv);
144 #ifdef FEAT_FLOAT
145 static void f_float2nr(typval_T *argvars, typval_T *rettv);
146 static void f_floor(typval_T *argvars, typval_T *rettv);
147 static void f_fmod(typval_T *argvars, typval_T *rettv);
148 #endif
149 static void f_fnameescape(typval_T *argvars, typval_T *rettv);
150 static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
151 static void f_foldclosed(typval_T *argvars, typval_T *rettv);
152 static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
153 static void f_foldlevel(typval_T *argvars, typval_T *rettv);
154 static void f_foldtext(typval_T *argvars, typval_T *rettv);
155 static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
156 static void f_foreground(typval_T *argvars, typval_T *rettv);
157 static void f_funcref(typval_T *argvars, typval_T *rettv);
158 static void f_function(typval_T *argvars, typval_T *rettv);
159 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
160 static void f_get(typval_T *argvars, typval_T *rettv);
161 static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
162 static void f_getbufline(typval_T *argvars, typval_T *rettv);
163 static void f_getbufvar(typval_T *argvars, typval_T *rettv);
164 static void f_getchar(typval_T *argvars, typval_T *rettv);
165 static void f_getcharmod(typval_T *argvars, typval_T *rettv);
166 static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
167 static void f_getcmdline(typval_T *argvars, typval_T *rettv);
168 #if defined(FEAT_CMDL_COMPL)
169 static void f_getcompletion(typval_T *argvars, typval_T *rettv);
170 #endif
171 static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
172 static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
173 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
174 static void f_getcwd(typval_T *argvars, typval_T *rettv);
175 static void f_getfontname(typval_T *argvars, typval_T *rettv);
176 static void f_getfperm(typval_T *argvars, typval_T *rettv);
177 static void f_getfsize(typval_T *argvars, typval_T *rettv);
178 static void f_getftime(typval_T *argvars, typval_T *rettv);
179 static void f_getftype(typval_T *argvars, typval_T *rettv);
180 static void f_getline(typval_T *argvars, typval_T *rettv);
181 static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
182 static void f_getmatches(typval_T *argvars, typval_T *rettv);
183 static void f_getpid(typval_T *argvars, typval_T *rettv);
184 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
185 static void f_getpos(typval_T *argvars, typval_T *rettv);
186 static void f_getqflist(typval_T *argvars, typval_T *rettv);
187 static void f_getreg(typval_T *argvars, typval_T *rettv);
188 static void f_getregtype(typval_T *argvars, typval_T *rettv);
189 static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
190 static void f_gettabvar(typval_T *argvars, typval_T *rettv);
191 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
192 static void f_getwininfo(typval_T *argvars, typval_T *rettv);
193 static void f_getwinposx(typval_T *argvars, typval_T *rettv);
194 static void f_getwinposy(typval_T *argvars, typval_T *rettv);
195 static void f_getwinvar(typval_T *argvars, typval_T *rettv);
196 static void f_glob(typval_T *argvars, typval_T *rettv);
197 static void f_globpath(typval_T *argvars, typval_T *rettv);
198 static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
199 static void f_has(typval_T *argvars, typval_T *rettv);
200 static void f_has_key(typval_T *argvars, typval_T *rettv);
201 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
202 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
203 static void f_histadd(typval_T *argvars, typval_T *rettv);
204 static void f_histdel(typval_T *argvars, typval_T *rettv);
205 static void f_histget(typval_T *argvars, typval_T *rettv);
206 static void f_histnr(typval_T *argvars, typval_T *rettv);
207 static void f_hlID(typval_T *argvars, typval_T *rettv);
208 static void f_hlexists(typval_T *argvars, typval_T *rettv);
209 static void f_hostname(typval_T *argvars, typval_T *rettv);
210 static void f_iconv(typval_T *argvars, typval_T *rettv);
211 static void f_indent(typval_T *argvars, typval_T *rettv);
212 static void f_index(typval_T *argvars, typval_T *rettv);
213 static void f_input(typval_T *argvars, typval_T *rettv);
214 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
215 static void f_inputlist(typval_T *argvars, typval_T *rettv);
216 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
217 static void f_inputsave(typval_T *argvars, typval_T *rettv);
218 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
219 static void f_insert(typval_T *argvars, typval_T *rettv);
220 static void f_invert(typval_T *argvars, typval_T *rettv);
221 static void f_isdirectory(typval_T *argvars, typval_T *rettv);
222 static void f_islocked(typval_T *argvars, typval_T *rettv);
223 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
224 static void f_isnan(typval_T *argvars, typval_T *rettv);
225 #endif
226 static void f_items(typval_T *argvars, typval_T *rettv);
227 #ifdef FEAT_JOB_CHANNEL
228 static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
229 static void f_job_info(typval_T *argvars, typval_T *rettv);
230 static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
231 static void f_job_start(typval_T *argvars, typval_T *rettv);
232 static void f_job_stop(typval_T *argvars, typval_T *rettv);
233 static void f_job_status(typval_T *argvars, typval_T *rettv);
234 #endif
235 static void f_join(typval_T *argvars, typval_T *rettv);
236 static void f_js_decode(typval_T *argvars, typval_T *rettv);
237 static void f_js_encode(typval_T *argvars, typval_T *rettv);
238 static void f_json_decode(typval_T *argvars, typval_T *rettv);
239 static void f_json_encode(typval_T *argvars, typval_T *rettv);
240 static void f_keys(typval_T *argvars, typval_T *rettv);
241 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
242 static void f_len(typval_T *argvars, typval_T *rettv);
243 static void f_libcall(typval_T *argvars, typval_T *rettv);
244 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
245 static void f_line(typval_T *argvars, typval_T *rettv);
246 static void f_line2byte(typval_T *argvars, typval_T *rettv);
247 static void f_lispindent(typval_T *argvars, typval_T *rettv);
248 static void f_localtime(typval_T *argvars, typval_T *rettv);
249 #ifdef FEAT_FLOAT
250 static void f_log(typval_T *argvars, typval_T *rettv);
251 static void f_log10(typval_T *argvars, typval_T *rettv);
252 #endif
253 #ifdef FEAT_LUA
254 static void f_luaeval(typval_T *argvars, typval_T *rettv);
255 #endif
256 static void f_map(typval_T *argvars, typval_T *rettv);
257 static void f_maparg(typval_T *argvars, typval_T *rettv);
258 static void f_mapcheck(typval_T *argvars, typval_T *rettv);
259 static void f_match(typval_T *argvars, typval_T *rettv);
260 static void f_matchadd(typval_T *argvars, typval_T *rettv);
261 static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
262 static void f_matcharg(typval_T *argvars, typval_T *rettv);
263 static void f_matchdelete(typval_T *argvars, typval_T *rettv);
264 static void f_matchend(typval_T *argvars, typval_T *rettv);
265 static void f_matchlist(typval_T *argvars, typval_T *rettv);
266 static void f_matchstr(typval_T *argvars, typval_T *rettv);
267 static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
268 static void f_max(typval_T *argvars, typval_T *rettv);
269 static void f_min(typval_T *argvars, typval_T *rettv);
270 #ifdef vim_mkdir
271 static void f_mkdir(typval_T *argvars, typval_T *rettv);
272 #endif
273 static void f_mode(typval_T *argvars, typval_T *rettv);
274 #ifdef FEAT_MZSCHEME
275 static void f_mzeval(typval_T *argvars, typval_T *rettv);
276 #endif
277 static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
278 static void f_nr2char(typval_T *argvars, typval_T *rettv);
279 static void f_or(typval_T *argvars, typval_T *rettv);
280 static void f_pathshorten(typval_T *argvars, typval_T *rettv);
281 #ifdef FEAT_PERL
282 static void f_perleval(typval_T *argvars, typval_T *rettv);
283 #endif
284 #ifdef FEAT_FLOAT
285 static void f_pow(typval_T *argvars, typval_T *rettv);
286 #endif
287 static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
288 static void f_printf(typval_T *argvars, typval_T *rettv);
289 static void f_pumvisible(typval_T *argvars, typval_T *rettv);
290 #ifdef FEAT_PYTHON3
291 static void f_py3eval(typval_T *argvars, typval_T *rettv);
292 #endif
293 #ifdef FEAT_PYTHON
294 static void f_pyeval(typval_T *argvars, typval_T *rettv);
295 #endif
296 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
297 static void f_pyxeval(typval_T *argvars, typval_T *rettv);
298 #endif
299 static void f_range(typval_T *argvars, typval_T *rettv);
300 static void f_readfile(typval_T *argvars, typval_T *rettv);
301 static void f_reltime(typval_T *argvars, typval_T *rettv);
302 #ifdef FEAT_FLOAT
303 static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
304 #endif
305 static void f_reltimestr(typval_T *argvars, typval_T *rettv);
306 static void f_remote_expr(typval_T *argvars, typval_T *rettv);
307 static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
308 static void f_remote_peek(typval_T *argvars, typval_T *rettv);
309 static void f_remote_read(typval_T *argvars, typval_T *rettv);
310 static void f_remote_send(typval_T *argvars, typval_T *rettv);
311 static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
312 static void f_remove(typval_T *argvars, typval_T *rettv);
313 static void f_rename(typval_T *argvars, typval_T *rettv);
314 static void f_repeat(typval_T *argvars, typval_T *rettv);
315 static void f_resolve(typval_T *argvars, typval_T *rettv);
316 static void f_reverse(typval_T *argvars, typval_T *rettv);
317 #ifdef FEAT_FLOAT
318 static void f_round(typval_T *argvars, typval_T *rettv);
319 #endif
320 static void f_screenattr(typval_T *argvars, typval_T *rettv);
321 static void f_screenchar(typval_T *argvars, typval_T *rettv);
322 static void f_screencol(typval_T *argvars, typval_T *rettv);
323 static void f_screenrow(typval_T *argvars, typval_T *rettv);
324 static void f_search(typval_T *argvars, typval_T *rettv);
325 static void f_searchdecl(typval_T *argvars, typval_T *rettv);
326 static void f_searchpair(typval_T *argvars, typval_T *rettv);
327 static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
328 static void f_searchpos(typval_T *argvars, typval_T *rettv);
329 static void f_server2client(typval_T *argvars, typval_T *rettv);
330 static void f_serverlist(typval_T *argvars, typval_T *rettv);
331 static void f_setbufvar(typval_T *argvars, typval_T *rettv);
332 static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
333 static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
334 static void f_setfperm(typval_T *argvars, typval_T *rettv);
335 static void f_setline(typval_T *argvars, typval_T *rettv);
336 static void f_setloclist(typval_T *argvars, typval_T *rettv);
337 static void f_setmatches(typval_T *argvars, typval_T *rettv);
338 static void f_setpos(typval_T *argvars, typval_T *rettv);
339 static void f_setqflist(typval_T *argvars, typval_T *rettv);
340 static void f_setreg(typval_T *argvars, typval_T *rettv);
341 static void f_settabvar(typval_T *argvars, typval_T *rettv);
342 static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
343 static void f_setwinvar(typval_T *argvars, typval_T *rettv);
344 #ifdef FEAT_CRYPT
345 static void f_sha256(typval_T *argvars, typval_T *rettv);
346 #endif /* FEAT_CRYPT */
347 static void f_shellescape(typval_T *argvars, typval_T *rettv);
348 static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
349 static void f_simplify(typval_T *argvars, typval_T *rettv);
350 #ifdef FEAT_FLOAT
351 static void f_sin(typval_T *argvars, typval_T *rettv);
352 static void f_sinh(typval_T *argvars, typval_T *rettv);
353 #endif
354 static void f_sort(typval_T *argvars, typval_T *rettv);
355 static void f_soundfold(typval_T *argvars, typval_T *rettv);
356 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
357 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
358 static void f_split(typval_T *argvars, typval_T *rettv);
359 #ifdef FEAT_FLOAT
360 static void f_sqrt(typval_T *argvars, typval_T *rettv);
361 static void f_str2float(typval_T *argvars, typval_T *rettv);
362 #endif
363 static void f_str2nr(typval_T *argvars, typval_T *rettv);
364 static void f_strchars(typval_T *argvars, typval_T *rettv);
365 #ifdef HAVE_STRFTIME
366 static void f_strftime(typval_T *argvars, typval_T *rettv);
367 #endif
368 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
369 static void f_stridx(typval_T *argvars, typval_T *rettv);
370 static void f_string(typval_T *argvars, typval_T *rettv);
371 static void f_strlen(typval_T *argvars, typval_T *rettv);
372 static void f_strcharpart(typval_T *argvars, typval_T *rettv);
373 static void f_strpart(typval_T *argvars, typval_T *rettv);
374 static void f_strridx(typval_T *argvars, typval_T *rettv);
375 static void f_strtrans(typval_T *argvars, typval_T *rettv);
376 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
377 static void f_strwidth(typval_T *argvars, typval_T *rettv);
378 static void f_submatch(typval_T *argvars, typval_T *rettv);
379 static void f_substitute(typval_T *argvars, typval_T *rettv);
380 static void f_synID(typval_T *argvars, typval_T *rettv);
381 static void f_synIDattr(typval_T *argvars, typval_T *rettv);
382 static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
383 static void f_synstack(typval_T *argvars, typval_T *rettv);
384 static void f_synconcealed(typval_T *argvars, typval_T *rettv);
385 static void f_system(typval_T *argvars, typval_T *rettv);
386 static void f_systemlist(typval_T *argvars, typval_T *rettv);
387 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
388 static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
389 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
390 static void f_taglist(typval_T *argvars, typval_T *rettv);
391 static void f_tagfiles(typval_T *argvars, typval_T *rettv);
392 static void f_tempname(typval_T *argvars, typval_T *rettv);
393 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
394 static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
395 static void f_test_override(typval_T *argvars, typval_T *rettv);
396 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
397 static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
398 #ifdef FEAT_JOB_CHANNEL
399 static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
400 #endif
401 static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
402 #ifdef FEAT_JOB_CHANNEL
403 static void f_test_null_job(typval_T *argvars, typval_T *rettv);
404 #endif
405 static void f_test_null_list(typval_T *argvars, typval_T *rettv);
406 static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
407 static void f_test_null_string(typval_T *argvars, typval_T *rettv);
408 static void f_test_settime(typval_T *argvars, typval_T *rettv);
409 #ifdef FEAT_FLOAT
410 static void f_tan(typval_T *argvars, typval_T *rettv);
411 static void f_tanh(typval_T *argvars, typval_T *rettv);
412 #endif
413 #ifdef FEAT_TIMERS
414 static void f_timer_info(typval_T *argvars, typval_T *rettv);
415 static void f_timer_pause(typval_T *argvars, typval_T *rettv);
416 static void f_timer_start(typval_T *argvars, typval_T *rettv);
417 static void f_timer_stop(typval_T *argvars, typval_T *rettv);
418 static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
419 #endif
420 static void f_tolower(typval_T *argvars, typval_T *rettv);
421 static void f_toupper(typval_T *argvars, typval_T *rettv);
422 static void f_tr(typval_T *argvars, typval_T *rettv);
423 #ifdef FEAT_FLOAT
424 static void f_trunc(typval_T *argvars, typval_T *rettv);
425 #endif
426 static void f_type(typval_T *argvars, typval_T *rettv);
427 static void f_undofile(typval_T *argvars, typval_T *rettv);
428 static void f_undotree(typval_T *argvars, typval_T *rettv);
429 static void f_uniq(typval_T *argvars, typval_T *rettv);
430 static void f_values(typval_T *argvars, typval_T *rettv);
431 static void f_virtcol(typval_T *argvars, typval_T *rettv);
432 static void f_visualmode(typval_T *argvars, typval_T *rettv);
433 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
434 static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
435 static void f_win_getid(typval_T *argvars, typval_T *rettv);
436 static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
437 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
438 static void f_win_id2win(typval_T *argvars, typval_T *rettv);
439 static void f_winbufnr(typval_T *argvars, typval_T *rettv);
440 static void f_wincol(typval_T *argvars, typval_T *rettv);
441 static void f_winheight(typval_T *argvars, typval_T *rettv);
442 static void f_winline(typval_T *argvars, typval_T *rettv);
443 static void f_winnr(typval_T *argvars, typval_T *rettv);
444 static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
445 static void f_winrestview(typval_T *argvars, typval_T *rettv);
446 static void f_winsaveview(typval_T *argvars, typval_T *rettv);
447 static void f_winwidth(typval_T *argvars, typval_T *rettv);
448 static void f_writefile(typval_T *argvars, typval_T *rettv);
449 static void f_wordcount(typval_T *argvars, typval_T *rettv);
450 static void f_xor(typval_T *argvars, typval_T *rettv);
451 
452 /*
453  * Array with names and number of arguments of all internal functions
454  * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
455  */
456 static struct fst
457 {
458     char	*f_name;	/* function name */
459     char	f_min_argc;	/* minimal number of arguments */
460     char	f_max_argc;	/* maximal number of arguments */
461     void	(*f_func)(typval_T *args, typval_T *rvar);
462 				/* implementation of function */
463 } functions[] =
464 {
465 #ifdef FEAT_FLOAT
466     {"abs",		1, 1, f_abs},
467     {"acos",		1, 1, f_acos},	/* WJMc */
468 #endif
469     {"add",		2, 2, f_add},
470     {"and",		2, 2, f_and},
471     {"append",		2, 2, f_append},
472     {"argc",		0, 0, f_argc},
473     {"argidx",		0, 0, f_argidx},
474     {"arglistid",	0, 2, f_arglistid},
475     {"argv",		0, 1, f_argv},
476 #ifdef FEAT_FLOAT
477     {"asin",		1, 1, f_asin},	/* WJMc */
478 #endif
479     {"assert_equal",	2, 3, f_assert_equal},
480     {"assert_exception", 1, 2, f_assert_exception},
481     {"assert_fails",	1, 2, f_assert_fails},
482     {"assert_false",	1, 2, f_assert_false},
483     {"assert_inrange",	3, 4, f_assert_inrange},
484     {"assert_match",	2, 3, f_assert_match},
485     {"assert_notequal",	2, 3, f_assert_notequal},
486     {"assert_notmatch",	2, 3, f_assert_notmatch},
487     {"assert_report",	1, 1, f_assert_report},
488     {"assert_true",	1, 2, f_assert_true},
489 #ifdef FEAT_FLOAT
490     {"atan",		1, 1, f_atan},
491     {"atan2",		2, 2, f_atan2},
492 #endif
493 #ifdef FEAT_BEVAL
494     {"balloon_show",	1, 1, f_balloon_show},
495 #endif
496     {"browse",		4, 4, f_browse},
497     {"browsedir",	2, 2, f_browsedir},
498     {"bufexists",	1, 1, f_bufexists},
499     {"buffer_exists",	1, 1, f_bufexists},	/* obsolete */
500     {"buffer_name",	1, 1, f_bufname},	/* obsolete */
501     {"buffer_number",	1, 1, f_bufnr},		/* obsolete */
502     {"buflisted",	1, 1, f_buflisted},
503     {"bufloaded",	1, 1, f_bufloaded},
504     {"bufname",		1, 1, f_bufname},
505     {"bufnr",		1, 2, f_bufnr},
506     {"bufwinid",	1, 1, f_bufwinid},
507     {"bufwinnr",	1, 1, f_bufwinnr},
508     {"byte2line",	1, 1, f_byte2line},
509     {"byteidx",		2, 2, f_byteidx},
510     {"byteidxcomp",	2, 2, f_byteidxcomp},
511     {"call",		2, 3, f_call},
512 #ifdef FEAT_FLOAT
513     {"ceil",		1, 1, f_ceil},
514 #endif
515 #ifdef FEAT_JOB_CHANNEL
516     {"ch_canread",	1, 1, f_ch_canread},
517     {"ch_close",	1, 1, f_ch_close},
518     {"ch_close_in",	1, 1, f_ch_close_in},
519     {"ch_evalexpr",	2, 3, f_ch_evalexpr},
520     {"ch_evalraw",	2, 3, f_ch_evalraw},
521     {"ch_getbufnr",	2, 2, f_ch_getbufnr},
522     {"ch_getjob",	1, 1, f_ch_getjob},
523     {"ch_info",		1, 1, f_ch_info},
524     {"ch_log",		1, 2, f_ch_log},
525     {"ch_logfile",	1, 2, f_ch_logfile},
526     {"ch_open",		1, 2, f_ch_open},
527     {"ch_read",		1, 2, f_ch_read},
528     {"ch_readraw",	1, 2, f_ch_readraw},
529     {"ch_sendexpr",	2, 3, f_ch_sendexpr},
530     {"ch_sendraw",	2, 3, f_ch_sendraw},
531     {"ch_setoptions",	2, 2, f_ch_setoptions},
532     {"ch_status",	1, 2, f_ch_status},
533 #endif
534     {"changenr",	0, 0, f_changenr},
535     {"char2nr",		1, 2, f_char2nr},
536     {"cindent",		1, 1, f_cindent},
537     {"clearmatches",	0, 0, f_clearmatches},
538     {"col",		1, 1, f_col},
539 #if defined(FEAT_INS_EXPAND)
540     {"complete",	2, 2, f_complete},
541     {"complete_add",	1, 1, f_complete_add},
542     {"complete_check",	0, 0, f_complete_check},
543 #endif
544     {"confirm",		1, 4, f_confirm},
545     {"copy",		1, 1, f_copy},
546 #ifdef FEAT_FLOAT
547     {"cos",		1, 1, f_cos},
548     {"cosh",		1, 1, f_cosh},
549 #endif
550     {"count",		2, 4, f_count},
551     {"cscope_connection",0,3, f_cscope_connection},
552     {"cursor",		1, 3, f_cursor},
553     {"deepcopy",	1, 2, f_deepcopy},
554     {"delete",		1, 2, f_delete},
555     {"did_filetype",	0, 0, f_did_filetype},
556     {"diff_filler",	1, 1, f_diff_filler},
557     {"diff_hlID",	2, 2, f_diff_hlID},
558     {"empty",		1, 1, f_empty},
559     {"escape",		2, 2, f_escape},
560     {"eval",		1, 1, f_eval},
561     {"eventhandler",	0, 0, f_eventhandler},
562     {"executable",	1, 1, f_executable},
563     {"execute",		1, 2, f_execute},
564     {"exepath",		1, 1, f_exepath},
565     {"exists",		1, 1, f_exists},
566 #ifdef FEAT_FLOAT
567     {"exp",		1, 1, f_exp},
568 #endif
569     {"expand",		1, 3, f_expand},
570     {"extend",		2, 3, f_extend},
571     {"feedkeys",	1, 2, f_feedkeys},
572     {"file_readable",	1, 1, f_filereadable},	/* obsolete */
573     {"filereadable",	1, 1, f_filereadable},
574     {"filewritable",	1, 1, f_filewritable},
575     {"filter",		2, 2, f_filter},
576     {"finddir",		1, 3, f_finddir},
577     {"findfile",	1, 3, f_findfile},
578 #ifdef FEAT_FLOAT
579     {"float2nr",	1, 1, f_float2nr},
580     {"floor",		1, 1, f_floor},
581     {"fmod",		2, 2, f_fmod},
582 #endif
583     {"fnameescape",	1, 1, f_fnameescape},
584     {"fnamemodify",	2, 2, f_fnamemodify},
585     {"foldclosed",	1, 1, f_foldclosed},
586     {"foldclosedend",	1, 1, f_foldclosedend},
587     {"foldlevel",	1, 1, f_foldlevel},
588     {"foldtext",	0, 0, f_foldtext},
589     {"foldtextresult",	1, 1, f_foldtextresult},
590     {"foreground",	0, 0, f_foreground},
591     {"funcref",		1, 3, f_funcref},
592     {"function",	1, 3, f_function},
593     {"garbagecollect",	0, 1, f_garbagecollect},
594     {"get",		2, 3, f_get},
595     {"getbufinfo",	0, 1, f_getbufinfo},
596     {"getbufline",	2, 3, f_getbufline},
597     {"getbufvar",	2, 3, f_getbufvar},
598     {"getchar",		0, 1, f_getchar},
599     {"getcharmod",	0, 0, f_getcharmod},
600     {"getcharsearch",	0, 0, f_getcharsearch},
601     {"getcmdline",	0, 0, f_getcmdline},
602     {"getcmdpos",	0, 0, f_getcmdpos},
603     {"getcmdtype",	0, 0, f_getcmdtype},
604     {"getcmdwintype",	0, 0, f_getcmdwintype},
605 #if defined(FEAT_CMDL_COMPL)
606     {"getcompletion",	2, 3, f_getcompletion},
607 #endif
608     {"getcurpos",	0, 0, f_getcurpos},
609     {"getcwd",		0, 2, f_getcwd},
610     {"getfontname",	0, 1, f_getfontname},
611     {"getfperm",	1, 1, f_getfperm},
612     {"getfsize",	1, 1, f_getfsize},
613     {"getftime",	1, 1, f_getftime},
614     {"getftype",	1, 1, f_getftype},
615     {"getline",		1, 2, f_getline},
616     {"getloclist",	1, 2, f_getloclist},
617     {"getmatches",	0, 0, f_getmatches},
618     {"getpid",		0, 0, f_getpid},
619     {"getpos",		1, 1, f_getpos},
620     {"getqflist",	0, 1, f_getqflist},
621     {"getreg",		0, 3, f_getreg},
622     {"getregtype",	0, 1, f_getregtype},
623     {"gettabinfo",	0, 1, f_gettabinfo},
624     {"gettabvar",	2, 3, f_gettabvar},
625     {"gettabwinvar",	3, 4, f_gettabwinvar},
626     {"getwininfo",	0, 1, f_getwininfo},
627     {"getwinposx",	0, 0, f_getwinposx},
628     {"getwinposy",	0, 0, f_getwinposy},
629     {"getwinvar",	2, 3, f_getwinvar},
630     {"glob",		1, 4, f_glob},
631     {"glob2regpat",	1, 1, f_glob2regpat},
632     {"globpath",	2, 5, f_globpath},
633     {"has",		1, 1, f_has},
634     {"has_key",		2, 2, f_has_key},
635     {"haslocaldir",	0, 2, f_haslocaldir},
636     {"hasmapto",	1, 3, f_hasmapto},
637     {"highlightID",	1, 1, f_hlID},		/* obsolete */
638     {"highlight_exists",1, 1, f_hlexists},	/* obsolete */
639     {"histadd",		2, 2, f_histadd},
640     {"histdel",		1, 2, f_histdel},
641     {"histget",		1, 2, f_histget},
642     {"histnr",		1, 1, f_histnr},
643     {"hlID",		1, 1, f_hlID},
644     {"hlexists",	1, 1, f_hlexists},
645     {"hostname",	0, 0, f_hostname},
646     {"iconv",		3, 3, f_iconv},
647     {"indent",		1, 1, f_indent},
648     {"index",		2, 4, f_index},
649     {"input",		1, 3, f_input},
650     {"inputdialog",	1, 3, f_inputdialog},
651     {"inputlist",	1, 1, f_inputlist},
652     {"inputrestore",	0, 0, f_inputrestore},
653     {"inputsave",	0, 0, f_inputsave},
654     {"inputsecret",	1, 2, f_inputsecret},
655     {"insert",		2, 3, f_insert},
656     {"invert",		1, 1, f_invert},
657     {"isdirectory",	1, 1, f_isdirectory},
658     {"islocked",	1, 1, f_islocked},
659 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
660     {"isnan",		1, 1, f_isnan},
661 #endif
662     {"items",		1, 1, f_items},
663 #ifdef FEAT_JOB_CHANNEL
664     {"job_getchannel",	1, 1, f_job_getchannel},
665     {"job_info",	1, 1, f_job_info},
666     {"job_setoptions",	2, 2, f_job_setoptions},
667     {"job_start",	1, 2, f_job_start},
668     {"job_status",	1, 1, f_job_status},
669     {"job_stop",	1, 2, f_job_stop},
670 #endif
671     {"join",		1, 2, f_join},
672     {"js_decode",	1, 1, f_js_decode},
673     {"js_encode",	1, 1, f_js_encode},
674     {"json_decode",	1, 1, f_json_decode},
675     {"json_encode",	1, 1, f_json_encode},
676     {"keys",		1, 1, f_keys},
677     {"last_buffer_nr",	0, 0, f_last_buffer_nr},/* obsolete */
678     {"len",		1, 1, f_len},
679     {"libcall",		3, 3, f_libcall},
680     {"libcallnr",	3, 3, f_libcallnr},
681     {"line",		1, 1, f_line},
682     {"line2byte",	1, 1, f_line2byte},
683     {"lispindent",	1, 1, f_lispindent},
684     {"localtime",	0, 0, f_localtime},
685 #ifdef FEAT_FLOAT
686     {"log",		1, 1, f_log},
687     {"log10",		1, 1, f_log10},
688 #endif
689 #ifdef FEAT_LUA
690     {"luaeval",		1, 2, f_luaeval},
691 #endif
692     {"map",		2, 2, f_map},
693     {"maparg",		1, 4, f_maparg},
694     {"mapcheck",	1, 3, f_mapcheck},
695     {"match",		2, 4, f_match},
696     {"matchadd",	2, 5, f_matchadd},
697     {"matchaddpos",	2, 5, f_matchaddpos},
698     {"matcharg",	1, 1, f_matcharg},
699     {"matchdelete",	1, 1, f_matchdelete},
700     {"matchend",	2, 4, f_matchend},
701     {"matchlist",	2, 4, f_matchlist},
702     {"matchstr",	2, 4, f_matchstr},
703     {"matchstrpos",	2, 4, f_matchstrpos},
704     {"max",		1, 1, f_max},
705     {"min",		1, 1, f_min},
706 #ifdef vim_mkdir
707     {"mkdir",		1, 3, f_mkdir},
708 #endif
709     {"mode",		0, 1, f_mode},
710 #ifdef FEAT_MZSCHEME
711     {"mzeval",		1, 1, f_mzeval},
712 #endif
713     {"nextnonblank",	1, 1, f_nextnonblank},
714     {"nr2char",		1, 2, f_nr2char},
715     {"or",		2, 2, f_or},
716     {"pathshorten",	1, 1, f_pathshorten},
717 #ifdef FEAT_PERL
718     {"perleval",	1, 1, f_perleval},
719 #endif
720 #ifdef FEAT_FLOAT
721     {"pow",		2, 2, f_pow},
722 #endif
723     {"prevnonblank",	1, 1, f_prevnonblank},
724     {"printf",		2, 19, f_printf},
725     {"pumvisible",	0, 0, f_pumvisible},
726 #ifdef FEAT_PYTHON3
727     {"py3eval",		1, 1, f_py3eval},
728 #endif
729 #ifdef FEAT_PYTHON
730     {"pyeval",		1, 1, f_pyeval},
731 #endif
732 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
733     {"pyxeval",		1, 1, f_pyxeval},
734 #endif
735     {"range",		1, 3, f_range},
736     {"readfile",	1, 3, f_readfile},
737     {"reltime",		0, 2, f_reltime},
738 #ifdef FEAT_FLOAT
739     {"reltimefloat",	1, 1, f_reltimefloat},
740 #endif
741     {"reltimestr",	1, 1, f_reltimestr},
742     {"remote_expr",	2, 4, f_remote_expr},
743     {"remote_foreground", 1, 1, f_remote_foreground},
744     {"remote_peek",	1, 2, f_remote_peek},
745     {"remote_read",	1, 2, f_remote_read},
746     {"remote_send",	2, 3, f_remote_send},
747     {"remote_startserver", 1, 1, f_remote_startserver},
748     {"remove",		2, 3, f_remove},
749     {"rename",		2, 2, f_rename},
750     {"repeat",		2, 2, f_repeat},
751     {"resolve",		1, 1, f_resolve},
752     {"reverse",		1, 1, f_reverse},
753 #ifdef FEAT_FLOAT
754     {"round",		1, 1, f_round},
755 #endif
756     {"screenattr",	2, 2, f_screenattr},
757     {"screenchar",	2, 2, f_screenchar},
758     {"screencol",	0, 0, f_screencol},
759     {"screenrow",	0, 0, f_screenrow},
760     {"search",		1, 4, f_search},
761     {"searchdecl",	1, 3, f_searchdecl},
762     {"searchpair",	3, 7, f_searchpair},
763     {"searchpairpos",	3, 7, f_searchpairpos},
764     {"searchpos",	1, 4, f_searchpos},
765     {"server2client",	2, 2, f_server2client},
766     {"serverlist",	0, 0, f_serverlist},
767     {"setbufvar",	3, 3, f_setbufvar},
768     {"setcharsearch",	1, 1, f_setcharsearch},
769     {"setcmdpos",	1, 1, f_setcmdpos},
770     {"setfperm",	2, 2, f_setfperm},
771     {"setline",		2, 2, f_setline},
772     {"setloclist",	2, 4, f_setloclist},
773     {"setmatches",	1, 1, f_setmatches},
774     {"setpos",		2, 2, f_setpos},
775     {"setqflist",	1, 3, f_setqflist},
776     {"setreg",		2, 3, f_setreg},
777     {"settabvar",	3, 3, f_settabvar},
778     {"settabwinvar",	4, 4, f_settabwinvar},
779     {"setwinvar",	3, 3, f_setwinvar},
780 #ifdef FEAT_CRYPT
781     {"sha256",		1, 1, f_sha256},
782 #endif
783     {"shellescape",	1, 2, f_shellescape},
784     {"shiftwidth",	0, 0, f_shiftwidth},
785     {"simplify",	1, 1, f_simplify},
786 #ifdef FEAT_FLOAT
787     {"sin",		1, 1, f_sin},
788     {"sinh",		1, 1, f_sinh},
789 #endif
790     {"sort",		1, 3, f_sort},
791     {"soundfold",	1, 1, f_soundfold},
792     {"spellbadword",	0, 1, f_spellbadword},
793     {"spellsuggest",	1, 3, f_spellsuggest},
794     {"split",		1, 3, f_split},
795 #ifdef FEAT_FLOAT
796     {"sqrt",		1, 1, f_sqrt},
797     {"str2float",	1, 1, f_str2float},
798 #endif
799     {"str2nr",		1, 2, f_str2nr},
800     {"strcharpart",	2, 3, f_strcharpart},
801     {"strchars",	1, 2, f_strchars},
802     {"strdisplaywidth",	1, 2, f_strdisplaywidth},
803 #ifdef HAVE_STRFTIME
804     {"strftime",	1, 2, f_strftime},
805 #endif
806     {"strgetchar",	2, 2, f_strgetchar},
807     {"stridx",		2, 3, f_stridx},
808     {"string",		1, 1, f_string},
809     {"strlen",		1, 1, f_strlen},
810     {"strpart",		2, 3, f_strpart},
811     {"strridx",		2, 3, f_strridx},
812     {"strtrans",	1, 1, f_strtrans},
813     {"strwidth",	1, 1, f_strwidth},
814     {"submatch",	1, 2, f_submatch},
815     {"substitute",	4, 4, f_substitute},
816     {"synID",		3, 3, f_synID},
817     {"synIDattr",	2, 3, f_synIDattr},
818     {"synIDtrans",	1, 1, f_synIDtrans},
819     {"synconcealed",	2, 2, f_synconcealed},
820     {"synstack",	2, 2, f_synstack},
821     {"system",		1, 2, f_system},
822     {"systemlist",	1, 2, f_systemlist},
823     {"tabpagebuflist",	0, 1, f_tabpagebuflist},
824     {"tabpagenr",	0, 1, f_tabpagenr},
825     {"tabpagewinnr",	1, 2, f_tabpagewinnr},
826     {"tagfiles",	0, 0, f_tagfiles},
827     {"taglist",		1, 2, f_taglist},
828 #ifdef FEAT_FLOAT
829     {"tan",		1, 1, f_tan},
830     {"tanh",		1, 1, f_tanh},
831 #endif
832     {"tempname",	0, 0, f_tempname},
833 #ifdef FEAT_TERMINAL
834     {"term_getattr",	2, 2, f_term_getattr},
835     {"term_getcursor",	1, 1, f_term_getcursor},
836     {"term_getjob",	1, 1, f_term_getjob},
837     {"term_getline",	1, 2, f_term_getline},
838     {"term_getsize",	1, 1, f_term_getsize},
839     {"term_getstatus",	1, 1, f_term_getstatus},
840     {"term_gettitle",	1, 1, f_term_gettitle},
841     {"term_gettty",	1, 1, f_term_gettty},
842     {"term_list",	0, 0, f_term_list},
843     {"term_scrape",	1, 2, f_term_scrape},
844     {"term_sendkeys",	2, 2, f_term_sendkeys},
845     {"term_start",	1, 2, f_term_start},
846     {"term_wait",	1, 1, f_term_wait},
847 #endif
848     {"test_alloc_fail",	3, 3, f_test_alloc_fail},
849     {"test_autochdir",	0, 0, f_test_autochdir},
850     {"test_garbagecollect_now",	0, 0, f_test_garbagecollect_now},
851     {"test_ignore_error",	1, 1, f_test_ignore_error},
852 #ifdef FEAT_JOB_CHANNEL
853     {"test_null_channel", 0, 0, f_test_null_channel},
854 #endif
855     {"test_null_dict",	0, 0, f_test_null_dict},
856 #ifdef FEAT_JOB_CHANNEL
857     {"test_null_job",	0, 0, f_test_null_job},
858 #endif
859     {"test_null_list",	0, 0, f_test_null_list},
860     {"test_null_partial", 0, 0, f_test_null_partial},
861     {"test_null_string", 0, 0, f_test_null_string},
862     {"test_override",    2, 2, f_test_override},
863     {"test_settime",	1, 1, f_test_settime},
864 #ifdef FEAT_TIMERS
865     {"timer_info",	0, 1, f_timer_info},
866     {"timer_pause",	2, 2, f_timer_pause},
867     {"timer_start",	2, 3, f_timer_start},
868     {"timer_stop",	1, 1, f_timer_stop},
869     {"timer_stopall",	0, 0, f_timer_stopall},
870 #endif
871     {"tolower",		1, 1, f_tolower},
872     {"toupper",		1, 1, f_toupper},
873     {"tr",		3, 3, f_tr},
874 #ifdef FEAT_FLOAT
875     {"trunc",		1, 1, f_trunc},
876 #endif
877     {"type",		1, 1, f_type},
878     {"undofile",	1, 1, f_undofile},
879     {"undotree",	0, 0, f_undotree},
880     {"uniq",		1, 3, f_uniq},
881     {"values",		1, 1, f_values},
882     {"virtcol",		1, 1, f_virtcol},
883     {"visualmode",	0, 1, f_visualmode},
884     {"wildmenumode",	0, 0, f_wildmenumode},
885     {"win_findbuf",	1, 1, f_win_findbuf},
886     {"win_getid",	0, 2, f_win_getid},
887     {"win_gotoid",	1, 1, f_win_gotoid},
888     {"win_id2tabwin",	1, 1, f_win_id2tabwin},
889     {"win_id2win",	1, 1, f_win_id2win},
890     {"winbufnr",	1, 1, f_winbufnr},
891     {"wincol",		0, 0, f_wincol},
892     {"winheight",	1, 1, f_winheight},
893     {"winline",		0, 0, f_winline},
894     {"winnr",		0, 1, f_winnr},
895     {"winrestcmd",	0, 0, f_winrestcmd},
896     {"winrestview",	1, 1, f_winrestview},
897     {"winsaveview",	0, 0, f_winsaveview},
898     {"winwidth",	1, 1, f_winwidth},
899     {"wordcount",	0, 0, f_wordcount},
900     {"writefile",	2, 3, f_writefile},
901     {"xor",		2, 2, f_xor},
902 };
903 
904 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
905 
906 /*
907  * Function given to ExpandGeneric() to obtain the list of internal
908  * or user defined function names.
909  */
910     char_u *
911 get_function_name(expand_T *xp, int idx)
912 {
913     static int	intidx = -1;
914     char_u	*name;
915 
916     if (idx == 0)
917 	intidx = -1;
918     if (intidx < 0)
919     {
920 	name = get_user_func_name(xp, idx);
921 	if (name != NULL)
922 	    return name;
923     }
924     if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
925     {
926 	STRCPY(IObuff, functions[intidx].f_name);
927 	STRCAT(IObuff, "(");
928 	if (functions[intidx].f_max_argc == 0)
929 	    STRCAT(IObuff, ")");
930 	return IObuff;
931     }
932 
933     return NULL;
934 }
935 
936 /*
937  * Function given to ExpandGeneric() to obtain the list of internal or
938  * user defined variable or function names.
939  */
940     char_u *
941 get_expr_name(expand_T *xp, int idx)
942 {
943     static int	intidx = -1;
944     char_u	*name;
945 
946     if (idx == 0)
947 	intidx = -1;
948     if (intidx < 0)
949     {
950 	name = get_function_name(xp, idx);
951 	if (name != NULL)
952 	    return name;
953     }
954     return get_user_var_name(xp, ++intidx);
955 }
956 
957 #endif /* FEAT_CMDL_COMPL */
958 
959 /*
960  * Find internal function in table above.
961  * Return index, or -1 if not found
962  */
963     int
964 find_internal_func(
965     char_u	*name)		/* name of the function */
966 {
967     int		first = 0;
968     int		last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
969     int		cmp;
970     int		x;
971 
972     /*
973      * Find the function name in the table. Binary search.
974      */
975     while (first <= last)
976     {
977 	x = first + ((unsigned)(last - first) >> 1);
978 	cmp = STRCMP(name, functions[x].f_name);
979 	if (cmp < 0)
980 	    last = x - 1;
981 	else if (cmp > 0)
982 	    first = x + 1;
983 	else
984 	    return x;
985     }
986     return -1;
987 }
988 
989     int
990 call_internal_func(
991 	char_u	    *name,
992 	int	    argcount,
993 	typval_T    *argvars,
994 	typval_T    *rettv)
995 {
996     int i;
997 
998     i = find_internal_func(name);
999     if (i < 0)
1000 	return ERROR_UNKNOWN;
1001     if (argcount < functions[i].f_min_argc)
1002 	return ERROR_TOOFEW;
1003     if (argcount > functions[i].f_max_argc)
1004 	return ERROR_TOOMANY;
1005     argvars[argcount].v_type = VAR_UNKNOWN;
1006     functions[i].f_func(argvars, rettv);
1007     return ERROR_NONE;
1008 }
1009 
1010 /*
1011  * Return TRUE for a non-zero Number and a non-empty String.
1012  */
1013     static int
1014 non_zero_arg(typval_T *argvars)
1015 {
1016     return ((argvars[0].v_type == VAR_NUMBER
1017 		&& argvars[0].vval.v_number != 0)
1018 	    || (argvars[0].v_type == VAR_SPECIAL
1019 		&& argvars[0].vval.v_number == VVAL_TRUE)
1020 	    || (argvars[0].v_type == VAR_STRING
1021 		&& argvars[0].vval.v_string != NULL
1022 		&& *argvars[0].vval.v_string != NUL));
1023 }
1024 
1025 /*
1026  * Get the lnum from the first argument.
1027  * Also accepts ".", "$", etc., but that only works for the current buffer.
1028  * Returns -1 on error.
1029  */
1030     static linenr_T
1031 get_tv_lnum(typval_T *argvars)
1032 {
1033     typval_T	rettv;
1034     linenr_T	lnum;
1035 
1036     lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1037     if (lnum == 0)  /* no valid number, try using line() */
1038     {
1039 	rettv.v_type = VAR_NUMBER;
1040 	f_line(argvars, &rettv);
1041 	lnum = (linenr_T)rettv.vval.v_number;
1042 	clear_tv(&rettv);
1043     }
1044     return lnum;
1045 }
1046 
1047 #ifdef FEAT_FLOAT
1048 static int get_float_arg(typval_T *argvars, float_T *f);
1049 
1050 /*
1051  * Get the float value of "argvars[0]" into "f".
1052  * Returns FAIL when the argument is not a Number or Float.
1053  */
1054     static int
1055 get_float_arg(typval_T *argvars, float_T *f)
1056 {
1057     if (argvars[0].v_type == VAR_FLOAT)
1058     {
1059 	*f = argvars[0].vval.v_float;
1060 	return OK;
1061     }
1062     if (argvars[0].v_type == VAR_NUMBER)
1063     {
1064 	*f = (float_T)argvars[0].vval.v_number;
1065 	return OK;
1066     }
1067     EMSG(_("E808: Number or Float required"));
1068     return FAIL;
1069 }
1070 
1071 /*
1072  * "abs(expr)" function
1073  */
1074     static void
1075 f_abs(typval_T *argvars, typval_T *rettv)
1076 {
1077     if (argvars[0].v_type == VAR_FLOAT)
1078     {
1079 	rettv->v_type = VAR_FLOAT;
1080 	rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1081     }
1082     else
1083     {
1084 	varnumber_T	n;
1085 	int		error = FALSE;
1086 
1087 	n = get_tv_number_chk(&argvars[0], &error);
1088 	if (error)
1089 	    rettv->vval.v_number = -1;
1090 	else if (n > 0)
1091 	    rettv->vval.v_number = n;
1092 	else
1093 	    rettv->vval.v_number = -n;
1094     }
1095 }
1096 
1097 /*
1098  * "acos()" function
1099  */
1100     static void
1101 f_acos(typval_T *argvars, typval_T *rettv)
1102 {
1103     float_T	f = 0.0;
1104 
1105     rettv->v_type = VAR_FLOAT;
1106     if (get_float_arg(argvars, &f) == OK)
1107 	rettv->vval.v_float = acos(f);
1108     else
1109 	rettv->vval.v_float = 0.0;
1110 }
1111 #endif
1112 
1113 /*
1114  * "add(list, item)" function
1115  */
1116     static void
1117 f_add(typval_T *argvars, typval_T *rettv)
1118 {
1119     list_T	*l;
1120 
1121     rettv->vval.v_number = 1; /* Default: Failed */
1122     if (argvars[0].v_type == VAR_LIST)
1123     {
1124 	if ((l = argvars[0].vval.v_list) != NULL
1125 		&& !tv_check_lock(l->lv_lock,
1126 					 (char_u *)N_("add() argument"), TRUE)
1127 		&& list_append_tv(l, &argvars[1]) == OK)
1128 	    copy_tv(&argvars[0], rettv);
1129     }
1130     else
1131 	EMSG(_(e_listreq));
1132 }
1133 
1134 /*
1135  * "and(expr, expr)" function
1136  */
1137     static void
1138 f_and(typval_T *argvars, typval_T *rettv)
1139 {
1140     rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1141 					& get_tv_number_chk(&argvars[1], NULL);
1142 }
1143 
1144 /*
1145  * "append(lnum, string/list)" function
1146  */
1147     static void
1148 f_append(typval_T *argvars, typval_T *rettv)
1149 {
1150     long	lnum;
1151     char_u	*line;
1152     list_T	*l = NULL;
1153     listitem_T	*li = NULL;
1154     typval_T	*tv;
1155     long	added = 0;
1156 
1157     /* When coming here from Insert mode, sync undo, so that this can be
1158      * undone separately from what was previously inserted. */
1159     if (u_sync_once == 2)
1160     {
1161 	u_sync_once = 1; /* notify that u_sync() was called */
1162 	u_sync(TRUE);
1163     }
1164 
1165     lnum = get_tv_lnum(argvars);
1166     if (lnum >= 0
1167 	    && lnum <= curbuf->b_ml.ml_line_count
1168 	    && u_save(lnum, lnum + 1) == OK)
1169     {
1170 	if (argvars[1].v_type == VAR_LIST)
1171 	{
1172 	    l = argvars[1].vval.v_list;
1173 	    if (l == NULL)
1174 		return;
1175 	    li = l->lv_first;
1176 	}
1177 	for (;;)
1178 	{
1179 	    if (l == NULL)
1180 		tv = &argvars[1];	/* append a string */
1181 	    else if (li == NULL)
1182 		break;			/* end of list */
1183 	    else
1184 		tv = &li->li_tv;	/* append item from list */
1185 	    line = get_tv_string_chk(tv);
1186 	    if (line == NULL)		/* type error */
1187 	    {
1188 		rettv->vval.v_number = 1;	/* Failed */
1189 		break;
1190 	    }
1191 	    ml_append(lnum + added, line, (colnr_T)0, FALSE);
1192 	    ++added;
1193 	    if (l == NULL)
1194 		break;
1195 	    li = li->li_next;
1196 	}
1197 
1198 	appended_lines_mark(lnum, added);
1199 	if (curwin->w_cursor.lnum > lnum)
1200 	    curwin->w_cursor.lnum += added;
1201     }
1202     else
1203 	rettv->vval.v_number = 1;	/* Failed */
1204 }
1205 
1206 /*
1207  * "argc()" function
1208  */
1209     static void
1210 f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1211 {
1212     rettv->vval.v_number = ARGCOUNT;
1213 }
1214 
1215 /*
1216  * "argidx()" function
1217  */
1218     static void
1219 f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1220 {
1221     rettv->vval.v_number = curwin->w_arg_idx;
1222 }
1223 
1224 /*
1225  * "arglistid()" function
1226  */
1227     static void
1228 f_arglistid(typval_T *argvars, typval_T *rettv)
1229 {
1230     win_T	*wp;
1231 
1232     rettv->vval.v_number = -1;
1233     wp = find_tabwin(&argvars[0], &argvars[1]);
1234     if (wp != NULL)
1235 	rettv->vval.v_number = wp->w_alist->id;
1236 }
1237 
1238 /*
1239  * "argv(nr)" function
1240  */
1241     static void
1242 f_argv(typval_T *argvars, typval_T *rettv)
1243 {
1244     int		idx;
1245 
1246     if (argvars[0].v_type != VAR_UNKNOWN)
1247     {
1248 	idx = (int)get_tv_number_chk(&argvars[0], NULL);
1249 	if (idx >= 0 && idx < ARGCOUNT)
1250 	    rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1251 	else
1252 	    rettv->vval.v_string = NULL;
1253 	rettv->v_type = VAR_STRING;
1254     }
1255     else if (rettv_list_alloc(rettv) == OK)
1256 	for (idx = 0; idx < ARGCOUNT; ++idx)
1257 	    list_append_string(rettv->vval.v_list,
1258 					       alist_name(&ARGLIST[idx]), -1);
1259 }
1260 
1261 /*
1262  * "assert_equal(expected, actual[, msg])" function
1263  */
1264     static void
1265 f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1266 {
1267     assert_equal_common(argvars, ASSERT_EQUAL);
1268 }
1269 
1270 /*
1271  * "assert_notequal(expected, actual[, msg])" function
1272  */
1273     static void
1274 f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1275 {
1276     assert_equal_common(argvars, ASSERT_NOTEQUAL);
1277 }
1278 
1279 /*
1280  * "assert_exception(string[, msg])" function
1281  */
1282     static void
1283 f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1284 {
1285     assert_exception(argvars);
1286 }
1287 
1288 /*
1289  * "assert_fails(cmd [, error])" function
1290  */
1291     static void
1292 f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1293 {
1294     assert_fails(argvars);
1295 }
1296 
1297 /*
1298  * "assert_false(actual[, msg])" function
1299  */
1300     static void
1301 f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1302 {
1303     assert_bool(argvars, FALSE);
1304 }
1305 
1306 /*
1307  * "assert_inrange(lower, upper[, msg])" function
1308  */
1309     static void
1310 f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1311 {
1312     assert_inrange(argvars);
1313 }
1314 
1315 /*
1316  * "assert_match(pattern, actual[, msg])" function
1317  */
1318     static void
1319 f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1320 {
1321     assert_match_common(argvars, ASSERT_MATCH);
1322 }
1323 
1324 /*
1325  * "assert_notmatch(pattern, actual[, msg])" function
1326  */
1327     static void
1328 f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1329 {
1330     assert_match_common(argvars, ASSERT_NOTMATCH);
1331 }
1332 
1333 /*
1334  * "assert_report(msg)" function
1335  */
1336     static void
1337 f_assert_report(typval_T *argvars, typval_T *rettv UNUSED)
1338 {
1339     assert_report(argvars);
1340 }
1341 
1342 /*
1343  * "assert_true(actual[, msg])" function
1344  */
1345     static void
1346 f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1347 {
1348     assert_bool(argvars, TRUE);
1349 }
1350 
1351 #ifdef FEAT_FLOAT
1352 /*
1353  * "asin()" function
1354  */
1355     static void
1356 f_asin(typval_T *argvars, typval_T *rettv)
1357 {
1358     float_T	f = 0.0;
1359 
1360     rettv->v_type = VAR_FLOAT;
1361     if (get_float_arg(argvars, &f) == OK)
1362 	rettv->vval.v_float = asin(f);
1363     else
1364 	rettv->vval.v_float = 0.0;
1365 }
1366 
1367 /*
1368  * "atan()" function
1369  */
1370     static void
1371 f_atan(typval_T *argvars, typval_T *rettv)
1372 {
1373     float_T	f = 0.0;
1374 
1375     rettv->v_type = VAR_FLOAT;
1376     if (get_float_arg(argvars, &f) == OK)
1377 	rettv->vval.v_float = atan(f);
1378     else
1379 	rettv->vval.v_float = 0.0;
1380 }
1381 
1382 /*
1383  * "atan2()" function
1384  */
1385     static void
1386 f_atan2(typval_T *argvars, typval_T *rettv)
1387 {
1388     float_T	fx = 0.0, fy = 0.0;
1389 
1390     rettv->v_type = VAR_FLOAT;
1391     if (get_float_arg(argvars, &fx) == OK
1392 				     && get_float_arg(&argvars[1], &fy) == OK)
1393 	rettv->vval.v_float = atan2(fx, fy);
1394     else
1395 	rettv->vval.v_float = 0.0;
1396 }
1397 #endif
1398 
1399 /*
1400  * "balloon_show()" function
1401  */
1402 #ifdef FEAT_BEVAL
1403     static void
1404 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1405 {
1406     if (balloonEval != NULL)
1407 	gui_mch_post_balloon(balloonEval, get_tv_string_chk(&argvars[0]));
1408 }
1409 #endif
1410 
1411 /*
1412  * "browse(save, title, initdir, default)" function
1413  */
1414     static void
1415 f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1416 {
1417 #ifdef FEAT_BROWSE
1418     int		save;
1419     char_u	*title;
1420     char_u	*initdir;
1421     char_u	*defname;
1422     char_u	buf[NUMBUFLEN];
1423     char_u	buf2[NUMBUFLEN];
1424     int		error = FALSE;
1425 
1426     save = (int)get_tv_number_chk(&argvars[0], &error);
1427     title = get_tv_string_chk(&argvars[1]);
1428     initdir = get_tv_string_buf_chk(&argvars[2], buf);
1429     defname = get_tv_string_buf_chk(&argvars[3], buf2);
1430 
1431     if (error || title == NULL || initdir == NULL || defname == NULL)
1432 	rettv->vval.v_string = NULL;
1433     else
1434 	rettv->vval.v_string =
1435 		 do_browse(save ? BROWSE_SAVE : 0,
1436 				 title, defname, NULL, initdir, NULL, curbuf);
1437 #else
1438     rettv->vval.v_string = NULL;
1439 #endif
1440     rettv->v_type = VAR_STRING;
1441 }
1442 
1443 /*
1444  * "browsedir(title, initdir)" function
1445  */
1446     static void
1447 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1448 {
1449 #ifdef FEAT_BROWSE
1450     char_u	*title;
1451     char_u	*initdir;
1452     char_u	buf[NUMBUFLEN];
1453 
1454     title = get_tv_string_chk(&argvars[0]);
1455     initdir = get_tv_string_buf_chk(&argvars[1], buf);
1456 
1457     if (title == NULL || initdir == NULL)
1458 	rettv->vval.v_string = NULL;
1459     else
1460 	rettv->vval.v_string = do_browse(BROWSE_DIR,
1461 				    title, NULL, NULL, initdir, NULL, curbuf);
1462 #else
1463     rettv->vval.v_string = NULL;
1464 #endif
1465     rettv->v_type = VAR_STRING;
1466 }
1467 
1468 static buf_T *find_buffer(typval_T *avar);
1469 
1470 /*
1471  * Find a buffer by number or exact name.
1472  */
1473     static buf_T *
1474 find_buffer(typval_T *avar)
1475 {
1476     buf_T	*buf = NULL;
1477 
1478     if (avar->v_type == VAR_NUMBER)
1479 	buf = buflist_findnr((int)avar->vval.v_number);
1480     else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1481     {
1482 	buf = buflist_findname_exp(avar->vval.v_string);
1483 	if (buf == NULL)
1484 	{
1485 	    /* No full path name match, try a match with a URL or a "nofile"
1486 	     * buffer, these don't use the full path. */
1487 	    FOR_ALL_BUFFERS(buf)
1488 		if (buf->b_fname != NULL
1489 			&& (path_with_url(buf->b_fname)
1490 #ifdef FEAT_QUICKFIX
1491 			    || bt_nofile(buf)
1492 #endif
1493 			   )
1494 			&& STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1495 		    break;
1496 	}
1497     }
1498     return buf;
1499 }
1500 
1501 /*
1502  * "bufexists(expr)" function
1503  */
1504     static void
1505 f_bufexists(typval_T *argvars, typval_T *rettv)
1506 {
1507     rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1508 }
1509 
1510 /*
1511  * "buflisted(expr)" function
1512  */
1513     static void
1514 f_buflisted(typval_T *argvars, typval_T *rettv)
1515 {
1516     buf_T	*buf;
1517 
1518     buf = find_buffer(&argvars[0]);
1519     rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1520 }
1521 
1522 /*
1523  * "bufloaded(expr)" function
1524  */
1525     static void
1526 f_bufloaded(typval_T *argvars, typval_T *rettv)
1527 {
1528     buf_T	*buf;
1529 
1530     buf = find_buffer(&argvars[0]);
1531     rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1532 }
1533 
1534     buf_T *
1535 buflist_find_by_name(char_u *name, int curtab_only)
1536 {
1537     int		save_magic;
1538     char_u	*save_cpo;
1539     buf_T	*buf;
1540 
1541     /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1542     save_magic = p_magic;
1543     p_magic = TRUE;
1544     save_cpo = p_cpo;
1545     p_cpo = (char_u *)"";
1546 
1547     buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1548 						    TRUE, FALSE, curtab_only));
1549 
1550     p_magic = save_magic;
1551     p_cpo = save_cpo;
1552     return buf;
1553 }
1554 
1555 /*
1556  * Get buffer by number or pattern.
1557  */
1558     buf_T *
1559 get_buf_tv(typval_T *tv, int curtab_only)
1560 {
1561     char_u	*name = tv->vval.v_string;
1562     buf_T	*buf;
1563 
1564     if (tv->v_type == VAR_NUMBER)
1565 	return buflist_findnr((int)tv->vval.v_number);
1566     if (tv->v_type != VAR_STRING)
1567 	return NULL;
1568     if (name == NULL || *name == NUL)
1569 	return curbuf;
1570     if (name[0] == '$' && name[1] == NUL)
1571 	return lastbuf;
1572 
1573     buf = buflist_find_by_name(name, curtab_only);
1574 
1575     /* If not found, try expanding the name, like done for bufexists(). */
1576     if (buf == NULL)
1577 	buf = find_buffer(tv);
1578 
1579     return buf;
1580 }
1581 
1582 /*
1583  * "bufname(expr)" function
1584  */
1585     static void
1586 f_bufname(typval_T *argvars, typval_T *rettv)
1587 {
1588     buf_T	*buf;
1589 
1590     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
1591     ++emsg_off;
1592     buf = get_buf_tv(&argvars[0], FALSE);
1593     rettv->v_type = VAR_STRING;
1594     if (buf != NULL && buf->b_fname != NULL)
1595 	rettv->vval.v_string = vim_strsave(buf->b_fname);
1596     else
1597 	rettv->vval.v_string = NULL;
1598     --emsg_off;
1599 }
1600 
1601 /*
1602  * "bufnr(expr)" function
1603  */
1604     static void
1605 f_bufnr(typval_T *argvars, typval_T *rettv)
1606 {
1607     buf_T	*buf;
1608     int		error = FALSE;
1609     char_u	*name;
1610 
1611     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
1612     ++emsg_off;
1613     buf = get_buf_tv(&argvars[0], FALSE);
1614     --emsg_off;
1615 
1616     /* If the buffer isn't found and the second argument is not zero create a
1617      * new buffer. */
1618     if (buf == NULL
1619 	    && argvars[1].v_type != VAR_UNKNOWN
1620 	    && get_tv_number_chk(&argvars[1], &error) != 0
1621 	    && !error
1622 	    && (name = get_tv_string_chk(&argvars[0])) != NULL
1623 	    && !error)
1624 	buf = buflist_new(name, NULL, (linenr_T)1, 0);
1625 
1626     if (buf != NULL)
1627 	rettv->vval.v_number = buf->b_fnum;
1628     else
1629 	rettv->vval.v_number = -1;
1630 }
1631 
1632     static void
1633 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1634 {
1635 #ifdef FEAT_WINDOWS
1636     win_T	*wp;
1637     int		winnr = 0;
1638 #endif
1639     buf_T	*buf;
1640 
1641     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
1642     ++emsg_off;
1643     buf = get_buf_tv(&argvars[0], TRUE);
1644 #ifdef FEAT_WINDOWS
1645     FOR_ALL_WINDOWS(wp)
1646     {
1647 	++winnr;
1648 	if (wp->w_buffer == buf)
1649 	    break;
1650     }
1651     rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
1652 #else
1653     rettv->vval.v_number = (curwin->w_buffer == buf
1654 					  ? (get_nr ? 1 : curwin->w_id) : -1);
1655 #endif
1656     --emsg_off;
1657 }
1658 
1659 /*
1660  * "bufwinid(nr)" function
1661  */
1662     static void
1663 f_bufwinid(typval_T *argvars, typval_T *rettv)
1664 {
1665     buf_win_common(argvars, rettv, FALSE);
1666 }
1667 
1668 /*
1669  * "bufwinnr(nr)" function
1670  */
1671     static void
1672 f_bufwinnr(typval_T *argvars, typval_T *rettv)
1673 {
1674     buf_win_common(argvars, rettv, TRUE);
1675 }
1676 
1677 /*
1678  * "byte2line(byte)" function
1679  */
1680     static void
1681 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1682 {
1683 #ifndef FEAT_BYTEOFF
1684     rettv->vval.v_number = -1;
1685 #else
1686     long	boff = 0;
1687 
1688     boff = get_tv_number(&argvars[0]) - 1;  /* boff gets -1 on type error */
1689     if (boff < 0)
1690 	rettv->vval.v_number = -1;
1691     else
1692 	rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1693 							  (linenr_T)0, &boff);
1694 #endif
1695 }
1696 
1697     static void
1698 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1699 {
1700 #ifdef FEAT_MBYTE
1701     char_u	*t;
1702 #endif
1703     char_u	*str;
1704     varnumber_T	idx;
1705 
1706     str = get_tv_string_chk(&argvars[0]);
1707     idx = get_tv_number_chk(&argvars[1], NULL);
1708     rettv->vval.v_number = -1;
1709     if (str == NULL || idx < 0)
1710 	return;
1711 
1712 #ifdef FEAT_MBYTE
1713     t = str;
1714     for ( ; idx > 0; idx--)
1715     {
1716 	if (*t == NUL)		/* EOL reached */
1717 	    return;
1718 	if (enc_utf8 && comp)
1719 	    t += utf_ptr2len(t);
1720 	else
1721 	    t += (*mb_ptr2len)(t);
1722     }
1723     rettv->vval.v_number = (varnumber_T)(t - str);
1724 #else
1725     if ((size_t)idx <= STRLEN(str))
1726 	rettv->vval.v_number = idx;
1727 #endif
1728 }
1729 
1730 /*
1731  * "byteidx()" function
1732  */
1733     static void
1734 f_byteidx(typval_T *argvars, typval_T *rettv)
1735 {
1736     byteidx(argvars, rettv, FALSE);
1737 }
1738 
1739 /*
1740  * "byteidxcomp()" function
1741  */
1742     static void
1743 f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1744 {
1745     byteidx(argvars, rettv, TRUE);
1746 }
1747 
1748 /*
1749  * "call(func, arglist [, dict])" function
1750  */
1751     static void
1752 f_call(typval_T *argvars, typval_T *rettv)
1753 {
1754     char_u	*func;
1755     partial_T   *partial = NULL;
1756     dict_T	*selfdict = NULL;
1757 
1758     if (argvars[1].v_type != VAR_LIST)
1759     {
1760 	EMSG(_(e_listreq));
1761 	return;
1762     }
1763     if (argvars[1].vval.v_list == NULL)
1764 	return;
1765 
1766     if (argvars[0].v_type == VAR_FUNC)
1767 	func = argvars[0].vval.v_string;
1768     else if (argvars[0].v_type == VAR_PARTIAL)
1769     {
1770 	partial = argvars[0].vval.v_partial;
1771 	func = partial_name(partial);
1772     }
1773     else
1774 	func = get_tv_string(&argvars[0]);
1775     if (*func == NUL)
1776 	return;		/* type error or empty name */
1777 
1778     if (argvars[2].v_type != VAR_UNKNOWN)
1779     {
1780 	if (argvars[2].v_type != VAR_DICT)
1781 	{
1782 	    EMSG(_(e_dictreq));
1783 	    return;
1784 	}
1785 	selfdict = argvars[2].vval.v_dict;
1786     }
1787 
1788     (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1789 }
1790 
1791 #ifdef FEAT_FLOAT
1792 /*
1793  * "ceil({float})" function
1794  */
1795     static void
1796 f_ceil(typval_T *argvars, typval_T *rettv)
1797 {
1798     float_T	f = 0.0;
1799 
1800     rettv->v_type = VAR_FLOAT;
1801     if (get_float_arg(argvars, &f) == OK)
1802 	rettv->vval.v_float = ceil(f);
1803     else
1804 	rettv->vval.v_float = 0.0;
1805 }
1806 #endif
1807 
1808 #ifdef FEAT_JOB_CHANNEL
1809 /*
1810  * "ch_canread()" function
1811  */
1812     static void
1813 f_ch_canread(typval_T *argvars, typval_T *rettv)
1814 {
1815     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1816 
1817     rettv->vval.v_number = 0;
1818     if (channel != NULL)
1819 	rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
1820 			    || channel_has_readahead(channel, PART_OUT)
1821 			    || channel_has_readahead(channel, PART_ERR);
1822 }
1823 
1824 /*
1825  * "ch_close()" function
1826  */
1827     static void
1828 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1829 {
1830     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1831 
1832     if (channel != NULL)
1833     {
1834 	channel_close(channel, FALSE);
1835 	channel_clear(channel);
1836     }
1837 }
1838 
1839 /*
1840  * "ch_close()" function
1841  */
1842     static void
1843 f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
1844 {
1845     channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1846 
1847     if (channel != NULL)
1848 	channel_close_in(channel);
1849 }
1850 
1851 /*
1852  * "ch_getbufnr()" function
1853  */
1854     static void
1855 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1856 {
1857     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1858 
1859     rettv->vval.v_number = -1;
1860     if (channel != NULL)
1861     {
1862 	char_u	*what = get_tv_string(&argvars[1]);
1863 	int	part;
1864 
1865 	if (STRCMP(what, "err") == 0)
1866 	    part = PART_ERR;
1867 	else if (STRCMP(what, "out") == 0)
1868 	    part = PART_OUT;
1869 	else if (STRCMP(what, "in") == 0)
1870 	    part = PART_IN;
1871 	else
1872 	    part = PART_SOCK;
1873 	if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1874 	    rettv->vval.v_number =
1875 			      channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1876     }
1877 }
1878 
1879 /*
1880  * "ch_getjob()" function
1881  */
1882     static void
1883 f_ch_getjob(typval_T *argvars, typval_T *rettv)
1884 {
1885     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1886 
1887     if (channel != NULL)
1888     {
1889 	rettv->v_type = VAR_JOB;
1890 	rettv->vval.v_job = channel->ch_job;
1891 	if (channel->ch_job != NULL)
1892 	    ++channel->ch_job->jv_refcount;
1893     }
1894 }
1895 
1896 /*
1897  * "ch_info()" function
1898  */
1899     static void
1900 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1901 {
1902     channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1903 
1904     if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1905 	channel_info(channel, rettv->vval.v_dict);
1906 }
1907 
1908 /*
1909  * "ch_log()" function
1910  */
1911     static void
1912 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1913 {
1914     char_u	*msg = get_tv_string(&argvars[0]);
1915     channel_T	*channel = NULL;
1916 
1917     if (argvars[1].v_type != VAR_UNKNOWN)
1918 	channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1919 
1920     ch_log(channel, (char *)msg);
1921 }
1922 
1923 /*
1924  * "ch_logfile()" function
1925  */
1926     static void
1927 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1928 {
1929     char_u *fname;
1930     char_u *opt = (char_u *)"";
1931     char_u buf[NUMBUFLEN];
1932 
1933     fname = get_tv_string(&argvars[0]);
1934     if (argvars[1].v_type == VAR_STRING)
1935 	opt = get_tv_string_buf(&argvars[1], buf);
1936     ch_logfile(fname, opt);
1937 }
1938 
1939 /*
1940  * "ch_open()" function
1941  */
1942     static void
1943 f_ch_open(typval_T *argvars, typval_T *rettv)
1944 {
1945     rettv->v_type = VAR_CHANNEL;
1946     if (check_restricted() || check_secure())
1947 	return;
1948     rettv->vval.v_channel = channel_open_func(argvars);
1949 }
1950 
1951 /*
1952  * "ch_read()" function
1953  */
1954     static void
1955 f_ch_read(typval_T *argvars, typval_T *rettv)
1956 {
1957     common_channel_read(argvars, rettv, FALSE);
1958 }
1959 
1960 /*
1961  * "ch_readraw()" function
1962  */
1963     static void
1964 f_ch_readraw(typval_T *argvars, typval_T *rettv)
1965 {
1966     common_channel_read(argvars, rettv, TRUE);
1967 }
1968 
1969 /*
1970  * "ch_evalexpr()" function
1971  */
1972     static void
1973 f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
1974 {
1975     ch_expr_common(argvars, rettv, TRUE);
1976 }
1977 
1978 /*
1979  * "ch_sendexpr()" function
1980  */
1981     static void
1982 f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
1983 {
1984     ch_expr_common(argvars, rettv, FALSE);
1985 }
1986 
1987 /*
1988  * "ch_evalraw()" function
1989  */
1990     static void
1991 f_ch_evalraw(typval_T *argvars, typval_T *rettv)
1992 {
1993     ch_raw_common(argvars, rettv, TRUE);
1994 }
1995 
1996 /*
1997  * "ch_sendraw()" function
1998  */
1999     static void
2000 f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2001 {
2002     ch_raw_common(argvars, rettv, FALSE);
2003 }
2004 
2005 /*
2006  * "ch_setoptions()" function
2007  */
2008     static void
2009 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2010 {
2011     channel_T	*channel;
2012     jobopt_T	opt;
2013 
2014     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2015     if (channel == NULL)
2016 	return;
2017     clear_job_options(&opt);
2018     if (get_job_options(&argvars[1], &opt,
2019 			      JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK)
2020 	channel_set_options(channel, &opt);
2021     free_job_options(&opt);
2022 }
2023 
2024 /*
2025  * "ch_status()" function
2026  */
2027     static void
2028 f_ch_status(typval_T *argvars, typval_T *rettv)
2029 {
2030     channel_T	*channel;
2031     jobopt_T	opt;
2032     int		part = -1;
2033 
2034     /* return an empty string by default */
2035     rettv->v_type = VAR_STRING;
2036     rettv->vval.v_string = NULL;
2037 
2038     channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2039 
2040     if (argvars[1].v_type != VAR_UNKNOWN)
2041     {
2042 	clear_job_options(&opt);
2043 	if (get_job_options(&argvars[1], &opt, JO_PART) == OK
2044 						     && (opt.jo_set & JO_PART))
2045 	    part = opt.jo_part;
2046     }
2047 
2048     rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
2049 }
2050 #endif
2051 
2052 /*
2053  * "changenr()" function
2054  */
2055     static void
2056 f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2057 {
2058     rettv->vval.v_number = curbuf->b_u_seq_cur;
2059 }
2060 
2061 /*
2062  * "char2nr(string)" function
2063  */
2064     static void
2065 f_char2nr(typval_T *argvars, typval_T *rettv)
2066 {
2067 #ifdef FEAT_MBYTE
2068     if (has_mbyte)
2069     {
2070 	int	utf8 = 0;
2071 
2072 	if (argvars[1].v_type != VAR_UNKNOWN)
2073 	    utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
2074 
2075 	if (utf8)
2076 	    rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
2077 	else
2078 	    rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
2079     }
2080     else
2081 #endif
2082     rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2083 }
2084 
2085 /*
2086  * "cindent(lnum)" function
2087  */
2088     static void
2089 f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2090 {
2091 #ifdef FEAT_CINDENT
2092     pos_T	pos;
2093     linenr_T	lnum;
2094 
2095     pos = curwin->w_cursor;
2096     lnum = get_tv_lnum(argvars);
2097     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2098     {
2099 	curwin->w_cursor.lnum = lnum;
2100 	rettv->vval.v_number = get_c_indent();
2101 	curwin->w_cursor = pos;
2102     }
2103     else
2104 #endif
2105 	rettv->vval.v_number = -1;
2106 }
2107 
2108 /*
2109  * "clearmatches()" function
2110  */
2111     static void
2112 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2113 {
2114 #ifdef FEAT_SEARCH_EXTRA
2115     clear_matches(curwin);
2116 #endif
2117 }
2118 
2119 /*
2120  * "col(string)" function
2121  */
2122     static void
2123 f_col(typval_T *argvars, typval_T *rettv)
2124 {
2125     colnr_T	col = 0;
2126     pos_T	*fp;
2127     int		fnum = curbuf->b_fnum;
2128 
2129     fp = var2fpos(&argvars[0], FALSE, &fnum);
2130     if (fp != NULL && fnum == curbuf->b_fnum)
2131     {
2132 	if (fp->col == MAXCOL)
2133 	{
2134 	    /* '> can be MAXCOL, get the length of the line then */
2135 	    if (fp->lnum <= curbuf->b_ml.ml_line_count)
2136 		col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2137 	    else
2138 		col = MAXCOL;
2139 	}
2140 	else
2141 	{
2142 	    col = fp->col + 1;
2143 #ifdef FEAT_VIRTUALEDIT
2144 	    /* col(".") when the cursor is on the NUL at the end of the line
2145 	     * because of "coladd" can be seen as an extra column. */
2146 	    if (virtual_active() && fp == &curwin->w_cursor)
2147 	    {
2148 		char_u	*p = ml_get_cursor();
2149 
2150 		if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2151 				 curwin->w_virtcol - curwin->w_cursor.coladd))
2152 		{
2153 # ifdef FEAT_MBYTE
2154 		    int		l;
2155 
2156 		    if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2157 			col += l;
2158 # else
2159 		    if (*p != NUL && p[1] == NUL)
2160 			++col;
2161 # endif
2162 		}
2163 	    }
2164 #endif
2165 	}
2166     }
2167     rettv->vval.v_number = col;
2168 }
2169 
2170 #if defined(FEAT_INS_EXPAND)
2171 /*
2172  * "complete()" function
2173  */
2174     static void
2175 f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2176 {
2177     int	    startcol;
2178 
2179     if ((State & INSERT) == 0)
2180     {
2181 	EMSG(_("E785: complete() can only be used in Insert mode"));
2182 	return;
2183     }
2184 
2185     /* Check for undo allowed here, because if something was already inserted
2186      * the line was already saved for undo and this check isn't done. */
2187     if (!undo_allowed())
2188 	return;
2189 
2190     if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2191     {
2192 	EMSG(_(e_invarg));
2193 	return;
2194     }
2195 
2196     startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2197     if (startcol <= 0)
2198 	return;
2199 
2200     set_completion(startcol - 1, argvars[1].vval.v_list);
2201 }
2202 
2203 /*
2204  * "complete_add()" function
2205  */
2206     static void
2207 f_complete_add(typval_T *argvars, typval_T *rettv)
2208 {
2209     rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2210 }
2211 
2212 /*
2213  * "complete_check()" function
2214  */
2215     static void
2216 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2217 {
2218     int		saved = RedrawingDisabled;
2219 
2220     RedrawingDisabled = 0;
2221     ins_compl_check_keys(0, TRUE);
2222     rettv->vval.v_number = compl_interrupted;
2223     RedrawingDisabled = saved;
2224 }
2225 #endif
2226 
2227 /*
2228  * "confirm(message, buttons[, default [, type]])" function
2229  */
2230     static void
2231 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2232 {
2233 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2234     char_u	*message;
2235     char_u	*buttons = NULL;
2236     char_u	buf[NUMBUFLEN];
2237     char_u	buf2[NUMBUFLEN];
2238     int		def = 1;
2239     int		type = VIM_GENERIC;
2240     char_u	*typestr;
2241     int		error = FALSE;
2242 
2243     message = get_tv_string_chk(&argvars[0]);
2244     if (message == NULL)
2245 	error = TRUE;
2246     if (argvars[1].v_type != VAR_UNKNOWN)
2247     {
2248 	buttons = get_tv_string_buf_chk(&argvars[1], buf);
2249 	if (buttons == NULL)
2250 	    error = TRUE;
2251 	if (argvars[2].v_type != VAR_UNKNOWN)
2252 	{
2253 	    def = (int)get_tv_number_chk(&argvars[2], &error);
2254 	    if (argvars[3].v_type != VAR_UNKNOWN)
2255 	    {
2256 		typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2257 		if (typestr == NULL)
2258 		    error = TRUE;
2259 		else
2260 		{
2261 		    switch (TOUPPER_ASC(*typestr))
2262 		    {
2263 			case 'E': type = VIM_ERROR; break;
2264 			case 'Q': type = VIM_QUESTION; break;
2265 			case 'I': type = VIM_INFO; break;
2266 			case 'W': type = VIM_WARNING; break;
2267 			case 'G': type = VIM_GENERIC; break;
2268 		    }
2269 		}
2270 	    }
2271 	}
2272     }
2273 
2274     if (buttons == NULL || *buttons == NUL)
2275 	buttons = (char_u *)_("&Ok");
2276 
2277     if (!error)
2278 	rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2279 							    def, NULL, FALSE);
2280 #endif
2281 }
2282 
2283 /*
2284  * "copy()" function
2285  */
2286     static void
2287 f_copy(typval_T *argvars, typval_T *rettv)
2288 {
2289     item_copy(&argvars[0], rettv, FALSE, 0);
2290 }
2291 
2292 #ifdef FEAT_FLOAT
2293 /*
2294  * "cos()" function
2295  */
2296     static void
2297 f_cos(typval_T *argvars, typval_T *rettv)
2298 {
2299     float_T	f = 0.0;
2300 
2301     rettv->v_type = VAR_FLOAT;
2302     if (get_float_arg(argvars, &f) == OK)
2303 	rettv->vval.v_float = cos(f);
2304     else
2305 	rettv->vval.v_float = 0.0;
2306 }
2307 
2308 /*
2309  * "cosh()" function
2310  */
2311     static void
2312 f_cosh(typval_T *argvars, typval_T *rettv)
2313 {
2314     float_T	f = 0.0;
2315 
2316     rettv->v_type = VAR_FLOAT;
2317     if (get_float_arg(argvars, &f) == OK)
2318 	rettv->vval.v_float = cosh(f);
2319     else
2320 	rettv->vval.v_float = 0.0;
2321 }
2322 #endif
2323 
2324 /*
2325  * "count()" function
2326  */
2327     static void
2328 f_count(typval_T *argvars, typval_T *rettv)
2329 {
2330     long	n = 0;
2331     int		ic = FALSE;
2332     int		error = FALSE;
2333 
2334     if (argvars[2].v_type != VAR_UNKNOWN)
2335 	ic = (int)get_tv_number_chk(&argvars[2], &error);
2336 
2337     if (argvars[0].v_type == VAR_STRING)
2338     {
2339 	char_u *expr = get_tv_string_chk(&argvars[1]);
2340 	char_u *p = argvars[0].vval.v_string;
2341 	char_u *next;
2342 
2343 	if (!error && expr != NULL && p != NULL)
2344 	{
2345 	    if (ic)
2346 	    {
2347 		size_t len = STRLEN(expr);
2348 
2349 		while (*p != NUL)
2350 		{
2351 		    if (MB_STRNICMP(p, expr, len) == 0)
2352 		    {
2353 			++n;
2354 			p += len;
2355 		    }
2356 		    else
2357 			MB_PTR_ADV(p);
2358 		}
2359 	    }
2360 	    else
2361 		while ((next = (char_u *)strstr((char *)p, (char *)expr))
2362 								       != NULL)
2363 		{
2364 		    ++n;
2365 		    p = next + STRLEN(expr);
2366 		}
2367 	}
2368 
2369     }
2370     else if (argvars[0].v_type == VAR_LIST)
2371     {
2372 	listitem_T	*li;
2373 	list_T		*l;
2374 	long		idx;
2375 
2376 	if ((l = argvars[0].vval.v_list) != NULL)
2377 	{
2378 	    li = l->lv_first;
2379 	    if (argvars[2].v_type != VAR_UNKNOWN)
2380 	    {
2381 		if (argvars[3].v_type != VAR_UNKNOWN)
2382 		{
2383 		    idx = (long)get_tv_number_chk(&argvars[3], &error);
2384 		    if (!error)
2385 		    {
2386 			li = list_find(l, idx);
2387 			if (li == NULL)
2388 			    EMSGN(_(e_listidx), idx);
2389 		    }
2390 		}
2391 		if (error)
2392 		    li = NULL;
2393 	    }
2394 
2395 	    for ( ; li != NULL; li = li->li_next)
2396 		if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2397 		    ++n;
2398 	}
2399     }
2400     else if (argvars[0].v_type == VAR_DICT)
2401     {
2402 	int		todo;
2403 	dict_T		*d;
2404 	hashitem_T	*hi;
2405 
2406 	if ((d = argvars[0].vval.v_dict) != NULL)
2407 	{
2408 	    if (argvars[2].v_type != VAR_UNKNOWN)
2409 	    {
2410 		if (argvars[3].v_type != VAR_UNKNOWN)
2411 		    EMSG(_(e_invarg));
2412 	    }
2413 
2414 	    todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2415 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2416 	    {
2417 		if (!HASHITEM_EMPTY(hi))
2418 		{
2419 		    --todo;
2420 		    if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2421 			++n;
2422 		}
2423 	    }
2424 	}
2425     }
2426     else
2427 	EMSG2(_(e_listdictarg), "count()");
2428     rettv->vval.v_number = n;
2429 }
2430 
2431 /*
2432  * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2433  *
2434  * Checks the existence of a cscope connection.
2435  */
2436     static void
2437 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2438 {
2439 #ifdef FEAT_CSCOPE
2440     int		num = 0;
2441     char_u	*dbpath = NULL;
2442     char_u	*prepend = NULL;
2443     char_u	buf[NUMBUFLEN];
2444 
2445     if (argvars[0].v_type != VAR_UNKNOWN
2446 	    && argvars[1].v_type != VAR_UNKNOWN)
2447     {
2448 	num = (int)get_tv_number(&argvars[0]);
2449 	dbpath = get_tv_string(&argvars[1]);
2450 	if (argvars[2].v_type != VAR_UNKNOWN)
2451 	    prepend = get_tv_string_buf(&argvars[2], buf);
2452     }
2453 
2454     rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2455 #endif
2456 }
2457 
2458 /*
2459  * "cursor(lnum, col)" function, or
2460  * "cursor(list)"
2461  *
2462  * Moves the cursor to the specified line and column.
2463  * Returns 0 when the position could be set, -1 otherwise.
2464  */
2465     static void
2466 f_cursor(typval_T *argvars, typval_T *rettv)
2467 {
2468     long	line, col;
2469 #ifdef FEAT_VIRTUALEDIT
2470     long	coladd = 0;
2471 #endif
2472     int		set_curswant = TRUE;
2473 
2474     rettv->vval.v_number = -1;
2475     if (argvars[1].v_type == VAR_UNKNOWN)
2476     {
2477 	pos_T	    pos;
2478 	colnr_T	    curswant = -1;
2479 
2480 	if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2481 	{
2482 	    EMSG(_(e_invarg));
2483 	    return;
2484 	}
2485 	line = pos.lnum;
2486 	col = pos.col;
2487 #ifdef FEAT_VIRTUALEDIT
2488 	coladd = pos.coladd;
2489 #endif
2490 	if (curswant >= 0)
2491 	{
2492 	    curwin->w_curswant = curswant - 1;
2493 	    set_curswant = FALSE;
2494 	}
2495     }
2496     else
2497     {
2498 	line = get_tv_lnum(argvars);
2499 	col = (long)get_tv_number_chk(&argvars[1], NULL);
2500 #ifdef FEAT_VIRTUALEDIT
2501 	if (argvars[2].v_type != VAR_UNKNOWN)
2502 	    coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2503 #endif
2504     }
2505     if (line < 0 || col < 0
2506 #ifdef FEAT_VIRTUALEDIT
2507 			    || coladd < 0
2508 #endif
2509 	    )
2510 	return;		/* type error; errmsg already given */
2511     if (line > 0)
2512 	curwin->w_cursor.lnum = line;
2513     if (col > 0)
2514 	curwin->w_cursor.col = col - 1;
2515 #ifdef FEAT_VIRTUALEDIT
2516     curwin->w_cursor.coladd = coladd;
2517 #endif
2518 
2519     /* Make sure the cursor is in a valid position. */
2520     check_cursor();
2521 #ifdef FEAT_MBYTE
2522     /* Correct cursor for multi-byte character. */
2523     if (has_mbyte)
2524 	mb_adjust_cursor();
2525 #endif
2526 
2527     curwin->w_set_curswant = set_curswant;
2528     rettv->vval.v_number = 0;
2529 }
2530 
2531 /*
2532  * "deepcopy()" function
2533  */
2534     static void
2535 f_deepcopy(typval_T *argvars, typval_T *rettv)
2536 {
2537     int		noref = 0;
2538     int		copyID;
2539 
2540     if (argvars[1].v_type != VAR_UNKNOWN)
2541 	noref = (int)get_tv_number_chk(&argvars[1], NULL);
2542     if (noref < 0 || noref > 1)
2543 	EMSG(_(e_invarg));
2544     else
2545     {
2546 	copyID = get_copyID();
2547 	item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2548     }
2549 }
2550 
2551 /*
2552  * "delete()" function
2553  */
2554     static void
2555 f_delete(typval_T *argvars, typval_T *rettv)
2556 {
2557     char_u	nbuf[NUMBUFLEN];
2558     char_u	*name;
2559     char_u	*flags;
2560 
2561     rettv->vval.v_number = -1;
2562     if (check_restricted() || check_secure())
2563 	return;
2564 
2565     name = get_tv_string(&argvars[0]);
2566     if (name == NULL || *name == NUL)
2567     {
2568 	EMSG(_(e_invarg));
2569 	return;
2570     }
2571 
2572     if (argvars[1].v_type != VAR_UNKNOWN)
2573 	flags = get_tv_string_buf(&argvars[1], nbuf);
2574     else
2575 	flags = (char_u *)"";
2576 
2577     if (*flags == NUL)
2578 	/* delete a file */
2579 	rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2580     else if (STRCMP(flags, "d") == 0)
2581 	/* delete an empty directory */
2582 	rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2583     else if (STRCMP(flags, "rf") == 0)
2584 	/* delete a directory recursively */
2585 	rettv->vval.v_number = delete_recursive(name);
2586     else
2587 	EMSG2(_(e_invexpr2), flags);
2588 }
2589 
2590 /*
2591  * "did_filetype()" function
2592  */
2593     static void
2594 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2595 {
2596 #ifdef FEAT_AUTOCMD
2597     rettv->vval.v_number = did_filetype;
2598 #endif
2599 }
2600 
2601 /*
2602  * "diff_filler()" function
2603  */
2604     static void
2605 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2606 {
2607 #ifdef FEAT_DIFF
2608     rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2609 #endif
2610 }
2611 
2612 /*
2613  * "diff_hlID()" function
2614  */
2615     static void
2616 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2617 {
2618 #ifdef FEAT_DIFF
2619     linenr_T		lnum = get_tv_lnum(argvars);
2620     static linenr_T	prev_lnum = 0;
2621     static varnumber_T	changedtick = 0;
2622     static int		fnum = 0;
2623     static int		change_start = 0;
2624     static int		change_end = 0;
2625     static hlf_T	hlID = (hlf_T)0;
2626     int			filler_lines;
2627     int			col;
2628 
2629     if (lnum < 0)	/* ignore type error in {lnum} arg */
2630 	lnum = 0;
2631     if (lnum != prev_lnum
2632 	    || changedtick != CHANGEDTICK(curbuf)
2633 	    || fnum != curbuf->b_fnum)
2634     {
2635 	/* New line, buffer, change: need to get the values. */
2636 	filler_lines = diff_check(curwin, lnum);
2637 	if (filler_lines < 0)
2638 	{
2639 	    if (filler_lines == -1)
2640 	    {
2641 		change_start = MAXCOL;
2642 		change_end = -1;
2643 		if (diff_find_change(curwin, lnum, &change_start, &change_end))
2644 		    hlID = HLF_ADD;	/* added line */
2645 		else
2646 		    hlID = HLF_CHD;	/* changed line */
2647 	    }
2648 	    else
2649 		hlID = HLF_ADD;	/* added line */
2650 	}
2651 	else
2652 	    hlID = (hlf_T)0;
2653 	prev_lnum = lnum;
2654 	changedtick = CHANGEDTICK(curbuf);
2655 	fnum = curbuf->b_fnum;
2656     }
2657 
2658     if (hlID == HLF_CHD || hlID == HLF_TXD)
2659     {
2660 	col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2661 	if (col >= change_start && col <= change_end)
2662 	    hlID = HLF_TXD;			/* changed text */
2663 	else
2664 	    hlID = HLF_CHD;			/* changed line */
2665     }
2666     rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2667 #endif
2668 }
2669 
2670 /*
2671  * "empty({expr})" function
2672  */
2673     static void
2674 f_empty(typval_T *argvars, typval_T *rettv)
2675 {
2676     int		n = FALSE;
2677 
2678     switch (argvars[0].v_type)
2679     {
2680 	case VAR_STRING:
2681 	case VAR_FUNC:
2682 	    n = argvars[0].vval.v_string == NULL
2683 					  || *argvars[0].vval.v_string == NUL;
2684 	    break;
2685 	case VAR_PARTIAL:
2686 	    n = FALSE;
2687 	    break;
2688 	case VAR_NUMBER:
2689 	    n = argvars[0].vval.v_number == 0;
2690 	    break;
2691 	case VAR_FLOAT:
2692 #ifdef FEAT_FLOAT
2693 	    n = argvars[0].vval.v_float == 0.0;
2694 	    break;
2695 #endif
2696 	case VAR_LIST:
2697 	    n = argvars[0].vval.v_list == NULL
2698 				  || argvars[0].vval.v_list->lv_first == NULL;
2699 	    break;
2700 	case VAR_DICT:
2701 	    n = argvars[0].vval.v_dict == NULL
2702 			|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2703 	    break;
2704 	case VAR_SPECIAL:
2705 	    n = argvars[0].vval.v_number != VVAL_TRUE;
2706 	    break;
2707 
2708 	case VAR_JOB:
2709 #ifdef FEAT_JOB_CHANNEL
2710 	    n = argvars[0].vval.v_job == NULL
2711 			   || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2712 	    break;
2713 #endif
2714 	case VAR_CHANNEL:
2715 #ifdef FEAT_JOB_CHANNEL
2716 	    n = argvars[0].vval.v_channel == NULL
2717 			       || !channel_is_open(argvars[0].vval.v_channel);
2718 	    break;
2719 #endif
2720 	case VAR_UNKNOWN:
2721 	    internal_error("f_empty(UNKNOWN)");
2722 	    n = TRUE;
2723 	    break;
2724     }
2725 
2726     rettv->vval.v_number = n;
2727 }
2728 
2729 /*
2730  * "escape({string}, {chars})" function
2731  */
2732     static void
2733 f_escape(typval_T *argvars, typval_T *rettv)
2734 {
2735     char_u	buf[NUMBUFLEN];
2736 
2737     rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2738 					 get_tv_string_buf(&argvars[1], buf));
2739     rettv->v_type = VAR_STRING;
2740 }
2741 
2742 /*
2743  * "eval()" function
2744  */
2745     static void
2746 f_eval(typval_T *argvars, typval_T *rettv)
2747 {
2748     char_u	*s, *p;
2749 
2750     s = get_tv_string_chk(&argvars[0]);
2751     if (s != NULL)
2752 	s = skipwhite(s);
2753 
2754     p = s;
2755     if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2756     {
2757 	if (p != NULL && !aborting())
2758 	    EMSG2(_(e_invexpr2), p);
2759 	need_clr_eos = FALSE;
2760 	rettv->v_type = VAR_NUMBER;
2761 	rettv->vval.v_number = 0;
2762     }
2763     else if (*s != NUL)
2764 	EMSG(_(e_trailing));
2765 }
2766 
2767 /*
2768  * "eventhandler()" function
2769  */
2770     static void
2771 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2772 {
2773     rettv->vval.v_number = vgetc_busy;
2774 }
2775 
2776 /*
2777  * "executable()" function
2778  */
2779     static void
2780 f_executable(typval_T *argvars, typval_T *rettv)
2781 {
2782     char_u *name = get_tv_string(&argvars[0]);
2783 
2784     /* Check in $PATH and also check directly if there is a directory name. */
2785     rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2786 		 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2787 }
2788 
2789 static garray_T	redir_execute_ga;
2790 
2791 /*
2792  * Append "value[value_len]" to the execute() output.
2793  */
2794     void
2795 execute_redir_str(char_u *value, int value_len)
2796 {
2797     int		len;
2798 
2799     if (value_len == -1)
2800 	len = (int)STRLEN(value);	/* Append the entire string */
2801     else
2802 	len = value_len;		/* Append only "value_len" characters */
2803     if (ga_grow(&redir_execute_ga, len) == OK)
2804     {
2805 	mch_memmove((char *)redir_execute_ga.ga_data
2806 				       + redir_execute_ga.ga_len, value, len);
2807 	redir_execute_ga.ga_len += len;
2808     }
2809 }
2810 
2811 /*
2812  * Get next line from a list.
2813  * Called by do_cmdline() to get the next line.
2814  * Returns allocated string, or NULL for end of function.
2815  */
2816 
2817     static char_u *
2818 get_list_line(
2819     int	    c UNUSED,
2820     void    *cookie,
2821     int	    indent UNUSED)
2822 {
2823     listitem_T **p = (listitem_T **)cookie;
2824     listitem_T *item = *p;
2825     char_u	buf[NUMBUFLEN];
2826     char_u	*s;
2827 
2828     if (item == NULL)
2829 	return NULL;
2830     s = get_tv_string_buf_chk(&item->li_tv, buf);
2831     *p = item->li_next;
2832     return s == NULL ? NULL : vim_strsave(s);
2833 }
2834 
2835 /*
2836  * "execute()" function
2837  */
2838     static void
2839 f_execute(typval_T *argvars, typval_T *rettv)
2840 {
2841     char_u	*cmd = NULL;
2842     list_T	*list = NULL;
2843     int		save_msg_silent = msg_silent;
2844     int		save_emsg_silent = emsg_silent;
2845     int		save_emsg_noredir = emsg_noredir;
2846     int		save_redir_execute = redir_execute;
2847     garray_T	save_ga;
2848 
2849     rettv->vval.v_string = NULL;
2850     rettv->v_type = VAR_STRING;
2851 
2852     if (argvars[0].v_type == VAR_LIST)
2853     {
2854 	list = argvars[0].vval.v_list;
2855 	if (list == NULL || list->lv_first == NULL)
2856 	    /* empty list, no commands, empty output */
2857 	    return;
2858 	++list->lv_refcount;
2859     }
2860     else
2861     {
2862 	cmd = get_tv_string_chk(&argvars[0]);
2863 	if (cmd == NULL)
2864 	    return;
2865     }
2866 
2867     if (argvars[1].v_type != VAR_UNKNOWN)
2868     {
2869 	char_u	buf[NUMBUFLEN];
2870 	char_u  *s = get_tv_string_buf_chk(&argvars[1], buf);
2871 
2872 	if (s == NULL)
2873 	    return;
2874 	if (STRNCMP(s, "silent", 6) == 0)
2875 	    ++msg_silent;
2876 	if (STRCMP(s, "silent!") == 0)
2877 	{
2878 	    emsg_silent = TRUE;
2879 	    emsg_noredir = TRUE;
2880 	}
2881     }
2882     else
2883 	++msg_silent;
2884 
2885     if (redir_execute)
2886 	save_ga = redir_execute_ga;
2887     ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2888     redir_execute = TRUE;
2889 
2890     if (cmd != NULL)
2891 	do_cmdline_cmd(cmd);
2892     else
2893     {
2894 	listitem_T	*item = list->lv_first;
2895 
2896 	do_cmdline(NULL, get_list_line, (void *)&item,
2897 		      DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2898 	--list->lv_refcount;
2899     }
2900 
2901     /* Need to append a NUL to the result. */
2902     if (ga_grow(&redir_execute_ga, 1) == OK)
2903     {
2904 	((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2905 	rettv->vval.v_string = redir_execute_ga.ga_data;
2906     }
2907     else
2908     {
2909 	ga_clear(&redir_execute_ga);
2910 	rettv->vval.v_string = NULL;
2911     }
2912     msg_silent = save_msg_silent;
2913     emsg_silent = save_emsg_silent;
2914     emsg_noredir = save_emsg_noredir;
2915 
2916     redir_execute = save_redir_execute;
2917     if (redir_execute)
2918 	redir_execute_ga = save_ga;
2919 
2920     /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2921      * line.  Put it back in the first column. */
2922     msg_col = 0;
2923 }
2924 
2925 /*
2926  * "exepath()" function
2927  */
2928     static void
2929 f_exepath(typval_T *argvars, typval_T *rettv)
2930 {
2931     char_u *p = NULL;
2932 
2933     (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2934     rettv->v_type = VAR_STRING;
2935     rettv->vval.v_string = p;
2936 }
2937 
2938 /*
2939  * "exists()" function
2940  */
2941     static void
2942 f_exists(typval_T *argvars, typval_T *rettv)
2943 {
2944     char_u	*p;
2945     char_u	*name;
2946     int		n = FALSE;
2947     int		len = 0;
2948 
2949     p = get_tv_string(&argvars[0]);
2950     if (*p == '$')			/* environment variable */
2951     {
2952 	/* first try "normal" environment variables (fast) */
2953 	if (mch_getenv(p + 1) != NULL)
2954 	    n = TRUE;
2955 	else
2956 	{
2957 	    /* try expanding things like $VIM and ${HOME} */
2958 	    p = expand_env_save(p);
2959 	    if (p != NULL && *p != '$')
2960 		n = TRUE;
2961 	    vim_free(p);
2962 	}
2963     }
2964     else if (*p == '&' || *p == '+')			/* option */
2965     {
2966 	n = (get_option_tv(&p, NULL, TRUE) == OK);
2967 	if (*skipwhite(p) != NUL)
2968 	    n = FALSE;			/* trailing garbage */
2969     }
2970     else if (*p == '*')			/* internal or user defined function */
2971     {
2972 	n = function_exists(p + 1, FALSE);
2973     }
2974     else if (*p == ':')
2975     {
2976 	n = cmd_exists(p + 1);
2977     }
2978     else if (*p == '#')
2979     {
2980 #ifdef FEAT_AUTOCMD
2981 	if (p[1] == '#')
2982 	    n = autocmd_supported(p + 2);
2983 	else
2984 	    n = au_exists(p + 1);
2985 #endif
2986     }
2987     else				/* internal variable */
2988     {
2989 	char_u	    *tofree;
2990 	typval_T    tv;
2991 
2992 	/* get_name_len() takes care of expanding curly braces */
2993 	name = p;
2994 	len = get_name_len(&p, &tofree, TRUE, FALSE);
2995 	if (len > 0)
2996 	{
2997 	    if (tofree != NULL)
2998 		name = tofree;
2999 	    n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
3000 	    if (n)
3001 	    {
3002 		/* handle d.key, l[idx], f(expr) */
3003 		n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
3004 		if (n)
3005 		    clear_tv(&tv);
3006 	    }
3007 	}
3008 	if (*p != NUL)
3009 	    n = FALSE;
3010 
3011 	vim_free(tofree);
3012     }
3013 
3014     rettv->vval.v_number = n;
3015 }
3016 
3017 #ifdef FEAT_FLOAT
3018 /*
3019  * "exp()" function
3020  */
3021     static void
3022 f_exp(typval_T *argvars, typval_T *rettv)
3023 {
3024     float_T	f = 0.0;
3025 
3026     rettv->v_type = VAR_FLOAT;
3027     if (get_float_arg(argvars, &f) == OK)
3028 	rettv->vval.v_float = exp(f);
3029     else
3030 	rettv->vval.v_float = 0.0;
3031 }
3032 #endif
3033 
3034 /*
3035  * "expand()" function
3036  */
3037     static void
3038 f_expand(typval_T *argvars, typval_T *rettv)
3039 {
3040     char_u	*s;
3041     int		len;
3042     char_u	*errormsg;
3043     int		options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3044     expand_T	xpc;
3045     int		error = FALSE;
3046     char_u	*result;
3047 
3048     rettv->v_type = VAR_STRING;
3049     if (argvars[1].v_type != VAR_UNKNOWN
3050 	    && argvars[2].v_type != VAR_UNKNOWN
3051 	    && get_tv_number_chk(&argvars[2], &error)
3052 	    && !error)
3053     {
3054 	rettv_list_set(rettv, NULL);
3055     }
3056 
3057     s = get_tv_string(&argvars[0]);
3058     if (*s == '%' || *s == '#' || *s == '<')
3059     {
3060 	++emsg_off;
3061 	result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3062 	--emsg_off;
3063 	if (rettv->v_type == VAR_LIST)
3064 	{
3065 	    if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3066 		list_append_string(rettv->vval.v_list, result, -1);
3067 	    else
3068 		vim_free(result);
3069 	}
3070 	else
3071 	    rettv->vval.v_string = result;
3072     }
3073     else
3074     {
3075 	/* When the optional second argument is non-zero, don't remove matches
3076 	 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3077 	if (argvars[1].v_type != VAR_UNKNOWN
3078 				    && get_tv_number_chk(&argvars[1], &error))
3079 	    options |= WILD_KEEP_ALL;
3080 	if (!error)
3081 	{
3082 	    ExpandInit(&xpc);
3083 	    xpc.xp_context = EXPAND_FILES;
3084 	    if (p_wic)
3085 		options += WILD_ICASE;
3086 	    if (rettv->v_type == VAR_STRING)
3087 		rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3088 							   options, WILD_ALL);
3089 	    else if (rettv_list_alloc(rettv) != FAIL)
3090 	    {
3091 		int i;
3092 
3093 		ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3094 		for (i = 0; i < xpc.xp_numfiles; i++)
3095 		    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3096 		ExpandCleanup(&xpc);
3097 	    }
3098 	}
3099 	else
3100 	    rettv->vval.v_string = NULL;
3101     }
3102 }
3103 
3104 /*
3105  * "extend(list, list [, idx])" function
3106  * "extend(dict, dict [, action])" function
3107  */
3108     static void
3109 f_extend(typval_T *argvars, typval_T *rettv)
3110 {
3111     char_u      *arg_errmsg = (char_u *)N_("extend() argument");
3112 
3113     if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3114     {
3115 	list_T		*l1, *l2;
3116 	listitem_T	*item;
3117 	long		before;
3118 	int		error = FALSE;
3119 
3120 	l1 = argvars[0].vval.v_list;
3121 	l2 = argvars[1].vval.v_list;
3122 	if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3123 		&& l2 != NULL)
3124 	{
3125 	    if (argvars[2].v_type != VAR_UNKNOWN)
3126 	    {
3127 		before = (long)get_tv_number_chk(&argvars[2], &error);
3128 		if (error)
3129 		    return;		/* type error; errmsg already given */
3130 
3131 		if (before == l1->lv_len)
3132 		    item = NULL;
3133 		else
3134 		{
3135 		    item = list_find(l1, before);
3136 		    if (item == NULL)
3137 		    {
3138 			EMSGN(_(e_listidx), before);
3139 			return;
3140 		    }
3141 		}
3142 	    }
3143 	    else
3144 		item = NULL;
3145 	    list_extend(l1, l2, item);
3146 
3147 	    copy_tv(&argvars[0], rettv);
3148 	}
3149     }
3150     else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3151     {
3152 	dict_T	*d1, *d2;
3153 	char_u	*action;
3154 	int	i;
3155 
3156 	d1 = argvars[0].vval.v_dict;
3157 	d2 = argvars[1].vval.v_dict;
3158 	if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3159 		&& d2 != NULL)
3160 	{
3161 	    /* Check the third argument. */
3162 	    if (argvars[2].v_type != VAR_UNKNOWN)
3163 	    {
3164 		static char *(av[]) = {"keep", "force", "error"};
3165 
3166 		action = get_tv_string_chk(&argvars[2]);
3167 		if (action == NULL)
3168 		    return;		/* type error; errmsg already given */
3169 		for (i = 0; i < 3; ++i)
3170 		    if (STRCMP(action, av[i]) == 0)
3171 			break;
3172 		if (i == 3)
3173 		{
3174 		    EMSG2(_(e_invarg2), action);
3175 		    return;
3176 		}
3177 	    }
3178 	    else
3179 		action = (char_u *)"force";
3180 
3181 	    dict_extend(d1, d2, action);
3182 
3183 	    copy_tv(&argvars[0], rettv);
3184 	}
3185     }
3186     else
3187 	EMSG2(_(e_listdictarg), "extend()");
3188 }
3189 
3190 /*
3191  * "feedkeys()" function
3192  */
3193     static void
3194 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3195 {
3196     int		remap = TRUE;
3197     int		insert = FALSE;
3198     char_u	*keys, *flags;
3199     char_u	nbuf[NUMBUFLEN];
3200     int		typed = FALSE;
3201     int		execute = FALSE;
3202     int		dangerous = FALSE;
3203     char_u	*keys_esc;
3204 
3205     /* This is not allowed in the sandbox.  If the commands would still be
3206      * executed in the sandbox it would be OK, but it probably happens later,
3207      * when "sandbox" is no longer set. */
3208     if (check_secure())
3209 	return;
3210 
3211     keys = get_tv_string(&argvars[0]);
3212 
3213     if (argvars[1].v_type != VAR_UNKNOWN)
3214     {
3215 	flags = get_tv_string_buf(&argvars[1], nbuf);
3216 	for ( ; *flags != NUL; ++flags)
3217 	{
3218 	    switch (*flags)
3219 	    {
3220 		case 'n': remap = FALSE; break;
3221 		case 'm': remap = TRUE; break;
3222 		case 't': typed = TRUE; break;
3223 		case 'i': insert = TRUE; break;
3224 		case 'x': execute = TRUE; break;
3225 		case '!': dangerous = TRUE; break;
3226 	    }
3227 	}
3228     }
3229 
3230     if (*keys != NUL || execute)
3231     {
3232 	/* Need to escape K_SPECIAL and CSI before putting the string in the
3233 	 * typeahead buffer. */
3234 	keys_esc = vim_strsave_escape_csi(keys);
3235 	if (keys_esc != NULL)
3236 	{
3237 	    ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3238 				  insert ? 0 : typebuf.tb_len, !typed, FALSE);
3239 	    vim_free(keys_esc);
3240 	    if (vgetc_busy
3241 #ifdef FEAT_TIMERS
3242 		    || timer_busy
3243 #endif
3244 		    )
3245 		typebuf_was_filled = TRUE;
3246 	    if (execute)
3247 	    {
3248 		int save_msg_scroll = msg_scroll;
3249 
3250 		/* Avoid a 1 second delay when the keys start Insert mode. */
3251 		msg_scroll = FALSE;
3252 
3253 		if (!dangerous)
3254 		    ++ex_normal_busy;
3255 		exec_normal(TRUE);
3256 		if (!dangerous)
3257 		    --ex_normal_busy;
3258 		msg_scroll |= save_msg_scroll;
3259 	    }
3260 	}
3261     }
3262 }
3263 
3264 /*
3265  * "filereadable()" function
3266  */
3267     static void
3268 f_filereadable(typval_T *argvars, typval_T *rettv)
3269 {
3270     int		fd;
3271     char_u	*p;
3272     int		n;
3273 
3274 #ifndef O_NONBLOCK
3275 # define O_NONBLOCK 0
3276 #endif
3277     p = get_tv_string(&argvars[0]);
3278     if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3279 					      O_RDONLY | O_NONBLOCK, 0)) >= 0)
3280     {
3281 	n = TRUE;
3282 	close(fd);
3283     }
3284     else
3285 	n = FALSE;
3286 
3287     rettv->vval.v_number = n;
3288 }
3289 
3290 /*
3291  * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3292  * rights to write into.
3293  */
3294     static void
3295 f_filewritable(typval_T *argvars, typval_T *rettv)
3296 {
3297     rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3298 }
3299 
3300     static void
3301 findfilendir(
3302     typval_T	*argvars UNUSED,
3303     typval_T	*rettv,
3304     int		find_what UNUSED)
3305 {
3306 #ifdef FEAT_SEARCHPATH
3307     char_u	*fname;
3308     char_u	*fresult = NULL;
3309     char_u	*path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3310     char_u	*p;
3311     char_u	pathbuf[NUMBUFLEN];
3312     int		count = 1;
3313     int		first = TRUE;
3314     int		error = FALSE;
3315 #endif
3316 
3317     rettv->vval.v_string = NULL;
3318     rettv->v_type = VAR_STRING;
3319 
3320 #ifdef FEAT_SEARCHPATH
3321     fname = get_tv_string(&argvars[0]);
3322 
3323     if (argvars[1].v_type != VAR_UNKNOWN)
3324     {
3325 	p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3326 	if (p == NULL)
3327 	    error = TRUE;
3328 	else
3329 	{
3330 	    if (*p != NUL)
3331 		path = p;
3332 
3333 	    if (argvars[2].v_type != VAR_UNKNOWN)
3334 		count = (int)get_tv_number_chk(&argvars[2], &error);
3335 	}
3336     }
3337 
3338     if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3339 	error = TRUE;
3340 
3341     if (*fname != NUL && !error)
3342     {
3343 	do
3344 	{
3345 	    if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3346 		vim_free(fresult);
3347 	    fresult = find_file_in_path_option(first ? fname : NULL,
3348 					       first ? (int)STRLEN(fname) : 0,
3349 					0, first, path,
3350 					find_what,
3351 					curbuf->b_ffname,
3352 					find_what == FINDFILE_DIR
3353 					    ? (char_u *)"" : curbuf->b_p_sua);
3354 	    first = FALSE;
3355 
3356 	    if (fresult != NULL && rettv->v_type == VAR_LIST)
3357 		list_append_string(rettv->vval.v_list, fresult, -1);
3358 
3359 	} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3360     }
3361 
3362     if (rettv->v_type == VAR_STRING)
3363 	rettv->vval.v_string = fresult;
3364 #endif
3365 }
3366 
3367 /*
3368  * "filter()" function
3369  */
3370     static void
3371 f_filter(typval_T *argvars, typval_T *rettv)
3372 {
3373     filter_map(argvars, rettv, FALSE);
3374 }
3375 
3376 /*
3377  * "finddir({fname}[, {path}[, {count}]])" function
3378  */
3379     static void
3380 f_finddir(typval_T *argvars, typval_T *rettv)
3381 {
3382     findfilendir(argvars, rettv, FINDFILE_DIR);
3383 }
3384 
3385 /*
3386  * "findfile({fname}[, {path}[, {count}]])" function
3387  */
3388     static void
3389 f_findfile(typval_T *argvars, typval_T *rettv)
3390 {
3391     findfilendir(argvars, rettv, FINDFILE_FILE);
3392 }
3393 
3394 #ifdef FEAT_FLOAT
3395 /*
3396  * "float2nr({float})" function
3397  */
3398     static void
3399 f_float2nr(typval_T *argvars, typval_T *rettv)
3400 {
3401     float_T	f = 0.0;
3402 
3403     if (get_float_arg(argvars, &f) == OK)
3404     {
3405 	if (f <= -VARNUM_MAX + DBL_EPSILON)
3406 	    rettv->vval.v_number = -VARNUM_MAX;
3407 	else if (f >= VARNUM_MAX - DBL_EPSILON)
3408 	    rettv->vval.v_number = VARNUM_MAX;
3409 	else
3410 	    rettv->vval.v_number = (varnumber_T)f;
3411     }
3412 }
3413 
3414 /*
3415  * "floor({float})" function
3416  */
3417     static void
3418 f_floor(typval_T *argvars, typval_T *rettv)
3419 {
3420     float_T	f = 0.0;
3421 
3422     rettv->v_type = VAR_FLOAT;
3423     if (get_float_arg(argvars, &f) == OK)
3424 	rettv->vval.v_float = floor(f);
3425     else
3426 	rettv->vval.v_float = 0.0;
3427 }
3428 
3429 /*
3430  * "fmod()" function
3431  */
3432     static void
3433 f_fmod(typval_T *argvars, typval_T *rettv)
3434 {
3435     float_T	fx = 0.0, fy = 0.0;
3436 
3437     rettv->v_type = VAR_FLOAT;
3438     if (get_float_arg(argvars, &fx) == OK
3439 				     && get_float_arg(&argvars[1], &fy) == OK)
3440 	rettv->vval.v_float = fmod(fx, fy);
3441     else
3442 	rettv->vval.v_float = 0.0;
3443 }
3444 #endif
3445 
3446 /*
3447  * "fnameescape({string})" function
3448  */
3449     static void
3450 f_fnameescape(typval_T *argvars, typval_T *rettv)
3451 {
3452     rettv->vval.v_string = vim_strsave_fnameescape(
3453 					   get_tv_string(&argvars[0]), FALSE);
3454     rettv->v_type = VAR_STRING;
3455 }
3456 
3457 /*
3458  * "fnamemodify({fname}, {mods})" function
3459  */
3460     static void
3461 f_fnamemodify(typval_T *argvars, typval_T *rettv)
3462 {
3463     char_u	*fname;
3464     char_u	*mods;
3465     int		usedlen = 0;
3466     int		len;
3467     char_u	*fbuf = NULL;
3468     char_u	buf[NUMBUFLEN];
3469 
3470     fname = get_tv_string_chk(&argvars[0]);
3471     mods = get_tv_string_buf_chk(&argvars[1], buf);
3472     if (fname == NULL || mods == NULL)
3473 	fname = NULL;
3474     else
3475     {
3476 	len = (int)STRLEN(fname);
3477 	(void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3478     }
3479 
3480     rettv->v_type = VAR_STRING;
3481     if (fname == NULL)
3482 	rettv->vval.v_string = NULL;
3483     else
3484 	rettv->vval.v_string = vim_strnsave(fname, len);
3485     vim_free(fbuf);
3486 }
3487 
3488 static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3489 
3490 /*
3491  * "foldclosed()" function
3492  */
3493     static void
3494 foldclosed_both(
3495     typval_T	*argvars UNUSED,
3496     typval_T	*rettv,
3497     int		end UNUSED)
3498 {
3499 #ifdef FEAT_FOLDING
3500     linenr_T	lnum;
3501     linenr_T	first, last;
3502 
3503     lnum = get_tv_lnum(argvars);
3504     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3505     {
3506 	if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3507 	{
3508 	    if (end)
3509 		rettv->vval.v_number = (varnumber_T)last;
3510 	    else
3511 		rettv->vval.v_number = (varnumber_T)first;
3512 	    return;
3513 	}
3514     }
3515 #endif
3516     rettv->vval.v_number = -1;
3517 }
3518 
3519 /*
3520  * "foldclosed()" function
3521  */
3522     static void
3523 f_foldclosed(typval_T *argvars, typval_T *rettv)
3524 {
3525     foldclosed_both(argvars, rettv, FALSE);
3526 }
3527 
3528 /*
3529  * "foldclosedend()" function
3530  */
3531     static void
3532 f_foldclosedend(typval_T *argvars, typval_T *rettv)
3533 {
3534     foldclosed_both(argvars, rettv, TRUE);
3535 }
3536 
3537 /*
3538  * "foldlevel()" function
3539  */
3540     static void
3541 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3542 {
3543 #ifdef FEAT_FOLDING
3544     linenr_T	lnum;
3545 
3546     lnum = get_tv_lnum(argvars);
3547     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3548 	rettv->vval.v_number = foldLevel(lnum);
3549 #endif
3550 }
3551 
3552 /*
3553  * "foldtext()" function
3554  */
3555     static void
3556 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3557 {
3558 #ifdef FEAT_FOLDING
3559     linenr_T	foldstart;
3560     linenr_T	foldend;
3561     char_u	*dashes;
3562     linenr_T	lnum;
3563     char_u	*s;
3564     char_u	*r;
3565     int		len;
3566     char	*txt;
3567     long	count;
3568 #endif
3569 
3570     rettv->v_type = VAR_STRING;
3571     rettv->vval.v_string = NULL;
3572 #ifdef FEAT_FOLDING
3573     foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3574     foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3575     dashes = get_vim_var_str(VV_FOLDDASHES);
3576     if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3577 	    && dashes != NULL)
3578     {
3579 	/* Find first non-empty line in the fold. */
3580 	for (lnum = foldstart; lnum < foldend; ++lnum)
3581 	    if (!linewhite(lnum))
3582 		break;
3583 
3584 	/* Find interesting text in this line. */
3585 	s = skipwhite(ml_get(lnum));
3586 	/* skip C comment-start */
3587 	if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3588 	{
3589 	    s = skipwhite(s + 2);
3590 	    if (*skipwhite(s) == NUL
3591 			    && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3592 	    {
3593 		s = skipwhite(ml_get(lnum + 1));
3594 		if (*s == '*')
3595 		    s = skipwhite(s + 1);
3596 	    }
3597 	}
3598 	count = (long)(foldend - foldstart + 1);
3599 	txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
3600 	r = alloc((unsigned)(STRLEN(txt)
3601 		    + STRLEN(dashes)	    /* for %s */
3602 		    + 20		    /* for %3ld */
3603 		    + STRLEN(s)));	    /* concatenated */
3604 	if (r != NULL)
3605 	{
3606 	    sprintf((char *)r, txt, dashes, count);
3607 	    len = (int)STRLEN(r);
3608 	    STRCAT(r, s);
3609 	    /* remove 'foldmarker' and 'commentstring' */
3610 	    foldtext_cleanup(r + len);
3611 	    rettv->vval.v_string = r;
3612 	}
3613     }
3614 #endif
3615 }
3616 
3617 /*
3618  * "foldtextresult(lnum)" function
3619  */
3620     static void
3621 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3622 {
3623 #ifdef FEAT_FOLDING
3624     linenr_T	lnum;
3625     char_u	*text;
3626     char_u	buf[FOLD_TEXT_LEN];
3627     foldinfo_T  foldinfo;
3628     int		fold_count;
3629 #endif
3630 
3631     rettv->v_type = VAR_STRING;
3632     rettv->vval.v_string = NULL;
3633 #ifdef FEAT_FOLDING
3634     lnum = get_tv_lnum(argvars);
3635     /* treat illegal types and illegal string values for {lnum} the same */
3636     if (lnum < 0)
3637 	lnum = 0;
3638     fold_count = foldedCount(curwin, lnum, &foldinfo);
3639     if (fold_count > 0)
3640     {
3641 	text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3642 							       &foldinfo, buf);
3643 	if (text == buf)
3644 	    text = vim_strsave(text);
3645 	rettv->vval.v_string = text;
3646     }
3647 #endif
3648 }
3649 
3650 /*
3651  * "foreground()" function
3652  */
3653     static void
3654 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3655 {
3656 #ifdef FEAT_GUI
3657     if (gui.in_use)
3658 	gui_mch_set_foreground();
3659 #else
3660 # ifdef WIN32
3661     win32_set_foreground();
3662 # endif
3663 #endif
3664 }
3665 
3666     static void
3667 common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
3668 {
3669     char_u	*s;
3670     char_u	*name;
3671     int		use_string = FALSE;
3672     partial_T   *arg_pt = NULL;
3673     char_u	*trans_name = NULL;
3674 
3675     if (argvars[0].v_type == VAR_FUNC)
3676     {
3677 	/* function(MyFunc, [arg], dict) */
3678 	s = argvars[0].vval.v_string;
3679     }
3680     else if (argvars[0].v_type == VAR_PARTIAL
3681 					 && argvars[0].vval.v_partial != NULL)
3682     {
3683 	/* function(dict.MyFunc, [arg]) */
3684 	arg_pt = argvars[0].vval.v_partial;
3685 	s = partial_name(arg_pt);
3686     }
3687     else
3688     {
3689 	/* function('MyFunc', [arg], dict) */
3690 	s = get_tv_string(&argvars[0]);
3691 	use_string = TRUE;
3692     }
3693 
3694     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
3695     {
3696 	name = s;
3697 	trans_name = trans_function_name(&name, FALSE,
3698 	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3699 	if (*name != NUL)
3700 	    s = NULL;
3701     }
3702 
3703     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3704 					 || (is_funcref && trans_name == NULL))
3705 	EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
3706     /* Don't check an autoload name for existence here. */
3707     else if (trans_name != NULL && (is_funcref
3708 				? find_func(trans_name) == NULL
3709 				: !translated_function_exists(trans_name)))
3710 	EMSG2(_("E700: Unknown function: %s"), s);
3711     else
3712     {
3713 	int	dict_idx = 0;
3714 	int	arg_idx = 0;
3715 	list_T	*list = NULL;
3716 
3717 	if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3718 	{
3719 	    char	sid_buf[25];
3720 	    int		off = *s == 's' ? 2 : 5;
3721 
3722 	    /* Expand s: and <SID> into <SNR>nr_, so that the function can
3723 	     * also be called from another script. Using trans_function_name()
3724 	     * would also work, but some plugins depend on the name being
3725 	     * printable text. */
3726 	    sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3727 	    name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3728 	    if (name != NULL)
3729 	    {
3730 		STRCPY(name, sid_buf);
3731 		STRCAT(name, s + off);
3732 	    }
3733 	}
3734 	else
3735 	    name = vim_strsave(s);
3736 
3737 	if (argvars[1].v_type != VAR_UNKNOWN)
3738 	{
3739 	    if (argvars[2].v_type != VAR_UNKNOWN)
3740 	    {
3741 		/* function(name, [args], dict) */
3742 		arg_idx = 1;
3743 		dict_idx = 2;
3744 	    }
3745 	    else if (argvars[1].v_type == VAR_DICT)
3746 		/* function(name, dict) */
3747 		dict_idx = 1;
3748 	    else
3749 		/* function(name, [args]) */
3750 		arg_idx = 1;
3751 	    if (dict_idx > 0)
3752 	    {
3753 		if (argvars[dict_idx].v_type != VAR_DICT)
3754 		{
3755 		    EMSG(_("E922: expected a dict"));
3756 		    vim_free(name);
3757 		    goto theend;
3758 		}
3759 		if (argvars[dict_idx].vval.v_dict == NULL)
3760 		    dict_idx = 0;
3761 	    }
3762 	    if (arg_idx > 0)
3763 	    {
3764 		if (argvars[arg_idx].v_type != VAR_LIST)
3765 		{
3766 		    EMSG(_("E923: Second argument of function() must be a list or a dict"));
3767 		    vim_free(name);
3768 		    goto theend;
3769 		}
3770 		list = argvars[arg_idx].vval.v_list;
3771 		if (list == NULL || list->lv_len == 0)
3772 		    arg_idx = 0;
3773 	    }
3774 	}
3775 	if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
3776 	{
3777 	    partial_T	*pt = (partial_T *)alloc_clear(sizeof(partial_T));
3778 
3779 	    /* result is a VAR_PARTIAL */
3780 	    if (pt == NULL)
3781 		vim_free(name);
3782 	    else
3783 	    {
3784 		if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3785 		{
3786 		    listitem_T	*li;
3787 		    int		i = 0;
3788 		    int		arg_len = 0;
3789 		    int		lv_len = 0;
3790 
3791 		    if (arg_pt != NULL)
3792 			arg_len = arg_pt->pt_argc;
3793 		    if (list != NULL)
3794 			lv_len = list->lv_len;
3795 		    pt->pt_argc = arg_len + lv_len;
3796 		    pt->pt_argv = (typval_T *)alloc(
3797 					      sizeof(typval_T) * pt->pt_argc);
3798 		    if (pt->pt_argv == NULL)
3799 		    {
3800 			vim_free(pt);
3801 			vim_free(name);
3802 			goto theend;
3803 		    }
3804 		    for (i = 0; i < arg_len; i++)
3805 			copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3806 		    if (lv_len > 0)
3807 			for (li = list->lv_first; li != NULL;
3808 							 li = li->li_next)
3809 			    copy_tv(&li->li_tv, &pt->pt_argv[i++]);
3810 		}
3811 
3812 		/* For "function(dict.func, [], dict)" and "func" is a partial
3813 		 * use "dict".  That is backwards compatible. */
3814 		if (dict_idx > 0)
3815 		{
3816 		    /* The dict is bound explicitly, pt_auto is FALSE. */
3817 		    pt->pt_dict = argvars[dict_idx].vval.v_dict;
3818 		    ++pt->pt_dict->dv_refcount;
3819 		}
3820 		else if (arg_pt != NULL)
3821 		{
3822 		    /* If the dict was bound automatically the result is also
3823 		     * bound automatically. */
3824 		    pt->pt_dict = arg_pt->pt_dict;
3825 		    pt->pt_auto = arg_pt->pt_auto;
3826 		    if (pt->pt_dict != NULL)
3827 			++pt->pt_dict->dv_refcount;
3828 		}
3829 
3830 		pt->pt_refcount = 1;
3831 		if (arg_pt != NULL && arg_pt->pt_func != NULL)
3832 		{
3833 		    pt->pt_func = arg_pt->pt_func;
3834 		    func_ptr_ref(pt->pt_func);
3835 		    vim_free(name);
3836 		}
3837 		else if (is_funcref)
3838 		{
3839 		    pt->pt_func = find_func(trans_name);
3840 		    func_ptr_ref(pt->pt_func);
3841 		    vim_free(name);
3842 		}
3843 		else
3844 		{
3845 		    pt->pt_name = name;
3846 		    func_ref(name);
3847 		}
3848 	    }
3849 	    rettv->v_type = VAR_PARTIAL;
3850 	    rettv->vval.v_partial = pt;
3851 	}
3852 	else
3853 	{
3854 	    /* result is a VAR_FUNC */
3855 	    rettv->v_type = VAR_FUNC;
3856 	    rettv->vval.v_string = name;
3857 	    func_ref(name);
3858 	}
3859     }
3860 theend:
3861     vim_free(trans_name);
3862 }
3863 
3864 /*
3865  * "funcref()" function
3866  */
3867     static void
3868 f_funcref(typval_T *argvars, typval_T *rettv)
3869 {
3870     common_function(argvars, rettv, TRUE);
3871 }
3872 
3873 /*
3874  * "function()" function
3875  */
3876     static void
3877 f_function(typval_T *argvars, typval_T *rettv)
3878 {
3879     common_function(argvars, rettv, FALSE);
3880 }
3881 
3882 /*
3883  * "garbagecollect()" function
3884  */
3885     static void
3886 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3887 {
3888     /* This is postponed until we are back at the toplevel, because we may be
3889      * using Lists and Dicts internally.  E.g.: ":echo [garbagecollect()]". */
3890     want_garbage_collect = TRUE;
3891 
3892     if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3893 	garbage_collect_at_exit = TRUE;
3894 }
3895 
3896 /*
3897  * "get()" function
3898  */
3899     static void
3900 f_get(typval_T *argvars, typval_T *rettv)
3901 {
3902     listitem_T	*li;
3903     list_T	*l;
3904     dictitem_T	*di;
3905     dict_T	*d;
3906     typval_T	*tv = NULL;
3907 
3908     if (argvars[0].v_type == VAR_LIST)
3909     {
3910 	if ((l = argvars[0].vval.v_list) != NULL)
3911 	{
3912 	    int		error = FALSE;
3913 
3914 	    li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3915 	    if (!error && li != NULL)
3916 		tv = &li->li_tv;
3917 	}
3918     }
3919     else if (argvars[0].v_type == VAR_DICT)
3920     {
3921 	if ((d = argvars[0].vval.v_dict) != NULL)
3922 	{
3923 	    di = dict_find(d, get_tv_string(&argvars[1]), -1);
3924 	    if (di != NULL)
3925 		tv = &di->di_tv;
3926 	}
3927     }
3928     else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3929     {
3930 	partial_T	*pt;
3931 	partial_T	fref_pt;
3932 
3933 	if (argvars[0].v_type == VAR_PARTIAL)
3934 	    pt = argvars[0].vval.v_partial;
3935 	else
3936 	{
3937 	    vim_memset(&fref_pt, 0, sizeof(fref_pt));
3938 	    fref_pt.pt_name = argvars[0].vval.v_string;
3939 	    pt = &fref_pt;
3940 	}
3941 
3942 	if (pt != NULL)
3943 	{
3944 	    char_u *what = get_tv_string(&argvars[1]);
3945 	    char_u *n;
3946 
3947 	    if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3948 	    {
3949 		rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
3950 		n = partial_name(pt);
3951 		if (n == NULL)
3952 		    rettv->vval.v_string = NULL;
3953 		else
3954 		{
3955 		    rettv->vval.v_string = vim_strsave(n);
3956 		    if (rettv->v_type == VAR_FUNC)
3957 			func_ref(rettv->vval.v_string);
3958 		}
3959 	    }
3960 	    else if (STRCMP(what, "dict") == 0)
3961 		rettv_dict_set(rettv, pt->pt_dict);
3962 	    else if (STRCMP(what, "args") == 0)
3963 	    {
3964 		rettv->v_type = VAR_LIST;
3965 		if (rettv_list_alloc(rettv) == OK)
3966 		{
3967 		    int i;
3968 
3969 		    for (i = 0; i < pt->pt_argc; ++i)
3970 			list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3971 		}
3972 	    }
3973 	    else
3974 		EMSG2(_(e_invarg2), what);
3975 	    return;
3976 	}
3977     }
3978     else
3979 	EMSG2(_(e_listdictarg), "get()");
3980 
3981     if (tv == NULL)
3982     {
3983 	if (argvars[2].v_type != VAR_UNKNOWN)
3984 	    copy_tv(&argvars[2], rettv);
3985     }
3986     else
3987 	copy_tv(tv, rettv);
3988 }
3989 
3990 #ifdef FEAT_SIGNS
3991 /*
3992  * Returns information about signs placed in a buffer as list of dicts.
3993  */
3994     static void
3995 get_buffer_signs(buf_T *buf, list_T *l)
3996 {
3997     signlist_T	*sign;
3998 
3999     for (sign = buf->b_signlist; sign; sign = sign->next)
4000     {
4001 	dict_T *d = dict_alloc();
4002 
4003 	if (d != NULL)
4004 	{
4005 	    dict_add_nr_str(d, "id", sign->id, NULL);
4006 	    dict_add_nr_str(d, "lnum", sign->lnum, NULL);
4007 	    dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
4008 
4009 	    list_append_dict(l, d);
4010 	}
4011     }
4012 }
4013 #endif
4014 
4015 /*
4016  * Returns buffer options, variables and other attributes in a dictionary.
4017  */
4018     static dict_T *
4019 get_buffer_info(buf_T *buf)
4020 {
4021     dict_T	*dict;
4022     tabpage_T	*tp;
4023     win_T	*wp;
4024     list_T	*windows;
4025 
4026     dict = dict_alloc();
4027     if (dict == NULL)
4028 	return NULL;
4029 
4030     dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
4031     dict_add_nr_str(dict, "name", 0L,
4032 	    buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
4033     dict_add_nr_str(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4034 						: buflist_findlnum(buf), NULL);
4035     dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
4036     dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
4037     dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
4038     dict_add_nr_str(dict, "changedtick", CHANGEDTICK(buf), NULL);
4039     dict_add_nr_str(dict, "hidden",
4040 		    buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
4041 		    NULL);
4042 
4043     /* Get a reference to buffer variables */
4044     dict_add_dict(dict, "variables", buf->b_vars);
4045 
4046     /* List of windows displaying this buffer */
4047     windows = list_alloc();
4048     if (windows != NULL)
4049     {
4050 	FOR_ALL_TAB_WINDOWS(tp, wp)
4051 	    if (wp->w_buffer == buf)
4052 		list_append_number(windows, (varnumber_T)wp->w_id);
4053 	dict_add_list(dict, "windows", windows);
4054     }
4055 
4056 #ifdef FEAT_SIGNS
4057     if (buf->b_signlist != NULL)
4058     {
4059 	/* List of signs placed in this buffer */
4060 	list_T	*signs = list_alloc();
4061 	if (signs != NULL)
4062 	{
4063 	    get_buffer_signs(buf, signs);
4064 	    dict_add_list(dict, "signs", signs);
4065 	}
4066     }
4067 #endif
4068 
4069     return dict;
4070 }
4071 
4072 /*
4073  * "getbufinfo()" function
4074  */
4075     static void
4076 f_getbufinfo(typval_T *argvars, typval_T *rettv)
4077 {
4078     buf_T	*buf = NULL;
4079     buf_T	*argbuf = NULL;
4080     dict_T	*d;
4081     int		filtered = FALSE;
4082     int		sel_buflisted = FALSE;
4083     int		sel_bufloaded = FALSE;
4084 
4085     if (rettv_list_alloc(rettv) != OK)
4086 	return;
4087 
4088     /* List of all the buffers or selected buffers */
4089     if (argvars[0].v_type == VAR_DICT)
4090     {
4091 	dict_T	*sel_d = argvars[0].vval.v_dict;
4092 
4093 	if (sel_d != NULL)
4094 	{
4095 	    dictitem_T	*di;
4096 
4097 	    filtered = TRUE;
4098 
4099 	    di = dict_find(sel_d, (char_u *)"buflisted", -1);
4100 	    if (di != NULL && get_tv_number(&di->di_tv))
4101 		sel_buflisted = TRUE;
4102 
4103 	    di = dict_find(sel_d, (char_u *)"bufloaded", -1);
4104 	    if (di != NULL && get_tv_number(&di->di_tv))
4105 		sel_bufloaded = TRUE;
4106 	}
4107     }
4108     else if (argvars[0].v_type != VAR_UNKNOWN)
4109     {
4110 	/* Information about one buffer.  Argument specifies the buffer */
4111 	(void)get_tv_number(&argvars[0]);   /* issue errmsg if type error */
4112 	++emsg_off;
4113 	argbuf = get_buf_tv(&argvars[0], FALSE);
4114 	--emsg_off;
4115 	if (argbuf == NULL)
4116 	    return;
4117     }
4118 
4119     /* Return information about all the buffers or a specified buffer */
4120     FOR_ALL_BUFFERS(buf)
4121     {
4122 	if (argbuf != NULL && argbuf != buf)
4123 	    continue;
4124 	if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
4125 					   || (sel_buflisted && !buf->b_p_bl)))
4126 	    continue;
4127 
4128 	d = get_buffer_info(buf);
4129 	if (d != NULL)
4130 	    list_append_dict(rettv->vval.v_list, d);
4131 	if (argbuf != NULL)
4132 	    return;
4133     }
4134 }
4135 
4136 static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
4137 
4138 /*
4139  * Get line or list of lines from buffer "buf" into "rettv".
4140  * Return a range (from start to end) of lines in rettv from the specified
4141  * buffer.
4142  * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4143  */
4144     static void
4145 get_buffer_lines(
4146     buf_T	*buf,
4147     linenr_T	start,
4148     linenr_T	end,
4149     int		retlist,
4150     typval_T	*rettv)
4151 {
4152     char_u	*p;
4153 
4154     rettv->v_type = VAR_STRING;
4155     rettv->vval.v_string = NULL;
4156     if (retlist && rettv_list_alloc(rettv) == FAIL)
4157 	return;
4158 
4159     if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4160 	return;
4161 
4162     if (!retlist)
4163     {
4164 	if (start >= 1 && start <= buf->b_ml.ml_line_count)
4165 	    p = ml_get_buf(buf, start, FALSE);
4166 	else
4167 	    p = (char_u *)"";
4168 	rettv->vval.v_string = vim_strsave(p);
4169     }
4170     else
4171     {
4172 	if (end < start)
4173 	    return;
4174 
4175 	if (start < 1)
4176 	    start = 1;
4177 	if (end > buf->b_ml.ml_line_count)
4178 	    end = buf->b_ml.ml_line_count;
4179 	while (start <= end)
4180 	    if (list_append_string(rettv->vval.v_list,
4181 				 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4182 		break;
4183     }
4184 }
4185 
4186 /*
4187  * Get the lnum from the first argument.
4188  * Also accepts "$", then "buf" is used.
4189  * Returns 0 on error.
4190  */
4191     static linenr_T
4192 get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
4193 {
4194     if (argvars[0].v_type == VAR_STRING
4195 	    && argvars[0].vval.v_string != NULL
4196 	    && argvars[0].vval.v_string[0] == '$'
4197 	    && buf != NULL)
4198 	return buf->b_ml.ml_line_count;
4199     return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
4200 }
4201 
4202 /*
4203  * "getbufline()" function
4204  */
4205     static void
4206 f_getbufline(typval_T *argvars, typval_T *rettv)
4207 {
4208     linenr_T	lnum;
4209     linenr_T	end;
4210     buf_T	*buf;
4211 
4212     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
4213     ++emsg_off;
4214     buf = get_buf_tv(&argvars[0], FALSE);
4215     --emsg_off;
4216 
4217     lnum = get_tv_lnum_buf(&argvars[1], buf);
4218     if (argvars[2].v_type == VAR_UNKNOWN)
4219 	end = lnum;
4220     else
4221 	end = get_tv_lnum_buf(&argvars[2], buf);
4222 
4223     get_buffer_lines(buf, lnum, end, TRUE, rettv);
4224 }
4225 
4226 /*
4227  * "getbufvar()" function
4228  */
4229     static void
4230 f_getbufvar(typval_T *argvars, typval_T *rettv)
4231 {
4232     buf_T	*buf;
4233     buf_T	*save_curbuf;
4234     char_u	*varname;
4235     dictitem_T	*v;
4236     int		done = FALSE;
4237 
4238     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
4239     varname = get_tv_string_chk(&argvars[1]);
4240     ++emsg_off;
4241     buf = get_buf_tv(&argvars[0], FALSE);
4242 
4243     rettv->v_type = VAR_STRING;
4244     rettv->vval.v_string = NULL;
4245 
4246     if (buf != NULL && varname != NULL)
4247     {
4248 	/* set curbuf to be our buf, temporarily */
4249 	save_curbuf = curbuf;
4250 	curbuf = buf;
4251 
4252 	if (*varname == '&')
4253 	{
4254 	    if (varname[1] == NUL)
4255 	    {
4256 		/* get all buffer-local options in a dict */
4257 		dict_T	*opts = get_winbuf_options(TRUE);
4258 
4259 		if (opts != NULL)
4260 		{
4261 		    rettv_dict_set(rettv, opts);
4262 		    done = TRUE;
4263 		}
4264 	    }
4265 	    else if (get_option_tv(&varname, rettv, TRUE) == OK)
4266 		/* buffer-local-option */
4267 		done = TRUE;
4268 	}
4269 	else
4270 	{
4271 	    /* Look up the variable. */
4272 	    /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4273 	    v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4274 							 'b', varname, FALSE);
4275 	    if (v != NULL)
4276 	    {
4277 		copy_tv(&v->di_tv, rettv);
4278 		done = TRUE;
4279 	    }
4280 	}
4281 
4282 	/* restore previous notion of curbuf */
4283 	curbuf = save_curbuf;
4284     }
4285 
4286     if (!done && argvars[2].v_type != VAR_UNKNOWN)
4287 	/* use the default value */
4288 	copy_tv(&argvars[2], rettv);
4289 
4290     --emsg_off;
4291 }
4292 
4293 /*
4294  * "getchar()" function
4295  */
4296     static void
4297 f_getchar(typval_T *argvars, typval_T *rettv)
4298 {
4299     varnumber_T		n;
4300     int			error = FALSE;
4301 
4302     /* Position the cursor.  Needed after a message that ends in a space. */
4303     windgoto(msg_row, msg_col);
4304 
4305     ++no_mapping;
4306     ++allow_keys;
4307     for (;;)
4308     {
4309 	if (argvars[0].v_type == VAR_UNKNOWN)
4310 	    /* getchar(): blocking wait. */
4311 	    n = plain_vgetc();
4312 	else if (get_tv_number_chk(&argvars[0], &error) == 1)
4313 	    /* getchar(1): only check if char avail */
4314 	    n = vpeekc_any();
4315 	else if (error || vpeekc_any() == NUL)
4316 	    /* illegal argument or getchar(0) and no char avail: return zero */
4317 	    n = 0;
4318 	else
4319 	    /* getchar(0) and char avail: return char */
4320 	    n = plain_vgetc();
4321 
4322 	if (n == K_IGNORE)
4323 	    continue;
4324 	break;
4325     }
4326     --no_mapping;
4327     --allow_keys;
4328 
4329     set_vim_var_nr(VV_MOUSE_WIN, 0);
4330     set_vim_var_nr(VV_MOUSE_WINID, 0);
4331     set_vim_var_nr(VV_MOUSE_LNUM, 0);
4332     set_vim_var_nr(VV_MOUSE_COL, 0);
4333 
4334     rettv->vval.v_number = n;
4335     if (IS_SPECIAL(n) || mod_mask != 0)
4336     {
4337 	char_u		temp[10];   /* modifier: 3, mbyte-char: 6, NUL: 1 */
4338 	int		i = 0;
4339 
4340 	/* Turn a special key into three bytes, plus modifier. */
4341 	if (mod_mask != 0)
4342 	{
4343 	    temp[i++] = K_SPECIAL;
4344 	    temp[i++] = KS_MODIFIER;
4345 	    temp[i++] = mod_mask;
4346 	}
4347 	if (IS_SPECIAL(n))
4348 	{
4349 	    temp[i++] = K_SPECIAL;
4350 	    temp[i++] = K_SECOND(n);
4351 	    temp[i++] = K_THIRD(n);
4352 	}
4353 #ifdef FEAT_MBYTE
4354 	else if (has_mbyte)
4355 	    i += (*mb_char2bytes)(n, temp + i);
4356 #endif
4357 	else
4358 	    temp[i++] = n;
4359 	temp[i++] = NUL;
4360 	rettv->v_type = VAR_STRING;
4361 	rettv->vval.v_string = vim_strsave(temp);
4362 
4363 #ifdef FEAT_MOUSE
4364 	if (is_mouse_key(n))
4365 	{
4366 	    int		row = mouse_row;
4367 	    int		col = mouse_col;
4368 	    win_T	*win;
4369 	    linenr_T	lnum;
4370 # ifdef FEAT_WINDOWS
4371 	    win_T	*wp;
4372 # endif
4373 	    int		winnr = 1;
4374 
4375 	    if (row >= 0 && col >= 0)
4376 	    {
4377 		/* Find the window at the mouse coordinates and compute the
4378 		 * text position. */
4379 		win = mouse_find_win(&row, &col);
4380 		(void)mouse_comp_pos(win, &row, &col, &lnum);
4381 # ifdef FEAT_WINDOWS
4382 		for (wp = firstwin; wp != win; wp = wp->w_next)
4383 		    ++winnr;
4384 # endif
4385 		set_vim_var_nr(VV_MOUSE_WIN, winnr);
4386 		set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4387 		set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4388 		set_vim_var_nr(VV_MOUSE_COL, col + 1);
4389 	    }
4390 	}
4391 #endif
4392     }
4393 }
4394 
4395 /*
4396  * "getcharmod()" function
4397  */
4398     static void
4399 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4400 {
4401     rettv->vval.v_number = mod_mask;
4402 }
4403 
4404 /*
4405  * "getcharsearch()" function
4406  */
4407     static void
4408 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4409 {
4410     if (rettv_dict_alloc(rettv) != FAIL)
4411     {
4412 	dict_T *dict = rettv->vval.v_dict;
4413 
4414 	dict_add_nr_str(dict, "char", 0L, last_csearch());
4415 	dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4416 	dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4417     }
4418 }
4419 
4420 /*
4421  * "getcmdline()" function
4422  */
4423     static void
4424 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4425 {
4426     rettv->v_type = VAR_STRING;
4427     rettv->vval.v_string = get_cmdline_str();
4428 }
4429 
4430 /*
4431  * "getcmdpos()" function
4432  */
4433     static void
4434 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4435 {
4436     rettv->vval.v_number = get_cmdline_pos() + 1;
4437 }
4438 
4439 /*
4440  * "getcmdtype()" function
4441  */
4442     static void
4443 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4444 {
4445     rettv->v_type = VAR_STRING;
4446     rettv->vval.v_string = alloc(2);
4447     if (rettv->vval.v_string != NULL)
4448     {
4449 	rettv->vval.v_string[0] = get_cmdline_type();
4450 	rettv->vval.v_string[1] = NUL;
4451     }
4452 }
4453 
4454 /*
4455  * "getcmdwintype()" function
4456  */
4457     static void
4458 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4459 {
4460     rettv->v_type = VAR_STRING;
4461     rettv->vval.v_string = NULL;
4462 #ifdef FEAT_CMDWIN
4463     rettv->vval.v_string = alloc(2);
4464     if (rettv->vval.v_string != NULL)
4465     {
4466 	rettv->vval.v_string[0] = cmdwin_type;
4467 	rettv->vval.v_string[1] = NUL;
4468     }
4469 #endif
4470 }
4471 
4472 #if defined(FEAT_CMDL_COMPL)
4473 /*
4474  * "getcompletion()" function
4475  */
4476     static void
4477 f_getcompletion(typval_T *argvars, typval_T *rettv)
4478 {
4479     char_u	*pat;
4480     expand_T	xpc;
4481     int		filtered = FALSE;
4482     int		options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4483 					| WILD_NO_BEEP;
4484 
4485     if (argvars[2].v_type != VAR_UNKNOWN)
4486 	filtered = get_tv_number_chk(&argvars[2], NULL);
4487 
4488     if (p_wic)
4489 	options |= WILD_ICASE;
4490 
4491     /* For filtered results, 'wildignore' is used */
4492     if (!filtered)
4493 	options |= WILD_KEEP_ALL;
4494 
4495     ExpandInit(&xpc);
4496     xpc.xp_pattern = get_tv_string(&argvars[0]);
4497     xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4498     xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4499     if (xpc.xp_context == EXPAND_NOTHING)
4500     {
4501 	if (argvars[1].v_type == VAR_STRING)
4502 	    EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4503 	else
4504 	    EMSG(_(e_invarg));
4505 	return;
4506     }
4507 
4508 # if defined(FEAT_MENU)
4509     if (xpc.xp_context == EXPAND_MENUS)
4510     {
4511 	set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4512 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4513     }
4514 # endif
4515 #ifdef FEAT_CSCOPE
4516     if (xpc.xp_context == EXPAND_CSCOPE)
4517     {
4518 	set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4519 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4520     }
4521 #endif
4522 #ifdef FEAT_SIGNS
4523     if (xpc.xp_context == EXPAND_SIGN)
4524     {
4525 	set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4526 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4527     }
4528 #endif
4529 
4530     pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4531     if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4532     {
4533 	int	i;
4534 
4535 	ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4536 
4537 	for (i = 0; i < xpc.xp_numfiles; i++)
4538 	    list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4539     }
4540     vim_free(pat);
4541     ExpandCleanup(&xpc);
4542 }
4543 #endif
4544 
4545 /*
4546  * "getcwd()" function
4547  */
4548     static void
4549 f_getcwd(typval_T *argvars, typval_T *rettv)
4550 {
4551     win_T	*wp = NULL;
4552     char_u	*cwd;
4553 
4554     rettv->v_type = VAR_STRING;
4555     rettv->vval.v_string = NULL;
4556 
4557     wp = find_tabwin(&argvars[0], &argvars[1]);
4558     if (wp != NULL)
4559     {
4560 	if (wp->w_localdir != NULL)
4561 	    rettv->vval.v_string = vim_strsave(wp->w_localdir);
4562 	else if (globaldir != NULL)
4563 	    rettv->vval.v_string = vim_strsave(globaldir);
4564 	else
4565 	{
4566 	    cwd = alloc(MAXPATHL);
4567 	    if (cwd != NULL)
4568 	    {
4569 		if (mch_dirname(cwd, MAXPATHL) != FAIL)
4570 		    rettv->vval.v_string = vim_strsave(cwd);
4571 		vim_free(cwd);
4572 	    }
4573 	}
4574 #ifdef BACKSLASH_IN_FILENAME
4575 	if (rettv->vval.v_string != NULL)
4576 	    slash_adjust(rettv->vval.v_string);
4577 #endif
4578     }
4579 }
4580 
4581 /*
4582  * "getfontname()" function
4583  */
4584     static void
4585 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4586 {
4587     rettv->v_type = VAR_STRING;
4588     rettv->vval.v_string = NULL;
4589 #ifdef FEAT_GUI
4590     if (gui.in_use)
4591     {
4592 	GuiFont font;
4593 	char_u	*name = NULL;
4594 
4595 	if (argvars[0].v_type == VAR_UNKNOWN)
4596 	{
4597 	    /* Get the "Normal" font.  Either the name saved by
4598 	     * hl_set_font_name() or from the font ID. */
4599 	    font = gui.norm_font;
4600 	    name = hl_get_font_name();
4601 	}
4602 	else
4603 	{
4604 	    name = get_tv_string(&argvars[0]);
4605 	    if (STRCMP(name, "*") == 0)	    /* don't use font dialog */
4606 		return;
4607 	    font = gui_mch_get_font(name, FALSE);
4608 	    if (font == NOFONT)
4609 		return;	    /* Invalid font name, return empty string. */
4610 	}
4611 	rettv->vval.v_string = gui_mch_get_fontname(font, name);
4612 	if (argvars[0].v_type != VAR_UNKNOWN)
4613 	    gui_mch_free_font(font);
4614     }
4615 #endif
4616 }
4617 
4618 /*
4619  * "getfperm({fname})" function
4620  */
4621     static void
4622 f_getfperm(typval_T *argvars, typval_T *rettv)
4623 {
4624     char_u	*fname;
4625     stat_T	st;
4626     char_u	*perm = NULL;
4627     char_u	flags[] = "rwx";
4628     int		i;
4629 
4630     fname = get_tv_string(&argvars[0]);
4631 
4632     rettv->v_type = VAR_STRING;
4633     if (mch_stat((char *)fname, &st) >= 0)
4634     {
4635 	perm = vim_strsave((char_u *)"---------");
4636 	if (perm != NULL)
4637 	{
4638 	    for (i = 0; i < 9; i++)
4639 	    {
4640 		if (st.st_mode & (1 << (8 - i)))
4641 		    perm[i] = flags[i % 3];
4642 	    }
4643 	}
4644     }
4645     rettv->vval.v_string = perm;
4646 }
4647 
4648 /*
4649  * "getfsize({fname})" function
4650  */
4651     static void
4652 f_getfsize(typval_T *argvars, typval_T *rettv)
4653 {
4654     char_u	*fname;
4655     stat_T	st;
4656 
4657     fname = get_tv_string(&argvars[0]);
4658 
4659     rettv->v_type = VAR_NUMBER;
4660 
4661     if (mch_stat((char *)fname, &st) >= 0)
4662     {
4663 	if (mch_isdir(fname))
4664 	    rettv->vval.v_number = 0;
4665 	else
4666 	{
4667 	    rettv->vval.v_number = (varnumber_T)st.st_size;
4668 
4669 	    /* non-perfect check for overflow */
4670 	    if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4671 		rettv->vval.v_number = -2;
4672 	}
4673     }
4674     else
4675 	  rettv->vval.v_number = -1;
4676 }
4677 
4678 /*
4679  * "getftime({fname})" function
4680  */
4681     static void
4682 f_getftime(typval_T *argvars, typval_T *rettv)
4683 {
4684     char_u	*fname;
4685     stat_T	st;
4686 
4687     fname = get_tv_string(&argvars[0]);
4688 
4689     if (mch_stat((char *)fname, &st) >= 0)
4690 	rettv->vval.v_number = (varnumber_T)st.st_mtime;
4691     else
4692 	rettv->vval.v_number = -1;
4693 }
4694 
4695 /*
4696  * "getftype({fname})" function
4697  */
4698     static void
4699 f_getftype(typval_T *argvars, typval_T *rettv)
4700 {
4701     char_u	*fname;
4702     stat_T	st;
4703     char_u	*type = NULL;
4704     char	*t;
4705 
4706     fname = get_tv_string(&argvars[0]);
4707 
4708     rettv->v_type = VAR_STRING;
4709     if (mch_lstat((char *)fname, &st) >= 0)
4710     {
4711 #ifdef S_ISREG
4712 	if (S_ISREG(st.st_mode))
4713 	    t = "file";
4714 	else if (S_ISDIR(st.st_mode))
4715 	    t = "dir";
4716 # ifdef S_ISLNK
4717 	else if (S_ISLNK(st.st_mode))
4718 	    t = "link";
4719 # endif
4720 # ifdef S_ISBLK
4721 	else if (S_ISBLK(st.st_mode))
4722 	    t = "bdev";
4723 # endif
4724 # ifdef S_ISCHR
4725 	else if (S_ISCHR(st.st_mode))
4726 	    t = "cdev";
4727 # endif
4728 # ifdef S_ISFIFO
4729 	else if (S_ISFIFO(st.st_mode))
4730 	    t = "fifo";
4731 # endif
4732 # ifdef S_ISSOCK
4733 	else if (S_ISSOCK(st.st_mode))
4734 	    t = "fifo";
4735 # endif
4736 	else
4737 	    t = "other";
4738 #else
4739 # ifdef S_IFMT
4740 	switch (st.st_mode & S_IFMT)
4741 	{
4742 	    case S_IFREG: t = "file"; break;
4743 	    case S_IFDIR: t = "dir"; break;
4744 #  ifdef S_IFLNK
4745 	    case S_IFLNK: t = "link"; break;
4746 #  endif
4747 #  ifdef S_IFBLK
4748 	    case S_IFBLK: t = "bdev"; break;
4749 #  endif
4750 #  ifdef S_IFCHR
4751 	    case S_IFCHR: t = "cdev"; break;
4752 #  endif
4753 #  ifdef S_IFIFO
4754 	    case S_IFIFO: t = "fifo"; break;
4755 #  endif
4756 #  ifdef S_IFSOCK
4757 	    case S_IFSOCK: t = "socket"; break;
4758 #  endif
4759 	    default: t = "other";
4760 	}
4761 # else
4762 	if (mch_isdir(fname))
4763 	    t = "dir";
4764 	else
4765 	    t = "file";
4766 # endif
4767 #endif
4768 	type = vim_strsave((char_u *)t);
4769     }
4770     rettv->vval.v_string = type;
4771 }
4772 
4773 /*
4774  * "getline(lnum, [end])" function
4775  */
4776     static void
4777 f_getline(typval_T *argvars, typval_T *rettv)
4778 {
4779     linenr_T	lnum;
4780     linenr_T	end;
4781     int		retlist;
4782 
4783     lnum = get_tv_lnum(argvars);
4784     if (argvars[1].v_type == VAR_UNKNOWN)
4785     {
4786 	end = 0;
4787 	retlist = FALSE;
4788     }
4789     else
4790     {
4791 	end = get_tv_lnum(&argvars[1]);
4792 	retlist = TRUE;
4793     }
4794 
4795     get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4796 }
4797 
4798 #ifdef FEAT_QUICKFIX
4799     static void
4800 get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
4801 {
4802     if (what_arg->v_type == VAR_UNKNOWN)
4803     {
4804 	if (rettv_list_alloc(rettv) == OK)
4805 	    if (is_qf || wp != NULL)
4806 		(void)get_errorlist(wp, -1, rettv->vval.v_list);
4807     }
4808     else
4809     {
4810 	if (rettv_dict_alloc(rettv) == OK)
4811 	    if (is_qf || (wp != NULL))
4812 	    {
4813 		if (what_arg->v_type == VAR_DICT)
4814 		{
4815 		    dict_T	*d = what_arg->vval.v_dict;
4816 
4817 		    if (d != NULL)
4818 			get_errorlist_properties(wp, d, rettv->vval.v_dict);
4819 		}
4820 		else
4821 		    EMSG(_(e_dictreq));
4822 	    }
4823     }
4824 }
4825 #endif
4826 
4827 /*
4828  * "getloclist()" function
4829  */
4830     static void
4831 f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4832 {
4833 #ifdef FEAT_QUICKFIX
4834     win_T	*wp;
4835 
4836     wp = find_win_by_nr(&argvars[0], NULL);
4837     get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
4838 #endif
4839 }
4840 
4841 /*
4842  * "getmatches()" function
4843  */
4844     static void
4845 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4846 {
4847 #ifdef FEAT_SEARCH_EXTRA
4848     dict_T	*dict;
4849     matchitem_T	*cur = curwin->w_match_head;
4850     int		i;
4851 
4852     if (rettv_list_alloc(rettv) == OK)
4853     {
4854 	while (cur != NULL)
4855 	{
4856 	    dict = dict_alloc();
4857 	    if (dict == NULL)
4858 		return;
4859 	    if (cur->match.regprog == NULL)
4860 	    {
4861 		/* match added with matchaddpos() */
4862 		for (i = 0; i < MAXPOSMATCH; ++i)
4863 		{
4864 		    llpos_T	*llpos;
4865 		    char	buf[6];
4866 		    list_T	*l;
4867 
4868 		    llpos = &cur->pos.pos[i];
4869 		    if (llpos->lnum == 0)
4870 			break;
4871 		    l = list_alloc();
4872 		    if (l == NULL)
4873 			break;
4874 		    list_append_number(l, (varnumber_T)llpos->lnum);
4875 		    if (llpos->col > 0)
4876 		    {
4877 			list_append_number(l, (varnumber_T)llpos->col);
4878 			list_append_number(l, (varnumber_T)llpos->len);
4879 		    }
4880 		    sprintf(buf, "pos%d", i + 1);
4881 		    dict_add_list(dict, buf, l);
4882 		}
4883 	    }
4884 	    else
4885 	    {
4886 		dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4887 	    }
4888 	    dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4889 	    dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4890 	    dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4891 # if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4892 	    if (cur->conceal_char)
4893 	    {
4894 		char_u buf[MB_MAXBYTES + 1];
4895 
4896 		buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4897 		dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4898 	    }
4899 # endif
4900 	    list_append_dict(rettv->vval.v_list, dict);
4901 	    cur = cur->next;
4902 	}
4903     }
4904 #endif
4905 }
4906 
4907 /*
4908  * "getpid()" function
4909  */
4910     static void
4911 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4912 {
4913     rettv->vval.v_number = mch_get_pid();
4914 }
4915 
4916     static void
4917 getpos_both(
4918     typval_T	*argvars,
4919     typval_T	*rettv,
4920     int		getcurpos)
4921 {
4922     pos_T	*fp;
4923     list_T	*l;
4924     int		fnum = -1;
4925 
4926     if (rettv_list_alloc(rettv) == OK)
4927     {
4928 	l = rettv->vval.v_list;
4929 	if (getcurpos)
4930 	    fp = &curwin->w_cursor;
4931 	else
4932 	    fp = var2fpos(&argvars[0], TRUE, &fnum);
4933 	if (fnum != -1)
4934 	    list_append_number(l, (varnumber_T)fnum);
4935 	else
4936 	    list_append_number(l, (varnumber_T)0);
4937 	list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4938 							    : (varnumber_T)0);
4939 	list_append_number(l, (fp != NULL)
4940 		     ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4941 							    : (varnumber_T)0);
4942 	list_append_number(l,
4943 #ifdef FEAT_VIRTUALEDIT
4944 				(fp != NULL) ? (varnumber_T)fp->coladd :
4945 #endif
4946 							      (varnumber_T)0);
4947 	if (getcurpos)
4948 	{
4949 	    update_curswant();
4950 	    list_append_number(l, curwin->w_curswant == MAXCOL ?
4951 		    (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
4952 	}
4953     }
4954     else
4955 	rettv->vval.v_number = FALSE;
4956 }
4957 
4958 
4959 /*
4960  * "getcurpos()" function
4961  */
4962     static void
4963 f_getcurpos(typval_T *argvars, typval_T *rettv)
4964 {
4965     getpos_both(argvars, rettv, TRUE);
4966 }
4967 
4968 /*
4969  * "getpos(string)" function
4970  */
4971     static void
4972 f_getpos(typval_T *argvars, typval_T *rettv)
4973 {
4974     getpos_both(argvars, rettv, FALSE);
4975 }
4976 
4977 /*
4978  * "getqflist()" function
4979  */
4980     static void
4981 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4982 {
4983 #ifdef FEAT_QUICKFIX
4984     get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
4985 #endif
4986 }
4987 
4988 /*
4989  * "getreg()" function
4990  */
4991     static void
4992 f_getreg(typval_T *argvars, typval_T *rettv)
4993 {
4994     char_u	*strregname;
4995     int		regname;
4996     int		arg2 = FALSE;
4997     int		return_list = FALSE;
4998     int		error = FALSE;
4999 
5000     if (argvars[0].v_type != VAR_UNKNOWN)
5001     {
5002 	strregname = get_tv_string_chk(&argvars[0]);
5003 	error = strregname == NULL;
5004 	if (argvars[1].v_type != VAR_UNKNOWN)
5005 	{
5006 	    arg2 = (int)get_tv_number_chk(&argvars[1], &error);
5007 	    if (!error && argvars[2].v_type != VAR_UNKNOWN)
5008 		return_list = (int)get_tv_number_chk(&argvars[2], &error);
5009 	}
5010     }
5011     else
5012 	strregname = get_vim_var_str(VV_REG);
5013 
5014     if (error)
5015 	return;
5016 
5017     regname = (strregname == NULL ? '"' : *strregname);
5018     if (regname == 0)
5019 	regname = '"';
5020 
5021     if (return_list)
5022     {
5023 	rettv->v_type = VAR_LIST;
5024 	rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5025 				      (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5026 	if (rettv->vval.v_list == NULL)
5027 	    (void)rettv_list_alloc(rettv);
5028 	else
5029 	    ++rettv->vval.v_list->lv_refcount;
5030     }
5031     else
5032     {
5033 	rettv->v_type = VAR_STRING;
5034 	rettv->vval.v_string = get_reg_contents(regname,
5035 						    arg2 ? GREG_EXPR_SRC : 0);
5036     }
5037 }
5038 
5039 /*
5040  * "getregtype()" function
5041  */
5042     static void
5043 f_getregtype(typval_T *argvars, typval_T *rettv)
5044 {
5045     char_u	*strregname;
5046     int		regname;
5047     char_u	buf[NUMBUFLEN + 2];
5048     long	reglen = 0;
5049 
5050     if (argvars[0].v_type != VAR_UNKNOWN)
5051     {
5052 	strregname = get_tv_string_chk(&argvars[0]);
5053 	if (strregname == NULL)	    /* type error; errmsg already given */
5054 	{
5055 	    rettv->v_type = VAR_STRING;
5056 	    rettv->vval.v_string = NULL;
5057 	    return;
5058 	}
5059     }
5060     else
5061 	/* Default to v:register */
5062 	strregname = get_vim_var_str(VV_REG);
5063 
5064     regname = (strregname == NULL ? '"' : *strregname);
5065     if (regname == 0)
5066 	regname = '"';
5067 
5068     buf[0] = NUL;
5069     buf[1] = NUL;
5070     switch (get_reg_type(regname, &reglen))
5071     {
5072 	case MLINE: buf[0] = 'V'; break;
5073 	case MCHAR: buf[0] = 'v'; break;
5074 	case MBLOCK:
5075 		buf[0] = Ctrl_V;
5076 		sprintf((char *)buf + 1, "%ld", reglen + 1);
5077 		break;
5078     }
5079     rettv->v_type = VAR_STRING;
5080     rettv->vval.v_string = vim_strsave(buf);
5081 }
5082 
5083 #ifdef FEAT_WINDOWS
5084 /*
5085  * Returns information (variables, options, etc.) about a tab page
5086  * as a dictionary.
5087  */
5088     static dict_T *
5089 get_tabpage_info(tabpage_T *tp, int tp_idx)
5090 {
5091     win_T	*wp;
5092     dict_T	*dict;
5093     list_T	*l;
5094 
5095     dict = dict_alloc();
5096     if (dict == NULL)
5097 	return NULL;
5098 
5099     dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
5100 
5101     l = list_alloc();
5102     if (l != NULL)
5103     {
5104 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5105 		wp; wp = wp->w_next)
5106 	    list_append_number(l, (varnumber_T)wp->w_id);
5107 	dict_add_list(dict, "windows", l);
5108     }
5109 
5110     /* Make a reference to tabpage variables */
5111     dict_add_dict(dict, "variables", tp->tp_vars);
5112 
5113     return dict;
5114 }
5115 #endif
5116 
5117 /*
5118  * "gettabinfo()" function
5119  */
5120     static void
5121 f_gettabinfo(typval_T *argvars, typval_T *rettv)
5122 {
5123 #ifdef FEAT_WINDOWS
5124     tabpage_T	*tp, *tparg = NULL;
5125     dict_T	*d;
5126     int		tpnr = 0;
5127 
5128     if (rettv_list_alloc(rettv) != OK)
5129 	return;
5130 
5131     if (argvars[0].v_type != VAR_UNKNOWN)
5132     {
5133 	/* Information about one tab page */
5134 	tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5135 	if (tparg == NULL)
5136 	    return;
5137     }
5138 
5139     /* Get information about a specific tab page or all tab pages */
5140     FOR_ALL_TABPAGES(tp)
5141     {
5142 	tpnr++;
5143 	if (tparg != NULL && tp != tparg)
5144 	    continue;
5145 	d = get_tabpage_info(tp, tpnr);
5146 	if (d != NULL)
5147 	    list_append_dict(rettv->vval.v_list, d);
5148 	if (tparg != NULL)
5149 	    return;
5150     }
5151 #endif
5152 }
5153 
5154 /*
5155  * "gettabvar()" function
5156  */
5157     static void
5158 f_gettabvar(typval_T *argvars, typval_T *rettv)
5159 {
5160     win_T	*oldcurwin;
5161     tabpage_T	*tp, *oldtabpage;
5162     dictitem_T	*v;
5163     char_u	*varname;
5164     int		done = FALSE;
5165 
5166     rettv->v_type = VAR_STRING;
5167     rettv->vval.v_string = NULL;
5168 
5169     varname = get_tv_string_chk(&argvars[1]);
5170     tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
5171     if (tp != NULL && varname != NULL)
5172     {
5173 	/* Set tp to be our tabpage, temporarily.  Also set the window to the
5174 	 * first window in the tabpage, otherwise the window is not valid. */
5175 	if (switch_win(&oldcurwin, &oldtabpage,
5176 		    tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE)
5177 									== OK)
5178 	{
5179 	    /* look up the variable */
5180 	    /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5181 	    v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5182 	    if (v != NULL)
5183 	    {
5184 		copy_tv(&v->di_tv, rettv);
5185 		done = TRUE;
5186 	    }
5187 	}
5188 
5189 	/* restore previous notion of curwin */
5190 	restore_win(oldcurwin, oldtabpage, TRUE);
5191     }
5192 
5193     if (!done && argvars[2].v_type != VAR_UNKNOWN)
5194 	copy_tv(&argvars[2], rettv);
5195 }
5196 
5197 /*
5198  * "gettabwinvar()" function
5199  */
5200     static void
5201 f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5202 {
5203     getwinvar(argvars, rettv, 1);
5204 }
5205 
5206 #ifdef FEAT_WINDOWS
5207 /*
5208  * Returns information about a window as a dictionary.
5209  */
5210     static dict_T *
5211 get_win_info(win_T *wp, short tpnr, short winnr)
5212 {
5213     dict_T	*dict;
5214 
5215     dict = dict_alloc();
5216     if (dict == NULL)
5217 	return NULL;
5218 
5219     dict_add_nr_str(dict, "tabnr", tpnr, NULL);
5220     dict_add_nr_str(dict, "winnr", winnr, NULL);
5221     dict_add_nr_str(dict, "winid", wp->w_id, NULL);
5222     dict_add_nr_str(dict, "height", wp->w_height, NULL);
5223     dict_add_nr_str(dict, "width", wp->w_width, NULL);
5224     dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
5225 
5226 #ifdef FEAT_QUICKFIX
5227     dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
5228     dict_add_nr_str(dict, "loclist",
5229 	    (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL);
5230 #endif
5231 
5232     /* Add a reference to window variables */
5233     dict_add_dict(dict, "variables", wp->w_vars);
5234 
5235     return dict;
5236 }
5237 #endif
5238 
5239 /*
5240  * "getwininfo()" function
5241  */
5242     static void
5243 f_getwininfo(typval_T *argvars, typval_T *rettv)
5244 {
5245 #ifdef FEAT_WINDOWS
5246     tabpage_T	*tp;
5247     win_T	*wp = NULL, *wparg = NULL;
5248     dict_T	*d;
5249     short	tabnr = 0, winnr;
5250 #endif
5251 
5252     if (rettv_list_alloc(rettv) != OK)
5253 	return;
5254 
5255 #ifdef FEAT_WINDOWS
5256     if (argvars[0].v_type != VAR_UNKNOWN)
5257     {
5258 	wparg = win_id2wp(argvars);
5259 	if (wparg == NULL)
5260 	    return;
5261     }
5262 
5263     /* Collect information about either all the windows across all the tab
5264      * pages or one particular window.
5265      */
5266     FOR_ALL_TABPAGES(tp)
5267     {
5268 	tabnr++;
5269 	winnr = 0;
5270 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
5271 	{
5272 	    winnr++;
5273 	    if (wparg != NULL && wp != wparg)
5274 		continue;
5275 	    d = get_win_info(wp, tabnr, winnr);
5276 	    if (d != NULL)
5277 		list_append_dict(rettv->vval.v_list, d);
5278 	    if (wparg != NULL)
5279 		/* found information about a specific window */
5280 		return;
5281 	}
5282     }
5283 #endif
5284 }
5285 
5286 /*
5287  * "win_findbuf()" function
5288  */
5289     static void
5290 f_win_findbuf(typval_T *argvars, typval_T *rettv)
5291 {
5292     if (rettv_list_alloc(rettv) != FAIL)
5293 	win_findbuf(argvars, rettv->vval.v_list);
5294 }
5295 
5296 /*
5297  * "win_getid()" function
5298  */
5299     static void
5300 f_win_getid(typval_T *argvars, typval_T *rettv)
5301 {
5302     rettv->vval.v_number = win_getid(argvars);
5303 }
5304 
5305 /*
5306  * "win_gotoid()" function
5307  */
5308     static void
5309 f_win_gotoid(typval_T *argvars, typval_T *rettv)
5310 {
5311     rettv->vval.v_number = win_gotoid(argvars);
5312 }
5313 
5314 /*
5315  * "win_id2tabwin()" function
5316  */
5317     static void
5318 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5319 {
5320     if (rettv_list_alloc(rettv) != FAIL)
5321 	win_id2tabwin(argvars, rettv->vval.v_list);
5322 }
5323 
5324 /*
5325  * "win_id2win()" function
5326  */
5327     static void
5328 f_win_id2win(typval_T *argvars, typval_T *rettv)
5329 {
5330     rettv->vval.v_number = win_id2win(argvars);
5331 }
5332 
5333 /*
5334  * "getwinposx()" function
5335  */
5336     static void
5337 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5338 {
5339     rettv->vval.v_number = -1;
5340 #ifdef FEAT_GUI
5341     if (gui.in_use)
5342     {
5343 	int	    x, y;
5344 
5345 	if (gui_mch_get_winpos(&x, &y) == OK)
5346 	    rettv->vval.v_number = x;
5347 	return;
5348     }
5349 #endif
5350 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5351     {
5352 	int	    x, y;
5353 
5354 	if (term_get_winpos(&x, &y) == OK)
5355 	    rettv->vval.v_number = x;
5356     }
5357 #endif
5358 }
5359 
5360 /*
5361  * "getwinposy()" function
5362  */
5363     static void
5364 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5365 {
5366     rettv->vval.v_number = -1;
5367 #ifdef FEAT_GUI
5368     if (gui.in_use)
5369     {
5370 	int	    x, y;
5371 
5372 	if (gui_mch_get_winpos(&x, &y) == OK)
5373 	    rettv->vval.v_number = y;
5374 	return;
5375     }
5376 #endif
5377 #if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5378     {
5379 	int	    x, y;
5380 
5381 	if (term_get_winpos(&x, &y) == OK)
5382 	    rettv->vval.v_number = y;
5383     }
5384 #endif
5385 }
5386 
5387 /*
5388  * "getwinvar()" function
5389  */
5390     static void
5391 f_getwinvar(typval_T *argvars, typval_T *rettv)
5392 {
5393     getwinvar(argvars, rettv, 0);
5394 }
5395 
5396 /*
5397  * "glob()" function
5398  */
5399     static void
5400 f_glob(typval_T *argvars, typval_T *rettv)
5401 {
5402     int		options = WILD_SILENT|WILD_USE_NL;
5403     expand_T	xpc;
5404     int		error = FALSE;
5405 
5406     /* When the optional second argument is non-zero, don't remove matches
5407      * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5408     rettv->v_type = VAR_STRING;
5409     if (argvars[1].v_type != VAR_UNKNOWN)
5410     {
5411 	if (get_tv_number_chk(&argvars[1], &error))
5412 	    options |= WILD_KEEP_ALL;
5413 	if (argvars[2].v_type != VAR_UNKNOWN)
5414 	{
5415 	    if (get_tv_number_chk(&argvars[2], &error))
5416 	    {
5417 		rettv_list_set(rettv, NULL);
5418 	    }
5419 	    if (argvars[3].v_type != VAR_UNKNOWN
5420 				    && get_tv_number_chk(&argvars[3], &error))
5421 		options |= WILD_ALLLINKS;
5422 	}
5423     }
5424     if (!error)
5425     {
5426 	ExpandInit(&xpc);
5427 	xpc.xp_context = EXPAND_FILES;
5428 	if (p_wic)
5429 	    options += WILD_ICASE;
5430 	if (rettv->v_type == VAR_STRING)
5431 	    rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
5432 						     NULL, options, WILD_ALL);
5433 	else if (rettv_list_alloc(rettv) != FAIL)
5434 	{
5435 	  int i;
5436 
5437 	  ExpandOne(&xpc, get_tv_string(&argvars[0]),
5438 						NULL, options, WILD_ALL_KEEP);
5439 	  for (i = 0; i < xpc.xp_numfiles; i++)
5440 	      list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5441 
5442 	  ExpandCleanup(&xpc);
5443 	}
5444     }
5445     else
5446 	rettv->vval.v_string = NULL;
5447 }
5448 
5449 /*
5450  * "globpath()" function
5451  */
5452     static void
5453 f_globpath(typval_T *argvars, typval_T *rettv)
5454 {
5455     int		flags = 0;
5456     char_u	buf1[NUMBUFLEN];
5457     char_u	*file = get_tv_string_buf_chk(&argvars[1], buf1);
5458     int		error = FALSE;
5459     garray_T	ga;
5460     int		i;
5461 
5462     /* When the optional second argument is non-zero, don't remove matches
5463     * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5464     rettv->v_type = VAR_STRING;
5465     if (argvars[2].v_type != VAR_UNKNOWN)
5466     {
5467 	if (get_tv_number_chk(&argvars[2], &error))
5468 	    flags |= WILD_KEEP_ALL;
5469 	if (argvars[3].v_type != VAR_UNKNOWN)
5470 	{
5471 	    if (get_tv_number_chk(&argvars[3], &error))
5472 	    {
5473 		rettv_list_set(rettv, NULL);
5474 	    }
5475 	    if (argvars[4].v_type != VAR_UNKNOWN
5476 				    && get_tv_number_chk(&argvars[4], &error))
5477 		flags |= WILD_ALLLINKS;
5478 	}
5479     }
5480     if (file != NULL && !error)
5481     {
5482 	ga_init2(&ga, (int)sizeof(char_u *), 10);
5483 	globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5484 	if (rettv->v_type == VAR_STRING)
5485 	    rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5486 	else if (rettv_list_alloc(rettv) != FAIL)
5487 	    for (i = 0; i < ga.ga_len; ++i)
5488 		list_append_string(rettv->vval.v_list,
5489 					    ((char_u **)(ga.ga_data))[i], -1);
5490 	ga_clear_strings(&ga);
5491     }
5492     else
5493 	rettv->vval.v_string = NULL;
5494 }
5495 
5496 /*
5497  * "glob2regpat()" function
5498  */
5499     static void
5500 f_glob2regpat(typval_T *argvars, typval_T *rettv)
5501 {
5502     char_u	*pat = get_tv_string_chk(&argvars[0]);
5503 
5504     rettv->v_type = VAR_STRING;
5505     rettv->vval.v_string = (pat == NULL)
5506 			 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5507 }
5508 
5509 /* for VIM_VERSION_ defines */
5510 #include "version.h"
5511 
5512 /*
5513  * "has()" function
5514  */
5515     static void
5516 f_has(typval_T *argvars, typval_T *rettv)
5517 {
5518     int		i;
5519     char_u	*name;
5520     int		n = FALSE;
5521     static char	*(has_list[]) =
5522     {
5523 #ifdef AMIGA
5524 	"amiga",
5525 # ifdef FEAT_ARP
5526 	"arp",
5527 # endif
5528 #endif
5529 #ifdef __BEOS__
5530 	"beos",
5531 #endif
5532 #ifdef MACOS
5533 	"mac",
5534 #endif
5535 #if defined(MACOS_X_UNIX)
5536 	"macunix",  /* built with 'darwin' enabled */
5537 #endif
5538 #if defined(__APPLE__) && __APPLE__ == 1
5539 	"osx",	    /* built with or without 'darwin' enabled */
5540 #endif
5541 #ifdef __QNX__
5542 	"qnx",
5543 #endif
5544 #ifdef UNIX
5545 	"unix",
5546 #endif
5547 #ifdef VMS
5548 	"vms",
5549 #endif
5550 #ifdef WIN32
5551 	"win32",
5552 #endif
5553 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5554 	"win32unix",
5555 #endif
5556 #if defined(WIN64) || defined(_WIN64)
5557 	"win64",
5558 #endif
5559 #ifdef EBCDIC
5560 	"ebcdic",
5561 #endif
5562 #ifndef CASE_INSENSITIVE_FILENAME
5563 	"fname_case",
5564 #endif
5565 #ifdef HAVE_ACL
5566 	"acl",
5567 #endif
5568 #ifdef FEAT_ARABIC
5569 	"arabic",
5570 #endif
5571 #ifdef FEAT_AUTOCMD
5572 	"autocmd",
5573 #endif
5574 #ifdef FEAT_BEVAL
5575 	"balloon_eval",
5576 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5577 	"balloon_multiline",
5578 # endif
5579 #endif
5580 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5581 	"builtin_terms",
5582 # ifdef ALL_BUILTIN_TCAPS
5583 	"all_builtin_terms",
5584 # endif
5585 #endif
5586 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5587 	|| defined(FEAT_GUI_W32) \
5588 	|| defined(FEAT_GUI_MOTIF))
5589 	"browsefilter",
5590 #endif
5591 #ifdef FEAT_BYTEOFF
5592 	"byte_offset",
5593 #endif
5594 #ifdef FEAT_JOB_CHANNEL
5595 	"channel",
5596 #endif
5597 #ifdef FEAT_CINDENT
5598 	"cindent",
5599 #endif
5600 #ifdef FEAT_CLIENTSERVER
5601 	"clientserver",
5602 #endif
5603 #ifdef FEAT_CLIPBOARD
5604 	"clipboard",
5605 #endif
5606 #ifdef FEAT_CMDL_COMPL
5607 	"cmdline_compl",
5608 #endif
5609 #ifdef FEAT_CMDHIST
5610 	"cmdline_hist",
5611 #endif
5612 #ifdef FEAT_COMMENTS
5613 	"comments",
5614 #endif
5615 #ifdef FEAT_CONCEAL
5616 	"conceal",
5617 #endif
5618 #ifdef FEAT_CRYPT
5619 	"cryptv",
5620 	"crypt-blowfish",
5621 	"crypt-blowfish2",
5622 #endif
5623 #ifdef FEAT_CSCOPE
5624 	"cscope",
5625 #endif
5626 #ifdef FEAT_CURSORBIND
5627 	"cursorbind",
5628 #endif
5629 #ifdef CURSOR_SHAPE
5630 	"cursorshape",
5631 #endif
5632 #ifdef DEBUG
5633 	"debug",
5634 #endif
5635 #ifdef FEAT_CON_DIALOG
5636 	"dialog_con",
5637 #endif
5638 #ifdef FEAT_GUI_DIALOG
5639 	"dialog_gui",
5640 #endif
5641 #ifdef FEAT_DIFF
5642 	"diff",
5643 #endif
5644 #ifdef FEAT_DIGRAPHS
5645 	"digraphs",
5646 #endif
5647 #ifdef FEAT_DIRECTX
5648 	"directx",
5649 #endif
5650 #ifdef FEAT_DND
5651 	"dnd",
5652 #endif
5653 #ifdef FEAT_EMACS_TAGS
5654 	"emacs_tags",
5655 #endif
5656 	"eval",	    /* always present, of course! */
5657 	"ex_extra", /* graduated feature */
5658 #ifdef FEAT_SEARCH_EXTRA
5659 	"extra_search",
5660 #endif
5661 #ifdef FEAT_FKMAP
5662 	"farsi",
5663 #endif
5664 #ifdef FEAT_SEARCHPATH
5665 	"file_in_path",
5666 #endif
5667 #ifdef FEAT_FILTERPIPE
5668 	"filterpipe",
5669 #endif
5670 #ifdef FEAT_FIND_ID
5671 	"find_in_path",
5672 #endif
5673 #ifdef FEAT_FLOAT
5674 	"float",
5675 #endif
5676 #ifdef FEAT_FOLDING
5677 	"folding",
5678 #endif
5679 #ifdef FEAT_FOOTER
5680 	"footer",
5681 #endif
5682 #if !defined(USE_SYSTEM) && defined(UNIX)
5683 	"fork",
5684 #endif
5685 #ifdef FEAT_GETTEXT
5686 	"gettext",
5687 #endif
5688 #ifdef FEAT_GUI
5689 	"gui",
5690 #endif
5691 #ifdef FEAT_GUI_ATHENA
5692 # ifdef FEAT_GUI_NEXTAW
5693 	"gui_neXtaw",
5694 # else
5695 	"gui_athena",
5696 # endif
5697 #endif
5698 #ifdef FEAT_GUI_GTK
5699 	"gui_gtk",
5700 # ifdef USE_GTK3
5701 	"gui_gtk3",
5702 # else
5703 	"gui_gtk2",
5704 # endif
5705 #endif
5706 #ifdef FEAT_GUI_GNOME
5707 	"gui_gnome",
5708 #endif
5709 #ifdef FEAT_GUI_MAC
5710 	"gui_mac",
5711 #endif
5712 #ifdef FEAT_GUI_MOTIF
5713 	"gui_motif",
5714 #endif
5715 #ifdef FEAT_GUI_PHOTON
5716 	"gui_photon",
5717 #endif
5718 #ifdef FEAT_GUI_W32
5719 	"gui_win32",
5720 #endif
5721 #ifdef FEAT_HANGULIN
5722 	"hangul_input",
5723 #endif
5724 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5725 	"iconv",
5726 #endif
5727 #ifdef FEAT_INS_EXPAND
5728 	"insert_expand",
5729 #endif
5730 #ifdef FEAT_JOB_CHANNEL
5731 	"job",
5732 #endif
5733 #ifdef FEAT_JUMPLIST
5734 	"jumplist",
5735 #endif
5736 #ifdef FEAT_KEYMAP
5737 	"keymap",
5738 #endif
5739 	"lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
5740 #ifdef FEAT_LANGMAP
5741 	"langmap",
5742 #endif
5743 #ifdef FEAT_LIBCALL
5744 	"libcall",
5745 #endif
5746 #ifdef FEAT_LINEBREAK
5747 	"linebreak",
5748 #endif
5749 #ifdef FEAT_LISP
5750 	"lispindent",
5751 #endif
5752 #ifdef FEAT_LISTCMDS
5753 	"listcmds",
5754 #endif
5755 #ifdef FEAT_LOCALMAP
5756 	"localmap",
5757 #endif
5758 #ifdef FEAT_LUA
5759 # ifndef DYNAMIC_LUA
5760 	"lua",
5761 # endif
5762 #endif
5763 #ifdef FEAT_MENU
5764 	"menu",
5765 #endif
5766 #ifdef FEAT_SESSION
5767 	"mksession",
5768 #endif
5769 #ifdef FEAT_MODIFY_FNAME
5770 	"modify_fname",
5771 #endif
5772 #ifdef FEAT_MOUSE
5773 	"mouse",
5774 #endif
5775 #ifdef FEAT_MOUSESHAPE
5776 	"mouseshape",
5777 #endif
5778 #if defined(UNIX) || defined(VMS)
5779 # ifdef FEAT_MOUSE_DEC
5780 	"mouse_dec",
5781 # endif
5782 # ifdef FEAT_MOUSE_GPM
5783 	"mouse_gpm",
5784 # endif
5785 # ifdef FEAT_MOUSE_JSB
5786 	"mouse_jsbterm",
5787 # endif
5788 # ifdef FEAT_MOUSE_NET
5789 	"mouse_netterm",
5790 # endif
5791 # ifdef FEAT_MOUSE_PTERM
5792 	"mouse_pterm",
5793 # endif
5794 # ifdef FEAT_MOUSE_SGR
5795 	"mouse_sgr",
5796 # endif
5797 # ifdef FEAT_SYSMOUSE
5798 	"mouse_sysmouse",
5799 # endif
5800 # ifdef FEAT_MOUSE_URXVT
5801 	"mouse_urxvt",
5802 # endif
5803 # ifdef FEAT_MOUSE_XTERM
5804 	"mouse_xterm",
5805 # endif
5806 #endif
5807 #ifdef FEAT_MBYTE
5808 	"multi_byte",
5809 #endif
5810 #ifdef FEAT_MBYTE_IME
5811 	"multi_byte_ime",
5812 #endif
5813 #ifdef FEAT_MULTI_LANG
5814 	"multi_lang",
5815 #endif
5816 #ifdef FEAT_MZSCHEME
5817 #ifndef DYNAMIC_MZSCHEME
5818 	"mzscheme",
5819 #endif
5820 #endif
5821 #ifdef FEAT_NUM64
5822 	"num64",
5823 #endif
5824 #ifdef FEAT_OLE
5825 	"ole",
5826 #endif
5827 	"packages",
5828 #ifdef FEAT_PATH_EXTRA
5829 	"path_extra",
5830 #endif
5831 #ifdef FEAT_PERL
5832 #ifndef DYNAMIC_PERL
5833 	"perl",
5834 #endif
5835 #endif
5836 #ifdef FEAT_PERSISTENT_UNDO
5837 	"persistent_undo",
5838 #endif
5839 #if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
5840 	"python",
5841 	"pythonx",
5842 #endif
5843 #if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
5844 	"python3",
5845 	"pythonx",
5846 #endif
5847 #ifdef FEAT_POSTSCRIPT
5848 	"postscript",
5849 #endif
5850 #ifdef FEAT_PRINTER
5851 	"printer",
5852 #endif
5853 #ifdef FEAT_PROFILE
5854 	"profile",
5855 #endif
5856 #ifdef FEAT_RELTIME
5857 	"reltime",
5858 #endif
5859 #ifdef FEAT_QUICKFIX
5860 	"quickfix",
5861 #endif
5862 #ifdef FEAT_RIGHTLEFT
5863 	"rightleft",
5864 #endif
5865 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5866 	"ruby",
5867 #endif
5868 #ifdef FEAT_SCROLLBIND
5869 	"scrollbind",
5870 #endif
5871 #ifdef FEAT_CMDL_INFO
5872 	"showcmd",
5873 	"cmdline_info",
5874 #endif
5875 #ifdef FEAT_SIGNS
5876 	"signs",
5877 #endif
5878 #ifdef FEAT_SMARTINDENT
5879 	"smartindent",
5880 #endif
5881 #ifdef STARTUPTIME
5882 	"startuptime",
5883 #endif
5884 #ifdef FEAT_STL_OPT
5885 	"statusline",
5886 #endif
5887 #ifdef FEAT_SUN_WORKSHOP
5888 	"sun_workshop",
5889 #endif
5890 #ifdef FEAT_NETBEANS_INTG
5891 	"netbeans_intg",
5892 #endif
5893 #ifdef FEAT_SPELL
5894 	"spell",
5895 #endif
5896 #ifdef FEAT_SYN_HL
5897 	"syntax",
5898 #endif
5899 #if defined(USE_SYSTEM) || !defined(UNIX)
5900 	"system",
5901 #endif
5902 #ifdef FEAT_TAG_BINS
5903 	"tag_binary",
5904 #endif
5905 #ifdef FEAT_TAG_OLDSTATIC
5906 	"tag_old_static",
5907 #endif
5908 #ifdef FEAT_TAG_ANYWHITE
5909 	"tag_any_white",
5910 #endif
5911 #ifdef FEAT_TCL
5912 # ifndef DYNAMIC_TCL
5913 	"tcl",
5914 # endif
5915 #endif
5916 #ifdef FEAT_TERMGUICOLORS
5917 	"termguicolors",
5918 #endif
5919 #ifdef FEAT_TERMINAL
5920 	"terminal",
5921 #endif
5922 #ifdef TERMINFO
5923 	"terminfo",
5924 #endif
5925 #ifdef FEAT_TERMRESPONSE
5926 	"termresponse",
5927 #endif
5928 #ifdef FEAT_TEXTOBJ
5929 	"textobjects",
5930 #endif
5931 #ifdef HAVE_TGETENT
5932 	"tgetent",
5933 #endif
5934 #ifdef FEAT_TIMERS
5935 	"timers",
5936 #endif
5937 #ifdef FEAT_TITLE
5938 	"title",
5939 #endif
5940 #ifdef FEAT_TOOLBAR
5941 	"toolbar",
5942 #endif
5943 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5944 	"unnamedplus",
5945 #endif
5946 #ifdef FEAT_USR_CMDS
5947 	"user-commands",    /* was accidentally included in 5.4 */
5948 	"user_commands",
5949 #endif
5950 #ifdef FEAT_VIMINFO
5951 	"viminfo",
5952 #endif
5953 #ifdef FEAT_WINDOWS
5954 	"vertsplit",
5955 #endif
5956 #ifdef FEAT_VIRTUALEDIT
5957 	"virtualedit",
5958 #endif
5959 	"visual",
5960 #ifdef FEAT_VISUALEXTRA
5961 	"visualextra",
5962 #endif
5963 #ifdef FEAT_VREPLACE
5964 	"vreplace",
5965 #endif
5966 #ifdef FEAT_WILDIGN
5967 	"wildignore",
5968 #endif
5969 #ifdef FEAT_WILDMENU
5970 	"wildmenu",
5971 #endif
5972 #ifdef FEAT_WINDOWS
5973 	"windows",
5974 #endif
5975 #ifdef FEAT_WAK
5976 	"winaltkeys",
5977 #endif
5978 #ifdef FEAT_WRITEBACKUP
5979 	"writebackup",
5980 #endif
5981 #ifdef FEAT_XIM
5982 	"xim",
5983 #endif
5984 #ifdef FEAT_XFONTSET
5985 	"xfontset",
5986 #endif
5987 #ifdef FEAT_XPM_W32
5988 	"xpm",
5989 	"xpm_w32",	/* for backward compatibility */
5990 #else
5991 # if defined(HAVE_XPM)
5992 	"xpm",
5993 # endif
5994 #endif
5995 #ifdef USE_XSMP
5996 	"xsmp",
5997 #endif
5998 #ifdef USE_XSMP_INTERACT
5999 	"xsmp_interact",
6000 #endif
6001 #ifdef FEAT_XCLIPBOARD
6002 	"xterm_clipboard",
6003 #endif
6004 #ifdef FEAT_XTERM_SAVE
6005 	"xterm_save",
6006 #endif
6007 #if defined(UNIX) && defined(FEAT_X11)
6008 	"X11",
6009 #endif
6010 	NULL
6011     };
6012 
6013     name = get_tv_string(&argvars[0]);
6014     for (i = 0; has_list[i] != NULL; ++i)
6015 	if (STRICMP(name, has_list[i]) == 0)
6016 	{
6017 	    n = TRUE;
6018 	    break;
6019 	}
6020 
6021     if (n == FALSE)
6022     {
6023 	if (STRNICMP(name, "patch", 5) == 0)
6024 	{
6025 	    if (name[5] == '-'
6026 		    && STRLEN(name) >= 11
6027 		    && vim_isdigit(name[6])
6028 		    && vim_isdigit(name[8])
6029 		    && vim_isdigit(name[10]))
6030 	    {
6031 		int major = atoi((char *)name + 6);
6032 		int minor = atoi((char *)name + 8);
6033 
6034 		/* Expect "patch-9.9.01234". */
6035 		n = (major < VIM_VERSION_MAJOR
6036 		     || (major == VIM_VERSION_MAJOR
6037 			 && (minor < VIM_VERSION_MINOR
6038 			     || (minor == VIM_VERSION_MINOR
6039 				 && has_patch(atoi((char *)name + 10))))));
6040 	    }
6041 	    else
6042 		n = has_patch(atoi((char *)name + 5));
6043 	}
6044 	else if (STRICMP(name, "vim_starting") == 0)
6045 	    n = (starting != 0);
6046 	else if (STRICMP(name, "ttyin") == 0)
6047 	    n = mch_input_isatty();
6048 	else if (STRICMP(name, "ttyout") == 0)
6049 	    n = stdout_isatty;
6050 #ifdef FEAT_MBYTE
6051 	else if (STRICMP(name, "multi_byte_encoding") == 0)
6052 	    n = has_mbyte;
6053 #endif
6054 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
6055 	else if (STRICMP(name, "balloon_multiline") == 0)
6056 	    n = multiline_balloon_available();
6057 #endif
6058 #ifdef DYNAMIC_TCL
6059 	else if (STRICMP(name, "tcl") == 0)
6060 	    n = tcl_enabled(FALSE);
6061 #endif
6062 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6063 	else if (STRICMP(name, "iconv") == 0)
6064 	    n = iconv_enabled(FALSE);
6065 #endif
6066 #ifdef DYNAMIC_LUA
6067 	else if (STRICMP(name, "lua") == 0)
6068 	    n = lua_enabled(FALSE);
6069 #endif
6070 #ifdef DYNAMIC_MZSCHEME
6071 	else if (STRICMP(name, "mzscheme") == 0)
6072 	    n = mzscheme_enabled(FALSE);
6073 #endif
6074 #ifdef DYNAMIC_RUBY
6075 	else if (STRICMP(name, "ruby") == 0)
6076 	    n = ruby_enabled(FALSE);
6077 #endif
6078 #ifdef DYNAMIC_PYTHON
6079 	else if (STRICMP(name, "python") == 0)
6080 	    n = python_enabled(FALSE);
6081 #endif
6082 #ifdef DYNAMIC_PYTHON3
6083 	else if (STRICMP(name, "python3") == 0)
6084 	    n = python3_enabled(FALSE);
6085 #endif
6086 #if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6087 	else if (STRICMP(name, "pythonx") == 0)
6088 	{
6089 # if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6090 	    if (p_pyx == 0)
6091 		n = python3_enabled(FALSE) || python_enabled(FALSE);
6092 	    else if (p_pyx == 3)
6093 		n = python3_enabled(FALSE);
6094 	    else if (p_pyx == 2)
6095 		n = python_enabled(FALSE);
6096 # elif defined(DYNAMIC_PYTHON)
6097 	    n = python_enabled(FALSE);
6098 # elif defined(DYNAMIC_PYTHON3)
6099 	    n = python3_enabled(FALSE);
6100 # endif
6101 	}
6102 #endif
6103 #ifdef DYNAMIC_PERL
6104 	else if (STRICMP(name, "perl") == 0)
6105 	    n = perl_enabled(FALSE);
6106 #endif
6107 #ifdef FEAT_GUI
6108 	else if (STRICMP(name, "gui_running") == 0)
6109 	    n = (gui.in_use || gui.starting);
6110 # ifdef FEAT_BROWSE
6111 	else if (STRICMP(name, "browse") == 0)
6112 	    n = gui.in_use;	/* gui_mch_browse() works when GUI is running */
6113 # endif
6114 #endif
6115 #ifdef FEAT_SYN_HL
6116 	else if (STRICMP(name, "syntax_items") == 0)
6117 	    n = syntax_present(curwin);
6118 #endif
6119 #if defined(WIN3264)
6120 	else if (STRICMP(name, "win95") == 0)
6121 	    n = FALSE;		/* Win9x is no more supported. */
6122 #endif
6123 #ifdef FEAT_NETBEANS_INTG
6124 	else if (STRICMP(name, "netbeans_enabled") == 0)
6125 	    n = netbeans_active();
6126 #endif
6127     }
6128 
6129     rettv->vval.v_number = n;
6130 }
6131 
6132 /*
6133  * "has_key()" function
6134  */
6135     static void
6136 f_has_key(typval_T *argvars, typval_T *rettv)
6137 {
6138     if (argvars[0].v_type != VAR_DICT)
6139     {
6140 	EMSG(_(e_dictreq));
6141 	return;
6142     }
6143     if (argvars[0].vval.v_dict == NULL)
6144 	return;
6145 
6146     rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
6147 				      get_tv_string(&argvars[1]), -1) != NULL;
6148 }
6149 
6150 /*
6151  * "haslocaldir()" function
6152  */
6153     static void
6154 f_haslocaldir(typval_T *argvars, typval_T *rettv)
6155 {
6156     win_T	*wp = NULL;
6157 
6158     wp = find_tabwin(&argvars[0], &argvars[1]);
6159     rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6160 }
6161 
6162 /*
6163  * "hasmapto()" function
6164  */
6165     static void
6166 f_hasmapto(typval_T *argvars, typval_T *rettv)
6167 {
6168     char_u	*name;
6169     char_u	*mode;
6170     char_u	buf[NUMBUFLEN];
6171     int		abbr = FALSE;
6172 
6173     name = get_tv_string(&argvars[0]);
6174     if (argvars[1].v_type == VAR_UNKNOWN)
6175 	mode = (char_u *)"nvo";
6176     else
6177     {
6178 	mode = get_tv_string_buf(&argvars[1], buf);
6179 	if (argvars[2].v_type != VAR_UNKNOWN)
6180 	    abbr = (int)get_tv_number(&argvars[2]);
6181     }
6182 
6183     if (map_to_exists(name, mode, abbr))
6184 	rettv->vval.v_number = TRUE;
6185     else
6186 	rettv->vval.v_number = FALSE;
6187 }
6188 
6189 /*
6190  * "histadd()" function
6191  */
6192     static void
6193 f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6194 {
6195 #ifdef FEAT_CMDHIST
6196     int		histype;
6197     char_u	*str;
6198     char_u	buf[NUMBUFLEN];
6199 #endif
6200 
6201     rettv->vval.v_number = FALSE;
6202     if (check_restricted() || check_secure())
6203 	return;
6204 #ifdef FEAT_CMDHIST
6205     str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
6206     histype = str != NULL ? get_histtype(str) : -1;
6207     if (histype >= 0)
6208     {
6209 	str = get_tv_string_buf(&argvars[1], buf);
6210 	if (*str != NUL)
6211 	{
6212 	    init_history();
6213 	    add_to_history(histype, str, FALSE, NUL);
6214 	    rettv->vval.v_number = TRUE;
6215 	    return;
6216 	}
6217     }
6218 #endif
6219 }
6220 
6221 /*
6222  * "histdel()" function
6223  */
6224     static void
6225 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6226 {
6227 #ifdef FEAT_CMDHIST
6228     int		n;
6229     char_u	buf[NUMBUFLEN];
6230     char_u	*str;
6231 
6232     str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
6233     if (str == NULL)
6234 	n = 0;
6235     else if (argvars[1].v_type == VAR_UNKNOWN)
6236 	/* only one argument: clear entire history */
6237 	n = clr_history(get_histtype(str));
6238     else if (argvars[1].v_type == VAR_NUMBER)
6239 	/* index given: remove that entry */
6240 	n = del_history_idx(get_histtype(str),
6241 					  (int)get_tv_number(&argvars[1]));
6242     else
6243 	/* string given: remove all matching entries */
6244 	n = del_history_entry(get_histtype(str),
6245 				      get_tv_string_buf(&argvars[1], buf));
6246     rettv->vval.v_number = n;
6247 #endif
6248 }
6249 
6250 /*
6251  * "histget()" function
6252  */
6253     static void
6254 f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6255 {
6256 #ifdef FEAT_CMDHIST
6257     int		type;
6258     int		idx;
6259     char_u	*str;
6260 
6261     str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
6262     if (str == NULL)
6263 	rettv->vval.v_string = NULL;
6264     else
6265     {
6266 	type = get_histtype(str);
6267 	if (argvars[1].v_type == VAR_UNKNOWN)
6268 	    idx = get_history_idx(type);
6269 	else
6270 	    idx = (int)get_tv_number_chk(&argvars[1], NULL);
6271 						    /* -1 on type error */
6272 	rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6273     }
6274 #else
6275     rettv->vval.v_string = NULL;
6276 #endif
6277     rettv->v_type = VAR_STRING;
6278 }
6279 
6280 /*
6281  * "histnr()" function
6282  */
6283     static void
6284 f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6285 {
6286     int		i;
6287 
6288 #ifdef FEAT_CMDHIST
6289     char_u	*history = get_tv_string_chk(&argvars[0]);
6290 
6291     i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6292     if (i >= HIST_CMD && i < HIST_COUNT)
6293 	i = get_history_idx(i);
6294     else
6295 #endif
6296 	i = -1;
6297     rettv->vval.v_number = i;
6298 }
6299 
6300 /*
6301  * "highlightID(name)" function
6302  */
6303     static void
6304 f_hlID(typval_T *argvars, typval_T *rettv)
6305 {
6306     rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
6307 }
6308 
6309 /*
6310  * "highlight_exists()" function
6311  */
6312     static void
6313 f_hlexists(typval_T *argvars, typval_T *rettv)
6314 {
6315     rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
6316 }
6317 
6318 /*
6319  * "hostname()" function
6320  */
6321     static void
6322 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6323 {
6324     char_u hostname[256];
6325 
6326     mch_get_host_name(hostname, 256);
6327     rettv->v_type = VAR_STRING;
6328     rettv->vval.v_string = vim_strsave(hostname);
6329 }
6330 
6331 /*
6332  * iconv() function
6333  */
6334     static void
6335 f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6336 {
6337 #ifdef FEAT_MBYTE
6338     char_u	buf1[NUMBUFLEN];
6339     char_u	buf2[NUMBUFLEN];
6340     char_u	*from, *to, *str;
6341     vimconv_T	vimconv;
6342 #endif
6343 
6344     rettv->v_type = VAR_STRING;
6345     rettv->vval.v_string = NULL;
6346 
6347 #ifdef FEAT_MBYTE
6348     str = get_tv_string(&argvars[0]);
6349     from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
6350     to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
6351     vimconv.vc_type = CONV_NONE;
6352     convert_setup(&vimconv, from, to);
6353 
6354     /* If the encodings are equal, no conversion needed. */
6355     if (vimconv.vc_type == CONV_NONE)
6356 	rettv->vval.v_string = vim_strsave(str);
6357     else
6358 	rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6359 
6360     convert_setup(&vimconv, NULL, NULL);
6361     vim_free(from);
6362     vim_free(to);
6363 #endif
6364 }
6365 
6366 /*
6367  * "indent()" function
6368  */
6369     static void
6370 f_indent(typval_T *argvars, typval_T *rettv)
6371 {
6372     linenr_T	lnum;
6373 
6374     lnum = get_tv_lnum(argvars);
6375     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6376 	rettv->vval.v_number = get_indent_lnum(lnum);
6377     else
6378 	rettv->vval.v_number = -1;
6379 }
6380 
6381 /*
6382  * "index()" function
6383  */
6384     static void
6385 f_index(typval_T *argvars, typval_T *rettv)
6386 {
6387     list_T	*l;
6388     listitem_T	*item;
6389     long	idx = 0;
6390     int		ic = FALSE;
6391 
6392     rettv->vval.v_number = -1;
6393     if (argvars[0].v_type != VAR_LIST)
6394     {
6395 	EMSG(_(e_listreq));
6396 	return;
6397     }
6398     l = argvars[0].vval.v_list;
6399     if (l != NULL)
6400     {
6401 	item = l->lv_first;
6402 	if (argvars[2].v_type != VAR_UNKNOWN)
6403 	{
6404 	    int		error = FALSE;
6405 
6406 	    /* Start at specified item.  Use the cached index that list_find()
6407 	     * sets, so that a negative number also works. */
6408 	    item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
6409 	    idx = l->lv_idx;
6410 	    if (argvars[3].v_type != VAR_UNKNOWN)
6411 		ic = (int)get_tv_number_chk(&argvars[3], &error);
6412 	    if (error)
6413 		item = NULL;
6414 	}
6415 
6416 	for ( ; item != NULL; item = item->li_next, ++idx)
6417 	    if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6418 	    {
6419 		rettv->vval.v_number = idx;
6420 		break;
6421 	    }
6422     }
6423 }
6424 
6425 static int inputsecret_flag = 0;
6426 
6427 /*
6428  * "input()" function
6429  *     Also handles inputsecret() when inputsecret is set.
6430  */
6431     static void
6432 f_input(typval_T *argvars, typval_T *rettv)
6433 {
6434     get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6435 }
6436 
6437 /*
6438  * "inputdialog()" function
6439  */
6440     static void
6441 f_inputdialog(typval_T *argvars, typval_T *rettv)
6442 {
6443 #if defined(FEAT_GUI_TEXTDIALOG)
6444     /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6445     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6446     {
6447 	char_u	*message;
6448 	char_u	buf[NUMBUFLEN];
6449 	char_u	*defstr = (char_u *)"";
6450 
6451 	message = get_tv_string_chk(&argvars[0]);
6452 	if (argvars[1].v_type != VAR_UNKNOWN
6453 		&& (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
6454 	    vim_strncpy(IObuff, defstr, IOSIZE - 1);
6455 	else
6456 	    IObuff[0] = NUL;
6457 	if (message != NULL && defstr != NULL
6458 		&& do_dialog(VIM_QUESTION, NULL, message,
6459 			  (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6460 	    rettv->vval.v_string = vim_strsave(IObuff);
6461 	else
6462 	{
6463 	    if (message != NULL && defstr != NULL
6464 					&& argvars[1].v_type != VAR_UNKNOWN
6465 					&& argvars[2].v_type != VAR_UNKNOWN)
6466 		rettv->vval.v_string = vim_strsave(
6467 				      get_tv_string_buf(&argvars[2], buf));
6468 	    else
6469 		rettv->vval.v_string = NULL;
6470 	}
6471 	rettv->v_type = VAR_STRING;
6472     }
6473     else
6474 #endif
6475 	get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6476 }
6477 
6478 /*
6479  * "inputlist()" function
6480  */
6481     static void
6482 f_inputlist(typval_T *argvars, typval_T *rettv)
6483 {
6484     listitem_T	*li;
6485     int		selected;
6486     int		mouse_used;
6487 
6488 #ifdef NO_CONSOLE_INPUT
6489     /* While starting up, there is no place to enter text. When running tests
6490      * with --not-a-term we assume feedkeys() will be used. */
6491     if (no_console_input() && !is_not_a_term())
6492 	return;
6493 #endif
6494     if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6495     {
6496 	EMSG2(_(e_listarg), "inputlist()");
6497 	return;
6498     }
6499 
6500     msg_start();
6501     msg_row = Rows - 1;	/* for when 'cmdheight' > 1 */
6502     lines_left = Rows;	/* avoid more prompt */
6503     msg_scroll = TRUE;
6504     msg_clr_eos();
6505 
6506     for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6507     {
6508 	msg_puts(get_tv_string(&li->li_tv));
6509 	msg_putchar('\n');
6510     }
6511 
6512     /* Ask for choice. */
6513     selected = prompt_for_number(&mouse_used);
6514     if (mouse_used)
6515 	selected -= lines_left;
6516 
6517     rettv->vval.v_number = selected;
6518 }
6519 
6520 
6521 static garray_T	    ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6522 
6523 /*
6524  * "inputrestore()" function
6525  */
6526     static void
6527 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6528 {
6529     if (ga_userinput.ga_len > 0)
6530     {
6531 	--ga_userinput.ga_len;
6532 	restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6533 						       + ga_userinput.ga_len);
6534 	/* default return is zero == OK */
6535     }
6536     else if (p_verbose > 1)
6537     {
6538 	verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6539 	rettv->vval.v_number = 1; /* Failed */
6540     }
6541 }
6542 
6543 /*
6544  * "inputsave()" function
6545  */
6546     static void
6547 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6548 {
6549     /* Add an entry to the stack of typeahead storage. */
6550     if (ga_grow(&ga_userinput, 1) == OK)
6551     {
6552 	save_typeahead((tasave_T *)(ga_userinput.ga_data)
6553 						       + ga_userinput.ga_len);
6554 	++ga_userinput.ga_len;
6555 	/* default return is zero == OK */
6556     }
6557     else
6558 	rettv->vval.v_number = 1; /* Failed */
6559 }
6560 
6561 /*
6562  * "inputsecret()" function
6563  */
6564     static void
6565 f_inputsecret(typval_T *argvars, typval_T *rettv)
6566 {
6567     ++cmdline_star;
6568     ++inputsecret_flag;
6569     f_input(argvars, rettv);
6570     --cmdline_star;
6571     --inputsecret_flag;
6572 }
6573 
6574 /*
6575  * "insert()" function
6576  */
6577     static void
6578 f_insert(typval_T *argvars, typval_T *rettv)
6579 {
6580     long	before = 0;
6581     listitem_T	*item;
6582     list_T	*l;
6583     int		error = FALSE;
6584 
6585     if (argvars[0].v_type != VAR_LIST)
6586 	EMSG2(_(e_listarg), "insert()");
6587     else if ((l = argvars[0].vval.v_list) != NULL
6588 	    && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6589     {
6590 	if (argvars[2].v_type != VAR_UNKNOWN)
6591 	    before = (long)get_tv_number_chk(&argvars[2], &error);
6592 	if (error)
6593 	    return;		/* type error; errmsg already given */
6594 
6595 	if (before == l->lv_len)
6596 	    item = NULL;
6597 	else
6598 	{
6599 	    item = list_find(l, before);
6600 	    if (item == NULL)
6601 	    {
6602 		EMSGN(_(e_listidx), before);
6603 		l = NULL;
6604 	    }
6605 	}
6606 	if (l != NULL)
6607 	{
6608 	    list_insert_tv(l, &argvars[1], item);
6609 	    copy_tv(&argvars[0], rettv);
6610 	}
6611     }
6612 }
6613 
6614 /*
6615  * "invert(expr)" function
6616  */
6617     static void
6618 f_invert(typval_T *argvars, typval_T *rettv)
6619 {
6620     rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6621 }
6622 
6623 /*
6624  * "isdirectory()" function
6625  */
6626     static void
6627 f_isdirectory(typval_T *argvars, typval_T *rettv)
6628 {
6629     rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6630 }
6631 
6632 /*
6633  * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6634  * or it refers to a List or Dictionary that is locked.
6635  */
6636     static int
6637 tv_islocked(typval_T *tv)
6638 {
6639     return (tv->v_lock & VAR_LOCKED)
6640 	|| (tv->v_type == VAR_LIST
6641 		&& tv->vval.v_list != NULL
6642 		&& (tv->vval.v_list->lv_lock & VAR_LOCKED))
6643 	|| (tv->v_type == VAR_DICT
6644 		&& tv->vval.v_dict != NULL
6645 		&& (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6646 }
6647 
6648 /*
6649  * "islocked()" function
6650  */
6651     static void
6652 f_islocked(typval_T *argvars, typval_T *rettv)
6653 {
6654     lval_T	lv;
6655     char_u	*end;
6656     dictitem_T	*di;
6657 
6658     rettv->vval.v_number = -1;
6659     end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6660 			     GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
6661     if (end != NULL && lv.ll_name != NULL)
6662     {
6663 	if (*end != NUL)
6664 	    EMSG(_(e_trailing));
6665 	else
6666 	{
6667 	    if (lv.ll_tv == NULL)
6668 	    {
6669 		di = find_var(lv.ll_name, NULL, TRUE);
6670 		if (di != NULL)
6671 		{
6672 		    /* Consider a variable locked when:
6673 		     * 1. the variable itself is locked
6674 		     * 2. the value of the variable is locked.
6675 		     * 3. the List or Dict value is locked.
6676 		     */
6677 		    rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6678 						   || tv_islocked(&di->di_tv));
6679 		}
6680 	    }
6681 	    else if (lv.ll_range)
6682 		EMSG(_("E786: Range not allowed"));
6683 	    else if (lv.ll_newkey != NULL)
6684 		EMSG2(_(e_dictkey), lv.ll_newkey);
6685 	    else if (lv.ll_list != NULL)
6686 		/* List item. */
6687 		rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6688 	    else
6689 		/* Dictionary item. */
6690 		rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6691 	}
6692     }
6693 
6694     clear_lval(&lv);
6695 }
6696 
6697 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6698 /*
6699  * "isnan()" function
6700  */
6701     static void
6702 f_isnan(typval_T *argvars, typval_T *rettv)
6703 {
6704     rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6705 					    && isnan(argvars[0].vval.v_float);
6706 }
6707 #endif
6708 
6709 /*
6710  * "items(dict)" function
6711  */
6712     static void
6713 f_items(typval_T *argvars, typval_T *rettv)
6714 {
6715     dict_list(argvars, rettv, 2);
6716 }
6717 
6718 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6719 /*
6720  * Get the job from the argument.
6721  * Returns NULL if the job is invalid.
6722  */
6723     static job_T *
6724 get_job_arg(typval_T *tv)
6725 {
6726     job_T *job;
6727 
6728     if (tv->v_type != VAR_JOB)
6729     {
6730 	EMSG2(_(e_invarg2), get_tv_string(tv));
6731 	return NULL;
6732     }
6733     job = tv->vval.v_job;
6734 
6735     if (job == NULL)
6736 	EMSG(_("E916: not a valid job"));
6737     return job;
6738 }
6739 
6740 /*
6741  * "job_getchannel()" function
6742  */
6743     static void
6744 f_job_getchannel(typval_T *argvars, typval_T *rettv)
6745 {
6746     job_T	*job = get_job_arg(&argvars[0]);
6747 
6748     if (job != NULL)
6749     {
6750 	rettv->v_type = VAR_CHANNEL;
6751 	rettv->vval.v_channel = job->jv_channel;
6752 	if (job->jv_channel != NULL)
6753 	    ++job->jv_channel->ch_refcount;
6754     }
6755 }
6756 
6757 /*
6758  * "job_info()" function
6759  */
6760     static void
6761 f_job_info(typval_T *argvars, typval_T *rettv)
6762 {
6763     job_T	*job = get_job_arg(&argvars[0]);
6764 
6765     if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6766 	job_info(job, rettv->vval.v_dict);
6767 }
6768 
6769 /*
6770  * "job_setoptions()" function
6771  */
6772     static void
6773 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6774 {
6775     job_T	*job = get_job_arg(&argvars[0]);
6776     jobopt_T	opt;
6777 
6778     if (job == NULL)
6779 	return;
6780     clear_job_options(&opt);
6781     if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
6782 	job_set_options(job, &opt);
6783     free_job_options(&opt);
6784 }
6785 
6786 /*
6787  * "job_start()" function
6788  */
6789     static void
6790 f_job_start(typval_T *argvars, typval_T *rettv)
6791 {
6792     rettv->v_type = VAR_JOB;
6793     if (check_restricted() || check_secure())
6794 	return;
6795     rettv->vval.v_job = job_start(argvars, NULL);
6796 }
6797 
6798 /*
6799  * "job_status()" function
6800  */
6801     static void
6802 f_job_status(typval_T *argvars, typval_T *rettv)
6803 {
6804     job_T	*job = get_job_arg(&argvars[0]);
6805 
6806     if (job != NULL)
6807     {
6808 	rettv->v_type = VAR_STRING;
6809 	rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6810     }
6811 }
6812 
6813 /*
6814  * "job_stop()" function
6815  */
6816     static void
6817 f_job_stop(typval_T *argvars, typval_T *rettv)
6818 {
6819     job_T	*job = get_job_arg(&argvars[0]);
6820 
6821     if (job != NULL)
6822 	rettv->vval.v_number = job_stop(job, argvars, NULL);
6823 }
6824 #endif
6825 
6826 /*
6827  * "join()" function
6828  */
6829     static void
6830 f_join(typval_T *argvars, typval_T *rettv)
6831 {
6832     garray_T	ga;
6833     char_u	*sep;
6834 
6835     if (argvars[0].v_type != VAR_LIST)
6836     {
6837 	EMSG(_(e_listreq));
6838 	return;
6839     }
6840     if (argvars[0].vval.v_list == NULL)
6841 	return;
6842     if (argvars[1].v_type == VAR_UNKNOWN)
6843 	sep = (char_u *)" ";
6844     else
6845 	sep = get_tv_string_chk(&argvars[1]);
6846 
6847     rettv->v_type = VAR_STRING;
6848 
6849     if (sep != NULL)
6850     {
6851 	ga_init2(&ga, (int)sizeof(char), 80);
6852 	list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6853 	ga_append(&ga, NUL);
6854 	rettv->vval.v_string = (char_u *)ga.ga_data;
6855     }
6856     else
6857 	rettv->vval.v_string = NULL;
6858 }
6859 
6860 /*
6861  * "js_decode()" function
6862  */
6863     static void
6864 f_js_decode(typval_T *argvars, typval_T *rettv)
6865 {
6866     js_read_T	reader;
6867 
6868     reader.js_buf = get_tv_string(&argvars[0]);
6869     reader.js_fill = NULL;
6870     reader.js_used = 0;
6871     if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6872 	EMSG(_(e_invarg));
6873 }
6874 
6875 /*
6876  * "js_encode()" function
6877  */
6878     static void
6879 f_js_encode(typval_T *argvars, typval_T *rettv)
6880 {
6881     rettv->v_type = VAR_STRING;
6882     rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6883 }
6884 
6885 /*
6886  * "json_decode()" function
6887  */
6888     static void
6889 f_json_decode(typval_T *argvars, typval_T *rettv)
6890 {
6891     js_read_T	reader;
6892 
6893     reader.js_buf = get_tv_string(&argvars[0]);
6894     reader.js_fill = NULL;
6895     reader.js_used = 0;
6896     json_decode_all(&reader, rettv, 0);
6897 }
6898 
6899 /*
6900  * "json_encode()" function
6901  */
6902     static void
6903 f_json_encode(typval_T *argvars, typval_T *rettv)
6904 {
6905     rettv->v_type = VAR_STRING;
6906     rettv->vval.v_string = json_encode(&argvars[0], 0);
6907 }
6908 
6909 /*
6910  * "keys()" function
6911  */
6912     static void
6913 f_keys(typval_T *argvars, typval_T *rettv)
6914 {
6915     dict_list(argvars, rettv, 0);
6916 }
6917 
6918 /*
6919  * "last_buffer_nr()" function.
6920  */
6921     static void
6922 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6923 {
6924     int		n = 0;
6925     buf_T	*buf;
6926 
6927     FOR_ALL_BUFFERS(buf)
6928 	if (n < buf->b_fnum)
6929 	    n = buf->b_fnum;
6930 
6931     rettv->vval.v_number = n;
6932 }
6933 
6934 /*
6935  * "len()" function
6936  */
6937     static void
6938 f_len(typval_T *argvars, typval_T *rettv)
6939 {
6940     switch (argvars[0].v_type)
6941     {
6942 	case VAR_STRING:
6943 	case VAR_NUMBER:
6944 	    rettv->vval.v_number = (varnumber_T)STRLEN(
6945 					       get_tv_string(&argvars[0]));
6946 	    break;
6947 	case VAR_LIST:
6948 	    rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6949 	    break;
6950 	case VAR_DICT:
6951 	    rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6952 	    break;
6953 	case VAR_UNKNOWN:
6954 	case VAR_SPECIAL:
6955 	case VAR_FLOAT:
6956 	case VAR_FUNC:
6957 	case VAR_PARTIAL:
6958 	case VAR_JOB:
6959 	case VAR_CHANNEL:
6960 	    EMSG(_("E701: Invalid type for len()"));
6961 	    break;
6962     }
6963 }
6964 
6965     static void
6966 libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
6967 {
6968 #ifdef FEAT_LIBCALL
6969     char_u		*string_in;
6970     char_u		**string_result;
6971     int			nr_result;
6972 #endif
6973 
6974     rettv->v_type = type;
6975     if (type != VAR_NUMBER)
6976 	rettv->vval.v_string = NULL;
6977 
6978     if (check_restricted() || check_secure())
6979 	return;
6980 
6981 #ifdef FEAT_LIBCALL
6982     /* The first two args must be strings, otherwise it's meaningless */
6983     if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6984     {
6985 	string_in = NULL;
6986 	if (argvars[2].v_type == VAR_STRING)
6987 	    string_in = argvars[2].vval.v_string;
6988 	if (type == VAR_NUMBER)
6989 	    string_result = NULL;
6990 	else
6991 	    string_result = &rettv->vval.v_string;
6992 	if (mch_libcall(argvars[0].vval.v_string,
6993 			     argvars[1].vval.v_string,
6994 			     string_in,
6995 			     argvars[2].vval.v_number,
6996 			     string_result,
6997 			     &nr_result) == OK
6998 		&& type == VAR_NUMBER)
6999 	    rettv->vval.v_number = nr_result;
7000     }
7001 #endif
7002 }
7003 
7004 /*
7005  * "libcall()" function
7006  */
7007     static void
7008 f_libcall(typval_T *argvars, typval_T *rettv)
7009 {
7010     libcall_common(argvars, rettv, VAR_STRING);
7011 }
7012 
7013 /*
7014  * "libcallnr()" function
7015  */
7016     static void
7017 f_libcallnr(typval_T *argvars, typval_T *rettv)
7018 {
7019     libcall_common(argvars, rettv, VAR_NUMBER);
7020 }
7021 
7022 /*
7023  * "line(string)" function
7024  */
7025     static void
7026 f_line(typval_T *argvars, typval_T *rettv)
7027 {
7028     linenr_T	lnum = 0;
7029     pos_T	*fp;
7030     int		fnum;
7031 
7032     fp = var2fpos(&argvars[0], TRUE, &fnum);
7033     if (fp != NULL)
7034 	lnum = fp->lnum;
7035     rettv->vval.v_number = lnum;
7036 }
7037 
7038 /*
7039  * "line2byte(lnum)" function
7040  */
7041     static void
7042 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7043 {
7044 #ifndef FEAT_BYTEOFF
7045     rettv->vval.v_number = -1;
7046 #else
7047     linenr_T	lnum;
7048 
7049     lnum = get_tv_lnum(argvars);
7050     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7051 	rettv->vval.v_number = -1;
7052     else
7053 	rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7054     if (rettv->vval.v_number >= 0)
7055 	++rettv->vval.v_number;
7056 #endif
7057 }
7058 
7059 /*
7060  * "lispindent(lnum)" function
7061  */
7062     static void
7063 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7064 {
7065 #ifdef FEAT_LISP
7066     pos_T	pos;
7067     linenr_T	lnum;
7068 
7069     pos = curwin->w_cursor;
7070     lnum = get_tv_lnum(argvars);
7071     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7072     {
7073 	curwin->w_cursor.lnum = lnum;
7074 	rettv->vval.v_number = get_lisp_indent();
7075 	curwin->w_cursor = pos;
7076     }
7077     else
7078 #endif
7079 	rettv->vval.v_number = -1;
7080 }
7081 
7082 /*
7083  * "localtime()" function
7084  */
7085     static void
7086 f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7087 {
7088     rettv->vval.v_number = (varnumber_T)time(NULL);
7089 }
7090 
7091 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
7092 
7093     static void
7094 get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7095 {
7096     char_u	*keys;
7097     char_u	*which;
7098     char_u	buf[NUMBUFLEN];
7099     char_u	*keys_buf = NULL;
7100     char_u	*rhs;
7101     int		mode;
7102     int		abbr = FALSE;
7103     int		get_dict = FALSE;
7104     mapblock_T	*mp;
7105     int		buffer_local;
7106 
7107     /* return empty string for failure */
7108     rettv->v_type = VAR_STRING;
7109     rettv->vval.v_string = NULL;
7110 
7111     keys = get_tv_string(&argvars[0]);
7112     if (*keys == NUL)
7113 	return;
7114 
7115     if (argvars[1].v_type != VAR_UNKNOWN)
7116     {
7117 	which = get_tv_string_buf_chk(&argvars[1], buf);
7118 	if (argvars[2].v_type != VAR_UNKNOWN)
7119 	{
7120 	    abbr = (int)get_tv_number(&argvars[2]);
7121 	    if (argvars[3].v_type != VAR_UNKNOWN)
7122 		get_dict = (int)get_tv_number(&argvars[3]);
7123 	}
7124     }
7125     else
7126 	which = (char_u *)"";
7127     if (which == NULL)
7128 	return;
7129 
7130     mode = get_map_mode(&which, 0);
7131 
7132     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7133     rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7134     vim_free(keys_buf);
7135 
7136     if (!get_dict)
7137     {
7138 	/* Return a string. */
7139 	if (rhs != NULL)
7140 	    rettv->vval.v_string = str2special_save(rhs, FALSE);
7141 
7142     }
7143     else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7144     {
7145 	/* Return a dictionary. */
7146 	char_u	    *lhs = str2special_save(mp->m_keys, TRUE);
7147 	char_u	    *mapmode = map_mode_to_chars(mp->m_mode);
7148 	dict_T	    *dict = rettv->vval.v_dict;
7149 
7150 	dict_add_nr_str(dict, "lhs",	 0L, lhs);
7151 	dict_add_nr_str(dict, "rhs",     0L, mp->m_orig_str);
7152 	dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
7153 	dict_add_nr_str(dict, "expr",    mp->m_expr    ? 1L : 0L, NULL);
7154 	dict_add_nr_str(dict, "silent",  mp->m_silent  ? 1L : 0L, NULL);
7155 	dict_add_nr_str(dict, "sid",     (long)mp->m_script_ID, NULL);
7156 	dict_add_nr_str(dict, "buffer",  (long)buffer_local, NULL);
7157 	dict_add_nr_str(dict, "nowait",  mp->m_nowait  ? 1L : 0L, NULL);
7158 	dict_add_nr_str(dict, "mode",    0L, mapmode);
7159 
7160 	vim_free(lhs);
7161 	vim_free(mapmode);
7162     }
7163 }
7164 
7165 #ifdef FEAT_FLOAT
7166 /*
7167  * "log()" function
7168  */
7169     static void
7170 f_log(typval_T *argvars, typval_T *rettv)
7171 {
7172     float_T	f = 0.0;
7173 
7174     rettv->v_type = VAR_FLOAT;
7175     if (get_float_arg(argvars, &f) == OK)
7176 	rettv->vval.v_float = log(f);
7177     else
7178 	rettv->vval.v_float = 0.0;
7179 }
7180 
7181 /*
7182  * "log10()" function
7183  */
7184     static void
7185 f_log10(typval_T *argvars, typval_T *rettv)
7186 {
7187     float_T	f = 0.0;
7188 
7189     rettv->v_type = VAR_FLOAT;
7190     if (get_float_arg(argvars, &f) == OK)
7191 	rettv->vval.v_float = log10(f);
7192     else
7193 	rettv->vval.v_float = 0.0;
7194 }
7195 #endif
7196 
7197 #ifdef FEAT_LUA
7198 /*
7199  * "luaeval()" function
7200  */
7201     static void
7202 f_luaeval(typval_T *argvars, typval_T *rettv)
7203 {
7204     char_u	*str;
7205     char_u	buf[NUMBUFLEN];
7206 
7207     str = get_tv_string_buf(&argvars[0], buf);
7208     do_luaeval(str, argvars + 1, rettv);
7209 }
7210 #endif
7211 
7212 /*
7213  * "map()" function
7214  */
7215     static void
7216 f_map(typval_T *argvars, typval_T *rettv)
7217 {
7218     filter_map(argvars, rettv, TRUE);
7219 }
7220 
7221 /*
7222  * "maparg()" function
7223  */
7224     static void
7225 f_maparg(typval_T *argvars, typval_T *rettv)
7226 {
7227     get_maparg(argvars, rettv, TRUE);
7228 }
7229 
7230 /*
7231  * "mapcheck()" function
7232  */
7233     static void
7234 f_mapcheck(typval_T *argvars, typval_T *rettv)
7235 {
7236     get_maparg(argvars, rettv, FALSE);
7237 }
7238 
7239 static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
7240 
7241     static void
7242 find_some_match(typval_T *argvars, typval_T *rettv, int type)
7243 {
7244     char_u	*str = NULL;
7245     long	len = 0;
7246     char_u	*expr = NULL;
7247     char_u	*pat;
7248     regmatch_T	regmatch;
7249     char_u	patbuf[NUMBUFLEN];
7250     char_u	strbuf[NUMBUFLEN];
7251     char_u	*save_cpo;
7252     long	start = 0;
7253     long	nth = 1;
7254     colnr_T	startcol = 0;
7255     int		match = 0;
7256     list_T	*l = NULL;
7257     listitem_T	*li = NULL;
7258     long	idx = 0;
7259     char_u	*tofree = NULL;
7260 
7261     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7262     save_cpo = p_cpo;
7263     p_cpo = (char_u *)"";
7264 
7265     rettv->vval.v_number = -1;
7266     if (type == 3 || type == 4)
7267     {
7268 	/* type 3: return empty list when there are no matches.
7269 	 * type 4: return ["", -1, -1, -1] */
7270 	if (rettv_list_alloc(rettv) == FAIL)
7271 	    goto theend;
7272 	if (type == 4
7273 		&& (list_append_string(rettv->vval.v_list,
7274 					    (char_u *)"", 0) == FAIL
7275 		    || list_append_number(rettv->vval.v_list,
7276 					    (varnumber_T)-1) == FAIL
7277 		    || list_append_number(rettv->vval.v_list,
7278 					    (varnumber_T)-1) == FAIL
7279 		    || list_append_number(rettv->vval.v_list,
7280 					    (varnumber_T)-1) == FAIL))
7281 	{
7282 		list_free(rettv->vval.v_list);
7283 		rettv->vval.v_list = NULL;
7284 		goto theend;
7285 	}
7286     }
7287     else if (type == 2)
7288     {
7289 	rettv->v_type = VAR_STRING;
7290 	rettv->vval.v_string = NULL;
7291     }
7292 
7293     if (argvars[0].v_type == VAR_LIST)
7294     {
7295 	if ((l = argvars[0].vval.v_list) == NULL)
7296 	    goto theend;
7297 	li = l->lv_first;
7298     }
7299     else
7300     {
7301 	expr = str = get_tv_string(&argvars[0]);
7302 	len = (long)STRLEN(str);
7303     }
7304 
7305     pat = get_tv_string_buf_chk(&argvars[1], patbuf);
7306     if (pat == NULL)
7307 	goto theend;
7308 
7309     if (argvars[2].v_type != VAR_UNKNOWN)
7310     {
7311 	int	    error = FALSE;
7312 
7313 	start = (long)get_tv_number_chk(&argvars[2], &error);
7314 	if (error)
7315 	    goto theend;
7316 	if (l != NULL)
7317 	{
7318 	    li = list_find(l, start);
7319 	    if (li == NULL)
7320 		goto theend;
7321 	    idx = l->lv_idx;	/* use the cached index */
7322 	}
7323 	else
7324 	{
7325 	    if (start < 0)
7326 		start = 0;
7327 	    if (start > len)
7328 		goto theend;
7329 	    /* When "count" argument is there ignore matches before "start",
7330 	     * otherwise skip part of the string.  Differs when pattern is "^"
7331 	     * or "\<". */
7332 	    if (argvars[3].v_type != VAR_UNKNOWN)
7333 		startcol = start;
7334 	    else
7335 	    {
7336 		str += start;
7337 		len -= start;
7338 	    }
7339 	}
7340 
7341 	if (argvars[3].v_type != VAR_UNKNOWN)
7342 	    nth = (long)get_tv_number_chk(&argvars[3], &error);
7343 	if (error)
7344 	    goto theend;
7345     }
7346 
7347     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7348     if (regmatch.regprog != NULL)
7349     {
7350 	regmatch.rm_ic = p_ic;
7351 
7352 	for (;;)
7353 	{
7354 	    if (l != NULL)
7355 	    {
7356 		if (li == NULL)
7357 		{
7358 		    match = FALSE;
7359 		    break;
7360 		}
7361 		vim_free(tofree);
7362 		expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7363 		if (str == NULL)
7364 		    break;
7365 	    }
7366 
7367 	    match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7368 
7369 	    if (match && --nth <= 0)
7370 		break;
7371 	    if (l == NULL && !match)
7372 		break;
7373 
7374 	    /* Advance to just after the match. */
7375 	    if (l != NULL)
7376 	    {
7377 		li = li->li_next;
7378 		++idx;
7379 	    }
7380 	    else
7381 	    {
7382 #ifdef FEAT_MBYTE
7383 		startcol = (colnr_T)(regmatch.startp[0]
7384 				    + (*mb_ptr2len)(regmatch.startp[0]) - str);
7385 #else
7386 		startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
7387 #endif
7388 		if (startcol > (colnr_T)len
7389 				      || str + startcol <= regmatch.startp[0])
7390 		{
7391 		    match = FALSE;
7392 		    break;
7393 		}
7394 	    }
7395 	}
7396 
7397 	if (match)
7398 	{
7399 	    if (type == 4)
7400 	    {
7401 		listitem_T *li1 = rettv->vval.v_list->lv_first;
7402 		listitem_T *li2 = li1->li_next;
7403 		listitem_T *li3 = li2->li_next;
7404 		listitem_T *li4 = li3->li_next;
7405 
7406 		vim_free(li1->li_tv.vval.v_string);
7407 		li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7408 				(int)(regmatch.endp[0] - regmatch.startp[0]));
7409 		li3->li_tv.vval.v_number =
7410 				      (varnumber_T)(regmatch.startp[0] - expr);
7411 		li4->li_tv.vval.v_number =
7412 					(varnumber_T)(regmatch.endp[0] - expr);
7413 		if (l != NULL)
7414 		    li2->li_tv.vval.v_number = (varnumber_T)idx;
7415 	    }
7416 	    else if (type == 3)
7417 	    {
7418 		int i;
7419 
7420 		/* return list with matched string and submatches */
7421 		for (i = 0; i < NSUBEXP; ++i)
7422 		{
7423 		    if (regmatch.endp[i] == NULL)
7424 		    {
7425 			if (list_append_string(rettv->vval.v_list,
7426 						     (char_u *)"", 0) == FAIL)
7427 			    break;
7428 		    }
7429 		    else if (list_append_string(rettv->vval.v_list,
7430 				regmatch.startp[i],
7431 				(int)(regmatch.endp[i] - regmatch.startp[i]))
7432 			    == FAIL)
7433 			break;
7434 		}
7435 	    }
7436 	    else if (type == 2)
7437 	    {
7438 		/* return matched string */
7439 		if (l != NULL)
7440 		    copy_tv(&li->li_tv, rettv);
7441 		else
7442 		    rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7443 				(int)(regmatch.endp[0] - regmatch.startp[0]));
7444 	    }
7445 	    else if (l != NULL)
7446 		rettv->vval.v_number = idx;
7447 	    else
7448 	    {
7449 		if (type != 0)
7450 		    rettv->vval.v_number =
7451 				      (varnumber_T)(regmatch.startp[0] - str);
7452 		else
7453 		    rettv->vval.v_number =
7454 					(varnumber_T)(regmatch.endp[0] - str);
7455 		rettv->vval.v_number += (varnumber_T)(str - expr);
7456 	    }
7457 	}
7458 	vim_regfree(regmatch.regprog);
7459     }
7460 
7461     if (type == 4 && l == NULL)
7462 	/* matchstrpos() without a list: drop the second item. */
7463 	listitem_remove(rettv->vval.v_list,
7464 				       rettv->vval.v_list->lv_first->li_next);
7465 
7466 theend:
7467     vim_free(tofree);
7468     p_cpo = save_cpo;
7469 }
7470 
7471 /*
7472  * "match()" function
7473  */
7474     static void
7475 f_match(typval_T *argvars, typval_T *rettv)
7476 {
7477     find_some_match(argvars, rettv, 1);
7478 }
7479 
7480 /*
7481  * "matchadd()" function
7482  */
7483     static void
7484 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7485 {
7486 #ifdef FEAT_SEARCH_EXTRA
7487     char_u	buf[NUMBUFLEN];
7488     char_u	*grp = get_tv_string_buf_chk(&argvars[0], buf);	/* group */
7489     char_u	*pat = get_tv_string_buf_chk(&argvars[1], buf);	/* pattern */
7490     int		prio = 10;	/* default priority */
7491     int		id = -1;
7492     int		error = FALSE;
7493     char_u	*conceal_char = NULL;
7494 
7495     rettv->vval.v_number = -1;
7496 
7497     if (grp == NULL || pat == NULL)
7498 	return;
7499     if (argvars[2].v_type != VAR_UNKNOWN)
7500     {
7501 	prio = (int)get_tv_number_chk(&argvars[2], &error);
7502 	if (argvars[3].v_type != VAR_UNKNOWN)
7503 	{
7504 	    id = (int)get_tv_number_chk(&argvars[3], &error);
7505 	    if (argvars[4].v_type != VAR_UNKNOWN)
7506 	    {
7507 		if (argvars[4].v_type != VAR_DICT)
7508 		{
7509 		    EMSG(_(e_dictreq));
7510 		    return;
7511 		}
7512 		if (dict_find(argvars[4].vval.v_dict,
7513 					     (char_u *)"conceal", -1) != NULL)
7514 		    conceal_char = get_dict_string(argvars[4].vval.v_dict,
7515 						  (char_u *)"conceal", FALSE);
7516 	    }
7517 	}
7518     }
7519     if (error == TRUE)
7520 	return;
7521     if (id >= 1 && id <= 3)
7522     {
7523 	EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
7524 	return;
7525     }
7526 
7527     rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7528 								conceal_char);
7529 #endif
7530 }
7531 
7532 /*
7533  * "matchaddpos()" function
7534  */
7535     static void
7536 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7537 {
7538 #ifdef FEAT_SEARCH_EXTRA
7539     char_u	buf[NUMBUFLEN];
7540     char_u	*group;
7541     int		prio = 10;
7542     int		id = -1;
7543     int		error = FALSE;
7544     list_T	*l;
7545     char_u	*conceal_char = NULL;
7546 
7547     rettv->vval.v_number = -1;
7548 
7549     group = get_tv_string_buf_chk(&argvars[0], buf);
7550     if (group == NULL)
7551 	return;
7552 
7553     if (argvars[1].v_type != VAR_LIST)
7554     {
7555 	EMSG2(_(e_listarg), "matchaddpos()");
7556 	return;
7557     }
7558     l = argvars[1].vval.v_list;
7559     if (l == NULL)
7560 	return;
7561 
7562     if (argvars[2].v_type != VAR_UNKNOWN)
7563     {
7564 	prio = (int)get_tv_number_chk(&argvars[2], &error);
7565 	if (argvars[3].v_type != VAR_UNKNOWN)
7566 	{
7567 	    id = (int)get_tv_number_chk(&argvars[3], &error);
7568 	    if (argvars[4].v_type != VAR_UNKNOWN)
7569 	    {
7570 		if (argvars[4].v_type != VAR_DICT)
7571 		{
7572 		    EMSG(_(e_dictreq));
7573 		    return;
7574 		}
7575 		if (dict_find(argvars[4].vval.v_dict,
7576 					     (char_u *)"conceal", -1) != NULL)
7577 		    conceal_char = get_dict_string(argvars[4].vval.v_dict,
7578 						  (char_u *)"conceal", FALSE);
7579 	    }
7580 	}
7581     }
7582     if (error == TRUE)
7583 	return;
7584 
7585     /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7586     if (id == 1 || id == 2)
7587     {
7588 	EMSGN(_("E798: ID is reserved for \":match\": %ld"), id);
7589 	return;
7590     }
7591 
7592     rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7593 								conceal_char);
7594 #endif
7595 }
7596 
7597 /*
7598  * "matcharg()" function
7599  */
7600     static void
7601 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7602 {
7603     if (rettv_list_alloc(rettv) == OK)
7604     {
7605 #ifdef FEAT_SEARCH_EXTRA
7606 	int	    id = (int)get_tv_number(&argvars[0]);
7607 	matchitem_T *m;
7608 
7609 	if (id >= 1 && id <= 3)
7610 	{
7611 	    if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7612 	    {
7613 		list_append_string(rettv->vval.v_list,
7614 						syn_id2name(m->hlg_id), -1);
7615 		list_append_string(rettv->vval.v_list, m->pattern, -1);
7616 	    }
7617 	    else
7618 	    {
7619 		list_append_string(rettv->vval.v_list, NULL, -1);
7620 		list_append_string(rettv->vval.v_list, NULL, -1);
7621 	    }
7622 	}
7623 #endif
7624     }
7625 }
7626 
7627 /*
7628  * "matchdelete()" function
7629  */
7630     static void
7631 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7632 {
7633 #ifdef FEAT_SEARCH_EXTRA
7634     rettv->vval.v_number = match_delete(curwin,
7635 				       (int)get_tv_number(&argvars[0]), TRUE);
7636 #endif
7637 }
7638 
7639 /*
7640  * "matchend()" function
7641  */
7642     static void
7643 f_matchend(typval_T *argvars, typval_T *rettv)
7644 {
7645     find_some_match(argvars, rettv, 0);
7646 }
7647 
7648 /*
7649  * "matchlist()" function
7650  */
7651     static void
7652 f_matchlist(typval_T *argvars, typval_T *rettv)
7653 {
7654     find_some_match(argvars, rettv, 3);
7655 }
7656 
7657 /*
7658  * "matchstr()" function
7659  */
7660     static void
7661 f_matchstr(typval_T *argvars, typval_T *rettv)
7662 {
7663     find_some_match(argvars, rettv, 2);
7664 }
7665 
7666 /*
7667  * "matchstrpos()" function
7668  */
7669     static void
7670 f_matchstrpos(typval_T *argvars, typval_T *rettv)
7671 {
7672     find_some_match(argvars, rettv, 4);
7673 }
7674 
7675 static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7676 
7677     static void
7678 max_min(typval_T *argvars, typval_T *rettv, int domax)
7679 {
7680     varnumber_T	n = 0;
7681     varnumber_T	i;
7682     int		error = FALSE;
7683 
7684     if (argvars[0].v_type == VAR_LIST)
7685     {
7686 	list_T		*l;
7687 	listitem_T	*li;
7688 
7689 	l = argvars[0].vval.v_list;
7690 	if (l != NULL)
7691 	{
7692 	    li = l->lv_first;
7693 	    if (li != NULL)
7694 	    {
7695 		n = get_tv_number_chk(&li->li_tv, &error);
7696 		for (;;)
7697 		{
7698 		    li = li->li_next;
7699 		    if (li == NULL)
7700 			break;
7701 		    i = get_tv_number_chk(&li->li_tv, &error);
7702 		    if (domax ? i > n : i < n)
7703 			n = i;
7704 		}
7705 	    }
7706 	}
7707     }
7708     else if (argvars[0].v_type == VAR_DICT)
7709     {
7710 	dict_T		*d;
7711 	int		first = TRUE;
7712 	hashitem_T	*hi;
7713 	int		todo;
7714 
7715 	d = argvars[0].vval.v_dict;
7716 	if (d != NULL)
7717 	{
7718 	    todo = (int)d->dv_hashtab.ht_used;
7719 	    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7720 	    {
7721 		if (!HASHITEM_EMPTY(hi))
7722 		{
7723 		    --todo;
7724 		    i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7725 		    if (first)
7726 		    {
7727 			n = i;
7728 			first = FALSE;
7729 		    }
7730 		    else if (domax ? i > n : i < n)
7731 			n = i;
7732 		}
7733 	    }
7734 	}
7735     }
7736     else
7737 	EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
7738     rettv->vval.v_number = error ? 0 : n;
7739 }
7740 
7741 /*
7742  * "max()" function
7743  */
7744     static void
7745 f_max(typval_T *argvars, typval_T *rettv)
7746 {
7747     max_min(argvars, rettv, TRUE);
7748 }
7749 
7750 /*
7751  * "min()" function
7752  */
7753     static void
7754 f_min(typval_T *argvars, typval_T *rettv)
7755 {
7756     max_min(argvars, rettv, FALSE);
7757 }
7758 
7759 static int mkdir_recurse(char_u *dir, int prot);
7760 
7761 /*
7762  * Create the directory in which "dir" is located, and higher levels when
7763  * needed.
7764  * Return OK or FAIL.
7765  */
7766     static int
7767 mkdir_recurse(char_u *dir, int prot)
7768 {
7769     char_u	*p;
7770     char_u	*updir;
7771     int		r = FAIL;
7772 
7773     /* Get end of directory name in "dir".
7774      * We're done when it's "/" or "c:/". */
7775     p = gettail_sep(dir);
7776     if (p <= get_past_head(dir))
7777 	return OK;
7778 
7779     /* If the directory exists we're done.  Otherwise: create it.*/
7780     updir = vim_strnsave(dir, (int)(p - dir));
7781     if (updir == NULL)
7782 	return FAIL;
7783     if (mch_isdir(updir))
7784 	r = OK;
7785     else if (mkdir_recurse(updir, prot) == OK)
7786 	r = vim_mkdir_emsg(updir, prot);
7787     vim_free(updir);
7788     return r;
7789 }
7790 
7791 #ifdef vim_mkdir
7792 /*
7793  * "mkdir()" function
7794  */
7795     static void
7796 f_mkdir(typval_T *argvars, typval_T *rettv)
7797 {
7798     char_u	*dir;
7799     char_u	buf[NUMBUFLEN];
7800     int		prot = 0755;
7801 
7802     rettv->vval.v_number = FAIL;
7803     if (check_restricted() || check_secure())
7804 	return;
7805 
7806     dir = get_tv_string_buf(&argvars[0], buf);
7807     if (*dir == NUL)
7808 	rettv->vval.v_number = FAIL;
7809     else
7810     {
7811 	if (*gettail(dir) == NUL)
7812 	    /* remove trailing slashes */
7813 	    *gettail_sep(dir) = NUL;
7814 
7815 	if (argvars[1].v_type != VAR_UNKNOWN)
7816 	{
7817 	    if (argvars[2].v_type != VAR_UNKNOWN)
7818 		prot = (int)get_tv_number_chk(&argvars[2], NULL);
7819 	    if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7820 		mkdir_recurse(dir, prot);
7821 	}
7822 	rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7823     }
7824 }
7825 #endif
7826 
7827 /*
7828  * "mode()" function
7829  */
7830     static void
7831 f_mode(typval_T *argvars, typval_T *rettv)
7832 {
7833     char_u	buf[3];
7834 
7835     buf[1] = NUL;
7836     buf[2] = NUL;
7837 
7838     if (time_for_testing == 93784)
7839     {
7840 	/* Testing the two-character code. */
7841 	buf[0] = 'x';
7842 	buf[1] = '!';
7843     }
7844     else if (VIsual_active)
7845     {
7846 	if (VIsual_select)
7847 	    buf[0] = VIsual_mode + 's' - 'v';
7848 	else
7849 	    buf[0] = VIsual_mode;
7850     }
7851     else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7852 		|| State == CONFIRM)
7853     {
7854 	buf[0] = 'r';
7855 	if (State == ASKMORE)
7856 	    buf[1] = 'm';
7857 	else if (State == CONFIRM)
7858 	    buf[1] = '?';
7859     }
7860     else if (State == EXTERNCMD)
7861 	buf[0] = '!';
7862     else if (State & INSERT)
7863     {
7864 #ifdef FEAT_VREPLACE
7865 	if (State & VREPLACE_FLAG)
7866 	{
7867 	    buf[0] = 'R';
7868 	    buf[1] = 'v';
7869 	}
7870 	else
7871 #endif
7872 	{
7873 	    if (State & REPLACE_FLAG)
7874 		buf[0] = 'R';
7875 	    else
7876 		buf[0] = 'i';
7877 #ifdef FEAT_INS_EXPAND
7878 	    if (ins_compl_active())
7879 		buf[1] = 'c';
7880 	    else if (ctrl_x_mode == 1)
7881 		buf[1] = 'x';
7882 #endif
7883 	}
7884     }
7885     else if ((State & CMDLINE) || exmode_active)
7886     {
7887 	buf[0] = 'c';
7888 	if (exmode_active == EXMODE_VIM)
7889 	    buf[1] = 'v';
7890 	else if (exmode_active == EXMODE_NORMAL)
7891 	    buf[1] = 'e';
7892     }
7893     else
7894     {
7895 	buf[0] = 'n';
7896 	if (finish_op)
7897 	    buf[1] = 'o';
7898     }
7899 
7900     /* Clear out the minor mode when the argument is not a non-zero number or
7901      * non-empty string.  */
7902     if (!non_zero_arg(&argvars[0]))
7903 	buf[1] = NUL;
7904 
7905     rettv->vval.v_string = vim_strsave(buf);
7906     rettv->v_type = VAR_STRING;
7907 }
7908 
7909 #if defined(FEAT_MZSCHEME) || defined(PROTO)
7910 /*
7911  * "mzeval()" function
7912  */
7913     static void
7914 f_mzeval(typval_T *argvars, typval_T *rettv)
7915 {
7916     char_u	*str;
7917     char_u	buf[NUMBUFLEN];
7918 
7919     str = get_tv_string_buf(&argvars[0], buf);
7920     do_mzeval(str, rettv);
7921 }
7922 
7923     void
7924 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7925 {
7926     typval_T argvars[3];
7927 
7928     argvars[0].v_type = VAR_STRING;
7929     argvars[0].vval.v_string = name;
7930     copy_tv(args, &argvars[1]);
7931     argvars[2].v_type = VAR_UNKNOWN;
7932     f_call(argvars, rettv);
7933     clear_tv(&argvars[1]);
7934 }
7935 #endif
7936 
7937 /*
7938  * "nextnonblank()" function
7939  */
7940     static void
7941 f_nextnonblank(typval_T *argvars, typval_T *rettv)
7942 {
7943     linenr_T	lnum;
7944 
7945     for (lnum = get_tv_lnum(argvars); ; ++lnum)
7946     {
7947 	if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7948 	{
7949 	    lnum = 0;
7950 	    break;
7951 	}
7952 	if (*skipwhite(ml_get(lnum)) != NUL)
7953 	    break;
7954     }
7955     rettv->vval.v_number = lnum;
7956 }
7957 
7958 /*
7959  * "nr2char()" function
7960  */
7961     static void
7962 f_nr2char(typval_T *argvars, typval_T *rettv)
7963 {
7964     char_u	buf[NUMBUFLEN];
7965 
7966 #ifdef FEAT_MBYTE
7967     if (has_mbyte)
7968     {
7969 	int	utf8 = 0;
7970 
7971 	if (argvars[1].v_type != VAR_UNKNOWN)
7972 	    utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7973 	if (utf8)
7974 	    buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7975 	else
7976 	    buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7977     }
7978     else
7979 #endif
7980     {
7981 	buf[0] = (char_u)get_tv_number(&argvars[0]);
7982 	buf[1] = NUL;
7983     }
7984     rettv->v_type = VAR_STRING;
7985     rettv->vval.v_string = vim_strsave(buf);
7986 }
7987 
7988 /*
7989  * "or(expr, expr)" function
7990  */
7991     static void
7992 f_or(typval_T *argvars, typval_T *rettv)
7993 {
7994     rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7995 					| get_tv_number_chk(&argvars[1], NULL);
7996 }
7997 
7998 /*
7999  * "pathshorten()" function
8000  */
8001     static void
8002 f_pathshorten(typval_T *argvars, typval_T *rettv)
8003 {
8004     char_u	*p;
8005 
8006     rettv->v_type = VAR_STRING;
8007     p = get_tv_string_chk(&argvars[0]);
8008     if (p == NULL)
8009 	rettv->vval.v_string = NULL;
8010     else
8011     {
8012 	p = vim_strsave(p);
8013 	rettv->vval.v_string = p;
8014 	if (p != NULL)
8015 	    shorten_dir(p);
8016     }
8017 }
8018 
8019 #ifdef FEAT_PERL
8020 /*
8021  * "perleval()" function
8022  */
8023     static void
8024 f_perleval(typval_T *argvars, typval_T *rettv)
8025 {
8026     char_u	*str;
8027     char_u	buf[NUMBUFLEN];
8028 
8029     str = get_tv_string_buf(&argvars[0], buf);
8030     do_perleval(str, rettv);
8031 }
8032 #endif
8033 
8034 #ifdef FEAT_FLOAT
8035 /*
8036  * "pow()" function
8037  */
8038     static void
8039 f_pow(typval_T *argvars, typval_T *rettv)
8040 {
8041     float_T	fx = 0.0, fy = 0.0;
8042 
8043     rettv->v_type = VAR_FLOAT;
8044     if (get_float_arg(argvars, &fx) == OK
8045 				     && get_float_arg(&argvars[1], &fy) == OK)
8046 	rettv->vval.v_float = pow(fx, fy);
8047     else
8048 	rettv->vval.v_float = 0.0;
8049 }
8050 #endif
8051 
8052 /*
8053  * "prevnonblank()" function
8054  */
8055     static void
8056 f_prevnonblank(typval_T *argvars, typval_T *rettv)
8057 {
8058     linenr_T	lnum;
8059 
8060     lnum = get_tv_lnum(argvars);
8061     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8062 	lnum = 0;
8063     else
8064 	while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8065 	    --lnum;
8066     rettv->vval.v_number = lnum;
8067 }
8068 
8069 /* This dummy va_list is here because:
8070  * - passing a NULL pointer doesn't work when va_list isn't a pointer
8071  * - locally in the function results in a "used before set" warning
8072  * - using va_start() to initialize it gives "function with fixed args" error */
8073 static va_list	ap;
8074 
8075 /*
8076  * "printf()" function
8077  */
8078     static void
8079 f_printf(typval_T *argvars, typval_T *rettv)
8080 {
8081     char_u	buf[NUMBUFLEN];
8082     int		len;
8083     char_u	*s;
8084     int		saved_did_emsg = did_emsg;
8085     char	*fmt;
8086 
8087     rettv->v_type = VAR_STRING;
8088     rettv->vval.v_string = NULL;
8089 
8090     /* Get the required length, allocate the buffer and do it for real. */
8091     did_emsg = FALSE;
8092     fmt = (char *)get_tv_string_buf(&argvars[0], buf);
8093     len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
8094     if (!did_emsg)
8095     {
8096 	s = alloc(len + 1);
8097 	if (s != NULL)
8098 	{
8099 	    rettv->vval.v_string = s;
8100 	    (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8101 							      ap, argvars + 1);
8102 	}
8103     }
8104     did_emsg |= saved_did_emsg;
8105 }
8106 
8107 /*
8108  * "pumvisible()" function
8109  */
8110     static void
8111 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8112 {
8113 #ifdef FEAT_INS_EXPAND
8114     if (pum_visible())
8115 	rettv->vval.v_number = 1;
8116 #endif
8117 }
8118 
8119 #ifdef FEAT_PYTHON3
8120 /*
8121  * "py3eval()" function
8122  */
8123     static void
8124 f_py3eval(typval_T *argvars, typval_T *rettv)
8125 {
8126     char_u	*str;
8127     char_u	buf[NUMBUFLEN];
8128 
8129     if (p_pyx == 0)
8130 	p_pyx = 3;
8131 
8132     str = get_tv_string_buf(&argvars[0], buf);
8133     do_py3eval(str, rettv);
8134 }
8135 #endif
8136 
8137 #ifdef FEAT_PYTHON
8138 /*
8139  * "pyeval()" function
8140  */
8141     static void
8142 f_pyeval(typval_T *argvars, typval_T *rettv)
8143 {
8144     char_u	*str;
8145     char_u	buf[NUMBUFLEN];
8146 
8147     if (p_pyx == 0)
8148 	p_pyx = 2;
8149 
8150     str = get_tv_string_buf(&argvars[0], buf);
8151     do_pyeval(str, rettv);
8152 }
8153 #endif
8154 
8155 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8156 /*
8157  * "pyxeval()" function
8158  */
8159     static void
8160 f_pyxeval(typval_T *argvars, typval_T *rettv)
8161 {
8162 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8163     init_pyxversion();
8164     if (p_pyx == 2)
8165 	f_pyeval(argvars, rettv);
8166     else
8167 	f_py3eval(argvars, rettv);
8168 # elif defined(FEAT_PYTHON)
8169     f_pyeval(argvars, rettv);
8170 # elif defined(FEAT_PYTHON3)
8171     f_py3eval(argvars, rettv);
8172 # endif
8173 }
8174 #endif
8175 
8176 /*
8177  * "range()" function
8178  */
8179     static void
8180 f_range(typval_T *argvars, typval_T *rettv)
8181 {
8182     varnumber_T	start;
8183     varnumber_T	end;
8184     varnumber_T	stride = 1;
8185     varnumber_T	i;
8186     int		error = FALSE;
8187 
8188     start = get_tv_number_chk(&argvars[0], &error);
8189     if (argvars[1].v_type == VAR_UNKNOWN)
8190     {
8191 	end = start - 1;
8192 	start = 0;
8193     }
8194     else
8195     {
8196 	end = get_tv_number_chk(&argvars[1], &error);
8197 	if (argvars[2].v_type != VAR_UNKNOWN)
8198 	    stride = get_tv_number_chk(&argvars[2], &error);
8199     }
8200 
8201     if (error)
8202 	return;		/* type error; errmsg already given */
8203     if (stride == 0)
8204 	EMSG(_("E726: Stride is zero"));
8205     else if (stride > 0 ? end + 1 < start : end - 1 > start)
8206 	EMSG(_("E727: Start past end"));
8207     else
8208     {
8209 	if (rettv_list_alloc(rettv) == OK)
8210 	    for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8211 		if (list_append_number(rettv->vval.v_list,
8212 						      (varnumber_T)i) == FAIL)
8213 		    break;
8214     }
8215 }
8216 
8217 /*
8218  * "readfile()" function
8219  */
8220     static void
8221 f_readfile(typval_T *argvars, typval_T *rettv)
8222 {
8223     int		binary = FALSE;
8224     int		failed = FALSE;
8225     char_u	*fname;
8226     FILE	*fd;
8227     char_u	buf[(IOSIZE/256)*256];	/* rounded to avoid odd + 1 */
8228     int		io_size = sizeof(buf);
8229     int		readlen;		/* size of last fread() */
8230     char_u	*prev	 = NULL;	/* previously read bytes, if any */
8231     long	prevlen  = 0;		/* length of data in prev */
8232     long	prevsize = 0;		/* size of prev buffer */
8233     long	maxline  = MAXLNUM;
8234     long	cnt	 = 0;
8235     char_u	*p;			/* position in buf */
8236     char_u	*start;			/* start of current line */
8237 
8238     if (argvars[1].v_type != VAR_UNKNOWN)
8239     {
8240 	if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
8241 	    binary = TRUE;
8242 	if (argvars[2].v_type != VAR_UNKNOWN)
8243 	    maxline = (long)get_tv_number(&argvars[2]);
8244     }
8245 
8246     if (rettv_list_alloc(rettv) == FAIL)
8247 	return;
8248 
8249     /* Always open the file in binary mode, library functions have a mind of
8250      * their own about CR-LF conversion. */
8251     fname = get_tv_string(&argvars[0]);
8252     if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8253     {
8254 	EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
8255 	return;
8256     }
8257 
8258     while (cnt < maxline || maxline < 0)
8259     {
8260 	readlen = (int)fread(buf, 1, io_size, fd);
8261 
8262 	/* This for loop processes what was read, but is also entered at end
8263 	 * of file so that either:
8264 	 * - an incomplete line gets written
8265 	 * - a "binary" file gets an empty line at the end if it ends in a
8266 	 *   newline.  */
8267 	for (p = buf, start = buf;
8268 		p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8269 		++p)
8270 	{
8271 	    if (*p == '\n' || readlen <= 0)
8272 	    {
8273 		listitem_T  *li;
8274 		char_u	    *s	= NULL;
8275 		long_u	    len = p - start;
8276 
8277 		/* Finished a line.  Remove CRs before NL. */
8278 		if (readlen > 0 && !binary)
8279 		{
8280 		    while (len > 0 && start[len - 1] == '\r')
8281 			--len;
8282 		    /* removal may cross back to the "prev" string */
8283 		    if (len == 0)
8284 			while (prevlen > 0 && prev[prevlen - 1] == '\r')
8285 			    --prevlen;
8286 		}
8287 		if (prevlen == 0)
8288 		    s = vim_strnsave(start, (int)len);
8289 		else
8290 		{
8291 		    /* Change "prev" buffer to be the right size.  This way
8292 		     * the bytes are only copied once, and very long lines are
8293 		     * allocated only once.  */
8294 		    if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8295 		    {
8296 			mch_memmove(s + prevlen, start, len);
8297 			s[prevlen + len] = NUL;
8298 			prev = NULL; /* the list will own the string */
8299 			prevlen = prevsize = 0;
8300 		    }
8301 		}
8302 		if (s == NULL)
8303 		{
8304 		    do_outofmem_msg((long_u) prevlen + len + 1);
8305 		    failed = TRUE;
8306 		    break;
8307 		}
8308 
8309 		if ((li = listitem_alloc()) == NULL)
8310 		{
8311 		    vim_free(s);
8312 		    failed = TRUE;
8313 		    break;
8314 		}
8315 		li->li_tv.v_type = VAR_STRING;
8316 		li->li_tv.v_lock = 0;
8317 		li->li_tv.vval.v_string = s;
8318 		list_append(rettv->vval.v_list, li);
8319 
8320 		start = p + 1; /* step over newline */
8321 		if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8322 		    break;
8323 	    }
8324 	    else if (*p == NUL)
8325 		*p = '\n';
8326 #ifdef FEAT_MBYTE
8327 	    /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF.  Do this
8328 	     * when finding the BF and check the previous two bytes. */
8329 	    else if (*p == 0xbf && enc_utf8 && !binary)
8330 	    {
8331 		/* Find the two bytes before the 0xbf.	If p is at buf, or buf
8332 		 * + 1, these may be in the "prev" string. */
8333 		char_u back1 = p >= buf + 1 ? p[-1]
8334 				     : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8335 		char_u back2 = p >= buf + 2 ? p[-2]
8336 			  : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8337 			  : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8338 
8339 		if (back2 == 0xef && back1 == 0xbb)
8340 		{
8341 		    char_u *dest = p - 2;
8342 
8343 		    /* Usually a BOM is at the beginning of a file, and so at
8344 		     * the beginning of a line; then we can just step over it.
8345 		     */
8346 		    if (start == dest)
8347 			start = p + 1;
8348 		    else
8349 		    {
8350 			/* have to shuffle buf to close gap */
8351 			int adjust_prevlen = 0;
8352 
8353 			if (dest < buf)
8354 			{
8355 			    adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8356 			    dest = buf;
8357 			}
8358 			if (readlen > p - buf + 1)
8359 			    mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8360 			readlen -= 3 - adjust_prevlen;
8361 			prevlen -= adjust_prevlen;
8362 			p = dest - 1;
8363 		    }
8364 		}
8365 	    }
8366 #endif
8367 	} /* for */
8368 
8369 	if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8370 	    break;
8371 	if (start < p)
8372 	{
8373 	    /* There's part of a line in buf, store it in "prev". */
8374 	    if (p - start + prevlen >= prevsize)
8375 	    {
8376 		/* need bigger "prev" buffer */
8377 		char_u *newprev;
8378 
8379 		/* A common use case is ordinary text files and "prev" gets a
8380 		 * fragment of a line, so the first allocation is made
8381 		 * small, to avoid repeatedly 'allocing' large and
8382 		 * 'reallocing' small. */
8383 		if (prevsize == 0)
8384 		    prevsize = (long)(p - start);
8385 		else
8386 		{
8387 		    long grow50pc = (prevsize * 3) / 2;
8388 		    long growmin  = (long)((p - start) * 2 + prevlen);
8389 		    prevsize = grow50pc > growmin ? grow50pc : growmin;
8390 		}
8391 		newprev = prev == NULL ? alloc(prevsize)
8392 						: vim_realloc(prev, prevsize);
8393 		if (newprev == NULL)
8394 		{
8395 		    do_outofmem_msg((long_u)prevsize);
8396 		    failed = TRUE;
8397 		    break;
8398 		}
8399 		prev = newprev;
8400 	    }
8401 	    /* Add the line part to end of "prev". */
8402 	    mch_memmove(prev + prevlen, start, p - start);
8403 	    prevlen += (long)(p - start);
8404 	}
8405     } /* while */
8406 
8407     /*
8408      * For a negative line count use only the lines at the end of the file,
8409      * free the rest.
8410      */
8411     if (!failed && maxline < 0)
8412 	while (cnt > -maxline)
8413 	{
8414 	    listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8415 	    --cnt;
8416 	}
8417 
8418     if (failed)
8419     {
8420 	list_free(rettv->vval.v_list);
8421 	/* readfile doc says an empty list is returned on error */
8422 	rettv->vval.v_list = list_alloc();
8423     }
8424 
8425     vim_free(prev);
8426     fclose(fd);
8427 }
8428 
8429 #if defined(FEAT_RELTIME)
8430 static int list2proftime(typval_T *arg, proftime_T *tm);
8431 
8432 /*
8433  * Convert a List to proftime_T.
8434  * Return FAIL when there is something wrong.
8435  */
8436     static int
8437 list2proftime(typval_T *arg, proftime_T *tm)
8438 {
8439     long	n1, n2;
8440     int	error = FALSE;
8441 
8442     if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8443 					     || arg->vval.v_list->lv_len != 2)
8444 	return FAIL;
8445     n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8446     n2 = list_find_nr(arg->vval.v_list, 1L, &error);
8447 # ifdef WIN3264
8448     tm->HighPart = n1;
8449     tm->LowPart = n2;
8450 # else
8451     tm->tv_sec = n1;
8452     tm->tv_usec = n2;
8453 # endif
8454     return error ? FAIL : OK;
8455 }
8456 #endif /* FEAT_RELTIME */
8457 
8458 /*
8459  * "reltime()" function
8460  */
8461     static void
8462 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8463 {
8464 #ifdef FEAT_RELTIME
8465     proftime_T	res;
8466     proftime_T	start;
8467 
8468     if (argvars[0].v_type == VAR_UNKNOWN)
8469     {
8470 	/* No arguments: get current time. */
8471 	profile_start(&res);
8472     }
8473     else if (argvars[1].v_type == VAR_UNKNOWN)
8474     {
8475 	if (list2proftime(&argvars[0], &res) == FAIL)
8476 	    return;
8477 	profile_end(&res);
8478     }
8479     else
8480     {
8481 	/* Two arguments: compute the difference. */
8482 	if (list2proftime(&argvars[0], &start) == FAIL
8483 		|| list2proftime(&argvars[1], &res) == FAIL)
8484 	    return;
8485 	profile_sub(&res, &start);
8486     }
8487 
8488     if (rettv_list_alloc(rettv) == OK)
8489     {
8490 	long	n1, n2;
8491 
8492 # ifdef WIN3264
8493 	n1 = res.HighPart;
8494 	n2 = res.LowPart;
8495 # else
8496 	n1 = res.tv_sec;
8497 	n2 = res.tv_usec;
8498 # endif
8499 	list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8500 	list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8501     }
8502 #endif
8503 }
8504 
8505 #ifdef FEAT_FLOAT
8506 /*
8507  * "reltimefloat()" function
8508  */
8509     static void
8510 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8511 {
8512 # ifdef FEAT_RELTIME
8513     proftime_T	tm;
8514 # endif
8515 
8516     rettv->v_type = VAR_FLOAT;
8517     rettv->vval.v_float = 0;
8518 # ifdef FEAT_RELTIME
8519     if (list2proftime(&argvars[0], &tm) == OK)
8520 	rettv->vval.v_float = profile_float(&tm);
8521 # endif
8522 }
8523 #endif
8524 
8525 /*
8526  * "reltimestr()" function
8527  */
8528     static void
8529 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8530 {
8531 #ifdef FEAT_RELTIME
8532     proftime_T	tm;
8533 #endif
8534 
8535     rettv->v_type = VAR_STRING;
8536     rettv->vval.v_string = NULL;
8537 #ifdef FEAT_RELTIME
8538     if (list2proftime(&argvars[0], &tm) == OK)
8539 	rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8540 #endif
8541 }
8542 
8543 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8544 static void make_connection(void);
8545 static int check_connection(void);
8546 
8547     static void
8548 make_connection(void)
8549 {
8550     if (X_DISPLAY == NULL
8551 # ifdef FEAT_GUI
8552 	    && !gui.in_use
8553 # endif
8554 	    )
8555     {
8556 	x_force_connect = TRUE;
8557 	setup_term_clip();
8558 	x_force_connect = FALSE;
8559     }
8560 }
8561 
8562     static int
8563 check_connection(void)
8564 {
8565     make_connection();
8566     if (X_DISPLAY == NULL)
8567     {
8568 	EMSG(_("E240: No connection to the X server"));
8569 	return FAIL;
8570     }
8571     return OK;
8572 }
8573 #endif
8574 
8575 #ifdef FEAT_CLIENTSERVER
8576     static void
8577 remote_common(typval_T *argvars, typval_T *rettv, int expr)
8578 {
8579     char_u	*server_name;
8580     char_u	*keys;
8581     char_u	*r = NULL;
8582     char_u	buf[NUMBUFLEN];
8583     int		timeout = 0;
8584 # ifdef WIN32
8585     HWND	w;
8586 # else
8587     Window	w;
8588 # endif
8589 
8590     if (check_restricted() || check_secure())
8591 	return;
8592 
8593 # ifdef FEAT_X11
8594     if (check_connection() == FAIL)
8595 	return;
8596 # endif
8597     if (argvars[2].v_type != VAR_UNKNOWN
8598 	    && argvars[3].v_type != VAR_UNKNOWN)
8599 	timeout = get_tv_number(&argvars[3]);
8600 
8601     server_name = get_tv_string_chk(&argvars[0]);
8602     if (server_name == NULL)
8603 	return;		/* type error; errmsg already given */
8604     keys = get_tv_string_buf(&argvars[1], buf);
8605 # ifdef WIN32
8606     if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
8607 # else
8608     if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8609 								  0, TRUE) < 0)
8610 # endif
8611     {
8612 	if (r != NULL)
8613 	    EMSG(r);		/* sending worked but evaluation failed */
8614 	else
8615 	    EMSG2(_("E241: Unable to send to %s"), server_name);
8616 	return;
8617     }
8618 
8619     rettv->vval.v_string = r;
8620 
8621     if (argvars[2].v_type != VAR_UNKNOWN)
8622     {
8623 	dictitem_T	v;
8624 	char_u		str[30];
8625 	char_u		*idvar;
8626 
8627 	idvar = get_tv_string_chk(&argvars[2]);
8628 	if (idvar != NULL && *idvar != NUL)
8629 	{
8630 	    sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8631 	    v.di_tv.v_type = VAR_STRING;
8632 	    v.di_tv.vval.v_string = vim_strsave(str);
8633 	    set_var(idvar, &v.di_tv, FALSE);
8634 	    vim_free(v.di_tv.vval.v_string);
8635 	}
8636     }
8637 }
8638 #endif
8639 
8640 /*
8641  * "remote_expr()" function
8642  */
8643     static void
8644 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8645 {
8646     rettv->v_type = VAR_STRING;
8647     rettv->vval.v_string = NULL;
8648 #ifdef FEAT_CLIENTSERVER
8649     remote_common(argvars, rettv, TRUE);
8650 #endif
8651 }
8652 
8653 /*
8654  * "remote_foreground()" function
8655  */
8656     static void
8657 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8658 {
8659 #ifdef FEAT_CLIENTSERVER
8660 # ifdef WIN32
8661     /* On Win32 it's done in this application. */
8662     {
8663 	char_u	*server_name = get_tv_string_chk(&argvars[0]);
8664 
8665 	if (server_name != NULL)
8666 	    serverForeground(server_name);
8667     }
8668 # else
8669     /* Send a foreground() expression to the server. */
8670     argvars[1].v_type = VAR_STRING;
8671     argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8672     argvars[2].v_type = VAR_UNKNOWN;
8673     remote_common(argvars, rettv, TRUE);
8674     vim_free(argvars[1].vval.v_string);
8675 # endif
8676 #endif
8677 }
8678 
8679     static void
8680 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8681 {
8682 #ifdef FEAT_CLIENTSERVER
8683     dictitem_T	v;
8684     char_u	*s = NULL;
8685 # ifdef WIN32
8686     long_u	n = 0;
8687 # endif
8688     char_u	*serverid;
8689 
8690     if (check_restricted() || check_secure())
8691     {
8692 	rettv->vval.v_number = -1;
8693 	return;
8694     }
8695     serverid = get_tv_string_chk(&argvars[0]);
8696     if (serverid == NULL)
8697     {
8698 	rettv->vval.v_number = -1;
8699 	return;		/* type error; errmsg already given */
8700     }
8701 # ifdef WIN32
8702     sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8703     if (n == 0)
8704 	rettv->vval.v_number = -1;
8705     else
8706     {
8707 	s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
8708 	rettv->vval.v_number = (s != NULL);
8709     }
8710 # else
8711     if (check_connection() == FAIL)
8712 	return;
8713 
8714     rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8715 						serverStrToWin(serverid), &s);
8716 # endif
8717 
8718     if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8719     {
8720 	char_u		*retvar;
8721 
8722 	v.di_tv.v_type = VAR_STRING;
8723 	v.di_tv.vval.v_string = vim_strsave(s);
8724 	retvar = get_tv_string_chk(&argvars[1]);
8725 	if (retvar != NULL)
8726 	    set_var(retvar, &v.di_tv, FALSE);
8727 	vim_free(v.di_tv.vval.v_string);
8728     }
8729 #else
8730     rettv->vval.v_number = -1;
8731 #endif
8732 }
8733 
8734     static void
8735 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8736 {
8737     char_u	*r = NULL;
8738 
8739 #ifdef FEAT_CLIENTSERVER
8740     char_u	*serverid = get_tv_string_chk(&argvars[0]);
8741 
8742     if (serverid != NULL && !check_restricted() && !check_secure())
8743     {
8744 	int timeout = 0;
8745 # ifdef WIN32
8746 	/* The server's HWND is encoded in the 'id' parameter */
8747 	long_u		n = 0;
8748 # endif
8749 
8750 	if (argvars[1].v_type != VAR_UNKNOWN)
8751 	    timeout = get_tv_number(&argvars[1]);
8752 
8753 # ifdef WIN32
8754 	sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8755 	if (n != 0)
8756 	    r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
8757 	if (r == NULL)
8758 # else
8759 	if (check_connection() == FAIL
8760 		|| serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8761 						       &r, FALSE, timeout) < 0)
8762 # endif
8763 	    EMSG(_("E277: Unable to read a server reply"));
8764     }
8765 #endif
8766     rettv->v_type = VAR_STRING;
8767     rettv->vval.v_string = r;
8768 }
8769 
8770 /*
8771  * "remote_send()" function
8772  */
8773     static void
8774 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8775 {
8776     rettv->v_type = VAR_STRING;
8777     rettv->vval.v_string = NULL;
8778 #ifdef FEAT_CLIENTSERVER
8779     remote_common(argvars, rettv, FALSE);
8780 #endif
8781 }
8782 
8783 /*
8784  * "remote_startserver()" function
8785  */
8786     static void
8787 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8788 {
8789 #ifdef FEAT_CLIENTSERVER
8790     char_u	*server = get_tv_string_chk(&argvars[0]);
8791 
8792     if (server == NULL)
8793 	return;		/* type error; errmsg already given */
8794     if (serverName != NULL)
8795 	EMSG(_("E941: already started a server"));
8796     else
8797     {
8798 # ifdef FEAT_X11
8799 	if (check_connection() == OK)
8800 	    serverRegisterName(X_DISPLAY, server);
8801 # else
8802 	serverSetName(server);
8803 # endif
8804     }
8805 #else
8806     EMSG(_("E942: +clientserver feature not available"));
8807 #endif
8808 }
8809 
8810 /*
8811  * "remove()" function
8812  */
8813     static void
8814 f_remove(typval_T *argvars, typval_T *rettv)
8815 {
8816     list_T	*l;
8817     listitem_T	*item, *item2;
8818     listitem_T	*li;
8819     long	idx;
8820     long	end;
8821     char_u	*key;
8822     dict_T	*d;
8823     dictitem_T	*di;
8824     char_u	*arg_errmsg = (char_u *)N_("remove() argument");
8825 
8826     if (argvars[0].v_type == VAR_DICT)
8827     {
8828 	if (argvars[2].v_type != VAR_UNKNOWN)
8829 	    EMSG2(_(e_toomanyarg), "remove()");
8830 	else if ((d = argvars[0].vval.v_dict) != NULL
8831 		&& !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8832 	{
8833 	    key = get_tv_string_chk(&argvars[1]);
8834 	    if (key != NULL)
8835 	    {
8836 		di = dict_find(d, key, -1);
8837 		if (di == NULL)
8838 		    EMSG2(_(e_dictkey), key);
8839 		else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8840 			    && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8841 		{
8842 		    *rettv = di->di_tv;
8843 		    init_tv(&di->di_tv);
8844 		    dictitem_remove(d, di);
8845 		}
8846 	    }
8847 	}
8848     }
8849     else if (argvars[0].v_type != VAR_LIST)
8850 	EMSG2(_(e_listdictarg), "remove()");
8851     else if ((l = argvars[0].vval.v_list) != NULL
8852 	    && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8853     {
8854 	int	    error = FALSE;
8855 
8856 	idx = (long)get_tv_number_chk(&argvars[1], &error);
8857 	if (error)
8858 	    ;		/* type error: do nothing, errmsg already given */
8859 	else if ((item = list_find(l, idx)) == NULL)
8860 	    EMSGN(_(e_listidx), idx);
8861 	else
8862 	{
8863 	    if (argvars[2].v_type == VAR_UNKNOWN)
8864 	    {
8865 		/* Remove one item, return its value. */
8866 		vimlist_remove(l, item, item);
8867 		*rettv = item->li_tv;
8868 		vim_free(item);
8869 	    }
8870 	    else
8871 	    {
8872 		/* Remove range of items, return list with values. */
8873 		end = (long)get_tv_number_chk(&argvars[2], &error);
8874 		if (error)
8875 		    ;		/* type error: do nothing */
8876 		else if ((item2 = list_find(l, end)) == NULL)
8877 		    EMSGN(_(e_listidx), end);
8878 		else
8879 		{
8880 		    int	    cnt = 0;
8881 
8882 		    for (li = item; li != NULL; li = li->li_next)
8883 		    {
8884 			++cnt;
8885 			if (li == item2)
8886 			    break;
8887 		    }
8888 		    if (li == NULL)  /* didn't find "item2" after "item" */
8889 			EMSG(_(e_invrange));
8890 		    else
8891 		    {
8892 			vimlist_remove(l, item, item2);
8893 			if (rettv_list_alloc(rettv) == OK)
8894 			{
8895 			    l = rettv->vval.v_list;
8896 			    l->lv_first = item;
8897 			    l->lv_last = item2;
8898 			    item->li_prev = NULL;
8899 			    item2->li_next = NULL;
8900 			    l->lv_len = cnt;
8901 			}
8902 		    }
8903 		}
8904 	    }
8905 	}
8906     }
8907 }
8908 
8909 /*
8910  * "rename({from}, {to})" function
8911  */
8912     static void
8913 f_rename(typval_T *argvars, typval_T *rettv)
8914 {
8915     char_u	buf[NUMBUFLEN];
8916 
8917     if (check_restricted() || check_secure())
8918 	rettv->vval.v_number = -1;
8919     else
8920 	rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8921 				      get_tv_string_buf(&argvars[1], buf));
8922 }
8923 
8924 /*
8925  * "repeat()" function
8926  */
8927     static void
8928 f_repeat(typval_T *argvars, typval_T *rettv)
8929 {
8930     char_u	*p;
8931     int		n;
8932     int		slen;
8933     int		len;
8934     char_u	*r;
8935     int		i;
8936 
8937     n = (int)get_tv_number(&argvars[1]);
8938     if (argvars[0].v_type == VAR_LIST)
8939     {
8940 	if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8941 	    while (n-- > 0)
8942 		if (list_extend(rettv->vval.v_list,
8943 					argvars[0].vval.v_list, NULL) == FAIL)
8944 		    break;
8945     }
8946     else
8947     {
8948 	p = get_tv_string(&argvars[0]);
8949 	rettv->v_type = VAR_STRING;
8950 	rettv->vval.v_string = NULL;
8951 
8952 	slen = (int)STRLEN(p);
8953 	len = slen * n;
8954 	if (len <= 0)
8955 	    return;
8956 
8957 	r = alloc(len + 1);
8958 	if (r != NULL)
8959 	{
8960 	    for (i = 0; i < n; i++)
8961 		mch_memmove(r + i * slen, p, (size_t)slen);
8962 	    r[len] = NUL;
8963 	}
8964 
8965 	rettv->vval.v_string = r;
8966     }
8967 }
8968 
8969 /*
8970  * "resolve()" function
8971  */
8972     static void
8973 f_resolve(typval_T *argvars, typval_T *rettv)
8974 {
8975     char_u	*p;
8976 #ifdef HAVE_READLINK
8977     char_u	*buf = NULL;
8978 #endif
8979 
8980     p = get_tv_string(&argvars[0]);
8981 #ifdef FEAT_SHORTCUT
8982     {
8983 	char_u	*v = NULL;
8984 
8985 	v = mch_resolve_shortcut(p);
8986 	if (v != NULL)
8987 	    rettv->vval.v_string = v;
8988 	else
8989 	    rettv->vval.v_string = vim_strsave(p);
8990     }
8991 #else
8992 # ifdef HAVE_READLINK
8993     {
8994 	char_u	*cpy;
8995 	int	len;
8996 	char_u	*remain = NULL;
8997 	char_u	*q;
8998 	int	is_relative_to_current = FALSE;
8999 	int	has_trailing_pathsep = FALSE;
9000 	int	limit = 100;
9001 
9002 	p = vim_strsave(p);
9003 
9004 	if (p[0] == '.' && (vim_ispathsep(p[1])
9005 				   || (p[1] == '.' && (vim_ispathsep(p[2])))))
9006 	    is_relative_to_current = TRUE;
9007 
9008 	len = STRLEN(p);
9009 	if (len > 0 && after_pathsep(p, p + len))
9010 	{
9011 	    has_trailing_pathsep = TRUE;
9012 	    p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9013 	}
9014 
9015 	q = getnextcomp(p);
9016 	if (*q != NUL)
9017 	{
9018 	    /* Separate the first path component in "p", and keep the
9019 	     * remainder (beginning with the path separator). */
9020 	    remain = vim_strsave(q - 1);
9021 	    q[-1] = NUL;
9022 	}
9023 
9024 	buf = alloc(MAXPATHL + 1);
9025 	if (buf == NULL)
9026 	    goto fail;
9027 
9028 	for (;;)
9029 	{
9030 	    for (;;)
9031 	    {
9032 		len = readlink((char *)p, (char *)buf, MAXPATHL);
9033 		if (len <= 0)
9034 		    break;
9035 		buf[len] = NUL;
9036 
9037 		if (limit-- == 0)
9038 		{
9039 		    vim_free(p);
9040 		    vim_free(remain);
9041 		    EMSG(_("E655: Too many symbolic links (cycle?)"));
9042 		    rettv->vval.v_string = NULL;
9043 		    goto fail;
9044 		}
9045 
9046 		/* Ensure that the result will have a trailing path separator
9047 		 * if the argument has one. */
9048 		if (remain == NULL && has_trailing_pathsep)
9049 		    add_pathsep(buf);
9050 
9051 		/* Separate the first path component in the link value and
9052 		 * concatenate the remainders. */
9053 		q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9054 		if (*q != NUL)
9055 		{
9056 		    if (remain == NULL)
9057 			remain = vim_strsave(q - 1);
9058 		    else
9059 		    {
9060 			cpy = concat_str(q - 1, remain);
9061 			if (cpy != NULL)
9062 			{
9063 			    vim_free(remain);
9064 			    remain = cpy;
9065 			}
9066 		    }
9067 		    q[-1] = NUL;
9068 		}
9069 
9070 		q = gettail(p);
9071 		if (q > p && *q == NUL)
9072 		{
9073 		    /* Ignore trailing path separator. */
9074 		    q[-1] = NUL;
9075 		    q = gettail(p);
9076 		}
9077 		if (q > p && !mch_isFullName(buf))
9078 		{
9079 		    /* symlink is relative to directory of argument */
9080 		    cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
9081 		    if (cpy != NULL)
9082 		    {
9083 			STRCPY(cpy, p);
9084 			STRCPY(gettail(cpy), buf);
9085 			vim_free(p);
9086 			p = cpy;
9087 		    }
9088 		}
9089 		else
9090 		{
9091 		    vim_free(p);
9092 		    p = vim_strsave(buf);
9093 		}
9094 	    }
9095 
9096 	    if (remain == NULL)
9097 		break;
9098 
9099 	    /* Append the first path component of "remain" to "p". */
9100 	    q = getnextcomp(remain + 1);
9101 	    len = q - remain - (*q != NUL);
9102 	    cpy = vim_strnsave(p, STRLEN(p) + len);
9103 	    if (cpy != NULL)
9104 	    {
9105 		STRNCAT(cpy, remain, len);
9106 		vim_free(p);
9107 		p = cpy;
9108 	    }
9109 	    /* Shorten "remain". */
9110 	    if (*q != NUL)
9111 		STRMOVE(remain, q - 1);
9112 	    else
9113 	    {
9114 		vim_free(remain);
9115 		remain = NULL;
9116 	    }
9117 	}
9118 
9119 	/* If the result is a relative path name, make it explicitly relative to
9120 	 * the current directory if and only if the argument had this form. */
9121 	if (!vim_ispathsep(*p))
9122 	{
9123 	    if (is_relative_to_current
9124 		    && *p != NUL
9125 		    && !(p[0] == '.'
9126 			&& (p[1] == NUL
9127 			    || vim_ispathsep(p[1])
9128 			    || (p[1] == '.'
9129 				&& (p[2] == NUL
9130 				    || vim_ispathsep(p[2]))))))
9131 	    {
9132 		/* Prepend "./". */
9133 		cpy = concat_str((char_u *)"./", p);
9134 		if (cpy != NULL)
9135 		{
9136 		    vim_free(p);
9137 		    p = cpy;
9138 		}
9139 	    }
9140 	    else if (!is_relative_to_current)
9141 	    {
9142 		/* Strip leading "./". */
9143 		q = p;
9144 		while (q[0] == '.' && vim_ispathsep(q[1]))
9145 		    q += 2;
9146 		if (q > p)
9147 		    STRMOVE(p, p + 2);
9148 	    }
9149 	}
9150 
9151 	/* Ensure that the result will have no trailing path separator
9152 	 * if the argument had none.  But keep "/" or "//". */
9153 	if (!has_trailing_pathsep)
9154 	{
9155 	    q = p + STRLEN(p);
9156 	    if (after_pathsep(p, q))
9157 		*gettail_sep(p) = NUL;
9158 	}
9159 
9160 	rettv->vval.v_string = p;
9161     }
9162 # else
9163     rettv->vval.v_string = vim_strsave(p);
9164 # endif
9165 #endif
9166 
9167     simplify_filename(rettv->vval.v_string);
9168 
9169 #ifdef HAVE_READLINK
9170 fail:
9171     vim_free(buf);
9172 #endif
9173     rettv->v_type = VAR_STRING;
9174 }
9175 
9176 /*
9177  * "reverse({list})" function
9178  */
9179     static void
9180 f_reverse(typval_T *argvars, typval_T *rettv)
9181 {
9182     list_T	*l;
9183     listitem_T	*li, *ni;
9184 
9185     if (argvars[0].v_type != VAR_LIST)
9186 	EMSG2(_(e_listarg), "reverse()");
9187     else if ((l = argvars[0].vval.v_list) != NULL
9188 	    && !tv_check_lock(l->lv_lock,
9189 				    (char_u *)N_("reverse() argument"), TRUE))
9190     {
9191 	li = l->lv_last;
9192 	l->lv_first = l->lv_last = NULL;
9193 	l->lv_len = 0;
9194 	while (li != NULL)
9195 	{
9196 	    ni = li->li_prev;
9197 	    list_append(l, li);
9198 	    li = ni;
9199 	}
9200 	rettv_list_set(rettv, l);
9201 	l->lv_idx = l->lv_len - l->lv_idx - 1;
9202     }
9203 }
9204 
9205 #define SP_NOMOVE	0x01	    /* don't move cursor */
9206 #define SP_REPEAT	0x02	    /* repeat to find outer pair */
9207 #define SP_RETCOUNT	0x04	    /* return matchcount */
9208 #define SP_SETPCMARK	0x08	    /* set previous context mark */
9209 #define SP_START	0x10	    /* accept match at start position */
9210 #define SP_SUBPAT	0x20	    /* return nr of matching sub-pattern */
9211 #define SP_END		0x40	    /* leave cursor at end of match */
9212 #define SP_COLUMN	0x80	    /* start at cursor column */
9213 
9214 static int get_search_arg(typval_T *varp, int *flagsp);
9215 
9216 /*
9217  * Get flags for a search function.
9218  * Possibly sets "p_ws".
9219  * Returns BACKWARD, FORWARD or zero (for an error).
9220  */
9221     static int
9222 get_search_arg(typval_T *varp, int *flagsp)
9223 {
9224     int		dir = FORWARD;
9225     char_u	*flags;
9226     char_u	nbuf[NUMBUFLEN];
9227     int		mask;
9228 
9229     if (varp->v_type != VAR_UNKNOWN)
9230     {
9231 	flags = get_tv_string_buf_chk(varp, nbuf);
9232 	if (flags == NULL)
9233 	    return 0;		/* type error; errmsg already given */
9234 	while (*flags != NUL)
9235 	{
9236 	    switch (*flags)
9237 	    {
9238 		case 'b': dir = BACKWARD; break;
9239 		case 'w': p_ws = TRUE; break;
9240 		case 'W': p_ws = FALSE; break;
9241 		default:  mask = 0;
9242 			  if (flagsp != NULL)
9243 			     switch (*flags)
9244 			     {
9245 				 case 'c': mask = SP_START; break;
9246 				 case 'e': mask = SP_END; break;
9247 				 case 'm': mask = SP_RETCOUNT; break;
9248 				 case 'n': mask = SP_NOMOVE; break;
9249 				 case 'p': mask = SP_SUBPAT; break;
9250 				 case 'r': mask = SP_REPEAT; break;
9251 				 case 's': mask = SP_SETPCMARK; break;
9252 				 case 'z': mask = SP_COLUMN; break;
9253 			     }
9254 			  if (mask == 0)
9255 			  {
9256 			      EMSG2(_(e_invarg2), flags);
9257 			      dir = 0;
9258 			  }
9259 			  else
9260 			      *flagsp |= mask;
9261 	    }
9262 	    if (dir == 0)
9263 		break;
9264 	    ++flags;
9265 	}
9266     }
9267     return dir;
9268 }
9269 
9270 /*
9271  * Shared by search() and searchpos() functions.
9272  */
9273     static int
9274 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9275 {
9276     int		flags;
9277     char_u	*pat;
9278     pos_T	pos;
9279     pos_T	save_cursor;
9280     int		save_p_ws = p_ws;
9281     int		dir;
9282     int		retval = 0;	/* default: FAIL */
9283     long	lnum_stop = 0;
9284     proftime_T	tm;
9285 #ifdef FEAT_RELTIME
9286     long	time_limit = 0;
9287 #endif
9288     int		options = SEARCH_KEEP;
9289     int		subpatnum;
9290 
9291     pat = get_tv_string(&argvars[0]);
9292     dir = get_search_arg(&argvars[1], flagsp);	/* may set p_ws */
9293     if (dir == 0)
9294 	goto theend;
9295     flags = *flagsp;
9296     if (flags & SP_START)
9297 	options |= SEARCH_START;
9298     if (flags & SP_END)
9299 	options |= SEARCH_END;
9300     if (flags & SP_COLUMN)
9301 	options |= SEARCH_COL;
9302 
9303     /* Optional arguments: line number to stop searching and timeout. */
9304     if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9305     {
9306 	lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
9307 	if (lnum_stop < 0)
9308 	    goto theend;
9309 #ifdef FEAT_RELTIME
9310 	if (argvars[3].v_type != VAR_UNKNOWN)
9311 	{
9312 	    time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
9313 	    if (time_limit < 0)
9314 		goto theend;
9315 	}
9316 #endif
9317     }
9318 
9319 #ifdef FEAT_RELTIME
9320     /* Set the time limit, if there is one. */
9321     profile_setlimit(time_limit, &tm);
9322 #endif
9323 
9324     /*
9325      * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9326      * Check to make sure only those flags are set.
9327      * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9328      * flags cannot be set. Check for that condition also.
9329      */
9330     if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9331 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9332     {
9333 	EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
9334 	goto theend;
9335     }
9336 
9337     pos = save_cursor = curwin->w_cursor;
9338     subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9339 			   options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
9340     if (subpatnum != FAIL)
9341     {
9342 	if (flags & SP_SUBPAT)
9343 	    retval = subpatnum;
9344 	else
9345 	    retval = pos.lnum;
9346 	if (flags & SP_SETPCMARK)
9347 	    setpcmark();
9348 	curwin->w_cursor = pos;
9349 	if (match_pos != NULL)
9350 	{
9351 	    /* Store the match cursor position */
9352 	    match_pos->lnum = pos.lnum;
9353 	    match_pos->col = pos.col + 1;
9354 	}
9355 	/* "/$" will put the cursor after the end of the line, may need to
9356 	 * correct that here */
9357 	check_cursor();
9358     }
9359 
9360     /* If 'n' flag is used: restore cursor position. */
9361     if (flags & SP_NOMOVE)
9362 	curwin->w_cursor = save_cursor;
9363     else
9364 	curwin->w_set_curswant = TRUE;
9365 theend:
9366     p_ws = save_p_ws;
9367 
9368     return retval;
9369 }
9370 
9371 #ifdef FEAT_FLOAT
9372 
9373 /*
9374  * round() is not in C90, use ceil() or floor() instead.
9375  */
9376     float_T
9377 vim_round(float_T f)
9378 {
9379     return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9380 }
9381 
9382 /*
9383  * "round({float})" function
9384  */
9385     static void
9386 f_round(typval_T *argvars, typval_T *rettv)
9387 {
9388     float_T	f = 0.0;
9389 
9390     rettv->v_type = VAR_FLOAT;
9391     if (get_float_arg(argvars, &f) == OK)
9392 	rettv->vval.v_float = vim_round(f);
9393     else
9394 	rettv->vval.v_float = 0.0;
9395 }
9396 #endif
9397 
9398 /*
9399  * "screenattr()" function
9400  */
9401     static void
9402 f_screenattr(typval_T *argvars, typval_T *rettv)
9403 {
9404     int		row;
9405     int		col;
9406     int		c;
9407 
9408     row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9409     col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9410     if (row < 0 || row >= screen_Rows
9411 	    || col < 0 || col >= screen_Columns)
9412 	c = -1;
9413     else
9414 	c = ScreenAttrs[LineOffset[row] + col];
9415     rettv->vval.v_number = c;
9416 }
9417 
9418 /*
9419  * "screenchar()" function
9420  */
9421     static void
9422 f_screenchar(typval_T *argvars, typval_T *rettv)
9423 {
9424     int		row;
9425     int		col;
9426     int		off;
9427     int		c;
9428 
9429     row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
9430     col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
9431     if (row < 0 || row >= screen_Rows
9432 	    || col < 0 || col >= screen_Columns)
9433 	c = -1;
9434     else
9435     {
9436 	off = LineOffset[row] + col;
9437 #ifdef FEAT_MBYTE
9438 	if (enc_utf8 && ScreenLinesUC[off] != 0)
9439 	    c = ScreenLinesUC[off];
9440 	else
9441 #endif
9442 	    c = ScreenLines[off];
9443     }
9444     rettv->vval.v_number = c;
9445 }
9446 
9447 /*
9448  * "screencol()" function
9449  *
9450  * First column is 1 to be consistent with virtcol().
9451  */
9452     static void
9453 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9454 {
9455     rettv->vval.v_number = screen_screencol() + 1;
9456 }
9457 
9458 /*
9459  * "screenrow()" function
9460  */
9461     static void
9462 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9463 {
9464     rettv->vval.v_number = screen_screenrow() + 1;
9465 }
9466 
9467 /*
9468  * "search()" function
9469  */
9470     static void
9471 f_search(typval_T *argvars, typval_T *rettv)
9472 {
9473     int		flags = 0;
9474 
9475     rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9476 }
9477 
9478 /*
9479  * "searchdecl()" function
9480  */
9481     static void
9482 f_searchdecl(typval_T *argvars, typval_T *rettv)
9483 {
9484     int		locally = 1;
9485     int		thisblock = 0;
9486     int		error = FALSE;
9487     char_u	*name;
9488 
9489     rettv->vval.v_number = 1;	/* default: FAIL */
9490 
9491     name = get_tv_string_chk(&argvars[0]);
9492     if (argvars[1].v_type != VAR_UNKNOWN)
9493     {
9494 	locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
9495 	if (!error && argvars[2].v_type != VAR_UNKNOWN)
9496 	    thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
9497     }
9498     if (!error && name != NULL)
9499 	rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9500 				     locally, thisblock, SEARCH_KEEP) == FAIL;
9501 }
9502 
9503 /*
9504  * Used by searchpair() and searchpairpos()
9505  */
9506     static int
9507 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9508 {
9509     char_u	*spat, *mpat, *epat;
9510     char_u	*skip;
9511     int		save_p_ws = p_ws;
9512     int		dir;
9513     int		flags = 0;
9514     char_u	nbuf1[NUMBUFLEN];
9515     char_u	nbuf2[NUMBUFLEN];
9516     char_u	nbuf3[NUMBUFLEN];
9517     int		retval = 0;		/* default: FAIL */
9518     long	lnum_stop = 0;
9519     long	time_limit = 0;
9520 
9521     /* Get the three pattern arguments: start, middle, end. */
9522     spat = get_tv_string_chk(&argvars[0]);
9523     mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
9524     epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
9525     if (spat == NULL || mpat == NULL || epat == NULL)
9526 	goto theend;	    /* type error */
9527 
9528     /* Handle the optional fourth argument: flags */
9529     dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9530     if (dir == 0)
9531 	goto theend;
9532 
9533     /* Don't accept SP_END or SP_SUBPAT.
9534      * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9535      */
9536     if ((flags & (SP_END | SP_SUBPAT)) != 0
9537 	    || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9538     {
9539 	EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
9540 	goto theend;
9541     }
9542 
9543     /* Using 'r' implies 'W', otherwise it doesn't work. */
9544     if (flags & SP_REPEAT)
9545 	p_ws = FALSE;
9546 
9547     /* Optional fifth argument: skip expression */
9548     if (argvars[3].v_type == VAR_UNKNOWN
9549 	    || argvars[4].v_type == VAR_UNKNOWN)
9550 	skip = (char_u *)"";
9551     else
9552     {
9553 	skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
9554 	if (argvars[5].v_type != VAR_UNKNOWN)
9555 	{
9556 	    lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9557 	    if (lnum_stop < 0)
9558 		goto theend;
9559 #ifdef FEAT_RELTIME
9560 	    if (argvars[6].v_type != VAR_UNKNOWN)
9561 	    {
9562 		time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9563 		if (time_limit < 0)
9564 		    goto theend;
9565 	    }
9566 #endif
9567 	}
9568     }
9569     if (skip == NULL)
9570 	goto theend;	    /* type error */
9571 
9572     retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9573 					    match_pos, lnum_stop, time_limit);
9574 
9575 theend:
9576     p_ws = save_p_ws;
9577 
9578     return retval;
9579 }
9580 
9581 /*
9582  * "searchpair()" function
9583  */
9584     static void
9585 f_searchpair(typval_T *argvars, typval_T *rettv)
9586 {
9587     rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9588 }
9589 
9590 /*
9591  * "searchpairpos()" function
9592  */
9593     static void
9594 f_searchpairpos(typval_T *argvars, typval_T *rettv)
9595 {
9596     pos_T	match_pos;
9597     int		lnum = 0;
9598     int		col = 0;
9599 
9600     if (rettv_list_alloc(rettv) == FAIL)
9601 	return;
9602 
9603     if (searchpair_cmn(argvars, &match_pos) > 0)
9604     {
9605 	lnum = match_pos.lnum;
9606 	col = match_pos.col;
9607     }
9608 
9609     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9610     list_append_number(rettv->vval.v_list, (varnumber_T)col);
9611 }
9612 
9613 /*
9614  * Search for a start/middle/end thing.
9615  * Used by searchpair(), see its documentation for the details.
9616  * Returns 0 or -1 for no match,
9617  */
9618     long
9619 do_searchpair(
9620     char_u	*spat,	    /* start pattern */
9621     char_u	*mpat,	    /* middle pattern */
9622     char_u	*epat,	    /* end pattern */
9623     int		dir,	    /* BACKWARD or FORWARD */
9624     char_u	*skip,	    /* skip expression */
9625     int		flags,	    /* SP_SETPCMARK and other SP_ values */
9626     pos_T	*match_pos,
9627     linenr_T	lnum_stop,  /* stop at this line if not zero */
9628     long	time_limit UNUSED) /* stop after this many msec */
9629 {
9630     char_u	*save_cpo;
9631     char_u	*pat, *pat2 = NULL, *pat3 = NULL;
9632     long	retval = 0;
9633     pos_T	pos;
9634     pos_T	firstpos;
9635     pos_T	foundpos;
9636     pos_T	save_cursor;
9637     pos_T	save_pos;
9638     int		n;
9639     int		r;
9640     int		nest = 1;
9641     int		err;
9642     int		options = SEARCH_KEEP;
9643     proftime_T	tm;
9644 
9645     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9646     save_cpo = p_cpo;
9647     p_cpo = empty_option;
9648 
9649 #ifdef FEAT_RELTIME
9650     /* Set the time limit, if there is one. */
9651     profile_setlimit(time_limit, &tm);
9652 #endif
9653 
9654     /* Make two search patterns: start/end (pat2, for in nested pairs) and
9655      * start/middle/end (pat3, for the top pair). */
9656     pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
9657     pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
9658     if (pat2 == NULL || pat3 == NULL)
9659 	goto theend;
9660     sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
9661     if (*mpat == NUL)
9662 	STRCPY(pat3, pat2);
9663     else
9664 	sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
9665 							    spat, epat, mpat);
9666     if (flags & SP_START)
9667 	options |= SEARCH_START;
9668 
9669     save_cursor = curwin->w_cursor;
9670     pos = curwin->w_cursor;
9671     CLEAR_POS(&firstpos);
9672     CLEAR_POS(&foundpos);
9673     pat = pat3;
9674     for (;;)
9675     {
9676 	n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9677 				     options, RE_SEARCH, lnum_stop, &tm, NULL);
9678 	if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
9679 	    /* didn't find it or found the first match again: FAIL */
9680 	    break;
9681 
9682 	if (firstpos.lnum == 0)
9683 	    firstpos = pos;
9684 	if (EQUAL_POS(pos, foundpos))
9685 	{
9686 	    /* Found the same position again.  Can happen with a pattern that
9687 	     * has "\zs" at the end and searching backwards.  Advance one
9688 	     * character and try again. */
9689 	    if (dir == BACKWARD)
9690 		decl(&pos);
9691 	    else
9692 		incl(&pos);
9693 	}
9694 	foundpos = pos;
9695 
9696 	/* clear the start flag to avoid getting stuck here */
9697 	options &= ~SEARCH_START;
9698 
9699 	/* If the skip pattern matches, ignore this match. */
9700 	if (*skip != NUL)
9701 	{
9702 	    save_pos = curwin->w_cursor;
9703 	    curwin->w_cursor = pos;
9704 	    r = eval_to_bool(skip, &err, NULL, FALSE);
9705 	    curwin->w_cursor = save_pos;
9706 	    if (err)
9707 	    {
9708 		/* Evaluating {skip} caused an error, break here. */
9709 		curwin->w_cursor = save_cursor;
9710 		retval = -1;
9711 		break;
9712 	    }
9713 	    if (r)
9714 		continue;
9715 	}
9716 
9717 	if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9718 	{
9719 	    /* Found end when searching backwards or start when searching
9720 	     * forward: nested pair. */
9721 	    ++nest;
9722 	    pat = pat2;		/* nested, don't search for middle */
9723 	}
9724 	else
9725 	{
9726 	    /* Found end when searching forward or start when searching
9727 	     * backward: end of (nested) pair; or found middle in outer pair. */
9728 	    if (--nest == 1)
9729 		pat = pat3;	/* outer level, search for middle */
9730 	}
9731 
9732 	if (nest == 0)
9733 	{
9734 	    /* Found the match: return matchcount or line number. */
9735 	    if (flags & SP_RETCOUNT)
9736 		++retval;
9737 	    else
9738 		retval = pos.lnum;
9739 	    if (flags & SP_SETPCMARK)
9740 		setpcmark();
9741 	    curwin->w_cursor = pos;
9742 	    if (!(flags & SP_REPEAT))
9743 		break;
9744 	    nest = 1;	    /* search for next unmatched */
9745 	}
9746     }
9747 
9748     if (match_pos != NULL)
9749     {
9750 	/* Store the match cursor position */
9751 	match_pos->lnum = curwin->w_cursor.lnum;
9752 	match_pos->col = curwin->w_cursor.col + 1;
9753     }
9754 
9755     /* If 'n' flag is used or search failed: restore cursor position. */
9756     if ((flags & SP_NOMOVE) || retval == 0)
9757 	curwin->w_cursor = save_cursor;
9758 
9759 theend:
9760     vim_free(pat2);
9761     vim_free(pat3);
9762     if (p_cpo == empty_option)
9763 	p_cpo = save_cpo;
9764     else
9765 	/* Darn, evaluating the {skip} expression changed the value. */
9766 	free_string_option(save_cpo);
9767 
9768     return retval;
9769 }
9770 
9771 /*
9772  * "searchpos()" function
9773  */
9774     static void
9775 f_searchpos(typval_T *argvars, typval_T *rettv)
9776 {
9777     pos_T	match_pos;
9778     int		lnum = 0;
9779     int		col = 0;
9780     int		n;
9781     int		flags = 0;
9782 
9783     if (rettv_list_alloc(rettv) == FAIL)
9784 	return;
9785 
9786     n = search_cmn(argvars, &match_pos, &flags);
9787     if (n > 0)
9788     {
9789 	lnum = match_pos.lnum;
9790 	col = match_pos.col;
9791     }
9792 
9793     list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9794     list_append_number(rettv->vval.v_list, (varnumber_T)col);
9795     if (flags & SP_SUBPAT)
9796 	list_append_number(rettv->vval.v_list, (varnumber_T)n);
9797 }
9798 
9799     static void
9800 f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9801 {
9802 #ifdef FEAT_CLIENTSERVER
9803     char_u	buf[NUMBUFLEN];
9804     char_u	*server = get_tv_string_chk(&argvars[0]);
9805     char_u	*reply = get_tv_string_buf_chk(&argvars[1], buf);
9806 
9807     rettv->vval.v_number = -1;
9808     if (server == NULL || reply == NULL)
9809 	return;
9810     if (check_restricted() || check_secure())
9811 	return;
9812 # ifdef FEAT_X11
9813     if (check_connection() == FAIL)
9814 	return;
9815 # endif
9816 
9817     if (serverSendReply(server, reply) < 0)
9818     {
9819 	EMSG(_("E258: Unable to send to client"));
9820 	return;
9821     }
9822     rettv->vval.v_number = 0;
9823 #else
9824     rettv->vval.v_number = -1;
9825 #endif
9826 }
9827 
9828     static void
9829 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9830 {
9831     char_u	*r = NULL;
9832 
9833 #ifdef FEAT_CLIENTSERVER
9834 # ifdef WIN32
9835     r = serverGetVimNames();
9836 # else
9837     make_connection();
9838     if (X_DISPLAY != NULL)
9839 	r = serverGetVimNames(X_DISPLAY);
9840 # endif
9841 #endif
9842     rettv->v_type = VAR_STRING;
9843     rettv->vval.v_string = r;
9844 }
9845 
9846 /*
9847  * "setbufvar()" function
9848  */
9849     static void
9850 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9851 {
9852     buf_T	*buf;
9853     char_u	*varname, *bufvarname;
9854     typval_T	*varp;
9855     char_u	nbuf[NUMBUFLEN];
9856 
9857     if (check_restricted() || check_secure())
9858 	return;
9859     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
9860     varname = get_tv_string_chk(&argvars[1]);
9861     buf = get_buf_tv(&argvars[0], FALSE);
9862     varp = &argvars[2];
9863 
9864     if (buf != NULL && varname != NULL && varp != NULL)
9865     {
9866 	if (*varname == '&')
9867 	{
9868 	    long	numval;
9869 	    char_u	*strval;
9870 	    int		error = FALSE;
9871 	    aco_save_T	aco;
9872 
9873 	    /* set curbuf to be our buf, temporarily */
9874 	    aucmd_prepbuf(&aco, buf);
9875 
9876 	    ++varname;
9877 	    numval = (long)get_tv_number_chk(varp, &error);
9878 	    strval = get_tv_string_buf_chk(varp, nbuf);
9879 	    if (!error && strval != NULL)
9880 		set_option_value(varname, numval, strval, OPT_LOCAL);
9881 
9882 	    /* reset notion of buffer */
9883 	    aucmd_restbuf(&aco);
9884 	}
9885 	else
9886 	{
9887 	    buf_T *save_curbuf = curbuf;
9888 
9889 	    bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9890 	    if (bufvarname != NULL)
9891 	    {
9892 		curbuf = buf;
9893 		STRCPY(bufvarname, "b:");
9894 		STRCPY(bufvarname + 2, varname);
9895 		set_var(bufvarname, varp, TRUE);
9896 		vim_free(bufvarname);
9897 		curbuf = save_curbuf;
9898 	    }
9899 	}
9900     }
9901 }
9902 
9903     static void
9904 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9905 {
9906     dict_T	*d;
9907     dictitem_T	*di;
9908     char_u	*csearch;
9909 
9910     if (argvars[0].v_type != VAR_DICT)
9911     {
9912 	EMSG(_(e_dictreq));
9913 	return;
9914     }
9915 
9916     if ((d = argvars[0].vval.v_dict) != NULL)
9917     {
9918 	csearch = get_dict_string(d, (char_u *)"char", FALSE);
9919 	if (csearch != NULL)
9920 	{
9921 #ifdef FEAT_MBYTE
9922 	    if (enc_utf8)
9923 	    {
9924 		int pcc[MAX_MCO];
9925 		int c = utfc_ptr2char(csearch, pcc);
9926 
9927 		set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9928 	    }
9929 	    else
9930 #endif
9931 		set_last_csearch(PTR2CHAR(csearch),
9932 						csearch, MB_PTR2LEN(csearch));
9933 	}
9934 
9935 	di = dict_find(d, (char_u *)"forward", -1);
9936 	if (di != NULL)
9937 	    set_csearch_direction((int)get_tv_number(&di->di_tv)
9938 							? FORWARD : BACKWARD);
9939 
9940 	di = dict_find(d, (char_u *)"until", -1);
9941 	if (di != NULL)
9942 	    set_csearch_until(!!get_tv_number(&di->di_tv));
9943     }
9944 }
9945 
9946 /*
9947  * "setcmdpos()" function
9948  */
9949     static void
9950 f_setcmdpos(typval_T *argvars, typval_T *rettv)
9951 {
9952     int		pos = (int)get_tv_number(&argvars[0]) - 1;
9953 
9954     if (pos >= 0)
9955 	rettv->vval.v_number = set_cmdline_pos(pos);
9956 }
9957 
9958 /*
9959  * "setfperm({fname}, {mode})" function
9960  */
9961     static void
9962 f_setfperm(typval_T *argvars, typval_T *rettv)
9963 {
9964     char_u	*fname;
9965     char_u	modebuf[NUMBUFLEN];
9966     char_u	*mode_str;
9967     int		i;
9968     int		mask;
9969     int		mode = 0;
9970 
9971     rettv->vval.v_number = 0;
9972     fname = get_tv_string_chk(&argvars[0]);
9973     if (fname == NULL)
9974 	return;
9975     mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9976     if (mode_str == NULL)
9977 	return;
9978     if (STRLEN(mode_str) != 9)
9979     {
9980 	EMSG2(_(e_invarg2), mode_str);
9981 	return;
9982     }
9983 
9984     mask = 1;
9985     for (i = 8; i >= 0; --i)
9986     {
9987 	if (mode_str[i] != '-')
9988 	    mode |= mask;
9989 	mask = mask << 1;
9990     }
9991     rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9992 }
9993 
9994 /*
9995  * "setline()" function
9996  */
9997     static void
9998 f_setline(typval_T *argvars, typval_T *rettv)
9999 {
10000     linenr_T	lnum;
10001     char_u	*line = NULL;
10002     list_T	*l = NULL;
10003     listitem_T	*li = NULL;
10004     long	added = 0;
10005     linenr_T	lcount = curbuf->b_ml.ml_line_count;
10006 
10007     lnum = get_tv_lnum(&argvars[0]);
10008     if (argvars[1].v_type == VAR_LIST)
10009     {
10010 	l = argvars[1].vval.v_list;
10011 	li = l->lv_first;
10012     }
10013     else
10014 	line = get_tv_string_chk(&argvars[1]);
10015 
10016     /* default result is zero == OK */
10017     for (;;)
10018     {
10019 	if (l != NULL)
10020 	{
10021 	    /* list argument, get next string */
10022 	    if (li == NULL)
10023 		break;
10024 	    line = get_tv_string_chk(&li->li_tv);
10025 	    li = li->li_next;
10026 	}
10027 
10028 	rettv->vval.v_number = 1;	/* FAIL */
10029 	if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10030 	    break;
10031 
10032 	/* When coming here from Insert mode, sync undo, so that this can be
10033 	 * undone separately from what was previously inserted. */
10034 	if (u_sync_once == 2)
10035 	{
10036 	    u_sync_once = 1; /* notify that u_sync() was called */
10037 	    u_sync(TRUE);
10038 	}
10039 
10040 	if (lnum <= curbuf->b_ml.ml_line_count)
10041 	{
10042 	    /* existing line, replace it */
10043 	    if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10044 	    {
10045 		changed_bytes(lnum, 0);
10046 		if (lnum == curwin->w_cursor.lnum)
10047 		    check_cursor_col();
10048 		rettv->vval.v_number = 0;	/* OK */
10049 	    }
10050 	}
10051 	else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10052 	{
10053 	    /* lnum is one past the last line, append the line */
10054 	    ++added;
10055 	    if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10056 		rettv->vval.v_number = 0;	/* OK */
10057 	}
10058 
10059 	if (l == NULL)			/* only one string argument */
10060 	    break;
10061 	++lnum;
10062     }
10063 
10064     if (added > 0)
10065 	appended_lines_mark(lcount, added);
10066 }
10067 
10068 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv);
10069 
10070 /*
10071  * Used by "setqflist()" and "setloclist()" functions
10072  */
10073     static void
10074 set_qf_ll_list(
10075     win_T	*wp UNUSED,
10076     typval_T	*list_arg UNUSED,
10077     typval_T	*action_arg UNUSED,
10078     typval_T	*what_arg UNUSED,
10079     typval_T	*rettv)
10080 {
10081 #ifdef FEAT_QUICKFIX
10082     static char *e_invact = N_("E927: Invalid action: '%s'");
10083     char_u	*act;
10084     int		action = 0;
10085 #endif
10086 
10087     rettv->vval.v_number = -1;
10088 
10089 #ifdef FEAT_QUICKFIX
10090     if (list_arg->v_type != VAR_LIST)
10091 	EMSG(_(e_listreq));
10092     else
10093     {
10094 	list_T  *l = list_arg->vval.v_list;
10095 	dict_T	*d = NULL;
10096 	int	valid_dict = TRUE;
10097 
10098 	if (action_arg->v_type == VAR_STRING)
10099 	{
10100 	    act = get_tv_string_chk(action_arg);
10101 	    if (act == NULL)
10102 		return;		/* type error; errmsg already given */
10103 	    if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10104 		    act[1] == NUL)
10105 		action = *act;
10106 	    else
10107 		EMSG2(_(e_invact), act);
10108 	}
10109 	else if (action_arg->v_type == VAR_UNKNOWN)
10110 	    action = ' ';
10111 	else
10112 	    EMSG(_(e_stringreq));
10113 
10114 	if (action_arg->v_type != VAR_UNKNOWN
10115 		&& what_arg->v_type != VAR_UNKNOWN)
10116 	{
10117 	    if (what_arg->v_type == VAR_DICT)
10118 		d = what_arg->vval.v_dict;
10119 	    else
10120 	    {
10121 		EMSG(_(e_dictreq));
10122 		valid_dict = FALSE;
10123 	    }
10124 	}
10125 
10126 	if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
10127 	    (char_u *)(wp == NULL ? "setqflist()" : "setloclist()"), d) == OK)
10128 	    rettv->vval.v_number = 0;
10129     }
10130 #endif
10131 }
10132 
10133 /*
10134  * "setloclist()" function
10135  */
10136     static void
10137 f_setloclist(typval_T *argvars, typval_T *rettv)
10138 {
10139     win_T	*win;
10140 
10141     rettv->vval.v_number = -1;
10142 
10143     win = find_win_by_nr(&argvars[0], NULL);
10144     if (win != NULL)
10145 	set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
10146 }
10147 
10148 /*
10149  * "setmatches()" function
10150  */
10151     static void
10152 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10153 {
10154 #ifdef FEAT_SEARCH_EXTRA
10155     list_T	*l;
10156     listitem_T	*li;
10157     dict_T	*d;
10158     list_T	*s = NULL;
10159 
10160     rettv->vval.v_number = -1;
10161     if (argvars[0].v_type != VAR_LIST)
10162     {
10163 	EMSG(_(e_listreq));
10164 	return;
10165     }
10166     if ((l = argvars[0].vval.v_list) != NULL)
10167     {
10168 
10169 	/* To some extent make sure that we are dealing with a list from
10170 	 * "getmatches()". */
10171 	li = l->lv_first;
10172 	while (li != NULL)
10173 	{
10174 	    if (li->li_tv.v_type != VAR_DICT
10175 		    || (d = li->li_tv.vval.v_dict) == NULL)
10176 	    {
10177 		EMSG(_(e_invarg));
10178 		return;
10179 	    }
10180 	    if (!(dict_find(d, (char_u *)"group", -1) != NULL
10181 			&& (dict_find(d, (char_u *)"pattern", -1) != NULL
10182 			    || dict_find(d, (char_u *)"pos1", -1) != NULL)
10183 			&& dict_find(d, (char_u *)"priority", -1) != NULL
10184 			&& dict_find(d, (char_u *)"id", -1) != NULL))
10185 	    {
10186 		EMSG(_(e_invarg));
10187 		return;
10188 	    }
10189 	    li = li->li_next;
10190 	}
10191 
10192 	clear_matches(curwin);
10193 	li = l->lv_first;
10194 	while (li != NULL)
10195 	{
10196 	    int		i = 0;
10197 	    char_u	buf[5];
10198 	    dictitem_T  *di;
10199 	    char_u	*group;
10200 	    int		priority;
10201 	    int		id;
10202 	    char_u	*conceal;
10203 
10204 	    d = li->li_tv.vval.v_dict;
10205 	    if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10206 	    {
10207 		if (s == NULL)
10208 		{
10209 		    s = list_alloc();
10210 		    if (s == NULL)
10211 			return;
10212 		}
10213 
10214 		/* match from matchaddpos() */
10215 		for (i = 1; i < 9; i++)
10216 		{
10217 		    sprintf((char *)buf, (char *)"pos%d", i);
10218 		    if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10219 		    {
10220 			if (di->di_tv.v_type != VAR_LIST)
10221 			    return;
10222 
10223 			list_append_tv(s, &di->di_tv);
10224 			s->lv_refcount++;
10225 		    }
10226 		    else
10227 			break;
10228 		}
10229 	    }
10230 
10231 	    group = get_dict_string(d, (char_u *)"group", TRUE);
10232 	    priority = (int)get_dict_number(d, (char_u *)"priority");
10233 	    id = (int)get_dict_number(d, (char_u *)"id");
10234 	    conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
10235 			      ? get_dict_string(d, (char_u *)"conceal", TRUE)
10236 			      : NULL;
10237 	    if (i == 0)
10238 	    {
10239 		match_add(curwin, group,
10240 		    get_dict_string(d, (char_u *)"pattern", FALSE),
10241 		    priority, id, NULL, conceal);
10242 	    }
10243 	    else
10244 	    {
10245 		match_add(curwin, group, NULL, priority, id, s, conceal);
10246 		list_unref(s);
10247 		s = NULL;
10248 	    }
10249 	    vim_free(group);
10250 	    vim_free(conceal);
10251 
10252 	    li = li->li_next;
10253 	}
10254 	rettv->vval.v_number = 0;
10255     }
10256 #endif
10257 }
10258 
10259 /*
10260  * "setpos()" function
10261  */
10262     static void
10263 f_setpos(typval_T *argvars, typval_T *rettv)
10264 {
10265     pos_T	pos;
10266     int		fnum;
10267     char_u	*name;
10268     colnr_T	curswant = -1;
10269 
10270     rettv->vval.v_number = -1;
10271     name = get_tv_string_chk(argvars);
10272     if (name != NULL)
10273     {
10274 	if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10275 	{
10276 	    if (--pos.col < 0)
10277 		pos.col = 0;
10278 	    if (name[0] == '.' && name[1] == NUL)
10279 	    {
10280 		/* set cursor; "fnum" is ignored */
10281 		curwin->w_cursor = pos;
10282 		if (curswant >= 0)
10283 		{
10284 		    curwin->w_curswant = curswant - 1;
10285 		    curwin->w_set_curswant = FALSE;
10286 		}
10287 		check_cursor();
10288 		rettv->vval.v_number = 0;
10289 	    }
10290 	    else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10291 	    {
10292 		/* set mark */
10293 		if (setmark_pos(name[1], &pos, fnum) == OK)
10294 		    rettv->vval.v_number = 0;
10295 	    }
10296 	    else
10297 		EMSG(_(e_invarg));
10298 	}
10299     }
10300 }
10301 
10302 /*
10303  * "setqflist()" function
10304  */
10305     static void
10306 f_setqflist(typval_T *argvars, typval_T *rettv)
10307 {
10308     set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
10309 }
10310 
10311 /*
10312  * "setreg()" function
10313  */
10314     static void
10315 f_setreg(typval_T *argvars, typval_T *rettv)
10316 {
10317     int		regname;
10318     char_u	*strregname;
10319     char_u	*stropt;
10320     char_u	*strval;
10321     int		append;
10322     char_u	yank_type;
10323     long	block_len;
10324 
10325     block_len = -1;
10326     yank_type = MAUTO;
10327     append = FALSE;
10328 
10329     strregname = get_tv_string_chk(argvars);
10330     rettv->vval.v_number = 1;		/* FAIL is default */
10331 
10332     if (strregname == NULL)
10333 	return;		/* type error; errmsg already given */
10334     regname = *strregname;
10335     if (regname == 0 || regname == '@')
10336 	regname = '"';
10337 
10338     if (argvars[2].v_type != VAR_UNKNOWN)
10339     {
10340 	stropt = get_tv_string_chk(&argvars[2]);
10341 	if (stropt == NULL)
10342 	    return;		/* type error */
10343 	for (; *stropt != NUL; ++stropt)
10344 	    switch (*stropt)
10345 	    {
10346 		case 'a': case 'A':	/* append */
10347 		    append = TRUE;
10348 		    break;
10349 		case 'v': case 'c':	/* character-wise selection */
10350 		    yank_type = MCHAR;
10351 		    break;
10352 		case 'V': case 'l':	/* line-wise selection */
10353 		    yank_type = MLINE;
10354 		    break;
10355 		case 'b': case Ctrl_V:	/* block-wise selection */
10356 		    yank_type = MBLOCK;
10357 		    if (VIM_ISDIGIT(stropt[1]))
10358 		    {
10359 			++stropt;
10360 			block_len = getdigits(&stropt) - 1;
10361 			--stropt;
10362 		    }
10363 		    break;
10364 	    }
10365     }
10366 
10367     if (argvars[1].v_type == VAR_LIST)
10368     {
10369 	char_u		**lstval;
10370 	char_u		**allocval;
10371 	char_u		buf[NUMBUFLEN];
10372 	char_u		**curval;
10373 	char_u		**curallocval;
10374 	list_T		*ll = argvars[1].vval.v_list;
10375 	listitem_T	*li;
10376 	int		len;
10377 
10378 	/* If the list is NULL handle like an empty list. */
10379 	len = ll == NULL ? 0 : ll->lv_len;
10380 
10381 	/* First half: use for pointers to result lines; second half: use for
10382 	 * pointers to allocated copies. */
10383 	lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
10384 	if (lstval == NULL)
10385 	    return;
10386 	curval = lstval;
10387 	allocval = lstval + len + 2;
10388 	curallocval = allocval;
10389 
10390 	for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10391 							     li = li->li_next)
10392 	{
10393 	    strval = get_tv_string_buf_chk(&li->li_tv, buf);
10394 	    if (strval == NULL)
10395 		goto free_lstval;
10396 	    if (strval == buf)
10397 	    {
10398 		/* Need to make a copy, next get_tv_string_buf_chk() will
10399 		 * overwrite the string. */
10400 		strval = vim_strsave(buf);
10401 		if (strval == NULL)
10402 		    goto free_lstval;
10403 		*curallocval++ = strval;
10404 	    }
10405 	    *curval++ = strval;
10406 	}
10407 	*curval++ = NULL;
10408 
10409 	write_reg_contents_lst(regname, lstval, -1,
10410 						append, yank_type, block_len);
10411 free_lstval:
10412 	while (curallocval > allocval)
10413 	    vim_free(*--curallocval);
10414 	vim_free(lstval);
10415     }
10416     else
10417     {
10418 	strval = get_tv_string_chk(&argvars[1]);
10419 	if (strval == NULL)
10420 	    return;
10421 	write_reg_contents_ex(regname, strval, -1,
10422 						append, yank_type, block_len);
10423     }
10424     rettv->vval.v_number = 0;
10425 }
10426 
10427 /*
10428  * "settabvar()" function
10429  */
10430     static void
10431 f_settabvar(typval_T *argvars, typval_T *rettv)
10432 {
10433 #ifdef FEAT_WINDOWS
10434     tabpage_T	*save_curtab;
10435     tabpage_T	*tp;
10436 #endif
10437     char_u	*varname, *tabvarname;
10438     typval_T	*varp;
10439 
10440     rettv->vval.v_number = 0;
10441 
10442     if (check_restricted() || check_secure())
10443 	return;
10444 
10445 #ifdef FEAT_WINDOWS
10446     tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
10447 #endif
10448     varname = get_tv_string_chk(&argvars[1]);
10449     varp = &argvars[2];
10450 
10451     if (varname != NULL && varp != NULL
10452 #ifdef FEAT_WINDOWS
10453 	    && tp != NULL
10454 #endif
10455 	    )
10456     {
10457 #ifdef FEAT_WINDOWS
10458 	save_curtab = curtab;
10459 	goto_tabpage_tp(tp, FALSE, FALSE);
10460 #endif
10461 
10462 	tabvarname = alloc((unsigned)STRLEN(varname) + 3);
10463 	if (tabvarname != NULL)
10464 	{
10465 	    STRCPY(tabvarname, "t:");
10466 	    STRCPY(tabvarname + 2, varname);
10467 	    set_var(tabvarname, varp, TRUE);
10468 	    vim_free(tabvarname);
10469 	}
10470 
10471 #ifdef FEAT_WINDOWS
10472 	/* Restore current tabpage */
10473 	if (valid_tabpage(save_curtab))
10474 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
10475 #endif
10476     }
10477 }
10478 
10479 /*
10480  * "settabwinvar()" function
10481  */
10482     static void
10483 f_settabwinvar(typval_T *argvars, typval_T *rettv)
10484 {
10485     setwinvar(argvars, rettv, 1);
10486 }
10487 
10488 /*
10489  * "setwinvar()" function
10490  */
10491     static void
10492 f_setwinvar(typval_T *argvars, typval_T *rettv)
10493 {
10494     setwinvar(argvars, rettv, 0);
10495 }
10496 
10497 #ifdef FEAT_CRYPT
10498 /*
10499  * "sha256({string})" function
10500  */
10501     static void
10502 f_sha256(typval_T *argvars, typval_T *rettv)
10503 {
10504     char_u	*p;
10505 
10506     p = get_tv_string(&argvars[0]);
10507     rettv->vval.v_string = vim_strsave(
10508 				    sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10509     rettv->v_type = VAR_STRING;
10510 }
10511 #endif /* FEAT_CRYPT */
10512 
10513 /*
10514  * "shellescape({string})" function
10515  */
10516     static void
10517 f_shellescape(typval_T *argvars, typval_T *rettv)
10518 {
10519     int do_special = non_zero_arg(&argvars[1]);
10520 
10521     rettv->vval.v_string = vim_strsave_shellescape(
10522 			   get_tv_string(&argvars[0]), do_special, do_special);
10523     rettv->v_type = VAR_STRING;
10524 }
10525 
10526 /*
10527  * shiftwidth() function
10528  */
10529     static void
10530 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10531 {
10532     rettv->vval.v_number = get_sw_value(curbuf);
10533 }
10534 
10535 /*
10536  * "simplify()" function
10537  */
10538     static void
10539 f_simplify(typval_T *argvars, typval_T *rettv)
10540 {
10541     char_u	*p;
10542 
10543     p = get_tv_string(&argvars[0]);
10544     rettv->vval.v_string = vim_strsave(p);
10545     simplify_filename(rettv->vval.v_string);	/* simplify in place */
10546     rettv->v_type = VAR_STRING;
10547 }
10548 
10549 #ifdef FEAT_FLOAT
10550 /*
10551  * "sin()" function
10552  */
10553     static void
10554 f_sin(typval_T *argvars, typval_T *rettv)
10555 {
10556     float_T	f = 0.0;
10557 
10558     rettv->v_type = VAR_FLOAT;
10559     if (get_float_arg(argvars, &f) == OK)
10560 	rettv->vval.v_float = sin(f);
10561     else
10562 	rettv->vval.v_float = 0.0;
10563 }
10564 
10565 /*
10566  * "sinh()" function
10567  */
10568     static void
10569 f_sinh(typval_T *argvars, typval_T *rettv)
10570 {
10571     float_T	f = 0.0;
10572 
10573     rettv->v_type = VAR_FLOAT;
10574     if (get_float_arg(argvars, &f) == OK)
10575 	rettv->vval.v_float = sinh(f);
10576     else
10577 	rettv->vval.v_float = 0.0;
10578 }
10579 #endif
10580 
10581 static int
10582 #ifdef __BORLANDC__
10583     _RTLENTRYF
10584 #endif
10585 	item_compare(const void *s1, const void *s2);
10586 static int
10587 #ifdef __BORLANDC__
10588     _RTLENTRYF
10589 #endif
10590 	item_compare2(const void *s1, const void *s2);
10591 
10592 /* struct used in the array that's given to qsort() */
10593 typedef struct
10594 {
10595     listitem_T	*item;
10596     int		idx;
10597 } sortItem_T;
10598 
10599 /* struct storing information about current sort */
10600 typedef struct
10601 {
10602     int		item_compare_ic;
10603     int		item_compare_numeric;
10604     int		item_compare_numbers;
10605 #ifdef FEAT_FLOAT
10606     int		item_compare_float;
10607 #endif
10608     char_u	*item_compare_func;
10609     partial_T	*item_compare_partial;
10610     dict_T	*item_compare_selfdict;
10611     int		item_compare_func_err;
10612     int		item_compare_keep_zero;
10613 } sortinfo_T;
10614 static sortinfo_T	*sortinfo = NULL;
10615 static void	do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10616 #define ITEM_COMPARE_FAIL 999
10617 
10618 /*
10619  * Compare functions for f_sort() and f_uniq() below.
10620  */
10621     static int
10622 #ifdef __BORLANDC__
10623 _RTLENTRYF
10624 #endif
10625 item_compare(const void *s1, const void *s2)
10626 {
10627     sortItem_T  *si1, *si2;
10628     typval_T	*tv1, *tv2;
10629     char_u	*p1, *p2;
10630     char_u	*tofree1 = NULL, *tofree2 = NULL;
10631     int		res;
10632     char_u	numbuf1[NUMBUFLEN];
10633     char_u	numbuf2[NUMBUFLEN];
10634 
10635     si1 = (sortItem_T *)s1;
10636     si2 = (sortItem_T *)s2;
10637     tv1 = &si1->item->li_tv;
10638     tv2 = &si2->item->li_tv;
10639 
10640     if (sortinfo->item_compare_numbers)
10641     {
10642 	varnumber_T	v1 = get_tv_number(tv1);
10643 	varnumber_T	v2 = get_tv_number(tv2);
10644 
10645 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10646     }
10647 
10648 #ifdef FEAT_FLOAT
10649     if (sortinfo->item_compare_float)
10650     {
10651 	float_T	v1 = get_tv_float(tv1);
10652 	float_T	v2 = get_tv_float(tv2);
10653 
10654 	return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10655     }
10656 #endif
10657 
10658     /* tv2string() puts quotes around a string and allocates memory.  Don't do
10659      * that for string variables. Use a single quote when comparing with a
10660      * non-string to do what the docs promise. */
10661     if (tv1->v_type == VAR_STRING)
10662     {
10663 	if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10664 	    p1 = (char_u *)"'";
10665 	else
10666 	    p1 = tv1->vval.v_string;
10667     }
10668     else
10669 	p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10670     if (tv2->v_type == VAR_STRING)
10671     {
10672 	if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10673 	    p2 = (char_u *)"'";
10674 	else
10675 	    p2 = tv2->vval.v_string;
10676     }
10677     else
10678 	p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10679     if (p1 == NULL)
10680 	p1 = (char_u *)"";
10681     if (p2 == NULL)
10682 	p2 = (char_u *)"";
10683     if (!sortinfo->item_compare_numeric)
10684     {
10685 	if (sortinfo->item_compare_ic)
10686 	    res = STRICMP(p1, p2);
10687 	else
10688 	    res = STRCMP(p1, p2);
10689     }
10690     else
10691     {
10692 	double n1, n2;
10693 	n1 = strtod((char *)p1, (char **)&p1);
10694 	n2 = strtod((char *)p2, (char **)&p2);
10695 	res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10696     }
10697 
10698     /* When the result would be zero, compare the item indexes.  Makes the
10699      * sort stable. */
10700     if (res == 0 && !sortinfo->item_compare_keep_zero)
10701 	res = si1->idx > si2->idx ? 1 : -1;
10702 
10703     vim_free(tofree1);
10704     vim_free(tofree2);
10705     return res;
10706 }
10707 
10708     static int
10709 #ifdef __BORLANDC__
10710 _RTLENTRYF
10711 #endif
10712 item_compare2(const void *s1, const void *s2)
10713 {
10714     sortItem_T  *si1, *si2;
10715     int		res;
10716     typval_T	rettv;
10717     typval_T	argv[3];
10718     int		dummy;
10719     char_u	*func_name;
10720     partial_T	*partial = sortinfo->item_compare_partial;
10721 
10722     /* shortcut after failure in previous call; compare all items equal */
10723     if (sortinfo->item_compare_func_err)
10724 	return 0;
10725 
10726     si1 = (sortItem_T *)s1;
10727     si2 = (sortItem_T *)s2;
10728 
10729     if (partial == NULL)
10730 	func_name = sortinfo->item_compare_func;
10731     else
10732 	func_name = partial_name(partial);
10733 
10734     /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
10735      * in the copy without changing the original list items. */
10736     copy_tv(&si1->item->li_tv, &argv[0]);
10737     copy_tv(&si2->item->li_tv, &argv[1]);
10738 
10739     rettv.v_type = VAR_UNKNOWN;		/* clear_tv() uses this */
10740     res = call_func(func_name, (int)STRLEN(func_name),
10741 				 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
10742 				 partial, sortinfo->item_compare_selfdict);
10743     clear_tv(&argv[0]);
10744     clear_tv(&argv[1]);
10745 
10746     if (res == FAIL)
10747 	res = ITEM_COMPARE_FAIL;
10748     else
10749 	res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10750     if (sortinfo->item_compare_func_err)
10751 	res = ITEM_COMPARE_FAIL;  /* return value has wrong type */
10752     clear_tv(&rettv);
10753 
10754     /* When the result would be zero, compare the pointers themselves.  Makes
10755      * the sort stable. */
10756     if (res == 0 && !sortinfo->item_compare_keep_zero)
10757 	res = si1->idx > si2->idx ? 1 : -1;
10758 
10759     return res;
10760 }
10761 
10762 /*
10763  * "sort({list})" function
10764  */
10765     static void
10766 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10767 {
10768     list_T	*l;
10769     listitem_T	*li;
10770     sortItem_T	*ptrs;
10771     sortinfo_T	*old_sortinfo;
10772     sortinfo_T	info;
10773     long	len;
10774     long	i;
10775 
10776     /* Pointer to current info struct used in compare function. Save and
10777      * restore the current one for nested calls. */
10778     old_sortinfo = sortinfo;
10779     sortinfo = &info;
10780 
10781     if (argvars[0].v_type != VAR_LIST)
10782 	EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10783     else
10784     {
10785 	l = argvars[0].vval.v_list;
10786 	if (l == NULL || tv_check_lock(l->lv_lock,
10787 	     (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10788 									TRUE))
10789 	    goto theend;
10790 	rettv_list_set(rettv, l);
10791 
10792 	len = list_len(l);
10793 	if (len <= 1)
10794 	    goto theend;	/* short list sorts pretty quickly */
10795 
10796 	info.item_compare_ic = FALSE;
10797 	info.item_compare_numeric = FALSE;
10798 	info.item_compare_numbers = FALSE;
10799 #ifdef FEAT_FLOAT
10800 	info.item_compare_float = FALSE;
10801 #endif
10802 	info.item_compare_func = NULL;
10803 	info.item_compare_partial = NULL;
10804 	info.item_compare_selfdict = NULL;
10805 	if (argvars[1].v_type != VAR_UNKNOWN)
10806 	{
10807 	    /* optional second argument: {func} */
10808 	    if (argvars[1].v_type == VAR_FUNC)
10809 		info.item_compare_func = argvars[1].vval.v_string;
10810 	    else if (argvars[1].v_type == VAR_PARTIAL)
10811 		info.item_compare_partial = argvars[1].vval.v_partial;
10812 	    else
10813 	    {
10814 		int	    error = FALSE;
10815 
10816 		i = (long)get_tv_number_chk(&argvars[1], &error);
10817 		if (error)
10818 		    goto theend;	/* type error; errmsg already given */
10819 		if (i == 1)
10820 		    info.item_compare_ic = TRUE;
10821 		else if (argvars[1].v_type != VAR_NUMBER)
10822 		    info.item_compare_func = get_tv_string(&argvars[1]);
10823 		else if (i != 0)
10824 		{
10825 		    EMSG(_(e_invarg));
10826 		    goto theend;
10827 		}
10828 		if (info.item_compare_func != NULL)
10829 		{
10830 		    if (*info.item_compare_func == NUL)
10831 		    {
10832 			/* empty string means default sort */
10833 			info.item_compare_func = NULL;
10834 		    }
10835 		    else if (STRCMP(info.item_compare_func, "n") == 0)
10836 		    {
10837 			info.item_compare_func = NULL;
10838 			info.item_compare_numeric = TRUE;
10839 		    }
10840 		    else if (STRCMP(info.item_compare_func, "N") == 0)
10841 		    {
10842 			info.item_compare_func = NULL;
10843 			info.item_compare_numbers = TRUE;
10844 		    }
10845 #ifdef FEAT_FLOAT
10846 		    else if (STRCMP(info.item_compare_func, "f") == 0)
10847 		    {
10848 			info.item_compare_func = NULL;
10849 			info.item_compare_float = TRUE;
10850 		    }
10851 #endif
10852 		    else if (STRCMP(info.item_compare_func, "i") == 0)
10853 		    {
10854 			info.item_compare_func = NULL;
10855 			info.item_compare_ic = TRUE;
10856 		    }
10857 		}
10858 	    }
10859 
10860 	    if (argvars[2].v_type != VAR_UNKNOWN)
10861 	    {
10862 		/* optional third argument: {dict} */
10863 		if (argvars[2].v_type != VAR_DICT)
10864 		{
10865 		    EMSG(_(e_dictreq));
10866 		    goto theend;
10867 		}
10868 		info.item_compare_selfdict = argvars[2].vval.v_dict;
10869 	    }
10870 	}
10871 
10872 	/* Make an array with each entry pointing to an item in the List. */
10873 	ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10874 	if (ptrs == NULL)
10875 	    goto theend;
10876 
10877 	i = 0;
10878 	if (sort)
10879 	{
10880 	    /* sort(): ptrs will be the list to sort */
10881 	    for (li = l->lv_first; li != NULL; li = li->li_next)
10882 	    {
10883 		ptrs[i].item = li;
10884 		ptrs[i].idx = i;
10885 		++i;
10886 	    }
10887 
10888 	    info.item_compare_func_err = FALSE;
10889 	    info.item_compare_keep_zero = FALSE;
10890 	    /* test the compare function */
10891 	    if ((info.item_compare_func != NULL
10892 					 || info.item_compare_partial != NULL)
10893 		    && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10894 							 == ITEM_COMPARE_FAIL)
10895 		EMSG(_("E702: Sort compare function failed"));
10896 	    else
10897 	    {
10898 		/* Sort the array with item pointers. */
10899 		qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10900 		    info.item_compare_func == NULL
10901 					  && info.item_compare_partial == NULL
10902 					       ? item_compare : item_compare2);
10903 
10904 		if (!info.item_compare_func_err)
10905 		{
10906 		    /* Clear the List and append the items in sorted order. */
10907 		    l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10908 		    l->lv_len = 0;
10909 		    for (i = 0; i < len; ++i)
10910 			list_append(l, ptrs[i].item);
10911 		}
10912 	    }
10913 	}
10914 	else
10915 	{
10916 	    int	(*item_compare_func_ptr)(const void *, const void *);
10917 
10918 	    /* f_uniq(): ptrs will be a stack of items to remove */
10919 	    info.item_compare_func_err = FALSE;
10920 	    info.item_compare_keep_zero = TRUE;
10921 	    item_compare_func_ptr = info.item_compare_func != NULL
10922 					  || info.item_compare_partial != NULL
10923 					       ? item_compare2 : item_compare;
10924 
10925 	    for (li = l->lv_first; li != NULL && li->li_next != NULL;
10926 							     li = li->li_next)
10927 	    {
10928 		if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10929 									 == 0)
10930 		    ptrs[i++].item = li;
10931 		if (info.item_compare_func_err)
10932 		{
10933 		    EMSG(_("E882: Uniq compare function failed"));
10934 		    break;
10935 		}
10936 	    }
10937 
10938 	    if (!info.item_compare_func_err)
10939 	    {
10940 		while (--i >= 0)
10941 		{
10942 		    li = ptrs[i].item->li_next;
10943 		    ptrs[i].item->li_next = li->li_next;
10944 		    if (li->li_next != NULL)
10945 			li->li_next->li_prev = ptrs[i].item;
10946 		    else
10947 			l->lv_last = ptrs[i].item;
10948 		    list_fix_watch(l, li);
10949 		    listitem_free(li);
10950 		    l->lv_len--;
10951 		}
10952 	    }
10953 	}
10954 
10955 	vim_free(ptrs);
10956     }
10957 theend:
10958     sortinfo = old_sortinfo;
10959 }
10960 
10961 /*
10962  * "sort({list})" function
10963  */
10964     static void
10965 f_sort(typval_T *argvars, typval_T *rettv)
10966 {
10967     do_sort_uniq(argvars, rettv, TRUE);
10968 }
10969 
10970 /*
10971  * "uniq({list})" function
10972  */
10973     static void
10974 f_uniq(typval_T *argvars, typval_T *rettv)
10975 {
10976     do_sort_uniq(argvars, rettv, FALSE);
10977 }
10978 
10979 /*
10980  * "soundfold({word})" function
10981  */
10982     static void
10983 f_soundfold(typval_T *argvars, typval_T *rettv)
10984 {
10985     char_u	*s;
10986 
10987     rettv->v_type = VAR_STRING;
10988     s = get_tv_string(&argvars[0]);
10989 #ifdef FEAT_SPELL
10990     rettv->vval.v_string = eval_soundfold(s);
10991 #else
10992     rettv->vval.v_string = vim_strsave(s);
10993 #endif
10994 }
10995 
10996 /*
10997  * "spellbadword()" function
10998  */
10999     static void
11000 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11001 {
11002     char_u	*word = (char_u *)"";
11003     hlf_T	attr = HLF_COUNT;
11004     int		len = 0;
11005 
11006     if (rettv_list_alloc(rettv) == FAIL)
11007 	return;
11008 
11009 #ifdef FEAT_SPELL
11010     if (argvars[0].v_type == VAR_UNKNOWN)
11011     {
11012 	/* Find the start and length of the badly spelled word. */
11013 	len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11014 	if (len != 0)
11015 	    word = ml_get_cursor();
11016     }
11017     else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11018     {
11019 	char_u	*str = get_tv_string_chk(&argvars[0]);
11020 	int	capcol = -1;
11021 
11022 	if (str != NULL)
11023 	{
11024 	    /* Check the argument for spelling. */
11025 	    while (*str != NUL)
11026 	    {
11027 		len = spell_check(curwin, str, &attr, &capcol, FALSE);
11028 		if (attr != HLF_COUNT)
11029 		{
11030 		    word = str;
11031 		    break;
11032 		}
11033 		str += len;
11034 	    }
11035 	}
11036     }
11037 #endif
11038 
11039     list_append_string(rettv->vval.v_list, word, len);
11040     list_append_string(rettv->vval.v_list, (char_u *)(
11041 			attr == HLF_SPB ? "bad" :
11042 			attr == HLF_SPR ? "rare" :
11043 			attr == HLF_SPL ? "local" :
11044 			attr == HLF_SPC ? "caps" :
11045 			""), -1);
11046 }
11047 
11048 /*
11049  * "spellsuggest()" function
11050  */
11051     static void
11052 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11053 {
11054 #ifdef FEAT_SPELL
11055     char_u	*str;
11056     int		typeerr = FALSE;
11057     int		maxcount;
11058     garray_T	ga;
11059     int		i;
11060     listitem_T	*li;
11061     int		need_capital = FALSE;
11062 #endif
11063 
11064     if (rettv_list_alloc(rettv) == FAIL)
11065 	return;
11066 
11067 #ifdef FEAT_SPELL
11068     if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11069     {
11070 	str = get_tv_string(&argvars[0]);
11071 	if (argvars[1].v_type != VAR_UNKNOWN)
11072 	{
11073 	    maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
11074 	    if (maxcount <= 0)
11075 		return;
11076 	    if (argvars[2].v_type != VAR_UNKNOWN)
11077 	    {
11078 		need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
11079 		if (typeerr)
11080 		    return;
11081 	    }
11082 	}
11083 	else
11084 	    maxcount = 25;
11085 
11086 	spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11087 
11088 	for (i = 0; i < ga.ga_len; ++i)
11089 	{
11090 	    str = ((char_u **)ga.ga_data)[i];
11091 
11092 	    li = listitem_alloc();
11093 	    if (li == NULL)
11094 		vim_free(str);
11095 	    else
11096 	    {
11097 		li->li_tv.v_type = VAR_STRING;
11098 		li->li_tv.v_lock = 0;
11099 		li->li_tv.vval.v_string = str;
11100 		list_append(rettv->vval.v_list, li);
11101 	    }
11102 	}
11103 	ga_clear(&ga);
11104     }
11105 #endif
11106 }
11107 
11108     static void
11109 f_split(typval_T *argvars, typval_T *rettv)
11110 {
11111     char_u	*str;
11112     char_u	*end;
11113     char_u	*pat = NULL;
11114     regmatch_T	regmatch;
11115     char_u	patbuf[NUMBUFLEN];
11116     char_u	*save_cpo;
11117     int		match;
11118     colnr_T	col = 0;
11119     int		keepempty = FALSE;
11120     int		typeerr = FALSE;
11121 
11122     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11123     save_cpo = p_cpo;
11124     p_cpo = (char_u *)"";
11125 
11126     str = get_tv_string(&argvars[0]);
11127     if (argvars[1].v_type != VAR_UNKNOWN)
11128     {
11129 	pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11130 	if (pat == NULL)
11131 	    typeerr = TRUE;
11132 	if (argvars[2].v_type != VAR_UNKNOWN)
11133 	    keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
11134     }
11135     if (pat == NULL || *pat == NUL)
11136 	pat = (char_u *)"[\\x01- ]\\+";
11137 
11138     if (rettv_list_alloc(rettv) == FAIL)
11139 	return;
11140     if (typeerr)
11141 	return;
11142 
11143     regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11144     if (regmatch.regprog != NULL)
11145     {
11146 	regmatch.rm_ic = FALSE;
11147 	while (*str != NUL || keepempty)
11148 	{
11149 	    if (*str == NUL)
11150 		match = FALSE;	/* empty item at the end */
11151 	    else
11152 		match = vim_regexec_nl(&regmatch, str, col);
11153 	    if (match)
11154 		end = regmatch.startp[0];
11155 	    else
11156 		end = str + STRLEN(str);
11157 	    if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11158 			   && *str != NUL && match && end < regmatch.endp[0]))
11159 	    {
11160 		if (list_append_string(rettv->vval.v_list, str,
11161 						    (int)(end - str)) == FAIL)
11162 		    break;
11163 	    }
11164 	    if (!match)
11165 		break;
11166 	    /* Advance to just after the match. */
11167 	    if (regmatch.endp[0] > str)
11168 		col = 0;
11169 	    else
11170 	    {
11171 		/* Don't get stuck at the same match. */
11172 #ifdef FEAT_MBYTE
11173 		col = (*mb_ptr2len)(regmatch.endp[0]);
11174 #else
11175 		col = 1;
11176 #endif
11177 	    }
11178 	    str = regmatch.endp[0];
11179 	}
11180 
11181 	vim_regfree(regmatch.regprog);
11182     }
11183 
11184     p_cpo = save_cpo;
11185 }
11186 
11187 #ifdef FEAT_FLOAT
11188 /*
11189  * "sqrt()" function
11190  */
11191     static void
11192 f_sqrt(typval_T *argvars, typval_T *rettv)
11193 {
11194     float_T	f = 0.0;
11195 
11196     rettv->v_type = VAR_FLOAT;
11197     if (get_float_arg(argvars, &f) == OK)
11198 	rettv->vval.v_float = sqrt(f);
11199     else
11200 	rettv->vval.v_float = 0.0;
11201 }
11202 
11203 /*
11204  * "str2float()" function
11205  */
11206     static void
11207 f_str2float(typval_T *argvars, typval_T *rettv)
11208 {
11209     char_u *p = skipwhite(get_tv_string(&argvars[0]));
11210     int     isneg = (*p == '-');
11211 
11212     if (*p == '+' || *p == '-')
11213 	p = skipwhite(p + 1);
11214     (void)string2float(p, &rettv->vval.v_float);
11215     if (isneg)
11216 	rettv->vval.v_float *= -1;
11217     rettv->v_type = VAR_FLOAT;
11218 }
11219 #endif
11220 
11221 /*
11222  * "str2nr()" function
11223  */
11224     static void
11225 f_str2nr(typval_T *argvars, typval_T *rettv)
11226 {
11227     int		base = 10;
11228     char_u	*p;
11229     varnumber_T	n;
11230     int		what;
11231     int		isneg;
11232 
11233     if (argvars[1].v_type != VAR_UNKNOWN)
11234     {
11235 	base = (int)get_tv_number(&argvars[1]);
11236 	if (base != 2 && base != 8 && base != 10 && base != 16)
11237 	{
11238 	    EMSG(_(e_invarg));
11239 	    return;
11240 	}
11241     }
11242 
11243     p = skipwhite(get_tv_string(&argvars[0]));
11244     isneg = (*p == '-');
11245     if (*p == '+' || *p == '-')
11246 	p = skipwhite(p + 1);
11247     switch (base)
11248     {
11249 	case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11250 	case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11251 	case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11252 	default: what = 0;
11253     }
11254     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
11255     if (isneg)
11256 	rettv->vval.v_number = -n;
11257     else
11258 	rettv->vval.v_number = n;
11259 
11260 }
11261 
11262 #ifdef HAVE_STRFTIME
11263 /*
11264  * "strftime({format}[, {time}])" function
11265  */
11266     static void
11267 f_strftime(typval_T *argvars, typval_T *rettv)
11268 {
11269     char_u	result_buf[256];
11270     struct tm	*curtime;
11271     time_t	seconds;
11272     char_u	*p;
11273 
11274     rettv->v_type = VAR_STRING;
11275 
11276     p = get_tv_string(&argvars[0]);
11277     if (argvars[1].v_type == VAR_UNKNOWN)
11278 	seconds = time(NULL);
11279     else
11280 	seconds = (time_t)get_tv_number(&argvars[1]);
11281     curtime = localtime(&seconds);
11282     /* MSVC returns NULL for an invalid value of seconds. */
11283     if (curtime == NULL)
11284 	rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11285     else
11286     {
11287 # ifdef FEAT_MBYTE
11288 	vimconv_T   conv;
11289 	char_u	    *enc;
11290 
11291 	conv.vc_type = CONV_NONE;
11292 	enc = enc_locale();
11293 	convert_setup(&conv, p_enc, enc);
11294 	if (conv.vc_type != CONV_NONE)
11295 	    p = string_convert(&conv, p, NULL);
11296 # endif
11297 	if (p != NULL)
11298 	    (void)strftime((char *)result_buf, sizeof(result_buf),
11299 							  (char *)p, curtime);
11300 	else
11301 	    result_buf[0] = NUL;
11302 
11303 # ifdef FEAT_MBYTE
11304 	if (conv.vc_type != CONV_NONE)
11305 	    vim_free(p);
11306 	convert_setup(&conv, enc, p_enc);
11307 	if (conv.vc_type != CONV_NONE)
11308 	    rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11309 	else
11310 # endif
11311 	    rettv->vval.v_string = vim_strsave(result_buf);
11312 
11313 # ifdef FEAT_MBYTE
11314 	/* Release conversion descriptors */
11315 	convert_setup(&conv, NULL, NULL);
11316 	vim_free(enc);
11317 # endif
11318     }
11319 }
11320 #endif
11321 
11322 /*
11323  * "strgetchar()" function
11324  */
11325     static void
11326 f_strgetchar(typval_T *argvars, typval_T *rettv)
11327 {
11328     char_u	*str;
11329     int		len;
11330     int		error = FALSE;
11331     int		charidx;
11332 
11333     rettv->vval.v_number = -1;
11334     str = get_tv_string_chk(&argvars[0]);
11335     if (str == NULL)
11336 	return;
11337     len = (int)STRLEN(str);
11338     charidx = (int)get_tv_number_chk(&argvars[1], &error);
11339     if (error)
11340 	return;
11341 #ifdef FEAT_MBYTE
11342     {
11343 	int	byteidx = 0;
11344 
11345 	while (charidx >= 0 && byteidx < len)
11346 	{
11347 	    if (charidx == 0)
11348 	    {
11349 		rettv->vval.v_number = mb_ptr2char(str + byteidx);
11350 		break;
11351 	    }
11352 	    --charidx;
11353 	    byteidx += MB_CPTR2LEN(str + byteidx);
11354 	}
11355     }
11356 #else
11357     if (charidx < len)
11358 	rettv->vval.v_number = str[charidx];
11359 #endif
11360 }
11361 
11362 /*
11363  * "stridx()" function
11364  */
11365     static void
11366 f_stridx(typval_T *argvars, typval_T *rettv)
11367 {
11368     char_u	buf[NUMBUFLEN];
11369     char_u	*needle;
11370     char_u	*haystack;
11371     char_u	*save_haystack;
11372     char_u	*pos;
11373     int		start_idx;
11374 
11375     needle = get_tv_string_chk(&argvars[1]);
11376     save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
11377     rettv->vval.v_number = -1;
11378     if (needle == NULL || haystack == NULL)
11379 	return;		/* type error; errmsg already given */
11380 
11381     if (argvars[2].v_type != VAR_UNKNOWN)
11382     {
11383 	int	    error = FALSE;
11384 
11385 	start_idx = (int)get_tv_number_chk(&argvars[2], &error);
11386 	if (error || start_idx >= (int)STRLEN(haystack))
11387 	    return;
11388 	if (start_idx >= 0)
11389 	    haystack += start_idx;
11390     }
11391 
11392     pos	= (char_u *)strstr((char *)haystack, (char *)needle);
11393     if (pos != NULL)
11394 	rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11395 }
11396 
11397 /*
11398  * "string()" function
11399  */
11400     static void
11401 f_string(typval_T *argvars, typval_T *rettv)
11402 {
11403     char_u	*tofree;
11404     char_u	numbuf[NUMBUFLEN];
11405 
11406     rettv->v_type = VAR_STRING;
11407     rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11408 								get_copyID());
11409     /* Make a copy if we have a value but it's not in allocated memory. */
11410     if (rettv->vval.v_string != NULL && tofree == NULL)
11411 	rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11412 }
11413 
11414 /*
11415  * "strlen()" function
11416  */
11417     static void
11418 f_strlen(typval_T *argvars, typval_T *rettv)
11419 {
11420     rettv->vval.v_number = (varnumber_T)(STRLEN(
11421 					      get_tv_string(&argvars[0])));
11422 }
11423 
11424 /*
11425  * "strchars()" function
11426  */
11427     static void
11428 f_strchars(typval_T *argvars, typval_T *rettv)
11429 {
11430     char_u		*s = get_tv_string(&argvars[0]);
11431     int			skipcc = 0;
11432 #ifdef FEAT_MBYTE
11433     varnumber_T		len = 0;
11434     int			(*func_mb_ptr2char_adv)(char_u **pp);
11435 #endif
11436 
11437     if (argvars[1].v_type != VAR_UNKNOWN)
11438 	skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
11439     if (skipcc < 0 || skipcc > 1)
11440 	EMSG(_(e_invarg));
11441     else
11442     {
11443 #ifdef FEAT_MBYTE
11444 	func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11445 	while (*s != NUL)
11446 	{
11447 	    func_mb_ptr2char_adv(&s);
11448 	    ++len;
11449 	}
11450 	rettv->vval.v_number = len;
11451 #else
11452 	rettv->vval.v_number = (varnumber_T)(STRLEN(s));
11453 #endif
11454     }
11455 }
11456 
11457 /*
11458  * "strdisplaywidth()" function
11459  */
11460     static void
11461 f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11462 {
11463     char_u	*s = get_tv_string(&argvars[0]);
11464     int		col = 0;
11465 
11466     if (argvars[1].v_type != VAR_UNKNOWN)
11467 	col = (int)get_tv_number(&argvars[1]);
11468 
11469     rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11470 }
11471 
11472 /*
11473  * "strwidth()" function
11474  */
11475     static void
11476 f_strwidth(typval_T *argvars, typval_T *rettv)
11477 {
11478     char_u	*s = get_tv_string(&argvars[0]);
11479 
11480     rettv->vval.v_number = (varnumber_T)(
11481 #ifdef FEAT_MBYTE
11482 	    mb_string2cells(s, -1)
11483 #else
11484 	    STRLEN(s)
11485 #endif
11486 	    );
11487 }
11488 
11489 /*
11490  * "strcharpart()" function
11491  */
11492     static void
11493 f_strcharpart(typval_T *argvars, typval_T *rettv)
11494 {
11495 #ifdef FEAT_MBYTE
11496     char_u	*p;
11497     int		nchar;
11498     int		nbyte = 0;
11499     int		charlen;
11500     int		len = 0;
11501     int		slen;
11502     int		error = FALSE;
11503 
11504     p = get_tv_string(&argvars[0]);
11505     slen = (int)STRLEN(p);
11506 
11507     nchar = (int)get_tv_number_chk(&argvars[1], &error);
11508     if (!error)
11509     {
11510 	if (nchar > 0)
11511 	    while (nchar > 0 && nbyte < slen)
11512 	    {
11513 		nbyte += MB_CPTR2LEN(p + nbyte);
11514 		--nchar;
11515 	    }
11516 	else
11517 	    nbyte = nchar;
11518 	if (argvars[2].v_type != VAR_UNKNOWN)
11519 	{
11520 	    charlen = (int)get_tv_number(&argvars[2]);
11521 	    while (charlen > 0 && nbyte + len < slen)
11522 	    {
11523 		int off = nbyte + len;
11524 
11525 		if (off < 0)
11526 		    len += 1;
11527 		else
11528 		    len += MB_CPTR2LEN(p + off);
11529 		--charlen;
11530 	    }
11531 	}
11532 	else
11533 	    len = slen - nbyte;    /* default: all bytes that are available. */
11534     }
11535 
11536     /*
11537      * Only return the overlap between the specified part and the actual
11538      * string.
11539      */
11540     if (nbyte < 0)
11541     {
11542 	len += nbyte;
11543 	nbyte = 0;
11544     }
11545     else if (nbyte > slen)
11546 	nbyte = slen;
11547     if (len < 0)
11548 	len = 0;
11549     else if (nbyte + len > slen)
11550 	len = slen - nbyte;
11551 
11552     rettv->v_type = VAR_STRING;
11553     rettv->vval.v_string = vim_strnsave(p + nbyte, len);
11554 #else
11555     f_strpart(argvars, rettv);
11556 #endif
11557 }
11558 
11559 /*
11560  * "strpart()" function
11561  */
11562     static void
11563 f_strpart(typval_T *argvars, typval_T *rettv)
11564 {
11565     char_u	*p;
11566     int		n;
11567     int		len;
11568     int		slen;
11569     int		error = FALSE;
11570 
11571     p = get_tv_string(&argvars[0]);
11572     slen = (int)STRLEN(p);
11573 
11574     n = (int)get_tv_number_chk(&argvars[1], &error);
11575     if (error)
11576 	len = 0;
11577     else if (argvars[2].v_type != VAR_UNKNOWN)
11578 	len = (int)get_tv_number(&argvars[2]);
11579     else
11580 	len = slen - n;	    /* default len: all bytes that are available. */
11581 
11582     /*
11583      * Only return the overlap between the specified part and the actual
11584      * string.
11585      */
11586     if (n < 0)
11587     {
11588 	len += n;
11589 	n = 0;
11590     }
11591     else if (n > slen)
11592 	n = slen;
11593     if (len < 0)
11594 	len = 0;
11595     else if (n + len > slen)
11596 	len = slen - n;
11597 
11598     rettv->v_type = VAR_STRING;
11599     rettv->vval.v_string = vim_strnsave(p + n, len);
11600 }
11601 
11602 /*
11603  * "strridx()" function
11604  */
11605     static void
11606 f_strridx(typval_T *argvars, typval_T *rettv)
11607 {
11608     char_u	buf[NUMBUFLEN];
11609     char_u	*needle;
11610     char_u	*haystack;
11611     char_u	*rest;
11612     char_u	*lastmatch = NULL;
11613     int		haystack_len, end_idx;
11614 
11615     needle = get_tv_string_chk(&argvars[1]);
11616     haystack = get_tv_string_buf_chk(&argvars[0], buf);
11617 
11618     rettv->vval.v_number = -1;
11619     if (needle == NULL || haystack == NULL)
11620 	return;		/* type error; errmsg already given */
11621 
11622     haystack_len = (int)STRLEN(haystack);
11623     if (argvars[2].v_type != VAR_UNKNOWN)
11624     {
11625 	/* Third argument: upper limit for index */
11626 	end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11627 	if (end_idx < 0)
11628 	    return;	/* can never find a match */
11629     }
11630     else
11631 	end_idx = haystack_len;
11632 
11633     if (*needle == NUL)
11634     {
11635 	/* Empty string matches past the end. */
11636 	lastmatch = haystack + end_idx;
11637     }
11638     else
11639     {
11640 	for (rest = haystack; *rest != '\0'; ++rest)
11641 	{
11642 	    rest = (char_u *)strstr((char *)rest, (char *)needle);
11643 	    if (rest == NULL || rest > haystack + end_idx)
11644 		break;
11645 	    lastmatch = rest;
11646 	}
11647     }
11648 
11649     if (lastmatch == NULL)
11650 	rettv->vval.v_number = -1;
11651     else
11652 	rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11653 }
11654 
11655 /*
11656  * "strtrans()" function
11657  */
11658     static void
11659 f_strtrans(typval_T *argvars, typval_T *rettv)
11660 {
11661     rettv->v_type = VAR_STRING;
11662     rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11663 }
11664 
11665 /*
11666  * "submatch()" function
11667  */
11668     static void
11669 f_submatch(typval_T *argvars, typval_T *rettv)
11670 {
11671     int		error = FALSE;
11672     int		no;
11673     int		retList = 0;
11674 
11675     no = (int)get_tv_number_chk(&argvars[0], &error);
11676     if (error)
11677 	return;
11678     if (no < 0 || no >= NSUBEXP)
11679     {
11680 	EMSGN(_("E935: invalid submatch number: %d"), no);
11681 	return;
11682     }
11683     if (argvars[1].v_type != VAR_UNKNOWN)
11684 	retList = (int)get_tv_number_chk(&argvars[1], &error);
11685     if (error)
11686 	return;
11687 
11688     if (retList == 0)
11689     {
11690 	rettv->v_type = VAR_STRING;
11691 	rettv->vval.v_string = reg_submatch(no);
11692     }
11693     else
11694     {
11695 	rettv->v_type = VAR_LIST;
11696 	rettv->vval.v_list = reg_submatch_list(no);
11697     }
11698 }
11699 
11700 /*
11701  * "substitute()" function
11702  */
11703     static void
11704 f_substitute(typval_T *argvars, typval_T *rettv)
11705 {
11706     char_u	patbuf[NUMBUFLEN];
11707     char_u	subbuf[NUMBUFLEN];
11708     char_u	flagsbuf[NUMBUFLEN];
11709 
11710     char_u	*str = get_tv_string_chk(&argvars[0]);
11711     char_u	*pat = get_tv_string_buf_chk(&argvars[1], patbuf);
11712     char_u	*sub = NULL;
11713     typval_T	*expr = NULL;
11714     char_u	*flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11715 
11716     if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11717 	expr = &argvars[2];
11718     else
11719 	sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11720 
11721     rettv->v_type = VAR_STRING;
11722     if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11723 								|| flg == NULL)
11724 	rettv->vval.v_string = NULL;
11725     else
11726 	rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
11727 }
11728 
11729 /*
11730  * "synID(lnum, col, trans)" function
11731  */
11732     static void
11733 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11734 {
11735     int		id = 0;
11736 #ifdef FEAT_SYN_HL
11737     linenr_T	lnum;
11738     colnr_T	col;
11739     int		trans;
11740     int		transerr = FALSE;
11741 
11742     lnum = get_tv_lnum(argvars);		/* -1 on type error */
11743     col = (linenr_T)get_tv_number(&argvars[1]) - 1;	/* -1 on type error */
11744     trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11745 
11746     if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11747 	    && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11748 	id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11749 #endif
11750 
11751     rettv->vval.v_number = id;
11752 }
11753 
11754 /*
11755  * "synIDattr(id, what [, mode])" function
11756  */
11757     static void
11758 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11759 {
11760     char_u	*p = NULL;
11761 #ifdef FEAT_SYN_HL
11762     int		id;
11763     char_u	*what;
11764     char_u	*mode;
11765     char_u	modebuf[NUMBUFLEN];
11766     int		modec;
11767 
11768     id = (int)get_tv_number(&argvars[0]);
11769     what = get_tv_string(&argvars[1]);
11770     if (argvars[2].v_type != VAR_UNKNOWN)
11771     {
11772 	mode = get_tv_string_buf(&argvars[2], modebuf);
11773 	modec = TOLOWER_ASC(mode[0]);
11774 	if (modec != 't' && modec != 'c' && modec != 'g')
11775 	    modec = 0;	/* replace invalid with current */
11776     }
11777     else
11778     {
11779 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11780 	if (USE_24BIT)
11781 	    modec = 'g';
11782 	else
11783 #endif
11784 	    if (t_colors > 1)
11785 	    modec = 'c';
11786 	else
11787 	    modec = 't';
11788     }
11789 
11790 
11791     switch (TOLOWER_ASC(what[0]))
11792     {
11793 	case 'b':
11794 		if (TOLOWER_ASC(what[1]) == 'g')	/* bg[#] */
11795 		    p = highlight_color(id, what, modec);
11796 		else					/* bold */
11797 		    p = highlight_has_attr(id, HL_BOLD, modec);
11798 		break;
11799 
11800 	case 'f':					/* fg[#] or font */
11801 		p = highlight_color(id, what, modec);
11802 		break;
11803 
11804 	case 'i':
11805 		if (TOLOWER_ASC(what[1]) == 'n')	/* inverse */
11806 		    p = highlight_has_attr(id, HL_INVERSE, modec);
11807 		else					/* italic */
11808 		    p = highlight_has_attr(id, HL_ITALIC, modec);
11809 		break;
11810 
11811 	case 'n':					/* name */
11812 		p = get_highlight_name_ext(NULL, id - 1, FALSE);
11813 		break;
11814 
11815 	case 'r':					/* reverse */
11816 		p = highlight_has_attr(id, HL_INVERSE, modec);
11817 		break;
11818 
11819 	case 's':
11820 		if (TOLOWER_ASC(what[1]) == 'p')	/* sp[#] */
11821 		    p = highlight_color(id, what, modec);
11822 		else					/* standout */
11823 		    p = highlight_has_attr(id, HL_STANDOUT, modec);
11824 		break;
11825 
11826 	case 'u':
11827 		if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11828 							/* underline */
11829 		    p = highlight_has_attr(id, HL_UNDERLINE, modec);
11830 		else
11831 							/* undercurl */
11832 		    p = highlight_has_attr(id, HL_UNDERCURL, modec);
11833 		break;
11834     }
11835 
11836     if (p != NULL)
11837 	p = vim_strsave(p);
11838 #endif
11839     rettv->v_type = VAR_STRING;
11840     rettv->vval.v_string = p;
11841 }
11842 
11843 /*
11844  * "synIDtrans(id)" function
11845  */
11846     static void
11847 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11848 {
11849     int		id;
11850 
11851 #ifdef FEAT_SYN_HL
11852     id = (int)get_tv_number(&argvars[0]);
11853 
11854     if (id > 0)
11855 	id = syn_get_final_id(id);
11856     else
11857 #endif
11858 	id = 0;
11859 
11860     rettv->vval.v_number = id;
11861 }
11862 
11863 /*
11864  * "synconcealed(lnum, col)" function
11865  */
11866     static void
11867 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11868 {
11869 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11870     linenr_T	lnum;
11871     colnr_T	col;
11872     int		syntax_flags = 0;
11873     int		cchar;
11874     int		matchid = 0;
11875     char_u	str[NUMBUFLEN];
11876 #endif
11877 
11878     rettv_list_set(rettv, NULL);
11879 
11880 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11881     lnum = get_tv_lnum(argvars);		/* -1 on type error */
11882     col = (colnr_T)get_tv_number(&argvars[1]) - 1;	/* -1 on type error */
11883 
11884     vim_memset(str, NUL, sizeof(str));
11885 
11886     if (rettv_list_alloc(rettv) != FAIL)
11887     {
11888 	if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11889 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11890 	    && curwin->w_p_cole > 0)
11891 	{
11892 	    (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11893 	    syntax_flags = get_syntax_info(&matchid);
11894 
11895 	    /* get the conceal character */
11896 	    if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11897 	    {
11898 		cchar = syn_get_sub_char();
11899 		if (cchar == NUL && curwin->w_p_cole == 1)
11900 		    cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
11901 		if (cchar != NUL)
11902 		{
11903 # ifdef FEAT_MBYTE
11904 		    if (has_mbyte)
11905 			(*mb_char2bytes)(cchar, str);
11906 		    else
11907 # endif
11908 			str[0] = cchar;
11909 		}
11910 	    }
11911 	}
11912 
11913 	list_append_number(rettv->vval.v_list,
11914 					    (syntax_flags & HL_CONCEAL) != 0);
11915 	/* -1 to auto-determine strlen */
11916 	list_append_string(rettv->vval.v_list, str, -1);
11917 	list_append_number(rettv->vval.v_list, matchid);
11918     }
11919 #endif
11920 }
11921 
11922 /*
11923  * "synstack(lnum, col)" function
11924  */
11925     static void
11926 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11927 {
11928 #ifdef FEAT_SYN_HL
11929     linenr_T	lnum;
11930     colnr_T	col;
11931     int		i;
11932     int		id;
11933 #endif
11934 
11935     rettv_list_set(rettv, NULL);
11936 
11937 #ifdef FEAT_SYN_HL
11938     lnum = get_tv_lnum(argvars);		/* -1 on type error */
11939     col = (colnr_T)get_tv_number(&argvars[1]) - 1;	/* -1 on type error */
11940 
11941     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11942 	    && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11943 	    && rettv_list_alloc(rettv) != FAIL)
11944     {
11945 	(void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11946 	for (i = 0; ; ++i)
11947 	{
11948 	    id = syn_get_stack_item(i);
11949 	    if (id < 0)
11950 		break;
11951 	    if (list_append_number(rettv->vval.v_list, id) == FAIL)
11952 		break;
11953 	}
11954     }
11955 #endif
11956 }
11957 
11958     static void
11959 get_cmd_output_as_rettv(
11960     typval_T	*argvars,
11961     typval_T	*rettv,
11962     int		retlist)
11963 {
11964     char_u	*res = NULL;
11965     char_u	*p;
11966     char_u	*infile = NULL;
11967     int		err = FALSE;
11968     FILE	*fd;
11969     list_T	*list = NULL;
11970     int		flags = SHELL_SILENT;
11971 
11972     rettv->v_type = VAR_STRING;
11973     rettv->vval.v_string = NULL;
11974     if (check_restricted() || check_secure())
11975 	goto errret;
11976 
11977     if (argvars[1].v_type != VAR_UNKNOWN)
11978     {
11979 	/*
11980 	 * Write the text to a temp file, to be used for input of the shell
11981 	 * command.
11982 	 */
11983 	if ((infile = vim_tempname('i', TRUE)) == NULL)
11984 	{
11985 	    EMSG(_(e_notmp));
11986 	    goto errret;
11987 	}
11988 
11989 	fd = mch_fopen((char *)infile, WRITEBIN);
11990 	if (fd == NULL)
11991 	{
11992 	    EMSG2(_(e_notopen), infile);
11993 	    goto errret;
11994 	}
11995 	if (argvars[1].v_type == VAR_NUMBER)
11996 	{
11997 	    linenr_T	lnum;
11998 	    buf_T	*buf;
11999 
12000 	    buf = buflist_findnr(argvars[1].vval.v_number);
12001 	    if (buf == NULL)
12002 	    {
12003 		EMSGN(_(e_nobufnr), argvars[1].vval.v_number);
12004 		fclose(fd);
12005 		goto errret;
12006 	    }
12007 
12008 	    for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12009 	    {
12010 		for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12011 		    if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12012 		    {
12013 			err = TRUE;
12014 			break;
12015 		    }
12016 		if (putc(NL, fd) == EOF)
12017 		{
12018 		    err = TRUE;
12019 		    break;
12020 		}
12021 	    }
12022 	}
12023 	else if (argvars[1].v_type == VAR_LIST)
12024 	{
12025 	    if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12026 		err = TRUE;
12027 	}
12028 	else
12029 	{
12030 	    size_t	len;
12031 	    char_u	buf[NUMBUFLEN];
12032 
12033 	    p = get_tv_string_buf_chk(&argvars[1], buf);
12034 	    if (p == NULL)
12035 	    {
12036 		fclose(fd);
12037 		goto errret;		/* type error; errmsg already given */
12038 	    }
12039 	    len = STRLEN(p);
12040 	    if (len > 0 && fwrite(p, len, 1, fd) != 1)
12041 		err = TRUE;
12042 	}
12043 	if (fclose(fd) != 0)
12044 	    err = TRUE;
12045 	if (err)
12046 	{
12047 	    EMSG(_("E677: Error writing temp file"));
12048 	    goto errret;
12049 	}
12050     }
12051 
12052     /* Omit SHELL_COOKED when invoked with ":silent".  Avoids that the shell
12053      * echoes typeahead, that messes up the display. */
12054     if (!msg_silent)
12055 	flags += SHELL_COOKED;
12056 
12057     if (retlist)
12058     {
12059 	int		len;
12060 	listitem_T	*li;
12061 	char_u		*s = NULL;
12062 	char_u		*start;
12063 	char_u		*end;
12064 	int		i;
12065 
12066 	res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
12067 	if (res == NULL)
12068 	    goto errret;
12069 
12070 	list = list_alloc();
12071 	if (list == NULL)
12072 	    goto errret;
12073 
12074 	for (i = 0; i < len; ++i)
12075 	{
12076 	    start = res + i;
12077 	    while (i < len && res[i] != NL)
12078 		++i;
12079 	    end = res + i;
12080 
12081 	    s = alloc((unsigned)(end - start + 1));
12082 	    if (s == NULL)
12083 		goto errret;
12084 
12085 	    for (p = s; start < end; ++p, ++start)
12086 		*p = *start == NUL ? NL : *start;
12087 	    *p = NUL;
12088 
12089 	    li = listitem_alloc();
12090 	    if (li == NULL)
12091 	    {
12092 		vim_free(s);
12093 		goto errret;
12094 	    }
12095 	    li->li_tv.v_type = VAR_STRING;
12096 	    li->li_tv.v_lock = 0;
12097 	    li->li_tv.vval.v_string = s;
12098 	    list_append(list, li);
12099 	}
12100 
12101 	rettv_list_set(rettv, list);
12102 	list = NULL;
12103     }
12104     else
12105     {
12106 	res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
12107 #ifdef USE_CR
12108 	/* translate <CR> into <NL> */
12109 	if (res != NULL)
12110 	{
12111 	    char_u	*s;
12112 
12113 	    for (s = res; *s; ++s)
12114 	    {
12115 		if (*s == CAR)
12116 		    *s = NL;
12117 	    }
12118 	}
12119 #else
12120 # ifdef USE_CRNL
12121 	/* translate <CR><NL> into <NL> */
12122 	if (res != NULL)
12123 	{
12124 	    char_u	*s, *d;
12125 
12126 	    d = res;
12127 	    for (s = res; *s; ++s)
12128 	    {
12129 		if (s[0] == CAR && s[1] == NL)
12130 		    ++s;
12131 		*d++ = *s;
12132 	    }
12133 	    *d = NUL;
12134 	}
12135 # endif
12136 #endif
12137 	rettv->vval.v_string = res;
12138 	res = NULL;
12139     }
12140 
12141 errret:
12142     if (infile != NULL)
12143     {
12144 	mch_remove(infile);
12145 	vim_free(infile);
12146     }
12147     if (res != NULL)
12148 	vim_free(res);
12149     if (list != NULL)
12150 	list_free(list);
12151 }
12152 
12153 /*
12154  * "system()" function
12155  */
12156     static void
12157 f_system(typval_T *argvars, typval_T *rettv)
12158 {
12159     get_cmd_output_as_rettv(argvars, rettv, FALSE);
12160 }
12161 
12162 /*
12163  * "systemlist()" function
12164  */
12165     static void
12166 f_systemlist(typval_T *argvars, typval_T *rettv)
12167 {
12168     get_cmd_output_as_rettv(argvars, rettv, TRUE);
12169 }
12170 
12171 /*
12172  * "tabpagebuflist()" function
12173  */
12174     static void
12175 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12176 {
12177 #ifdef FEAT_WINDOWS
12178     tabpage_T	*tp;
12179     win_T	*wp = NULL;
12180 
12181     if (argvars[0].v_type == VAR_UNKNOWN)
12182 	wp = firstwin;
12183     else
12184     {
12185 	tp = find_tabpage((int)get_tv_number(&argvars[0]));
12186 	if (tp != NULL)
12187 	    wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12188     }
12189     if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12190     {
12191 	for (; wp != NULL; wp = wp->w_next)
12192 	    if (list_append_number(rettv->vval.v_list,
12193 						wp->w_buffer->b_fnum) == FAIL)
12194 		break;
12195     }
12196 #endif
12197 }
12198 
12199 
12200 /*
12201  * "tabpagenr()" function
12202  */
12203     static void
12204 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12205 {
12206     int		nr = 1;
12207 #ifdef FEAT_WINDOWS
12208     char_u	*arg;
12209 
12210     if (argvars[0].v_type != VAR_UNKNOWN)
12211     {
12212 	arg = get_tv_string_chk(&argvars[0]);
12213 	nr = 0;
12214 	if (arg != NULL)
12215 	{
12216 	    if (STRCMP(arg, "$") == 0)
12217 		nr = tabpage_index(NULL) - 1;
12218 	    else
12219 		EMSG2(_(e_invexpr2), arg);
12220 	}
12221     }
12222     else
12223 	nr = tabpage_index(curtab);
12224 #endif
12225     rettv->vval.v_number = nr;
12226 }
12227 
12228 
12229 #ifdef FEAT_WINDOWS
12230 static int get_winnr(tabpage_T *tp, typval_T *argvar);
12231 
12232 /*
12233  * Common code for tabpagewinnr() and winnr().
12234  */
12235     static int
12236 get_winnr(tabpage_T *tp, typval_T *argvar)
12237 {
12238     win_T	*twin;
12239     int		nr = 1;
12240     win_T	*wp;
12241     char_u	*arg;
12242 
12243     twin = (tp == curtab) ? curwin : tp->tp_curwin;
12244     if (argvar->v_type != VAR_UNKNOWN)
12245     {
12246 	arg = get_tv_string_chk(argvar);
12247 	if (arg == NULL)
12248 	    nr = 0;		/* type error; errmsg already given */
12249 	else if (STRCMP(arg, "$") == 0)
12250 	    twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12251 	else if (STRCMP(arg, "#") == 0)
12252 	{
12253 	    twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12254 	    if (twin == NULL)
12255 		nr = 0;
12256 	}
12257 	else
12258 	{
12259 	    EMSG2(_(e_invexpr2), arg);
12260 	    nr = 0;
12261 	}
12262     }
12263 
12264     if (nr > 0)
12265 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12266 					      wp != twin; wp = wp->w_next)
12267 	{
12268 	    if (wp == NULL)
12269 	    {
12270 		/* didn't find it in this tabpage */
12271 		nr = 0;
12272 		break;
12273 	    }
12274 	    ++nr;
12275 	}
12276     return nr;
12277 }
12278 #endif
12279 
12280 /*
12281  * "tabpagewinnr()" function
12282  */
12283     static void
12284 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12285 {
12286     int		nr = 1;
12287 #ifdef FEAT_WINDOWS
12288     tabpage_T	*tp;
12289 
12290     tp = find_tabpage((int)get_tv_number(&argvars[0]));
12291     if (tp == NULL)
12292 	nr = 0;
12293     else
12294 	nr = get_winnr(tp, &argvars[1]);
12295 #endif
12296     rettv->vval.v_number = nr;
12297 }
12298 
12299 
12300 /*
12301  * "tagfiles()" function
12302  */
12303     static void
12304 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12305 {
12306     char_u	*fname;
12307     tagname_T	tn;
12308     int		first;
12309 
12310     if (rettv_list_alloc(rettv) == FAIL)
12311 	return;
12312     fname = alloc(MAXPATHL);
12313     if (fname == NULL)
12314 	return;
12315 
12316     for (first = TRUE; ; first = FALSE)
12317 	if (get_tagfname(&tn, first, fname) == FAIL
12318 		|| list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12319 	    break;
12320     tagname_free(&tn);
12321     vim_free(fname);
12322 }
12323 
12324 /*
12325  * "taglist()" function
12326  */
12327     static void
12328 f_taglist(typval_T *argvars, typval_T *rettv)
12329 {
12330     char_u  *fname = NULL;
12331     char_u  *tag_pattern;
12332 
12333     tag_pattern = get_tv_string(&argvars[0]);
12334 
12335     rettv->vval.v_number = FALSE;
12336     if (*tag_pattern == NUL)
12337 	return;
12338 
12339     if (argvars[1].v_type != VAR_UNKNOWN)
12340 	fname = get_tv_string(&argvars[1]);
12341     if (rettv_list_alloc(rettv) == OK)
12342 	(void)get_tags(rettv->vval.v_list, tag_pattern, fname);
12343 }
12344 
12345 /*
12346  * "tempname()" function
12347  */
12348     static void
12349 f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12350 {
12351     static int	x = 'A';
12352 
12353     rettv->v_type = VAR_STRING;
12354     rettv->vval.v_string = vim_tempname(x, FALSE);
12355 
12356     /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12357      * names.  Skip 'I' and 'O', they are used for shell redirection. */
12358     do
12359     {
12360 	if (x == 'Z')
12361 	    x = '0';
12362 	else if (x == '9')
12363 	    x = 'A';
12364 	else
12365 	{
12366 #ifdef EBCDIC
12367 	    if (x == 'I')
12368 		x = 'J';
12369 	    else if (x == 'R')
12370 		x = 'S';
12371 	    else
12372 #endif
12373 		++x;
12374 	}
12375     } while (x == 'I' || x == 'O');
12376 }
12377 
12378 #ifdef FEAT_FLOAT
12379 /*
12380  * "tan()" function
12381  */
12382     static void
12383 f_tan(typval_T *argvars, typval_T *rettv)
12384 {
12385     float_T	f = 0.0;
12386 
12387     rettv->v_type = VAR_FLOAT;
12388     if (get_float_arg(argvars, &f) == OK)
12389 	rettv->vval.v_float = tan(f);
12390     else
12391 	rettv->vval.v_float = 0.0;
12392 }
12393 
12394 /*
12395  * "tanh()" function
12396  */
12397     static void
12398 f_tanh(typval_T *argvars, typval_T *rettv)
12399 {
12400     float_T	f = 0.0;
12401 
12402     rettv->v_type = VAR_FLOAT;
12403     if (get_float_arg(argvars, &f) == OK)
12404 	rettv->vval.v_float = tanh(f);
12405     else
12406 	rettv->vval.v_float = 0.0;
12407 }
12408 #endif
12409 
12410 /*
12411  * "test_alloc_fail(id, countdown, repeat)" function
12412  */
12413     static void
12414 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
12415 {
12416     if (argvars[0].v_type != VAR_NUMBER
12417 	    || argvars[0].vval.v_number <= 0
12418 	    || argvars[1].v_type != VAR_NUMBER
12419 	    || argvars[1].vval.v_number < 0
12420 	    || argvars[2].v_type != VAR_NUMBER)
12421 	EMSG(_(e_invarg));
12422     else
12423     {
12424 	alloc_fail_id = argvars[0].vval.v_number;
12425 	if (alloc_fail_id >= aid_last)
12426 	    EMSG(_(e_invarg));
12427 	alloc_fail_countdown = argvars[1].vval.v_number;
12428 	alloc_fail_repeat = argvars[2].vval.v_number;
12429 	did_outofmem_msg = FALSE;
12430     }
12431 }
12432 
12433 /*
12434  * "test_autochdir()"
12435  */
12436     static void
12437 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12438 {
12439 #if defined(FEAT_AUTOCHDIR)
12440     test_autochdir = TRUE;
12441 #endif
12442 }
12443 
12444 /*
12445  * "test_disable({name}, {val})" function
12446  */
12447     static void
12448 f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
12449 {
12450     char_u *name = (char_u *)"";
12451     int     val;
12452     static int save_starting = -1;
12453 
12454     if (argvars[0].v_type != VAR_STRING
12455 	    || (argvars[1].v_type) != VAR_NUMBER)
12456 	EMSG(_(e_invarg));
12457     else
12458     {
12459 	name = get_tv_string_chk(&argvars[0]);
12460 	val = (int)get_tv_number(&argvars[1]);
12461 
12462 	if (STRCMP(name, (char_u *)"redraw") == 0)
12463 	    disable_redraw_for_testing = val;
12464 	else if (STRCMP(name, (char_u *)"char_avail") == 0)
12465 	    disable_char_avail_for_testing = val;
12466 	else if (STRCMP(name, (char_u *)"starting") == 0)
12467 	{
12468 	    if (val)
12469 	    {
12470 		if (save_starting < 0)
12471 		    save_starting = starting;
12472 		starting = 0;
12473 	    }
12474 	    else
12475 	    {
12476 		starting = save_starting;
12477 		save_starting = -1;
12478 	    }
12479 	}
12480 	else if (STRCMP(name, (char_u *)"ALL") == 0)
12481 	{
12482 	    disable_char_avail_for_testing = FALSE;
12483 	    disable_redraw_for_testing = FALSE;
12484 	    if (save_starting >= 0)
12485 	    {
12486 		starting = save_starting;
12487 		save_starting = -1;
12488 	    }
12489 	}
12490 	else
12491 	    EMSG2(_(e_invarg2), name);
12492     }
12493 }
12494 
12495 /*
12496  * "test_garbagecollect_now()" function
12497  */
12498     static void
12499 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12500 {
12501     /* This is dangerous, any Lists and Dicts used internally may be freed
12502      * while still in use. */
12503     garbage_collect(TRUE);
12504 }
12505 
12506 /*
12507  * "test_ignore_error()" function
12508  */
12509     static void
12510 f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
12511 {
12512      ignore_error_for_testing(get_tv_string(&argvars[0]));
12513 }
12514 
12515 #ifdef FEAT_JOB_CHANNEL
12516     static void
12517 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
12518 {
12519     rettv->v_type = VAR_CHANNEL;
12520     rettv->vval.v_channel = NULL;
12521 }
12522 #endif
12523 
12524     static void
12525 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
12526 {
12527     rettv_dict_set(rettv, NULL);
12528 }
12529 
12530 #ifdef FEAT_JOB_CHANNEL
12531     static void
12532 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
12533 {
12534     rettv->v_type = VAR_JOB;
12535     rettv->vval.v_job = NULL;
12536 }
12537 #endif
12538 
12539     static void
12540 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
12541 {
12542     rettv_list_set(rettv, NULL);
12543 }
12544 
12545     static void
12546 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
12547 {
12548     rettv->v_type = VAR_PARTIAL;
12549     rettv->vval.v_partial = NULL;
12550 }
12551 
12552     static void
12553 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
12554 {
12555     rettv->v_type = VAR_STRING;
12556     rettv->vval.v_string = NULL;
12557 }
12558 
12559     static void
12560 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
12561 {
12562     time_for_testing = (time_t)get_tv_number(&argvars[0]);
12563 }
12564 
12565 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
12566 /*
12567  * Get a callback from "arg".  It can be a Funcref or a function name.
12568  * When "arg" is zero return an empty string.
12569  * Return NULL for an invalid argument.
12570  */
12571     char_u *
12572 get_callback(typval_T *arg, partial_T **pp)
12573 {
12574     if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12575     {
12576 	*pp = arg->vval.v_partial;
12577 	++(*pp)->pt_refcount;
12578 	return partial_name(*pp);
12579     }
12580     *pp = NULL;
12581     if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12582     {
12583 	func_ref(arg->vval.v_string);
12584 	return arg->vval.v_string;
12585     }
12586     if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12587 	return (char_u *)"";
12588     EMSG(_("E921: Invalid callback argument"));
12589     return NULL;
12590 }
12591 
12592 /*
12593  * Unref/free "callback" and "partial" retured by get_callback().
12594  */
12595     void
12596 free_callback(char_u *callback, partial_T *partial)
12597 {
12598     if (partial != NULL)
12599 	partial_unref(partial);
12600     else if (callback != NULL)
12601     {
12602 	func_unref(callback);
12603 	vim_free(callback);
12604     }
12605 }
12606 #endif
12607 
12608 #ifdef FEAT_TIMERS
12609 /*
12610  * "timer_info([timer])" function
12611  */
12612     static void
12613 f_timer_info(typval_T *argvars, typval_T *rettv)
12614 {
12615     timer_T *timer = NULL;
12616 
12617     if (rettv_list_alloc(rettv) != OK)
12618 	return;
12619     if (argvars[0].v_type != VAR_UNKNOWN)
12620     {
12621 	if (argvars[0].v_type != VAR_NUMBER)
12622 	    EMSG(_(e_number_exp));
12623 	else
12624 	{
12625 	    timer = find_timer((int)get_tv_number(&argvars[0]));
12626 	    if (timer != NULL)
12627 		add_timer_info(rettv, timer);
12628 	}
12629     }
12630     else
12631 	add_timer_info_all(rettv);
12632 }
12633 
12634 /*
12635  * "timer_pause(timer, paused)" function
12636  */
12637     static void
12638 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12639 {
12640     timer_T	*timer = NULL;
12641     int		paused = (int)get_tv_number(&argvars[1]);
12642 
12643     if (argvars[0].v_type != VAR_NUMBER)
12644 	EMSG(_(e_number_exp));
12645     else
12646     {
12647 	timer = find_timer((int)get_tv_number(&argvars[0]));
12648 	if (timer != NULL)
12649 	    timer->tr_paused = paused;
12650     }
12651 }
12652 
12653 /*
12654  * "timer_start(time, callback [, options])" function
12655  */
12656     static void
12657 f_timer_start(typval_T *argvars, typval_T *rettv)
12658 {
12659     long	msec = (long)get_tv_number(&argvars[0]);
12660     timer_T	*timer;
12661     int		repeat = 0;
12662     char_u	*callback;
12663     dict_T	*dict;
12664     partial_T	*partial;
12665 
12666     rettv->vval.v_number = -1;
12667     if (check_secure())
12668 	return;
12669     if (argvars[2].v_type != VAR_UNKNOWN)
12670     {
12671 	if (argvars[2].v_type != VAR_DICT
12672 				   || (dict = argvars[2].vval.v_dict) == NULL)
12673 	{
12674 	    EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
12675 	    return;
12676 	}
12677 	if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
12678 	    repeat = get_dict_number(dict, (char_u *)"repeat");
12679     }
12680 
12681     callback = get_callback(&argvars[1], &partial);
12682     if (callback == NULL)
12683 	return;
12684 
12685     timer = create_timer(msec, repeat);
12686     if (timer == NULL)
12687 	free_callback(callback, partial);
12688     else
12689     {
12690 	if (partial == NULL)
12691 	    timer->tr_callback = vim_strsave(callback);
12692 	else
12693 	    /* pointer into the partial */
12694 	    timer->tr_callback = callback;
12695 	timer->tr_partial = partial;
12696 	rettv->vval.v_number = (varnumber_T)timer->tr_id;
12697     }
12698 }
12699 
12700 /*
12701  * "timer_stop(timer)" function
12702  */
12703     static void
12704 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12705 {
12706     timer_T *timer;
12707 
12708     if (argvars[0].v_type != VAR_NUMBER)
12709     {
12710 	EMSG(_(e_number_exp));
12711 	return;
12712     }
12713     timer = find_timer((int)get_tv_number(&argvars[0]));
12714     if (timer != NULL)
12715 	stop_timer(timer);
12716 }
12717 
12718 /*
12719  * "timer_stopall()" function
12720  */
12721     static void
12722 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12723 {
12724     stop_all_timers();
12725 }
12726 #endif
12727 
12728 /*
12729  * "tolower(string)" function
12730  */
12731     static void
12732 f_tolower(typval_T *argvars, typval_T *rettv)
12733 {
12734     rettv->v_type = VAR_STRING;
12735     rettv->vval.v_string = strlow_save(get_tv_string(&argvars[0]));
12736 }
12737 
12738 /*
12739  * "toupper(string)" function
12740  */
12741     static void
12742 f_toupper(typval_T *argvars, typval_T *rettv)
12743 {
12744     rettv->v_type = VAR_STRING;
12745     rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12746 }
12747 
12748 /*
12749  * "tr(string, fromstr, tostr)" function
12750  */
12751     static void
12752 f_tr(typval_T *argvars, typval_T *rettv)
12753 {
12754     char_u	*in_str;
12755     char_u	*fromstr;
12756     char_u	*tostr;
12757     char_u	*p;
12758 #ifdef FEAT_MBYTE
12759     int		inlen;
12760     int		fromlen;
12761     int		tolen;
12762     int		idx;
12763     char_u	*cpstr;
12764     int		cplen;
12765     int		first = TRUE;
12766 #endif
12767     char_u	buf[NUMBUFLEN];
12768     char_u	buf2[NUMBUFLEN];
12769     garray_T	ga;
12770 
12771     in_str = get_tv_string(&argvars[0]);
12772     fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12773     tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12774 
12775     /* Default return value: empty string. */
12776     rettv->v_type = VAR_STRING;
12777     rettv->vval.v_string = NULL;
12778     if (fromstr == NULL || tostr == NULL)
12779 	    return;		/* type error; errmsg already given */
12780     ga_init2(&ga, (int)sizeof(char), 80);
12781 
12782 #ifdef FEAT_MBYTE
12783     if (!has_mbyte)
12784 #endif
12785 	/* not multi-byte: fromstr and tostr must be the same length */
12786 	if (STRLEN(fromstr) != STRLEN(tostr))
12787 	{
12788 #ifdef FEAT_MBYTE
12789 error:
12790 #endif
12791 	    EMSG2(_(e_invarg2), fromstr);
12792 	    ga_clear(&ga);
12793 	    return;
12794 	}
12795 
12796     /* fromstr and tostr have to contain the same number of chars */
12797     while (*in_str != NUL)
12798     {
12799 #ifdef FEAT_MBYTE
12800 	if (has_mbyte)
12801 	{
12802 	    inlen = (*mb_ptr2len)(in_str);
12803 	    cpstr = in_str;
12804 	    cplen = inlen;
12805 	    idx = 0;
12806 	    for (p = fromstr; *p != NUL; p += fromlen)
12807 	    {
12808 		fromlen = (*mb_ptr2len)(p);
12809 		if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12810 		{
12811 		    for (p = tostr; *p != NUL; p += tolen)
12812 		    {
12813 			tolen = (*mb_ptr2len)(p);
12814 			if (idx-- == 0)
12815 			{
12816 			    cplen = tolen;
12817 			    cpstr = p;
12818 			    break;
12819 			}
12820 		    }
12821 		    if (*p == NUL)	/* tostr is shorter than fromstr */
12822 			goto error;
12823 		    break;
12824 		}
12825 		++idx;
12826 	    }
12827 
12828 	    if (first && cpstr == in_str)
12829 	    {
12830 		/* Check that fromstr and tostr have the same number of
12831 		 * (multi-byte) characters.  Done only once when a character
12832 		 * of in_str doesn't appear in fromstr. */
12833 		first = FALSE;
12834 		for (p = tostr; *p != NUL; p += tolen)
12835 		{
12836 		    tolen = (*mb_ptr2len)(p);
12837 		    --idx;
12838 		}
12839 		if (idx != 0)
12840 		    goto error;
12841 	    }
12842 
12843 	    (void)ga_grow(&ga, cplen);
12844 	    mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12845 	    ga.ga_len += cplen;
12846 
12847 	    in_str += inlen;
12848 	}
12849 	else
12850 #endif
12851 	{
12852 	    /* When not using multi-byte chars we can do it faster. */
12853 	    p = vim_strchr(fromstr, *in_str);
12854 	    if (p != NULL)
12855 		ga_append(&ga, tostr[p - fromstr]);
12856 	    else
12857 		ga_append(&ga, *in_str);
12858 	    ++in_str;
12859 	}
12860     }
12861 
12862     /* add a terminating NUL */
12863     (void)ga_grow(&ga, 1);
12864     ga_append(&ga, NUL);
12865 
12866     rettv->vval.v_string = ga.ga_data;
12867 }
12868 
12869 #ifdef FEAT_FLOAT
12870 /*
12871  * "trunc({float})" function
12872  */
12873     static void
12874 f_trunc(typval_T *argvars, typval_T *rettv)
12875 {
12876     float_T	f = 0.0;
12877 
12878     rettv->v_type = VAR_FLOAT;
12879     if (get_float_arg(argvars, &f) == OK)
12880 	/* trunc() is not in C90, use floor() or ceil() instead. */
12881 	rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12882     else
12883 	rettv->vval.v_float = 0.0;
12884 }
12885 #endif
12886 
12887 /*
12888  * "type(expr)" function
12889  */
12890     static void
12891 f_type(typval_T *argvars, typval_T *rettv)
12892 {
12893     int n = -1;
12894 
12895     switch (argvars[0].v_type)
12896     {
12897 	case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12898 	case VAR_STRING: n = VAR_TYPE_STRING; break;
12899 	case VAR_PARTIAL:
12900 	case VAR_FUNC:   n = VAR_TYPE_FUNC; break;
12901 	case VAR_LIST:   n = VAR_TYPE_LIST; break;
12902 	case VAR_DICT:   n = VAR_TYPE_DICT; break;
12903 	case VAR_FLOAT:  n = VAR_TYPE_FLOAT; break;
12904 	case VAR_SPECIAL:
12905 	     if (argvars[0].vval.v_number == VVAL_FALSE
12906 		     || argvars[0].vval.v_number == VVAL_TRUE)
12907 		 n = VAR_TYPE_BOOL;
12908 	     else
12909 		 n = VAR_TYPE_NONE;
12910 	     break;
12911 	case VAR_JOB:     n = VAR_TYPE_JOB; break;
12912 	case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
12913 	case VAR_UNKNOWN:
12914 	     internal_error("f_type(UNKNOWN)");
12915 	     n = -1;
12916 	     break;
12917     }
12918     rettv->vval.v_number = n;
12919 }
12920 
12921 /*
12922  * "undofile(name)" function
12923  */
12924     static void
12925 f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12926 {
12927     rettv->v_type = VAR_STRING;
12928 #ifdef FEAT_PERSISTENT_UNDO
12929     {
12930 	char_u *fname = get_tv_string(&argvars[0]);
12931 
12932 	if (*fname == NUL)
12933 	{
12934 	    /* If there is no file name there will be no undo file. */
12935 	    rettv->vval.v_string = NULL;
12936 	}
12937 	else
12938 	{
12939 	    char_u *ffname = FullName_save(fname, FALSE);
12940 
12941 	    if (ffname != NULL)
12942 		rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12943 	    vim_free(ffname);
12944 	}
12945     }
12946 #else
12947     rettv->vval.v_string = NULL;
12948 #endif
12949 }
12950 
12951 /*
12952  * "undotree()" function
12953  */
12954     static void
12955 f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12956 {
12957     if (rettv_dict_alloc(rettv) == OK)
12958     {
12959 	dict_T *dict = rettv->vval.v_dict;
12960 	list_T *list;
12961 
12962 	dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12963 	dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12964 	dict_add_nr_str(dict, "save_last",
12965 					(long)curbuf->b_u_save_nr_last, NULL);
12966 	dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12967 	dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12968 	dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12969 
12970 	list = list_alloc();
12971 	if (list != NULL)
12972 	{
12973 	    u_eval_tree(curbuf->b_u_oldhead, list);
12974 	    dict_add_list(dict, "entries", list);
12975 	}
12976     }
12977 }
12978 
12979 /*
12980  * "values(dict)" function
12981  */
12982     static void
12983 f_values(typval_T *argvars, typval_T *rettv)
12984 {
12985     dict_list(argvars, rettv, 1);
12986 }
12987 
12988 /*
12989  * "virtcol(string)" function
12990  */
12991     static void
12992 f_virtcol(typval_T *argvars, typval_T *rettv)
12993 {
12994     colnr_T	vcol = 0;
12995     pos_T	*fp;
12996     int		fnum = curbuf->b_fnum;
12997 
12998     fp = var2fpos(&argvars[0], FALSE, &fnum);
12999     if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13000 						    && fnum == curbuf->b_fnum)
13001     {
13002 	getvvcol(curwin, fp, NULL, NULL, &vcol);
13003 	++vcol;
13004     }
13005 
13006     rettv->vval.v_number = vcol;
13007 }
13008 
13009 /*
13010  * "visualmode()" function
13011  */
13012     static void
13013 f_visualmode(typval_T *argvars, typval_T *rettv)
13014 {
13015     char_u	str[2];
13016 
13017     rettv->v_type = VAR_STRING;
13018     str[0] = curbuf->b_visual_mode_eval;
13019     str[1] = NUL;
13020     rettv->vval.v_string = vim_strsave(str);
13021 
13022     /* A non-zero number or non-empty string argument: reset mode. */
13023     if (non_zero_arg(&argvars[0]))
13024 	curbuf->b_visual_mode_eval = NUL;
13025 }
13026 
13027 /*
13028  * "wildmenumode()" function
13029  */
13030     static void
13031 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13032 {
13033 #ifdef FEAT_WILDMENU
13034     if (wild_menu_showing)
13035 	rettv->vval.v_number = 1;
13036 #endif
13037 }
13038 
13039 /*
13040  * "winbufnr(nr)" function
13041  */
13042     static void
13043 f_winbufnr(typval_T *argvars, typval_T *rettv)
13044 {
13045     win_T	*wp;
13046 
13047     wp = find_win_by_nr(&argvars[0], NULL);
13048     if (wp == NULL)
13049 	rettv->vval.v_number = -1;
13050     else
13051 	rettv->vval.v_number = wp->w_buffer->b_fnum;
13052 }
13053 
13054 /*
13055  * "wincol()" function
13056  */
13057     static void
13058 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13059 {
13060     validate_cursor();
13061     rettv->vval.v_number = curwin->w_wcol + 1;
13062 }
13063 
13064 /*
13065  * "winheight(nr)" function
13066  */
13067     static void
13068 f_winheight(typval_T *argvars, typval_T *rettv)
13069 {
13070     win_T	*wp;
13071 
13072     wp = find_win_by_nr(&argvars[0], NULL);
13073     if (wp == NULL)
13074 	rettv->vval.v_number = -1;
13075     else
13076 	rettv->vval.v_number = wp->w_height;
13077 }
13078 
13079 /*
13080  * "winline()" function
13081  */
13082     static void
13083 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13084 {
13085     validate_cursor();
13086     rettv->vval.v_number = curwin->w_wrow + 1;
13087 }
13088 
13089 /*
13090  * "winnr()" function
13091  */
13092     static void
13093 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13094 {
13095     int		nr = 1;
13096 
13097 #ifdef FEAT_WINDOWS
13098     nr = get_winnr(curtab, &argvars[0]);
13099 #endif
13100     rettv->vval.v_number = nr;
13101 }
13102 
13103 /*
13104  * "winrestcmd()" function
13105  */
13106     static void
13107 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13108 {
13109 #ifdef FEAT_WINDOWS
13110     win_T	*wp;
13111     int		winnr = 1;
13112     garray_T	ga;
13113     char_u	buf[50];
13114 
13115     ga_init2(&ga, (int)sizeof(char), 70);
13116     FOR_ALL_WINDOWS(wp)
13117     {
13118 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13119 	ga_concat(&ga, buf);
13120 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13121 	ga_concat(&ga, buf);
13122 	++winnr;
13123     }
13124     ga_append(&ga, NUL);
13125 
13126     rettv->vval.v_string = ga.ga_data;
13127 #else
13128     rettv->vval.v_string = NULL;
13129 #endif
13130     rettv->v_type = VAR_STRING;
13131 }
13132 
13133 /*
13134  * "winrestview()" function
13135  */
13136     static void
13137 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13138 {
13139     dict_T	*dict;
13140 
13141     if (argvars[0].v_type != VAR_DICT
13142 	    || (dict = argvars[0].vval.v_dict) == NULL)
13143 	EMSG(_(e_invarg));
13144     else
13145     {
13146 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
13147 	    curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
13148 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
13149 	    curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
13150 #ifdef FEAT_VIRTUALEDIT
13151 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
13152 	    curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
13153 #endif
13154 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13155 	{
13156 	    curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
13157 	    curwin->w_set_curswant = FALSE;
13158 	}
13159 
13160 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
13161 	    set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
13162 #ifdef FEAT_DIFF
13163 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
13164 	    curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
13165 #endif
13166 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
13167 	    curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
13168 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
13169 	    curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
13170 
13171 	check_cursor();
13172 	win_new_height(curwin, curwin->w_height);
13173 # ifdef FEAT_WINDOWS
13174 	win_new_width(curwin, W_WIDTH(curwin));
13175 # endif
13176 	changed_window_setting();
13177 
13178 	if (curwin->w_topline <= 0)
13179 	    curwin->w_topline = 1;
13180 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13181 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
13182 #ifdef FEAT_DIFF
13183 	check_topfill(curwin, TRUE);
13184 #endif
13185     }
13186 }
13187 
13188 /*
13189  * "winsaveview()" function
13190  */
13191     static void
13192 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13193 {
13194     dict_T	*dict;
13195 
13196     if (rettv_dict_alloc(rettv) == FAIL)
13197 	return;
13198     dict = rettv->vval.v_dict;
13199 
13200     dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
13201     dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
13202 #ifdef FEAT_VIRTUALEDIT
13203     dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
13204 #endif
13205     update_curswant();
13206     dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
13207 
13208     dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
13209 #ifdef FEAT_DIFF
13210     dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
13211 #endif
13212     dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
13213     dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
13214 }
13215 
13216 /*
13217  * "winwidth(nr)" function
13218  */
13219     static void
13220 f_winwidth(typval_T *argvars, typval_T *rettv)
13221 {
13222     win_T	*wp;
13223 
13224     wp = find_win_by_nr(&argvars[0], NULL);
13225     if (wp == NULL)
13226 	rettv->vval.v_number = -1;
13227     else
13228 #ifdef FEAT_WINDOWS
13229 	rettv->vval.v_number = wp->w_width;
13230 #else
13231 	rettv->vval.v_number = Columns;
13232 #endif
13233 }
13234 
13235 /*
13236  * "wordcount()" function
13237  */
13238     static void
13239 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13240 {
13241     if (rettv_dict_alloc(rettv) == FAIL)
13242 	return;
13243     cursor_pos_info(rettv->vval.v_dict);
13244 }
13245 
13246 /*
13247  * "writefile()" function
13248  */
13249     static void
13250 f_writefile(typval_T *argvars, typval_T *rettv)
13251 {
13252     int		binary = FALSE;
13253     int		append = FALSE;
13254     char_u	*fname;
13255     FILE	*fd;
13256     int		ret = 0;
13257     listitem_T	*li;
13258     list_T	*list;
13259 
13260     rettv->vval.v_number = -1;
13261     if (check_restricted() || check_secure())
13262 	return;
13263 
13264     if (argvars[0].v_type != VAR_LIST)
13265     {
13266 	EMSG2(_(e_listarg), "writefile()");
13267 	return;
13268     }
13269     list = argvars[0].vval.v_list;
13270     if (list == NULL)
13271 	return;
13272     for (li = list->lv_first; li != NULL; li = li->li_next)
13273 	if (get_tv_string_chk(&li->li_tv) == NULL)
13274 	    return;
13275 
13276     if (argvars[2].v_type != VAR_UNKNOWN)
13277     {
13278 	char_u *arg2 = get_tv_string_chk(&argvars[2]);
13279 
13280 	if (arg2 == NULL)
13281 	    return;
13282 	if (vim_strchr(arg2, 'b') != NULL)
13283 	    binary = TRUE;
13284 	if (vim_strchr(arg2, 'a') != NULL)
13285 	    append = TRUE;
13286     }
13287 
13288     fname = get_tv_string_chk(&argvars[1]);
13289     if (fname == NULL)
13290 	return;
13291 
13292     /* Always open the file in binary mode, library functions have a mind of
13293      * their own about CR-LF conversion. */
13294     if (*fname == NUL || (fd = mch_fopen((char *)fname,
13295 				      append ? APPENDBIN : WRITEBIN)) == NULL)
13296     {
13297 	EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
13298 	ret = -1;
13299     }
13300     else
13301     {
13302 	if (write_list(fd, list, binary) == FAIL)
13303 	    ret = -1;
13304 	fclose(fd);
13305     }
13306 
13307     rettv->vval.v_number = ret;
13308 }
13309 
13310 /*
13311  * "xor(expr, expr)" function
13312  */
13313     static void
13314 f_xor(typval_T *argvars, typval_T *rettv)
13315 {
13316     rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
13317 					^ get_tv_number_chk(&argvars[1], NULL);
13318 }
13319 
13320 
13321 #endif /* FEAT_EVAL */
13322