comparison src/eval.c @ 9571:5eaa708ab50d v7.4.2063

commit https://github.com/vim/vim/commit/73dad1e64cb42842d8259cb1a255a6fa59822f76 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 17 22:13:49 2016 +0200 patch 7.4.2063 Problem: eval.c is still too big. Solution: Split off internal functions to evalfunc.c.
author Christian Brabandt <cb@256bit.org>
date Sun, 17 Jul 2016 22:30:06 +0200
parents 86af4a48c00a
children 05a56bbe34a1
comparison
equal deleted inserted replaced
9570:695186e11daa 9571:5eaa708ab50d
14 14
15 #include "vim.h" 15 #include "vim.h"
16 16
17 #if defined(FEAT_EVAL) || defined(PROTO) 17 #if defined(FEAT_EVAL) || defined(PROTO)
18 18
19 #ifdef AMIGA
20 # include <time.h> /* for strftime() */
21 #endif
22
23 #ifdef VMS 19 #ifdef VMS
24 # include <float.h> 20 # include <float.h>
25 #endif
26
27 #ifdef MACOS
28 # include <time.h> /* for time_t */
29 #endif 21 #endif
30 22
31 #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ 23 #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
32 24
33 static char *e_letunexp = N_("E18: Unexpected characters in :let"); 25 static char *e_letunexp = N_("E18: Unexpected characters in :let");
34 static char *e_undefvar = N_("E121: Undefined variable: %s"); 26 static char *e_undefvar = N_("E121: Undefined variable: %s");
35 static char *e_missbrac = N_("E111: Missing ']'"); 27 static char *e_missbrac = N_("E111: Missing ']'");
36 static char *e_listarg = N_("E686: Argument of %s must be a List");
37 static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionary");
38 static char *e_listreq = N_("E714: List required");
39 #ifdef FEAT_QUICKFIX
40 static char *e_stringreq = N_("E928: String required");
41 #endif
42 static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); 28 static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
43 static char *e_letwrong = N_("E734: Wrong variable type for %s="); 29 static char *e_letwrong = N_("E734: Wrong variable type for %s=");
44 static char *e_illvar = N_("E461: Illegal variable name: %s"); 30 static char *e_illvar = N_("E461: Illegal variable name: %s");
45 #ifdef FEAT_FLOAT 31 #ifdef FEAT_FLOAT
46 static char *e_float_as_string = N_("E806: using Float as a String"); 32 static char *e_float_as_string = N_("E806: using Float as a String");
99 * Array to hold the value of v: variables. 85 * Array to hold the value of v: variables.
100 * The value is in a dictitem, so that it can also be used in the v: scope. 86 * The value is in a dictitem, so that it can also be used in the v: scope.
101 * The reason to use this table anyway is for very quick access to the 87 * The reason to use this table anyway is for very quick access to the
102 * variables with the VV_ defines. 88 * variables with the VV_ defines.
103 */ 89 */
104 #include "version.h"
105 90
106 /* values for vv_flags: */ 91 /* values for vv_flags: */
107 #define VV_COMPAT 1 /* compatible, also used without "v:" */ 92 #define VV_COMPAT 1 /* compatible, also used without "v:" */
108 #define VV_RO 2 /* read-only */ 93 #define VV_RO 2 /* read-only */
109 #define VV_RO_SBX 4 /* read-only in the sandbox */ 94 #define VV_RO_SBX 4 /* read-only in the sandbox */
204 #define vv_tv vv_di.di_tv 189 #define vv_tv vv_di.di_tv
205 190
206 static dictitem_T vimvars_var; /* variable used for v: */ 191 static dictitem_T vimvars_var; /* variable used for v: */
207 #define vimvarht vimvardict.dv_hashtab 192 #define vimvarht vimvardict.dv_hashtab
208 193
209 static void prepare_vimvar(int idx, typval_T *save_tv);
210 static void restore_vimvar(int idx, typval_T *save_tv);
211 static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars); 194 static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars);
212 static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon); 195 static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon);
213 static char_u *skip_var_one(char_u *arg); 196 static char_u *skip_var_one(char_u *arg);
214 static void list_glob_vars(int *first); 197 static void list_glob_vars(int *first);
215 static void list_buf_vars(int *first); 198 static void list_buf_vars(int *first);
219 #endif 202 #endif
220 static void list_vim_vars(int *first); 203 static void list_vim_vars(int *first);
221 static void list_script_vars(int *first); 204 static void list_script_vars(int *first);
222 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); 205 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
223 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op); 206 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op);
224 static int check_changedtick(char_u *arg);
225 static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op); 207 static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op);
226 static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); 208 static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
227 static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep); 209 static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep);
228 static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit); 210 static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
229 static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock); 211 static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
230 static void item_lock(typval_T *tv, int deep, int lock); 212 static void item_lock(typval_T *tv, int deep, int lock);
231 static int tv_islocked(typval_T *tv);
232 213
233 static int eval2(char_u **arg, typval_T *rettv, int evaluate); 214 static int eval2(char_u **arg, typval_T *rettv, int evaluate);
234 static int eval3(char_u **arg, typval_T *rettv, int evaluate); 215 static int eval3(char_u **arg, typval_T *rettv, int evaluate);
235 static int eval4(char_u **arg, typval_T *rettv, int evaluate); 216 static int eval4(char_u **arg, typval_T *rettv, int evaluate);
236 static int eval5(char_u **arg, typval_T *rettv, int evaluate); 217 static int eval5(char_u **arg, typval_T *rettv, int evaluate);
237 static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); 218 static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string);
238 static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); 219 static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string);
239 220
240 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); 221 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose);
241 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
242 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); 222 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate);
243 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); 223 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate);
244 static int free_unref_items(int copyID); 224 static int free_unref_items(int copyID);
245 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); 225 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
246 static int non_zero_arg(typval_T *argvars); 226
247 227
248 #ifdef FEAT_FLOAT
249 static void f_abs(typval_T *argvars, typval_T *rettv);
250 static void f_acos(typval_T *argvars, typval_T *rettv);
251 #endif
252 static void f_add(typval_T *argvars, typval_T *rettv);
253 static void f_and(typval_T *argvars, typval_T *rettv);
254 static void f_append(typval_T *argvars, typval_T *rettv);
255 static void f_argc(typval_T *argvars, typval_T *rettv);
256 static void f_argidx(typval_T *argvars, typval_T *rettv);
257 static void f_arglistid(typval_T *argvars, typval_T *rettv);
258 static void f_argv(typval_T *argvars, typval_T *rettv);
259 static void f_assert_equal(typval_T *argvars, typval_T *rettv);
260 static void f_assert_exception(typval_T *argvars, typval_T *rettv);
261 static void f_assert_fails(typval_T *argvars, typval_T *rettv);
262 static void f_assert_false(typval_T *argvars, typval_T *rettv);
263 static void f_assert_match(typval_T *argvars, typval_T *rettv);
264 static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
265 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
266 static void f_assert_true(typval_T *argvars, typval_T *rettv);
267 #ifdef FEAT_FLOAT
268 static void f_asin(typval_T *argvars, typval_T *rettv);
269 static void f_atan(typval_T *argvars, typval_T *rettv);
270 static void f_atan2(typval_T *argvars, typval_T *rettv);
271 #endif
272 static void f_browse(typval_T *argvars, typval_T *rettv);
273 static void f_browsedir(typval_T *argvars, typval_T *rettv);
274 static void f_bufexists(typval_T *argvars, typval_T *rettv);
275 static void f_buflisted(typval_T *argvars, typval_T *rettv);
276 static void f_bufloaded(typval_T *argvars, typval_T *rettv);
277 static void f_bufname(typval_T *argvars, typval_T *rettv);
278 static void f_bufnr(typval_T *argvars, typval_T *rettv);
279 static void f_bufwinid(typval_T *argvars, typval_T *rettv);
280 static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
281 static void f_byte2line(typval_T *argvars, typval_T *rettv);
282 static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
283 static void f_byteidx(typval_T *argvars, typval_T *rettv);
284 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
285 static void f_call(typval_T *argvars, typval_T *rettv);
286 #ifdef FEAT_FLOAT
287 static void f_ceil(typval_T *argvars, typval_T *rettv);
288 #endif
289 #ifdef FEAT_JOB_CHANNEL
290 static void f_ch_close(typval_T *argvars, typval_T *rettv);
291 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
292 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
293 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
294 static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
295 static void f_ch_info(typval_T *argvars, typval_T *rettv);
296 static void f_ch_log(typval_T *argvars, typval_T *rettv);
297 static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
298 static void f_ch_open(typval_T *argvars, typval_T *rettv);
299 static void f_ch_read(typval_T *argvars, typval_T *rettv);
300 static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
301 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
302 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
303 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
304 static void f_ch_status(typval_T *argvars, typval_T *rettv);
305 #endif
306 static void f_changenr(typval_T *argvars, typval_T *rettv);
307 static void f_char2nr(typval_T *argvars, typval_T *rettv);
308 static void f_cindent(typval_T *argvars, typval_T *rettv);
309 static void f_clearmatches(typval_T *argvars, typval_T *rettv);
310 static void f_col(typval_T *argvars, typval_T *rettv);
311 #if defined(FEAT_INS_EXPAND)
312 static void f_complete(typval_T *argvars, typval_T *rettv);
313 static void f_complete_add(typval_T *argvars, typval_T *rettv);
314 static void f_complete_check(typval_T *argvars, typval_T *rettv);
315 #endif
316 static void f_confirm(typval_T *argvars, typval_T *rettv);
317 static void f_copy(typval_T *argvars, typval_T *rettv);
318 #ifdef FEAT_FLOAT
319 static void f_cos(typval_T *argvars, typval_T *rettv);
320 static void f_cosh(typval_T *argvars, typval_T *rettv);
321 #endif
322 static void f_count(typval_T *argvars, typval_T *rettv);
323 static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
324 static void f_cursor(typval_T *argsvars, typval_T *rettv);
325 static void f_deepcopy(typval_T *argvars, typval_T *rettv);
326 static void f_delete(typval_T *argvars, typval_T *rettv);
327 static void f_did_filetype(typval_T *argvars, typval_T *rettv);
328 static void f_diff_filler(typval_T *argvars, typval_T *rettv);
329 static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
330 static void f_empty(typval_T *argvars, typval_T *rettv);
331 static void f_escape(typval_T *argvars, typval_T *rettv);
332 static void f_eval(typval_T *argvars, typval_T *rettv);
333 static void f_eventhandler(typval_T *argvars, typval_T *rettv);
334 static void f_executable(typval_T *argvars, typval_T *rettv);
335 static void f_execute(typval_T *argvars, typval_T *rettv);
336 static void f_exepath(typval_T *argvars, typval_T *rettv);
337 static void f_exists(typval_T *argvars, typval_T *rettv);
338 #ifdef FEAT_FLOAT
339 static void f_exp(typval_T *argvars, typval_T *rettv);
340 #endif
341 static void f_expand(typval_T *argvars, typval_T *rettv);
342 static void f_extend(typval_T *argvars, typval_T *rettv);
343 static void f_feedkeys(typval_T *argvars, typval_T *rettv);
344 static void f_filereadable(typval_T *argvars, typval_T *rettv);
345 static void f_filewritable(typval_T *argvars, typval_T *rettv);
346 static void f_filter(typval_T *argvars, typval_T *rettv);
347 static void f_finddir(typval_T *argvars, typval_T *rettv);
348 static void f_findfile(typval_T *argvars, typval_T *rettv);
349 #ifdef FEAT_FLOAT
350 static void f_float2nr(typval_T *argvars, typval_T *rettv);
351 static void f_floor(typval_T *argvars, typval_T *rettv);
352 static void f_fmod(typval_T *argvars, typval_T *rettv);
353 #endif
354 static void f_fnameescape(typval_T *argvars, typval_T *rettv);
355 static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
356 static void f_foldclosed(typval_T *argvars, typval_T *rettv);
357 static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
358 static void f_foldlevel(typval_T *argvars, typval_T *rettv);
359 static void f_foldtext(typval_T *argvars, typval_T *rettv);
360 static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
361 static void f_foreground(typval_T *argvars, typval_T *rettv);
362 static void f_function(typval_T *argvars, typval_T *rettv);
363 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
364 static void f_get(typval_T *argvars, typval_T *rettv);
365 static void f_getbufline(typval_T *argvars, typval_T *rettv);
366 static void f_getbufvar(typval_T *argvars, typval_T *rettv);
367 static void f_getchar(typval_T *argvars, typval_T *rettv);
368 static void f_getcharmod(typval_T *argvars, typval_T *rettv);
369 static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
370 static void f_getcmdline(typval_T *argvars, typval_T *rettv);
371 #if defined(FEAT_CMDL_COMPL)
372 static void f_getcompletion(typval_T *argvars, typval_T *rettv);
373 #endif
374 static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
375 static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
376 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
377 static void f_getcwd(typval_T *argvars, typval_T *rettv);
378 static void f_getfontname(typval_T *argvars, typval_T *rettv);
379 static void f_getfperm(typval_T *argvars, typval_T *rettv);
380 static void f_getfsize(typval_T *argvars, typval_T *rettv);
381 static void f_getftime(typval_T *argvars, typval_T *rettv);
382 static void f_getftype(typval_T *argvars, typval_T *rettv);
383 static void f_getline(typval_T *argvars, typval_T *rettv);
384 static void f_getmatches(typval_T *argvars, typval_T *rettv);
385 static void f_getpid(typval_T *argvars, typval_T *rettv);
386 static void f_getcurpos(typval_T *argvars, typval_T *rettv);
387 static void f_getpos(typval_T *argvars, typval_T *rettv);
388 static void f_getqflist(typval_T *argvars, typval_T *rettv);
389 static void f_getreg(typval_T *argvars, typval_T *rettv);
390 static void f_getregtype(typval_T *argvars, typval_T *rettv);
391 static void f_gettabvar(typval_T *argvars, typval_T *rettv);
392 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
393 static void f_getwinposx(typval_T *argvars, typval_T *rettv);
394 static void f_getwinposy(typval_T *argvars, typval_T *rettv);
395 static void f_getwinvar(typval_T *argvars, typval_T *rettv);
396 static void f_glob(typval_T *argvars, typval_T *rettv);
397 static void f_globpath(typval_T *argvars, typval_T *rettv);
398 static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
399 static void f_has(typval_T *argvars, typval_T *rettv);
400 static void f_has_key(typval_T *argvars, typval_T *rettv);
401 static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
402 static void f_hasmapto(typval_T *argvars, typval_T *rettv);
403 static void f_histadd(typval_T *argvars, typval_T *rettv);
404 static void f_histdel(typval_T *argvars, typval_T *rettv);
405 static void f_histget(typval_T *argvars, typval_T *rettv);
406 static void f_histnr(typval_T *argvars, typval_T *rettv);
407 static void f_hlID(typval_T *argvars, typval_T *rettv);
408 static void f_hlexists(typval_T *argvars, typval_T *rettv);
409 static void f_hostname(typval_T *argvars, typval_T *rettv);
410 static void f_iconv(typval_T *argvars, typval_T *rettv);
411 static void f_indent(typval_T *argvars, typval_T *rettv);
412 static void f_index(typval_T *argvars, typval_T *rettv);
413 static void f_input(typval_T *argvars, typval_T *rettv);
414 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
415 static void f_inputlist(typval_T *argvars, typval_T *rettv);
416 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
417 static void f_inputsave(typval_T *argvars, typval_T *rettv);
418 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
419 static void f_insert(typval_T *argvars, typval_T *rettv);
420 static void f_invert(typval_T *argvars, typval_T *rettv);
421 static void f_isdirectory(typval_T *argvars, typval_T *rettv);
422 static void f_islocked(typval_T *argvars, typval_T *rettv);
423 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
424 static void f_isnan(typval_T *argvars, typval_T *rettv);
425 #endif
426 static void f_items(typval_T *argvars, typval_T *rettv);
427 #ifdef FEAT_JOB_CHANNEL
428 static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
429 static void f_job_info(typval_T *argvars, typval_T *rettv);
430 static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
431 static void f_job_start(typval_T *argvars, typval_T *rettv);
432 static void f_job_stop(typval_T *argvars, typval_T *rettv);
433 static void f_job_status(typval_T *argvars, typval_T *rettv);
434 #endif
435 static void f_join(typval_T *argvars, typval_T *rettv);
436 static void f_js_decode(typval_T *argvars, typval_T *rettv);
437 static void f_js_encode(typval_T *argvars, typval_T *rettv);
438 static void f_json_decode(typval_T *argvars, typval_T *rettv);
439 static void f_json_encode(typval_T *argvars, typval_T *rettv);
440 static void f_keys(typval_T *argvars, typval_T *rettv);
441 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
442 static void f_len(typval_T *argvars, typval_T *rettv);
443 static void f_libcall(typval_T *argvars, typval_T *rettv);
444 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
445 static void f_line(typval_T *argvars, typval_T *rettv);
446 static void f_line2byte(typval_T *argvars, typval_T *rettv);
447 static void f_lispindent(typval_T *argvars, typval_T *rettv);
448 static void f_localtime(typval_T *argvars, typval_T *rettv);
449 #ifdef FEAT_FLOAT
450 static void f_log(typval_T *argvars, typval_T *rettv);
451 static void f_log10(typval_T *argvars, typval_T *rettv);
452 #endif
453 #ifdef FEAT_LUA
454 static void f_luaeval(typval_T *argvars, typval_T *rettv);
455 #endif
456 static void f_map(typval_T *argvars, typval_T *rettv);
457 static void f_maparg(typval_T *argvars, typval_T *rettv);
458 static void f_mapcheck(typval_T *argvars, typval_T *rettv);
459 static void f_match(typval_T *argvars, typval_T *rettv);
460 static void f_matchadd(typval_T *argvars, typval_T *rettv);
461 static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
462 static void f_matcharg(typval_T *argvars, typval_T *rettv);
463 static void f_matchdelete(typval_T *argvars, typval_T *rettv);
464 static void f_matchend(typval_T *argvars, typval_T *rettv);
465 static void f_matchlist(typval_T *argvars, typval_T *rettv);
466 static void f_matchstr(typval_T *argvars, typval_T *rettv);
467 static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
468 static void f_max(typval_T *argvars, typval_T *rettv);
469 static void f_min(typval_T *argvars, typval_T *rettv);
470 #ifdef vim_mkdir
471 static void f_mkdir(typval_T *argvars, typval_T *rettv);
472 #endif
473 static void f_mode(typval_T *argvars, typval_T *rettv);
474 #ifdef FEAT_MZSCHEME
475 static void f_mzeval(typval_T *argvars, typval_T *rettv);
476 #endif
477 static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
478 static void f_nr2char(typval_T *argvars, typval_T *rettv);
479 static void f_or(typval_T *argvars, typval_T *rettv);
480 static void f_pathshorten(typval_T *argvars, typval_T *rettv);
481 #ifdef FEAT_PERL
482 static void f_perleval(typval_T *argvars, typval_T *rettv);
483 #endif
484 #ifdef FEAT_FLOAT
485 static void f_pow(typval_T *argvars, typval_T *rettv);
486 #endif
487 static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
488 static void f_printf(typval_T *argvars, typval_T *rettv);
489 static void f_pumvisible(typval_T *argvars, typval_T *rettv);
490 #ifdef FEAT_PYTHON3
491 static void f_py3eval(typval_T *argvars, typval_T *rettv);
492 #endif
493 #ifdef FEAT_PYTHON
494 static void f_pyeval(typval_T *argvars, typval_T *rettv);
495 #endif
496 static void f_range(typval_T *argvars, typval_T *rettv);
497 static void f_readfile(typval_T *argvars, typval_T *rettv);
498 static void f_reltime(typval_T *argvars, typval_T *rettv);
499 #ifdef FEAT_FLOAT
500 static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
501 #endif
502 static void f_reltimestr(typval_T *argvars, typval_T *rettv);
503 static void f_remote_expr(typval_T *argvars, typval_T *rettv);
504 static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
505 static void f_remote_peek(typval_T *argvars, typval_T *rettv);
506 static void f_remote_read(typval_T *argvars, typval_T *rettv);
507 static void f_remote_send(typval_T *argvars, typval_T *rettv);
508 static void f_remove(typval_T *argvars, typval_T *rettv);
509 static void f_rename(typval_T *argvars, typval_T *rettv);
510 static void f_repeat(typval_T *argvars, typval_T *rettv);
511 static void f_resolve(typval_T *argvars, typval_T *rettv);
512 static void f_reverse(typval_T *argvars, typval_T *rettv);
513 #ifdef FEAT_FLOAT
514 static void f_round(typval_T *argvars, typval_T *rettv);
515 #endif
516 static void f_screenattr(typval_T *argvars, typval_T *rettv);
517 static void f_screenchar(typval_T *argvars, typval_T *rettv);
518 static void f_screencol(typval_T *argvars, typval_T *rettv);
519 static void f_screenrow(typval_T *argvars, typval_T *rettv);
520 static void f_search(typval_T *argvars, typval_T *rettv);
521 static void f_searchdecl(typval_T *argvars, typval_T *rettv);
522 static void f_searchpair(typval_T *argvars, typval_T *rettv);
523 static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
524 static void f_searchpos(typval_T *argvars, typval_T *rettv);
525 static void f_server2client(typval_T *argvars, typval_T *rettv);
526 static void f_serverlist(typval_T *argvars, typval_T *rettv);
527 static void f_setbufvar(typval_T *argvars, typval_T *rettv);
528 static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
529 static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
530 static void f_setfperm(typval_T *argvars, typval_T *rettv);
531 static void f_setline(typval_T *argvars, typval_T *rettv);
532 static void f_setloclist(typval_T *argvars, typval_T *rettv);
533 static void f_setmatches(typval_T *argvars, typval_T *rettv);
534 static void f_setpos(typval_T *argvars, typval_T *rettv);
535 static void f_setqflist(typval_T *argvars, typval_T *rettv);
536 static void f_setreg(typval_T *argvars, typval_T *rettv);
537 static void f_settabvar(typval_T *argvars, typval_T *rettv);
538 static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
539 static void f_setwinvar(typval_T *argvars, typval_T *rettv);
540 #ifdef FEAT_CRYPT
541 static void f_sha256(typval_T *argvars, typval_T *rettv);
542 #endif /* FEAT_CRYPT */
543 static void f_shellescape(typval_T *argvars, typval_T *rettv);
544 static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
545 static void f_simplify(typval_T *argvars, typval_T *rettv);
546 #ifdef FEAT_FLOAT
547 static void f_sin(typval_T *argvars, typval_T *rettv);
548 static void f_sinh(typval_T *argvars, typval_T *rettv);
549 #endif
550 static void f_sort(typval_T *argvars, typval_T *rettv);
551 static void f_soundfold(typval_T *argvars, typval_T *rettv);
552 static void f_spellbadword(typval_T *argvars, typval_T *rettv);
553 static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
554 static void f_split(typval_T *argvars, typval_T *rettv);
555 #ifdef FEAT_FLOAT
556 static void f_sqrt(typval_T *argvars, typval_T *rettv);
557 static void f_str2float(typval_T *argvars, typval_T *rettv);
558 #endif
559 static void f_str2nr(typval_T *argvars, typval_T *rettv);
560 static void f_strchars(typval_T *argvars, typval_T *rettv);
561 #ifdef HAVE_STRFTIME
562 static void f_strftime(typval_T *argvars, typval_T *rettv);
563 #endif
564 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
565 static void f_stridx(typval_T *argvars, typval_T *rettv);
566 static void f_string(typval_T *argvars, typval_T *rettv);
567 static void f_strlen(typval_T *argvars, typval_T *rettv);
568 static void f_strcharpart(typval_T *argvars, typval_T *rettv);
569 static void f_strpart(typval_T *argvars, typval_T *rettv);
570 static void f_strridx(typval_T *argvars, typval_T *rettv);
571 static void f_strtrans(typval_T *argvars, typval_T *rettv);
572 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
573 static void f_strwidth(typval_T *argvars, typval_T *rettv);
574 static void f_submatch(typval_T *argvars, typval_T *rettv);
575 static void f_substitute(typval_T *argvars, typval_T *rettv);
576 static void f_synID(typval_T *argvars, typval_T *rettv);
577 static void f_synIDattr(typval_T *argvars, typval_T *rettv);
578 static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
579 static void f_synstack(typval_T *argvars, typval_T *rettv);
580 static void f_synconcealed(typval_T *argvars, typval_T *rettv);
581 static void f_system(typval_T *argvars, typval_T *rettv);
582 static void f_systemlist(typval_T *argvars, typval_T *rettv);
583 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
584 static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
585 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
586 static void f_taglist(typval_T *argvars, typval_T *rettv);
587 static void f_tagfiles(typval_T *argvars, typval_T *rettv);
588 static void f_tempname(typval_T *argvars, typval_T *rettv);
589 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
590 static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
591 static void f_test_disable_char_avail(typval_T *argvars, typval_T *rettv);
592 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
593 #ifdef FEAT_JOB_CHANNEL
594 static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
595 #endif
596 static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
597 #ifdef FEAT_JOB_CHANNEL
598 static void f_test_null_job(typval_T *argvars, typval_T *rettv);
599 #endif
600 static void f_test_null_list(typval_T *argvars, typval_T *rettv);
601 static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
602 static void f_test_null_string(typval_T *argvars, typval_T *rettv);
603 static void f_test_settime(typval_T *argvars, typval_T *rettv);
604 #ifdef FEAT_FLOAT
605 static void f_tan(typval_T *argvars, typval_T *rettv);
606 static void f_tanh(typval_T *argvars, typval_T *rettv);
607 #endif
608 #ifdef FEAT_TIMERS
609 static void f_timer_start(typval_T *argvars, typval_T *rettv);
610 static void f_timer_stop(typval_T *argvars, typval_T *rettv);
611 #endif
612 static void f_tolower(typval_T *argvars, typval_T *rettv);
613 static void f_toupper(typval_T *argvars, typval_T *rettv);
614 static void f_tr(typval_T *argvars, typval_T *rettv);
615 #ifdef FEAT_FLOAT
616 static void f_trunc(typval_T *argvars, typval_T *rettv);
617 #endif
618 static void f_type(typval_T *argvars, typval_T *rettv);
619 static void f_undofile(typval_T *argvars, typval_T *rettv);
620 static void f_undotree(typval_T *argvars, typval_T *rettv);
621 static void f_uniq(typval_T *argvars, typval_T *rettv);
622 static void f_values(typval_T *argvars, typval_T *rettv);
623 static void f_virtcol(typval_T *argvars, typval_T *rettv);
624 static void f_visualmode(typval_T *argvars, typval_T *rettv);
625 static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
626 static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
627 static void f_win_getid(typval_T *argvars, typval_T *rettv);
628 static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
629 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
630 static void f_win_id2win(typval_T *argvars, typval_T *rettv);
631 static void f_winbufnr(typval_T *argvars, typval_T *rettv);
632 static void f_wincol(typval_T *argvars, typval_T *rettv);
633 static void f_winheight(typval_T *argvars, typval_T *rettv);
634 static void f_winline(typval_T *argvars, typval_T *rettv);
635 static void f_winnr(typval_T *argvars, typval_T *rettv);
636 static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
637 static void f_winrestview(typval_T *argvars, typval_T *rettv);
638 static void f_winsaveview(typval_T *argvars, typval_T *rettv);
639 static void f_winwidth(typval_T *argvars, typval_T *rettv);
640 static void f_writefile(typval_T *argvars, typval_T *rettv);
641 static void f_wordcount(typval_T *argvars, typval_T *rettv);
642 static void f_xor(typval_T *argvars, typval_T *rettv);
643
644 static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp);
645 static pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum);
646 static int get_env_len(char_u **arg); 228 static int get_env_len(char_u **arg);
647 static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
648 static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); 229 static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
649 static int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload);
650 static typval_T *alloc_string_tv(char_u *string); 230 static typval_T *alloc_string_tv(char_u *string);
651 static void init_tv(typval_T *varp);
652 #ifdef FEAT_FLOAT
653 static float_T get_tv_float(typval_T *varp);
654 #endif
655 static linenr_T get_tv_lnum(typval_T *argvars);
656 static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf);
657 static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
658 static hashtab_T *find_var_ht(char_u *name, char_u **varname); 231 static hashtab_T *find_var_ht(char_u *name, char_u **varname);
659 static void delete_var(hashtab_T *ht, hashitem_T *hi); 232 static void delete_var(hashtab_T *ht, hashitem_T *hi);
660 static void list_one_var(dictitem_T *v, char_u *prefix, int *first); 233 static void list_one_var(dictitem_T *v, char_u *prefix, int *first);
661 static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first); 234 static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first);
662 static void set_var(char_u *name, typval_T *varp, int copy);
663 static int var_check_fixed(int flags, char_u *name, int use_gettext);
664 static char_u *find_option_end(char_u **arg, int *opt_flags); 235 static char_u *find_option_end(char_u **arg, int *opt_flags);
665 static win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp);
666 static win_T *find_tabwin(typval_T *wvp, typval_T *tvp);
667 static void getwinvar(typval_T *argvars, typval_T *rettv, int off);
668 static int searchpair_cmn(typval_T *argvars, pos_T *match_pos);
669 static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp);
670 static void setwinvar(typval_T *argvars, typval_T *rettv, int off);
671 static int write_list(FILE *fd, list_T *list, int binary);
672 static void get_cmd_output_as_rettv(typval_T *argvars, typval_T *rettv, int retlist);
673
674 236
675 #ifdef EBCDIC 237 #ifdef EBCDIC
676 static int compare_func_name(const void *s1, const void *s2); 238 static int compare_func_name(const void *s1, const void *s2);
677 static void sortFunctions(); 239 static void sortFunctions();
678 #endif 240 #endif
241
242 /* for VIM_VERSION_ defines */
243 #include "version.h"
679 244
680 /* 245 /*
681 * Initialize the global and v: variables. 246 * Initialize the global and v: variables.
682 */ 247 */
683 void 248 void
2198 } 1763 }
2199 1764
2200 /* 1765 /*
2201 * If "arg" is equal to "b:changedtick" give an error and return TRUE. 1766 * If "arg" is equal to "b:changedtick" give an error and return TRUE.
2202 */ 1767 */
2203 static int 1768 int
2204 check_changedtick(char_u *arg) 1769 check_changedtick(char_u *arg)
2205 { 1770 {
2206 if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) 1771 if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13]))
2207 { 1772 {
2208 EMSG2(_(e_readonlyvar), arg); 1773 EMSG2(_(e_readonlyvar), arg);
3411 } 2976 }
3412 } 2977 }
3413 --recurse; 2978 --recurse;
3414 } 2979 }
3415 2980
3416 /*
3417 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
3418 * or it refers to a List or Dictionary that is locked.
3419 */
3420 static int
3421 tv_islocked(typval_T *tv)
3422 {
3423 return (tv->v_lock & VAR_LOCKED)
3424 || (tv->v_type == VAR_LIST
3425 && tv->vval.v_list != NULL
3426 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
3427 || (tv->v_type == VAR_DICT
3428 && tv->vval.v_dict != NULL
3429 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
3430 }
3431
3432 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO) 2981 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
3433 /* 2982 /*
3434 * Delete all "menutrans_" variables. 2983 * Delete all "menutrans_" variables.
3435 */ 2984 */
3436 void 2985 void
5157 * Get an option value. 4706 * Get an option value.
5158 * "arg" points to the '&' or '+' before the option name. 4707 * "arg" points to the '&' or '+' before the option name.
5159 * "arg" is advanced to character after the option name. 4708 * "arg" is advanced to character after the option name.
5160 * Return OK or FAIL. 4709 * Return OK or FAIL.
5161 */ 4710 */
5162 static int 4711 int
5163 get_option_tv( 4712 get_option_tv(
5164 char_u **arg, 4713 char_u **arg,
5165 typval_T *rettv, /* when NULL, only check if option exists */ 4714 typval_T *rettv, /* when NULL, only check if option exists */
5166 int evaluate) 4715 int evaluate)
5167 { 4716 {
6419 } 5968 }
6420 5969
6421 return OK; 5970 return OK;
6422 } 5971 }
6423 5972
6424 /*
6425 * Array with names and number of arguments of all internal functions
6426 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
6427 */
6428 static struct fst
6429 {
6430 char *f_name; /* function name */
6431 char f_min_argc; /* minimal number of arguments */
6432 char f_max_argc; /* maximal number of arguments */
6433 void (*f_func)(typval_T *args, typval_T *rvar);
6434 /* implementation of function */
6435 } functions[] =
6436 {
6437 #ifdef FEAT_FLOAT
6438 {"abs", 1, 1, f_abs},
6439 {"acos", 1, 1, f_acos}, /* WJMc */
6440 #endif
6441 {"add", 2, 2, f_add},
6442 {"and", 2, 2, f_and},
6443 {"append", 2, 2, f_append},
6444 {"argc", 0, 0, f_argc},
6445 {"argidx", 0, 0, f_argidx},
6446 {"arglistid", 0, 2, f_arglistid},
6447 {"argv", 0, 1, f_argv},
6448 #ifdef FEAT_FLOAT
6449 {"asin", 1, 1, f_asin}, /* WJMc */
6450 #endif
6451 {"assert_equal", 2, 3, f_assert_equal},
6452 {"assert_exception", 1, 2, f_assert_exception},
6453 {"assert_fails", 1, 2, f_assert_fails},
6454 {"assert_false", 1, 2, f_assert_false},
6455 {"assert_match", 2, 3, f_assert_match},
6456 {"assert_notequal", 2, 3, f_assert_notequal},
6457 {"assert_notmatch", 2, 3, f_assert_notmatch},
6458 {"assert_true", 1, 2, f_assert_true},
6459 #ifdef FEAT_FLOAT
6460 {"atan", 1, 1, f_atan},
6461 {"atan2", 2, 2, f_atan2},
6462 #endif
6463 {"browse", 4, 4, f_browse},
6464 {"browsedir", 2, 2, f_browsedir},
6465 {"bufexists", 1, 1, f_bufexists},
6466 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
6467 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
6468 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
6469 {"buflisted", 1, 1, f_buflisted},
6470 {"bufloaded", 1, 1, f_bufloaded},
6471 {"bufname", 1, 1, f_bufname},
6472 {"bufnr", 1, 2, f_bufnr},
6473 {"bufwinid", 1, 1, f_bufwinid},
6474 {"bufwinnr", 1, 1, f_bufwinnr},
6475 {"byte2line", 1, 1, f_byte2line},
6476 {"byteidx", 2, 2, f_byteidx},
6477 {"byteidxcomp", 2, 2, f_byteidxcomp},
6478 {"call", 2, 3, f_call},
6479 #ifdef FEAT_FLOAT
6480 {"ceil", 1, 1, f_ceil},
6481 #endif
6482 #ifdef FEAT_JOB_CHANNEL
6483 {"ch_close", 1, 1, f_ch_close},
6484 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
6485 {"ch_evalraw", 2, 3, f_ch_evalraw},
6486 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
6487 {"ch_getjob", 1, 1, f_ch_getjob},
6488 {"ch_info", 1, 1, f_ch_info},
6489 {"ch_log", 1, 2, f_ch_log},
6490 {"ch_logfile", 1, 2, f_ch_logfile},
6491 {"ch_open", 1, 2, f_ch_open},
6492 {"ch_read", 1, 2, f_ch_read},
6493 {"ch_readraw", 1, 2, f_ch_readraw},
6494 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
6495 {"ch_sendraw", 2, 3, f_ch_sendraw},
6496 {"ch_setoptions", 2, 2, f_ch_setoptions},
6497 {"ch_status", 1, 1, f_ch_status},
6498 #endif
6499 {"changenr", 0, 0, f_changenr},
6500 {"char2nr", 1, 2, f_char2nr},
6501 {"cindent", 1, 1, f_cindent},
6502 {"clearmatches", 0, 0, f_clearmatches},
6503 {"col", 1, 1, f_col},
6504 #if defined(FEAT_INS_EXPAND)
6505 {"complete", 2, 2, f_complete},
6506 {"complete_add", 1, 1, f_complete_add},
6507 {"complete_check", 0, 0, f_complete_check},
6508 #endif
6509 {"confirm", 1, 4, f_confirm},
6510 {"copy", 1, 1, f_copy},
6511 #ifdef FEAT_FLOAT
6512 {"cos", 1, 1, f_cos},
6513 {"cosh", 1, 1, f_cosh},
6514 #endif
6515 {"count", 2, 4, f_count},
6516 {"cscope_connection",0,3, f_cscope_connection},
6517 {"cursor", 1, 3, f_cursor},
6518 {"deepcopy", 1, 2, f_deepcopy},
6519 {"delete", 1, 2, f_delete},
6520 {"did_filetype", 0, 0, f_did_filetype},
6521 {"diff_filler", 1, 1, f_diff_filler},
6522 {"diff_hlID", 2, 2, f_diff_hlID},
6523 {"empty", 1, 1, f_empty},
6524 {"escape", 2, 2, f_escape},
6525 {"eval", 1, 1, f_eval},
6526 {"eventhandler", 0, 0, f_eventhandler},
6527 {"executable", 1, 1, f_executable},
6528 {"execute", 1, 2, f_execute},
6529 {"exepath", 1, 1, f_exepath},
6530 {"exists", 1, 1, f_exists},
6531 #ifdef FEAT_FLOAT
6532 {"exp", 1, 1, f_exp},
6533 #endif
6534 {"expand", 1, 3, f_expand},
6535 {"extend", 2, 3, f_extend},
6536 {"feedkeys", 1, 2, f_feedkeys},
6537 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
6538 {"filereadable", 1, 1, f_filereadable},
6539 {"filewritable", 1, 1, f_filewritable},
6540 {"filter", 2, 2, f_filter},
6541 {"finddir", 1, 3, f_finddir},
6542 {"findfile", 1, 3, f_findfile},
6543 #ifdef FEAT_FLOAT
6544 {"float2nr", 1, 1, f_float2nr},
6545 {"floor", 1, 1, f_floor},
6546 {"fmod", 2, 2, f_fmod},
6547 #endif
6548 {"fnameescape", 1, 1, f_fnameescape},
6549 {"fnamemodify", 2, 2, f_fnamemodify},
6550 {"foldclosed", 1, 1, f_foldclosed},
6551 {"foldclosedend", 1, 1, f_foldclosedend},
6552 {"foldlevel", 1, 1, f_foldlevel},
6553 {"foldtext", 0, 0, f_foldtext},
6554 {"foldtextresult", 1, 1, f_foldtextresult},
6555 {"foreground", 0, 0, f_foreground},
6556 {"function", 1, 3, f_function},
6557 {"garbagecollect", 0, 1, f_garbagecollect},
6558 {"get", 2, 3, f_get},
6559 {"getbufline", 2, 3, f_getbufline},
6560 {"getbufvar", 2, 3, f_getbufvar},
6561 {"getchar", 0, 1, f_getchar},
6562 {"getcharmod", 0, 0, f_getcharmod},
6563 {"getcharsearch", 0, 0, f_getcharsearch},
6564 {"getcmdline", 0, 0, f_getcmdline},
6565 {"getcmdpos", 0, 0, f_getcmdpos},
6566 {"getcmdtype", 0, 0, f_getcmdtype},
6567 {"getcmdwintype", 0, 0, f_getcmdwintype},
6568 #if defined(FEAT_CMDL_COMPL)
6569 {"getcompletion", 2, 2, f_getcompletion},
6570 #endif
6571 {"getcurpos", 0, 0, f_getcurpos},
6572 {"getcwd", 0, 2, f_getcwd},
6573 {"getfontname", 0, 1, f_getfontname},
6574 {"getfperm", 1, 1, f_getfperm},
6575 {"getfsize", 1, 1, f_getfsize},
6576 {"getftime", 1, 1, f_getftime},
6577 {"getftype", 1, 1, f_getftype},
6578 {"getline", 1, 2, f_getline},
6579 {"getloclist", 1, 1, f_getqflist},
6580 {"getmatches", 0, 0, f_getmatches},
6581 {"getpid", 0, 0, f_getpid},
6582 {"getpos", 1, 1, f_getpos},
6583 {"getqflist", 0, 0, f_getqflist},
6584 {"getreg", 0, 3, f_getreg},
6585 {"getregtype", 0, 1, f_getregtype},
6586 {"gettabvar", 2, 3, f_gettabvar},
6587 {"gettabwinvar", 3, 4, f_gettabwinvar},
6588 {"getwinposx", 0, 0, f_getwinposx},
6589 {"getwinposy", 0, 0, f_getwinposy},
6590 {"getwinvar", 2, 3, f_getwinvar},
6591 {"glob", 1, 4, f_glob},
6592 {"glob2regpat", 1, 1, f_glob2regpat},
6593 {"globpath", 2, 5, f_globpath},
6594 {"has", 1, 1, f_has},
6595 {"has_key", 2, 2, f_has_key},
6596 {"haslocaldir", 0, 2, f_haslocaldir},
6597 {"hasmapto", 1, 3, f_hasmapto},
6598 {"highlightID", 1, 1, f_hlID}, /* obsolete */
6599 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
6600 {"histadd", 2, 2, f_histadd},
6601 {"histdel", 1, 2, f_histdel},
6602 {"histget", 1, 2, f_histget},
6603 {"histnr", 1, 1, f_histnr},
6604 {"hlID", 1, 1, f_hlID},
6605 {"hlexists", 1, 1, f_hlexists},
6606 {"hostname", 0, 0, f_hostname},
6607 {"iconv", 3, 3, f_iconv},
6608 {"indent", 1, 1, f_indent},
6609 {"index", 2, 4, f_index},
6610 {"input", 1, 3, f_input},
6611 {"inputdialog", 1, 3, f_inputdialog},
6612 {"inputlist", 1, 1, f_inputlist},
6613 {"inputrestore", 0, 0, f_inputrestore},
6614 {"inputsave", 0, 0, f_inputsave},
6615 {"inputsecret", 1, 2, f_inputsecret},
6616 {"insert", 2, 3, f_insert},
6617 {"invert", 1, 1, f_invert},
6618 {"isdirectory", 1, 1, f_isdirectory},
6619 {"islocked", 1, 1, f_islocked},
6620 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6621 {"isnan", 1, 1, f_isnan},
6622 #endif
6623 {"items", 1, 1, f_items},
6624 #ifdef FEAT_JOB_CHANNEL
6625 {"job_getchannel", 1, 1, f_job_getchannel},
6626 {"job_info", 1, 1, f_job_info},
6627 {"job_setoptions", 2, 2, f_job_setoptions},
6628 {"job_start", 1, 2, f_job_start},
6629 {"job_status", 1, 1, f_job_status},
6630 {"job_stop", 1, 2, f_job_stop},
6631 #endif
6632 {"join", 1, 2, f_join},
6633 {"js_decode", 1, 1, f_js_decode},
6634 {"js_encode", 1, 1, f_js_encode},
6635 {"json_decode", 1, 1, f_json_decode},
6636 {"json_encode", 1, 1, f_json_encode},
6637 {"keys", 1, 1, f_keys},
6638 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
6639 {"len", 1, 1, f_len},
6640 {"libcall", 3, 3, f_libcall},
6641 {"libcallnr", 3, 3, f_libcallnr},
6642 {"line", 1, 1, f_line},
6643 {"line2byte", 1, 1, f_line2byte},
6644 {"lispindent", 1, 1, f_lispindent},
6645 {"localtime", 0, 0, f_localtime},
6646 #ifdef FEAT_FLOAT
6647 {"log", 1, 1, f_log},
6648 {"log10", 1, 1, f_log10},
6649 #endif
6650 #ifdef FEAT_LUA
6651 {"luaeval", 1, 2, f_luaeval},
6652 #endif
6653 {"map", 2, 2, f_map},
6654 {"maparg", 1, 4, f_maparg},
6655 {"mapcheck", 1, 3, f_mapcheck},
6656 {"match", 2, 4, f_match},
6657 {"matchadd", 2, 5, f_matchadd},
6658 {"matchaddpos", 2, 5, f_matchaddpos},
6659 {"matcharg", 1, 1, f_matcharg},
6660 {"matchdelete", 1, 1, f_matchdelete},
6661 {"matchend", 2, 4, f_matchend},
6662 {"matchlist", 2, 4, f_matchlist},
6663 {"matchstr", 2, 4, f_matchstr},
6664 {"matchstrpos", 2, 4, f_matchstrpos},
6665 {"max", 1, 1, f_max},
6666 {"min", 1, 1, f_min},
6667 #ifdef vim_mkdir
6668 {"mkdir", 1, 3, f_mkdir},
6669 #endif
6670 {"mode", 0, 1, f_mode},
6671 #ifdef FEAT_MZSCHEME
6672 {"mzeval", 1, 1, f_mzeval},
6673 #endif
6674 {"nextnonblank", 1, 1, f_nextnonblank},
6675 {"nr2char", 1, 2, f_nr2char},
6676 {"or", 2, 2, f_or},
6677 {"pathshorten", 1, 1, f_pathshorten},
6678 #ifdef FEAT_PERL
6679 {"perleval", 1, 1, f_perleval},
6680 #endif
6681 #ifdef FEAT_FLOAT
6682 {"pow", 2, 2, f_pow},
6683 #endif
6684 {"prevnonblank", 1, 1, f_prevnonblank},
6685 {"printf", 2, 19, f_printf},
6686 {"pumvisible", 0, 0, f_pumvisible},
6687 #ifdef FEAT_PYTHON3
6688 {"py3eval", 1, 1, f_py3eval},
6689 #endif
6690 #ifdef FEAT_PYTHON
6691 {"pyeval", 1, 1, f_pyeval},
6692 #endif
6693 {"range", 1, 3, f_range},
6694 {"readfile", 1, 3, f_readfile},
6695 {"reltime", 0, 2, f_reltime},
6696 #ifdef FEAT_FLOAT
6697 {"reltimefloat", 1, 1, f_reltimefloat},
6698 #endif
6699 {"reltimestr", 1, 1, f_reltimestr},
6700 {"remote_expr", 2, 3, f_remote_expr},
6701 {"remote_foreground", 1, 1, f_remote_foreground},
6702 {"remote_peek", 1, 2, f_remote_peek},
6703 {"remote_read", 1, 1, f_remote_read},
6704 {"remote_send", 2, 3, f_remote_send},
6705 {"remove", 2, 3, f_remove},
6706 {"rename", 2, 2, f_rename},
6707 {"repeat", 2, 2, f_repeat},
6708 {"resolve", 1, 1, f_resolve},
6709 {"reverse", 1, 1, f_reverse},
6710 #ifdef FEAT_FLOAT
6711 {"round", 1, 1, f_round},
6712 #endif
6713 {"screenattr", 2, 2, f_screenattr},
6714 {"screenchar", 2, 2, f_screenchar},
6715 {"screencol", 0, 0, f_screencol},
6716 {"screenrow", 0, 0, f_screenrow},
6717 {"search", 1, 4, f_search},
6718 {"searchdecl", 1, 3, f_searchdecl},
6719 {"searchpair", 3, 7, f_searchpair},
6720 {"searchpairpos", 3, 7, f_searchpairpos},
6721 {"searchpos", 1, 4, f_searchpos},
6722 {"server2client", 2, 2, f_server2client},
6723 {"serverlist", 0, 0, f_serverlist},
6724 {"setbufvar", 3, 3, f_setbufvar},
6725 {"setcharsearch", 1, 1, f_setcharsearch},
6726 {"setcmdpos", 1, 1, f_setcmdpos},
6727 {"setfperm", 2, 2, f_setfperm},
6728 {"setline", 2, 2, f_setline},
6729 {"setloclist", 2, 3, f_setloclist},
6730 {"setmatches", 1, 1, f_setmatches},
6731 {"setpos", 2, 2, f_setpos},
6732 {"setqflist", 1, 2, f_setqflist},
6733 {"setreg", 2, 3, f_setreg},
6734 {"settabvar", 3, 3, f_settabvar},
6735 {"settabwinvar", 4, 4, f_settabwinvar},
6736 {"setwinvar", 3, 3, f_setwinvar},
6737 #ifdef FEAT_CRYPT
6738 {"sha256", 1, 1, f_sha256},
6739 #endif
6740 {"shellescape", 1, 2, f_shellescape},
6741 {"shiftwidth", 0, 0, f_shiftwidth},
6742 {"simplify", 1, 1, f_simplify},
6743 #ifdef FEAT_FLOAT
6744 {"sin", 1, 1, f_sin},
6745 {"sinh", 1, 1, f_sinh},
6746 #endif
6747 {"sort", 1, 3, f_sort},
6748 {"soundfold", 1, 1, f_soundfold},
6749 {"spellbadword", 0, 1, f_spellbadword},
6750 {"spellsuggest", 1, 3, f_spellsuggest},
6751 {"split", 1, 3, f_split},
6752 #ifdef FEAT_FLOAT
6753 {"sqrt", 1, 1, f_sqrt},
6754 {"str2float", 1, 1, f_str2float},
6755 #endif
6756 {"str2nr", 1, 2, f_str2nr},
6757 {"strcharpart", 2, 3, f_strcharpart},
6758 {"strchars", 1, 2, f_strchars},
6759 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
6760 #ifdef HAVE_STRFTIME
6761 {"strftime", 1, 2, f_strftime},
6762 #endif
6763 {"strgetchar", 2, 2, f_strgetchar},
6764 {"stridx", 2, 3, f_stridx},
6765 {"string", 1, 1, f_string},
6766 {"strlen", 1, 1, f_strlen},
6767 {"strpart", 2, 3, f_strpart},
6768 {"strridx", 2, 3, f_strridx},
6769 {"strtrans", 1, 1, f_strtrans},
6770 {"strwidth", 1, 1, f_strwidth},
6771 {"submatch", 1, 2, f_submatch},
6772 {"substitute", 4, 4, f_substitute},
6773 {"synID", 3, 3, f_synID},
6774 {"synIDattr", 2, 3, f_synIDattr},
6775 {"synIDtrans", 1, 1, f_synIDtrans},
6776 {"synconcealed", 2, 2, f_synconcealed},
6777 {"synstack", 2, 2, f_synstack},
6778 {"system", 1, 2, f_system},
6779 {"systemlist", 1, 2, f_systemlist},
6780 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
6781 {"tabpagenr", 0, 1, f_tabpagenr},
6782 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
6783 {"tagfiles", 0, 0, f_tagfiles},
6784 {"taglist", 1, 1, f_taglist},
6785 #ifdef FEAT_FLOAT
6786 {"tan", 1, 1, f_tan},
6787 {"tanh", 1, 1, f_tanh},
6788 #endif
6789 {"tempname", 0, 0, f_tempname},
6790 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
6791 {"test_autochdir", 0, 0, f_test_autochdir},
6792 {"test_disable_char_avail", 1, 1, f_test_disable_char_avail},
6793 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
6794 #ifdef FEAT_JOB_CHANNEL
6795 {"test_null_channel", 0, 0, f_test_null_channel},
6796 #endif
6797 {"test_null_dict", 0, 0, f_test_null_dict},
6798 #ifdef FEAT_JOB_CHANNEL
6799 {"test_null_job", 0, 0, f_test_null_job},
6800 #endif
6801 {"test_null_list", 0, 0, f_test_null_list},
6802 {"test_null_partial", 0, 0, f_test_null_partial},
6803 {"test_null_string", 0, 0, f_test_null_string},
6804 {"test_settime", 1, 1, f_test_settime},
6805 #ifdef FEAT_TIMERS
6806 {"timer_start", 2, 3, f_timer_start},
6807 {"timer_stop", 1, 1, f_timer_stop},
6808 #endif
6809 {"tolower", 1, 1, f_tolower},
6810 {"toupper", 1, 1, f_toupper},
6811 {"tr", 3, 3, f_tr},
6812 #ifdef FEAT_FLOAT
6813 {"trunc", 1, 1, f_trunc},
6814 #endif
6815 {"type", 1, 1, f_type},
6816 {"undofile", 1, 1, f_undofile},
6817 {"undotree", 0, 0, f_undotree},
6818 {"uniq", 1, 3, f_uniq},
6819 {"values", 1, 1, f_values},
6820 {"virtcol", 1, 1, f_virtcol},
6821 {"visualmode", 0, 1, f_visualmode},
6822 {"wildmenumode", 0, 0, f_wildmenumode},
6823 {"win_findbuf", 1, 1, f_win_findbuf},
6824 {"win_getid", 0, 2, f_win_getid},
6825 {"win_gotoid", 1, 1, f_win_gotoid},
6826 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
6827 {"win_id2win", 1, 1, f_win_id2win},
6828 {"winbufnr", 1, 1, f_winbufnr},
6829 {"wincol", 0, 0, f_wincol},
6830 {"winheight", 1, 1, f_winheight},
6831 {"winline", 0, 0, f_winline},
6832 {"winnr", 0, 1, f_winnr},
6833 {"winrestcmd", 0, 0, f_winrestcmd},
6834 {"winrestview", 1, 1, f_winrestview},
6835 {"winsaveview", 0, 0, f_winsaveview},
6836 {"winwidth", 1, 1, f_winwidth},
6837 {"wordcount", 0, 0, f_wordcount},
6838 {"writefile", 2, 3, f_writefile},
6839 {"xor", 2, 2, f_xor},
6840 };
6841
6842 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
6843
6844 /*
6845 * Function given to ExpandGeneric() to obtain the list of internal
6846 * or user defined function names.
6847 */
6848 char_u *
6849 get_function_name(expand_T *xp, int idx)
6850 {
6851 static int intidx = -1;
6852 char_u *name;
6853
6854 if (idx == 0)
6855 intidx = -1;
6856 if (intidx < 0)
6857 {
6858 name = get_user_func_name(xp, idx);
6859 if (name != NULL)
6860 return name;
6861 }
6862 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
6863 {
6864 STRCPY(IObuff, functions[intidx].f_name);
6865 STRCAT(IObuff, "(");
6866 if (functions[intidx].f_max_argc == 0)
6867 STRCAT(IObuff, ")");
6868 return IObuff;
6869 }
6870
6871 return NULL;
6872 }
6873
6874 /*
6875 * Function given to ExpandGeneric() to obtain the list of internal or
6876 * user defined variable or function names.
6877 */
6878 char_u *
6879 get_expr_name(expand_T *xp, int idx)
6880 {
6881 static int intidx = -1;
6882 char_u *name;
6883
6884 if (idx == 0)
6885 intidx = -1;
6886 if (intidx < 0)
6887 {
6888 name = get_function_name(xp, idx);
6889 if (name != NULL)
6890 return name;
6891 }
6892 return get_user_var_name(xp, ++intidx);
6893 }
6894
6895 #endif /* FEAT_CMDL_COMPL */
6896
6897 #if defined(EBCDIC) || defined(PROTO)
6898 /*
6899 * Compare struct fst by function name.
6900 */
6901 static int
6902 compare_func_name(const void *s1, const void *s2)
6903 {
6904 struct fst *p1 = (struct fst *)s1;
6905 struct fst *p2 = (struct fst *)s2;
6906
6907 return STRCMP(p1->f_name, p2->f_name);
6908 }
6909
6910 /*
6911 * Sort the function table by function name.
6912 * The sorting of the table above is ASCII dependant.
6913 * On machines using EBCDIC we have to sort it.
6914 */
6915 static void
6916 sortFunctions(void)
6917 {
6918 int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
6919
6920 qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name);
6921 }
6922 #endif
6923
6924
6925 /*
6926 * Find internal function in table above.
6927 * Return index, or -1 if not found
6928 */
6929 int
6930 find_internal_func(
6931 char_u *name) /* name of the function */
6932 {
6933 int first = 0;
6934 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
6935 int cmp;
6936 int x;
6937
6938 /*
6939 * Find the function name in the table. Binary search.
6940 */
6941 while (first <= last)
6942 {
6943 x = first + ((unsigned)(last - first) >> 1);
6944 cmp = STRCMP(name, functions[x].f_name);
6945 if (cmp < 0)
6946 last = x - 1;
6947 else if (cmp > 0)
6948 first = x + 1;
6949 else
6950 return x;
6951 }
6952 return -1;
6953 }
6954
6955 int
6956 call_internal_func(
6957 char_u *name,
6958 int argcount,
6959 typval_T *argvars,
6960 typval_T *rettv)
6961 {
6962 int i;
6963
6964 i = find_internal_func(name);
6965 if (i < 0)
6966 return ERROR_UNKNOWN;
6967 if (argcount < functions[i].f_min_argc)
6968 return ERROR_TOOFEW;
6969 if (argcount > functions[i].f_max_argc)
6970 return ERROR_TOOMANY;
6971 argvars[argcount].v_type = VAR_UNKNOWN;
6972 functions[i].f_func(argvars, rettv);
6973 return ERROR_NONE;
6974 }
6975
6976 /*
6977 * Return TRUE for a non-zero Number and a non-empty String.
6978 */
6979 static int
6980 non_zero_arg(typval_T *argvars)
6981 {
6982 return ((argvars[0].v_type == VAR_NUMBER
6983 && argvars[0].vval.v_number != 0)
6984 || (argvars[0].v_type == VAR_SPECIAL
6985 && argvars[0].vval.v_number == VVAL_TRUE)
6986 || (argvars[0].v_type == VAR_STRING
6987 && argvars[0].vval.v_string != NULL
6988 && *argvars[0].vval.v_string != NUL));
6989 }
6990
6991 /*********************************************
6992 * Implementation of the built-in functions
6993 */
6994
6995 #ifdef FEAT_FLOAT
6996 static int get_float_arg(typval_T *argvars, float_T *f);
6997
6998 /*
6999 * Get the float value of "argvars[0]" into "f".
7000 * Returns FAIL when the argument is not a Number or Float.
7001 */
7002 static int
7003 get_float_arg(typval_T *argvars, float_T *f)
7004 {
7005 if (argvars[0].v_type == VAR_FLOAT)
7006 {
7007 *f = argvars[0].vval.v_float;
7008 return OK;
7009 }
7010 if (argvars[0].v_type == VAR_NUMBER)
7011 {
7012 *f = (float_T)argvars[0].vval.v_number;
7013 return OK;
7014 }
7015 EMSG(_("E808: Number or Float required"));
7016 return FAIL;
7017 }
7018
7019 /*
7020 * "abs(expr)" function
7021 */
7022 static void
7023 f_abs(typval_T *argvars, typval_T *rettv)
7024 {
7025 if (argvars[0].v_type == VAR_FLOAT)
7026 {
7027 rettv->v_type = VAR_FLOAT;
7028 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
7029 }
7030 else
7031 {
7032 varnumber_T n;
7033 int error = FALSE;
7034
7035 n = get_tv_number_chk(&argvars[0], &error);
7036 if (error)
7037 rettv->vval.v_number = -1;
7038 else if (n > 0)
7039 rettv->vval.v_number = n;
7040 else
7041 rettv->vval.v_number = -n;
7042 }
7043 }
7044
7045 /*
7046 * "acos()" function
7047 */
7048 static void
7049 f_acos(typval_T *argvars, typval_T *rettv)
7050 {
7051 float_T f = 0.0;
7052
7053 rettv->v_type = VAR_FLOAT;
7054 if (get_float_arg(argvars, &f) == OK)
7055 rettv->vval.v_float = acos(f);
7056 else
7057 rettv->vval.v_float = 0.0;
7058 }
7059 #endif
7060
7061 /*
7062 * "add(list, item)" function
7063 */
7064 static void
7065 f_add(typval_T *argvars, typval_T *rettv)
7066 {
7067 list_T *l;
7068
7069 rettv->vval.v_number = 1; /* Default: Failed */
7070 if (argvars[0].v_type == VAR_LIST)
7071 {
7072 if ((l = argvars[0].vval.v_list) != NULL
7073 && !tv_check_lock(l->lv_lock,
7074 (char_u *)N_("add() argument"), TRUE)
7075 && list_append_tv(l, &argvars[1]) == OK)
7076 copy_tv(&argvars[0], rettv);
7077 }
7078 else
7079 EMSG(_(e_listreq));
7080 }
7081
7082 /*
7083 * "and(expr, expr)" function
7084 */
7085 static void
7086 f_and(typval_T *argvars, typval_T *rettv)
7087 {
7088 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7089 & get_tv_number_chk(&argvars[1], NULL);
7090 }
7091
7092 /*
7093 * "append(lnum, string/list)" function
7094 */
7095 static void
7096 f_append(typval_T *argvars, typval_T *rettv)
7097 {
7098 long lnum;
7099 char_u *line;
7100 list_T *l = NULL;
7101 listitem_T *li = NULL;
7102 typval_T *tv;
7103 long added = 0;
7104
7105 /* When coming here from Insert mode, sync undo, so that this can be
7106 * undone separately from what was previously inserted. */
7107 if (u_sync_once == 2)
7108 {
7109 u_sync_once = 1; /* notify that u_sync() was called */
7110 u_sync(TRUE);
7111 }
7112
7113 lnum = get_tv_lnum(argvars);
7114 if (lnum >= 0
7115 && lnum <= curbuf->b_ml.ml_line_count
7116 && u_save(lnum, lnum + 1) == OK)
7117 {
7118 if (argvars[1].v_type == VAR_LIST)
7119 {
7120 l = argvars[1].vval.v_list;
7121 if (l == NULL)
7122 return;
7123 li = l->lv_first;
7124 }
7125 for (;;)
7126 {
7127 if (l == NULL)
7128 tv = &argvars[1]; /* append a string */
7129 else if (li == NULL)
7130 break; /* end of list */
7131 else
7132 tv = &li->li_tv; /* append item from list */
7133 line = get_tv_string_chk(tv);
7134 if (line == NULL) /* type error */
7135 {
7136 rettv->vval.v_number = 1; /* Failed */
7137 break;
7138 }
7139 ml_append(lnum + added, line, (colnr_T)0, FALSE);
7140 ++added;
7141 if (l == NULL)
7142 break;
7143 li = li->li_next;
7144 }
7145
7146 appended_lines_mark(lnum, added);
7147 if (curwin->w_cursor.lnum > lnum)
7148 curwin->w_cursor.lnum += added;
7149 }
7150 else
7151 rettv->vval.v_number = 1; /* Failed */
7152 }
7153
7154 /*
7155 * "argc()" function
7156 */
7157 static void
7158 f_argc(typval_T *argvars UNUSED, typval_T *rettv)
7159 {
7160 rettv->vval.v_number = ARGCOUNT;
7161 }
7162
7163 /*
7164 * "argidx()" function
7165 */
7166 static void
7167 f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
7168 {
7169 rettv->vval.v_number = curwin->w_arg_idx;
7170 }
7171
7172 /*
7173 * "arglistid()" function
7174 */
7175 static void
7176 f_arglistid(typval_T *argvars, typval_T *rettv)
7177 {
7178 win_T *wp;
7179
7180 rettv->vval.v_number = -1;
7181 wp = find_tabwin(&argvars[0], &argvars[1]);
7182 if (wp != NULL)
7183 rettv->vval.v_number = wp->w_alist->id;
7184 }
7185
7186 /*
7187 * "argv(nr)" function
7188 */
7189 static void
7190 f_argv(typval_T *argvars, typval_T *rettv)
7191 {
7192 int idx;
7193
7194 if (argvars[0].v_type != VAR_UNKNOWN)
7195 {
7196 idx = (int)get_tv_number_chk(&argvars[0], NULL);
7197 if (idx >= 0 && idx < ARGCOUNT)
7198 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
7199 else
7200 rettv->vval.v_string = NULL;
7201 rettv->v_type = VAR_STRING;
7202 }
7203 else if (rettv_list_alloc(rettv) == OK)
7204 for (idx = 0; idx < ARGCOUNT; ++idx)
7205 list_append_string(rettv->vval.v_list,
7206 alist_name(&ARGLIST[idx]), -1);
7207 }
7208
7209 typedef enum
7210 {
7211 ASSERT_EQUAL,
7212 ASSERT_NOTEQUAL,
7213 ASSERT_MATCH,
7214 ASSERT_NOTMATCH,
7215 ASSERT_OTHER
7216 } assert_type_T;
7217
7218 static void prepare_assert_error(garray_T*gap);
7219 static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T is_match);
7220 static void assert_error(garray_T *gap);
7221 static void assert_bool(typval_T *argvars, int isTrue);
7222
7223 /*
7224 * Prepare "gap" for an assert error and add the sourcing position.
7225 */
7226 static void
7227 prepare_assert_error(garray_T *gap)
7228 {
7229 char buf[NUMBUFLEN];
7230
7231 ga_init2(gap, 1, 100);
7232 if (sourcing_name != NULL)
7233 {
7234 ga_concat(gap, sourcing_name);
7235 if (sourcing_lnum > 0)
7236 ga_concat(gap, (char_u *)" ");
7237 }
7238 if (sourcing_lnum > 0)
7239 {
7240 sprintf(buf, "line %ld", (long)sourcing_lnum);
7241 ga_concat(gap, (char_u *)buf);
7242 }
7243 if (sourcing_name != NULL || sourcing_lnum > 0)
7244 ga_concat(gap, (char_u *)": ");
7245 }
7246
7247 /*
7248 * Append "str" to "gap", escaping unprintable characters.
7249 * Changes NL to \n, CR to \r, etc.
7250 */
7251 static void
7252 ga_concat_esc(garray_T *gap, char_u *str)
7253 {
7254 char_u *p;
7255 char_u buf[NUMBUFLEN];
7256
7257 if (str == NULL)
7258 {
7259 ga_concat(gap, (char_u *)"NULL");
7260 return;
7261 }
7262
7263 for (p = str; *p != NUL; ++p)
7264 switch (*p)
7265 {
7266 case BS: ga_concat(gap, (char_u *)"\\b"); break;
7267 case ESC: ga_concat(gap, (char_u *)"\\e"); break;
7268 case FF: ga_concat(gap, (char_u *)"\\f"); break;
7269 case NL: ga_concat(gap, (char_u *)"\\n"); break;
7270 case TAB: ga_concat(gap, (char_u *)"\\t"); break;
7271 case CAR: ga_concat(gap, (char_u *)"\\r"); break;
7272 case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
7273 default:
7274 if (*p < ' ')
7275 {
7276 vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
7277 ga_concat(gap, buf);
7278 }
7279 else
7280 ga_append(gap, *p);
7281 break;
7282 }
7283 }
7284
7285 /*
7286 * Fill "gap" with information about an assert error.
7287 */
7288 static void
7289 fill_assert_error(
7290 garray_T *gap,
7291 typval_T *opt_msg_tv,
7292 char_u *exp_str,
7293 typval_T *exp_tv,
7294 typval_T *got_tv,
7295 assert_type_T atype)
7296 {
7297 char_u numbuf[NUMBUFLEN];
7298 char_u *tofree;
7299
7300 if (opt_msg_tv->v_type != VAR_UNKNOWN)
7301 {
7302 ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0));
7303 vim_free(tofree);
7304 }
7305 else
7306 {
7307 if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH)
7308 ga_concat(gap, (char_u *)"Pattern ");
7309 else
7310 ga_concat(gap, (char_u *)"Expected ");
7311 if (exp_str == NULL)
7312 {
7313 ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
7314 vim_free(tofree);
7315 }
7316 else
7317 ga_concat_esc(gap, exp_str);
7318 if (atype == ASSERT_MATCH)
7319 ga_concat(gap, (char_u *)" does not match ");
7320 else if (atype == ASSERT_NOTMATCH)
7321 ga_concat(gap, (char_u *)" does match ");
7322 else if (atype == ASSERT_NOTEQUAL)
7323 ga_concat(gap, (char_u *)" differs from ");
7324 else
7325 ga_concat(gap, (char_u *)" but got ");
7326 ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
7327 vim_free(tofree);
7328 }
7329 }
7330
7331 /*
7332 * Add an assert error to v:errors.
7333 */
7334 static void
7335 assert_error(garray_T *gap)
7336 {
7337 struct vimvar *vp = &vimvars[VV_ERRORS];
7338
7339 if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
7340 /* Make sure v:errors is a list. */
7341 set_vim_var_list(VV_ERRORS, list_alloc());
7342 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
7343 }
7344
7345 static void
7346 assert_equal_common(typval_T *argvars, assert_type_T atype)
7347 {
7348 garray_T ga;
7349
7350 if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE)
7351 != (atype == ASSERT_EQUAL))
7352 {
7353 prepare_assert_error(&ga);
7354 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
7355 atype);
7356 assert_error(&ga);
7357 ga_clear(&ga);
7358 }
7359 }
7360
7361 /*
7362 * "assert_equal(expected, actual[, msg])" function
7363 */
7364 static void
7365 f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
7366 {
7367 assert_equal_common(argvars, ASSERT_EQUAL);
7368 }
7369
7370 /*
7371 * "assert_notequal(expected, actual[, msg])" function
7372 */
7373 static void
7374 f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
7375 {
7376 assert_equal_common(argvars, ASSERT_NOTEQUAL);
7377 }
7378
7379 /*
7380 * "assert_exception(string[, msg])" function
7381 */
7382 static void
7383 f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
7384 {
7385 garray_T ga;
7386 char *error;
7387
7388 error = (char *)get_tv_string_chk(&argvars[0]);
7389 if (vimvars[VV_EXCEPTION].vv_str == NULL)
7390 {
7391 prepare_assert_error(&ga);
7392 ga_concat(&ga, (char_u *)"v:exception is not set");
7393 assert_error(&ga);
7394 ga_clear(&ga);
7395 }
7396 else if (error != NULL
7397 && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL)
7398 {
7399 prepare_assert_error(&ga);
7400 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
7401 &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER);
7402 assert_error(&ga);
7403 ga_clear(&ga);
7404 }
7405 }
7406
7407 /*
7408 * "assert_fails(cmd [, error])" function
7409 */
7410 static void
7411 f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
7412 {
7413 char_u *cmd = get_tv_string_chk(&argvars[0]);
7414 garray_T ga;
7415
7416 called_emsg = FALSE;
7417 suppress_errthrow = TRUE;
7418 emsg_silent = TRUE;
7419 do_cmdline_cmd(cmd);
7420 if (!called_emsg)
7421 {
7422 prepare_assert_error(&ga);
7423 ga_concat(&ga, (char_u *)"command did not fail: ");
7424 ga_concat(&ga, cmd);
7425 assert_error(&ga);
7426 ga_clear(&ga);
7427 }
7428 else if (argvars[1].v_type != VAR_UNKNOWN)
7429 {
7430 char_u buf[NUMBUFLEN];
7431 char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf);
7432
7433 if (error == NULL
7434 || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL)
7435 {
7436 prepare_assert_error(&ga);
7437 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
7438 &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
7439 assert_error(&ga);
7440 ga_clear(&ga);
7441 }
7442 }
7443
7444 called_emsg = FALSE;
7445 suppress_errthrow = FALSE;
7446 emsg_silent = FALSE;
7447 emsg_on_display = FALSE;
7448 set_vim_var_string(VV_ERRMSG, NULL, 0);
7449 }
7450
7451 /*
7452 * Common for assert_true() and assert_false().
7453 */
7454 static void
7455 assert_bool(typval_T *argvars, int isTrue)
7456 {
7457 int error = FALSE;
7458 garray_T ga;
7459
7460 if (argvars[0].v_type == VAR_SPECIAL
7461 && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE))
7462 return;
7463 if (argvars[0].v_type != VAR_NUMBER
7464 || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue
7465 || error)
7466 {
7467 prepare_assert_error(&ga);
7468 fill_assert_error(&ga, &argvars[1],
7469 (char_u *)(isTrue ? "True" : "False"),
7470 NULL, &argvars[0], ASSERT_OTHER);
7471 assert_error(&ga);
7472 ga_clear(&ga);
7473 }
7474 }
7475
7476 /*
7477 * "assert_false(actual[, msg])" function
7478 */
7479 static void
7480 f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
7481 {
7482 assert_bool(argvars, FALSE);
7483 }
7484
7485 static void
7486 assert_match_common(typval_T *argvars, assert_type_T atype)
7487 {
7488 garray_T ga;
7489 char_u buf1[NUMBUFLEN];
7490 char_u buf2[NUMBUFLEN];
7491 char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1);
7492 char_u *text = get_tv_string_buf_chk(&argvars[1], buf2);
7493
7494 if (pat == NULL || text == NULL)
7495 EMSG(_(e_invarg));
7496 else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH))
7497 {
7498 prepare_assert_error(&ga);
7499 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
7500 atype);
7501 assert_error(&ga);
7502 ga_clear(&ga);
7503 }
7504 }
7505
7506 /*
7507 * "assert_match(pattern, actual[, msg])" function
7508 */
7509 static void
7510 f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
7511 {
7512 assert_match_common(argvars, ASSERT_MATCH);
7513 }
7514
7515 /*
7516 * "assert_notmatch(pattern, actual[, msg])" function
7517 */
7518 static void
7519 f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
7520 {
7521 assert_match_common(argvars, ASSERT_NOTMATCH);
7522 }
7523
7524 /*
7525 * "assert_true(actual[, msg])" function
7526 */
7527 static void
7528 f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
7529 {
7530 assert_bool(argvars, TRUE);
7531 }
7532
7533 #ifdef FEAT_FLOAT
7534 /*
7535 * "asin()" function
7536 */
7537 static void
7538 f_asin(typval_T *argvars, typval_T *rettv)
7539 {
7540 float_T f = 0.0;
7541
7542 rettv->v_type = VAR_FLOAT;
7543 if (get_float_arg(argvars, &f) == OK)
7544 rettv->vval.v_float = asin(f);
7545 else
7546 rettv->vval.v_float = 0.0;
7547 }
7548
7549 /*
7550 * "atan()" function
7551 */
7552 static void
7553 f_atan(typval_T *argvars, typval_T *rettv)
7554 {
7555 float_T f = 0.0;
7556
7557 rettv->v_type = VAR_FLOAT;
7558 if (get_float_arg(argvars, &f) == OK)
7559 rettv->vval.v_float = atan(f);
7560 else
7561 rettv->vval.v_float = 0.0;
7562 }
7563
7564 /*
7565 * "atan2()" function
7566 */
7567 static void
7568 f_atan2(typval_T *argvars, typval_T *rettv)
7569 {
7570 float_T fx = 0.0, fy = 0.0;
7571
7572 rettv->v_type = VAR_FLOAT;
7573 if (get_float_arg(argvars, &fx) == OK
7574 && get_float_arg(&argvars[1], &fy) == OK)
7575 rettv->vval.v_float = atan2(fx, fy);
7576 else
7577 rettv->vval.v_float = 0.0;
7578 }
7579 #endif
7580
7581 /*
7582 * "browse(save, title, initdir, default)" function
7583 */
7584 static void
7585 f_browse(typval_T *argvars UNUSED, typval_T *rettv)
7586 {
7587 #ifdef FEAT_BROWSE
7588 int save;
7589 char_u *title;
7590 char_u *initdir;
7591 char_u *defname;
7592 char_u buf[NUMBUFLEN];
7593 char_u buf2[NUMBUFLEN];
7594 int error = FALSE;
7595
7596 save = (int)get_tv_number_chk(&argvars[0], &error);
7597 title = get_tv_string_chk(&argvars[1]);
7598 initdir = get_tv_string_buf_chk(&argvars[2], buf);
7599 defname = get_tv_string_buf_chk(&argvars[3], buf2);
7600
7601 if (error || title == NULL || initdir == NULL || defname == NULL)
7602 rettv->vval.v_string = NULL;
7603 else
7604 rettv->vval.v_string =
7605 do_browse(save ? BROWSE_SAVE : 0,
7606 title, defname, NULL, initdir, NULL, curbuf);
7607 #else
7608 rettv->vval.v_string = NULL;
7609 #endif
7610 rettv->v_type = VAR_STRING;
7611 }
7612
7613 /*
7614 * "browsedir(title, initdir)" function
7615 */
7616 static void
7617 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
7618 {
7619 #ifdef FEAT_BROWSE
7620 char_u *title;
7621 char_u *initdir;
7622 char_u buf[NUMBUFLEN];
7623
7624 title = get_tv_string_chk(&argvars[0]);
7625 initdir = get_tv_string_buf_chk(&argvars[1], buf);
7626
7627 if (title == NULL || initdir == NULL)
7628 rettv->vval.v_string = NULL;
7629 else
7630 rettv->vval.v_string = do_browse(BROWSE_DIR,
7631 title, NULL, NULL, initdir, NULL, curbuf);
7632 #else
7633 rettv->vval.v_string = NULL;
7634 #endif
7635 rettv->v_type = VAR_STRING;
7636 }
7637
7638 static buf_T *find_buffer(typval_T *avar);
7639
7640 /*
7641 * Find a buffer by number or exact name.
7642 */
7643 static buf_T *
7644 find_buffer(typval_T *avar)
7645 {
7646 buf_T *buf = NULL;
7647
7648 if (avar->v_type == VAR_NUMBER)
7649 buf = buflist_findnr((int)avar->vval.v_number);
7650 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
7651 {
7652 buf = buflist_findname_exp(avar->vval.v_string);
7653 if (buf == NULL)
7654 {
7655 /* No full path name match, try a match with a URL or a "nofile"
7656 * buffer, these don't use the full path. */
7657 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
7658 if (buf->b_fname != NULL
7659 && (path_with_url(buf->b_fname)
7660 #ifdef FEAT_QUICKFIX
7661 || bt_nofile(buf)
7662 #endif
7663 )
7664 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
7665 break;
7666 }
7667 }
7668 return buf;
7669 }
7670
7671 /*
7672 * "bufexists(expr)" function
7673 */
7674 static void
7675 f_bufexists(typval_T *argvars, typval_T *rettv)
7676 {
7677 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
7678 }
7679
7680 /*
7681 * "buflisted(expr)" function
7682 */
7683 static void
7684 f_buflisted(typval_T *argvars, typval_T *rettv)
7685 {
7686 buf_T *buf;
7687
7688 buf = find_buffer(&argvars[0]);
7689 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
7690 }
7691
7692 /*
7693 * "bufloaded(expr)" function
7694 */
7695 static void
7696 f_bufloaded(typval_T *argvars, typval_T *rettv)
7697 {
7698 buf_T *buf;
7699
7700 buf = find_buffer(&argvars[0]);
7701 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
7702 }
7703
7704 buf_T *
7705 buflist_find_by_name(char_u *name, int curtab_only)
7706 {
7707 int save_magic;
7708 char_u *save_cpo;
7709 buf_T *buf;
7710
7711 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
7712 save_magic = p_magic;
7713 p_magic = TRUE;
7714 save_cpo = p_cpo;
7715 p_cpo = (char_u *)"";
7716
7717 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
7718 TRUE, FALSE, curtab_only));
7719
7720 p_magic = save_magic;
7721 p_cpo = save_cpo;
7722 return buf;
7723 }
7724
7725 /*
7726 * Get buffer by number or pattern.
7727 */
7728 static buf_T *
7729 get_buf_tv(typval_T *tv, int curtab_only)
7730 {
7731 char_u *name = tv->vval.v_string;
7732 buf_T *buf;
7733
7734 if (tv->v_type == VAR_NUMBER)
7735 return buflist_findnr((int)tv->vval.v_number);
7736 if (tv->v_type != VAR_STRING)
7737 return NULL;
7738 if (name == NULL || *name == NUL)
7739 return curbuf;
7740 if (name[0] == '$' && name[1] == NUL)
7741 return lastbuf;
7742
7743 buf = buflist_find_by_name(name, curtab_only);
7744
7745 /* If not found, try expanding the name, like done for bufexists(). */
7746 if (buf == NULL)
7747 buf = find_buffer(tv);
7748
7749 return buf;
7750 }
7751
7752 /*
7753 * "bufname(expr)" function
7754 */
7755 static void
7756 f_bufname(typval_T *argvars, typval_T *rettv)
7757 {
7758 buf_T *buf;
7759
7760 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
7761 ++emsg_off;
7762 buf = get_buf_tv(&argvars[0], FALSE);
7763 rettv->v_type = VAR_STRING;
7764 if (buf != NULL && buf->b_fname != NULL)
7765 rettv->vval.v_string = vim_strsave(buf->b_fname);
7766 else
7767 rettv->vval.v_string = NULL;
7768 --emsg_off;
7769 }
7770
7771 /*
7772 * "bufnr(expr)" function
7773 */
7774 static void
7775 f_bufnr(typval_T *argvars, typval_T *rettv)
7776 {
7777 buf_T *buf;
7778 int error = FALSE;
7779 char_u *name;
7780
7781 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
7782 ++emsg_off;
7783 buf = get_buf_tv(&argvars[0], FALSE);
7784 --emsg_off;
7785
7786 /* If the buffer isn't found and the second argument is not zero create a
7787 * new buffer. */
7788 if (buf == NULL
7789 && argvars[1].v_type != VAR_UNKNOWN
7790 && get_tv_number_chk(&argvars[1], &error) != 0
7791 && !error
7792 && (name = get_tv_string_chk(&argvars[0])) != NULL
7793 && !error)
7794 buf = buflist_new(name, NULL, (linenr_T)1, 0);
7795
7796 if (buf != NULL)
7797 rettv->vval.v_number = buf->b_fnum;
7798 else
7799 rettv->vval.v_number = -1;
7800 }
7801
7802 static void
7803 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
7804 {
7805 #ifdef FEAT_WINDOWS
7806 win_T *wp;
7807 int winnr = 0;
7808 #endif
7809 buf_T *buf;
7810
7811 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
7812 ++emsg_off;
7813 buf = get_buf_tv(&argvars[0], TRUE);
7814 #ifdef FEAT_WINDOWS
7815 for (wp = firstwin; wp; wp = wp->w_next)
7816 {
7817 ++winnr;
7818 if (wp->w_buffer == buf)
7819 break;
7820 }
7821 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
7822 #else
7823 rettv->vval.v_number = (curwin->w_buffer == buf
7824 ? (get_nr ? 1 : curwin->w_id) : -1);
7825 #endif
7826 --emsg_off;
7827 }
7828
7829 /*
7830 * "bufwinid(nr)" function
7831 */
7832 static void
7833 f_bufwinid(typval_T *argvars, typval_T *rettv)
7834 {
7835 buf_win_common(argvars, rettv, FALSE);
7836 }
7837
7838 /*
7839 * "bufwinnr(nr)" function
7840 */
7841 static void
7842 f_bufwinnr(typval_T *argvars, typval_T *rettv)
7843 {
7844 buf_win_common(argvars, rettv, TRUE);
7845 }
7846
7847 /*
7848 * "byte2line(byte)" function
7849 */
7850 static void
7851 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
7852 {
7853 #ifndef FEAT_BYTEOFF
7854 rettv->vval.v_number = -1;
7855 #else
7856 long boff = 0;
7857
7858 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
7859 if (boff < 0)
7860 rettv->vval.v_number = -1;
7861 else
7862 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
7863 (linenr_T)0, &boff);
7864 #endif
7865 }
7866
7867 static void
7868 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
7869 {
7870 #ifdef FEAT_MBYTE
7871 char_u *t;
7872 #endif
7873 char_u *str;
7874 varnumber_T idx;
7875
7876 str = get_tv_string_chk(&argvars[0]);
7877 idx = get_tv_number_chk(&argvars[1], NULL);
7878 rettv->vval.v_number = -1;
7879 if (str == NULL || idx < 0)
7880 return;
7881
7882 #ifdef FEAT_MBYTE
7883 t = str;
7884 for ( ; idx > 0; idx--)
7885 {
7886 if (*t == NUL) /* EOL reached */
7887 return;
7888 if (enc_utf8 && comp)
7889 t += utf_ptr2len(t);
7890 else
7891 t += (*mb_ptr2len)(t);
7892 }
7893 rettv->vval.v_number = (varnumber_T)(t - str);
7894 #else
7895 if ((size_t)idx <= STRLEN(str))
7896 rettv->vval.v_number = idx;
7897 #endif
7898 }
7899
7900 /*
7901 * "byteidx()" function
7902 */
7903 static void
7904 f_byteidx(typval_T *argvars, typval_T *rettv)
7905 {
7906 byteidx(argvars, rettv, FALSE);
7907 }
7908
7909 /*
7910 * "byteidxcomp()" function
7911 */
7912 static void
7913 f_byteidxcomp(typval_T *argvars, typval_T *rettv)
7914 {
7915 byteidx(argvars, rettv, TRUE);
7916 }
7917
7918 /*
7919 * "call(func, arglist [, dict])" function
7920 */
7921 static void
7922 f_call(typval_T *argvars, typval_T *rettv)
7923 {
7924 char_u *func;
7925 partial_T *partial = NULL;
7926 dict_T *selfdict = NULL;
7927
7928 if (argvars[1].v_type != VAR_LIST)
7929 {
7930 EMSG(_(e_listreq));
7931 return;
7932 }
7933 if (argvars[1].vval.v_list == NULL)
7934 return;
7935
7936 if (argvars[0].v_type == VAR_FUNC)
7937 func = argvars[0].vval.v_string;
7938 else if (argvars[0].v_type == VAR_PARTIAL)
7939 {
7940 partial = argvars[0].vval.v_partial;
7941 func = partial->pt_name;
7942 }
7943 else
7944 func = get_tv_string(&argvars[0]);
7945 if (*func == NUL)
7946 return; /* type error or empty name */
7947
7948 if (argvars[2].v_type != VAR_UNKNOWN)
7949 {
7950 if (argvars[2].v_type != VAR_DICT)
7951 {
7952 EMSG(_(e_dictreq));
7953 return;
7954 }
7955 selfdict = argvars[2].vval.v_dict;
7956 }
7957
7958 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
7959 }
7960
7961 #ifdef FEAT_FLOAT
7962 /*
7963 * "ceil({float})" function
7964 */
7965 static void
7966 f_ceil(typval_T *argvars, typval_T *rettv)
7967 {
7968 float_T f = 0.0;
7969
7970 rettv->v_type = VAR_FLOAT;
7971 if (get_float_arg(argvars, &f) == OK)
7972 rettv->vval.v_float = ceil(f);
7973 else
7974 rettv->vval.v_float = 0.0;
7975 }
7976 #endif
7977
7978 #ifdef FEAT_JOB_CHANNEL
7979 /*
7980 * "ch_close()" function
7981 */
7982 static void
7983 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
7984 {
7985 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
7986
7987 if (channel != NULL)
7988 {
7989 channel_close(channel, FALSE);
7990 channel_clear(channel);
7991 }
7992 }
7993
7994 /*
7995 * "ch_getbufnr()" function
7996 */
7997 static void
7998 f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
7999 {
8000 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
8001
8002 rettv->vval.v_number = -1;
8003 if (channel != NULL)
8004 {
8005 char_u *what = get_tv_string(&argvars[1]);
8006 int part;
8007
8008 if (STRCMP(what, "err") == 0)
8009 part = PART_ERR;
8010 else if (STRCMP(what, "out") == 0)
8011 part = PART_OUT;
8012 else if (STRCMP(what, "in") == 0)
8013 part = PART_IN;
8014 else
8015 part = PART_SOCK;
8016 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
8017 rettv->vval.v_number =
8018 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
8019 }
8020 }
8021
8022 /*
8023 * "ch_getjob()" function
8024 */
8025 static void
8026 f_ch_getjob(typval_T *argvars, typval_T *rettv)
8027 {
8028 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
8029
8030 if (channel != NULL)
8031 {
8032 rettv->v_type = VAR_JOB;
8033 rettv->vval.v_job = channel->ch_job;
8034 if (channel->ch_job != NULL)
8035 ++channel->ch_job->jv_refcount;
8036 }
8037 }
8038
8039 /*
8040 * "ch_info()" function
8041 */
8042 static void
8043 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
8044 {
8045 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
8046
8047 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
8048 channel_info(channel, rettv->vval.v_dict);
8049 }
8050
8051 /*
8052 * "ch_log()" function
8053 */
8054 static void
8055 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
8056 {
8057 char_u *msg = get_tv_string(&argvars[0]);
8058 channel_T *channel = NULL;
8059
8060 if (argvars[1].v_type != VAR_UNKNOWN)
8061 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
8062
8063 ch_log(channel, (char *)msg);
8064 }
8065
8066 /*
8067 * "ch_logfile()" function
8068 */
8069 static void
8070 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
8071 {
8072 char_u *fname;
8073 char_u *opt = (char_u *)"";
8074 char_u buf[NUMBUFLEN];
8075
8076 fname = get_tv_string(&argvars[0]);
8077 if (argvars[1].v_type == VAR_STRING)
8078 opt = get_tv_string_buf(&argvars[1], buf);
8079 ch_logfile(fname, opt);
8080 }
8081
8082 /*
8083 * "ch_open()" function
8084 */
8085 static void
8086 f_ch_open(typval_T *argvars, typval_T *rettv)
8087 {
8088 rettv->v_type = VAR_CHANNEL;
8089 if (check_restricted() || check_secure())
8090 return;
8091 rettv->vval.v_channel = channel_open_func(argvars);
8092 }
8093
8094 /*
8095 * "ch_read()" function
8096 */
8097 static void
8098 f_ch_read(typval_T *argvars, typval_T *rettv)
8099 {
8100 common_channel_read(argvars, rettv, FALSE);
8101 }
8102
8103 /*
8104 * "ch_readraw()" function
8105 */
8106 static void
8107 f_ch_readraw(typval_T *argvars, typval_T *rettv)
8108 {
8109 common_channel_read(argvars, rettv, TRUE);
8110 }
8111
8112 /*
8113 * "ch_evalexpr()" function
8114 */
8115 static void
8116 f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
8117 {
8118 ch_expr_common(argvars, rettv, TRUE);
8119 }
8120
8121 /*
8122 * "ch_sendexpr()" function
8123 */
8124 static void
8125 f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
8126 {
8127 ch_expr_common(argvars, rettv, FALSE);
8128 }
8129
8130 /*
8131 * "ch_evalraw()" function
8132 */
8133 static void
8134 f_ch_evalraw(typval_T *argvars, typval_T *rettv)
8135 {
8136 ch_raw_common(argvars, rettv, TRUE);
8137 }
8138
8139 /*
8140 * "ch_sendraw()" function
8141 */
8142 static void
8143 f_ch_sendraw(typval_T *argvars, typval_T *rettv)
8144 {
8145 ch_raw_common(argvars, rettv, FALSE);
8146 }
8147
8148 /*
8149 * "ch_setoptions()" function
8150 */
8151 static void
8152 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
8153 {
8154 channel_T *channel;
8155 jobopt_T opt;
8156
8157 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
8158 if (channel == NULL)
8159 return;
8160 clear_job_options(&opt);
8161 if (get_job_options(&argvars[1], &opt,
8162 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK)
8163 channel_set_options(channel, &opt);
8164 free_job_options(&opt);
8165 }
8166
8167 /*
8168 * "ch_status()" function
8169 */
8170 static void
8171 f_ch_status(typval_T *argvars, typval_T *rettv)
8172 {
8173 channel_T *channel;
8174
8175 /* return an empty string by default */
8176 rettv->v_type = VAR_STRING;
8177 rettv->vval.v_string = NULL;
8178
8179 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
8180 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel));
8181 }
8182 #endif
8183
8184 /*
8185 * "changenr()" function
8186 */
8187 static void
8188 f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
8189 {
8190 rettv->vval.v_number = curbuf->b_u_seq_cur;
8191 }
8192
8193 /*
8194 * "char2nr(string)" function
8195 */
8196 static void
8197 f_char2nr(typval_T *argvars, typval_T *rettv)
8198 {
8199 #ifdef FEAT_MBYTE
8200 if (has_mbyte)
8201 {
8202 int utf8 = 0;
8203
8204 if (argvars[1].v_type != VAR_UNKNOWN)
8205 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
8206
8207 if (utf8)
8208 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
8209 else
8210 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
8211 }
8212 else
8213 #endif
8214 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
8215 }
8216
8217 /*
8218 * "cindent(lnum)" function
8219 */
8220 static void
8221 f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
8222 {
8223 #ifdef FEAT_CINDENT
8224 pos_T pos;
8225 linenr_T lnum;
8226
8227 pos = curwin->w_cursor;
8228 lnum = get_tv_lnum(argvars);
8229 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
8230 {
8231 curwin->w_cursor.lnum = lnum;
8232 rettv->vval.v_number = get_c_indent();
8233 curwin->w_cursor = pos;
8234 }
8235 else
8236 #endif
8237 rettv->vval.v_number = -1;
8238 }
8239
8240 /*
8241 * "clearmatches()" function
8242 */
8243 static void
8244 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8245 {
8246 #ifdef FEAT_SEARCH_EXTRA
8247 clear_matches(curwin);
8248 #endif
8249 }
8250
8251 /*
8252 * "col(string)" function
8253 */
8254 static void
8255 f_col(typval_T *argvars, typval_T *rettv)
8256 {
8257 colnr_T col = 0;
8258 pos_T *fp;
8259 int fnum = curbuf->b_fnum;
8260
8261 fp = var2fpos(&argvars[0], FALSE, &fnum);
8262 if (fp != NULL && fnum == curbuf->b_fnum)
8263 {
8264 if (fp->col == MAXCOL)
8265 {
8266 /* '> can be MAXCOL, get the length of the line then */
8267 if (fp->lnum <= curbuf->b_ml.ml_line_count)
8268 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
8269 else
8270 col = MAXCOL;
8271 }
8272 else
8273 {
8274 col = fp->col + 1;
8275 #ifdef FEAT_VIRTUALEDIT
8276 /* col(".") when the cursor is on the NUL at the end of the line
8277 * because of "coladd" can be seen as an extra column. */
8278 if (virtual_active() && fp == &curwin->w_cursor)
8279 {
8280 char_u *p = ml_get_cursor();
8281
8282 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
8283 curwin->w_virtcol - curwin->w_cursor.coladd))
8284 {
8285 # ifdef FEAT_MBYTE
8286 int l;
8287
8288 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
8289 col += l;
8290 # else
8291 if (*p != NUL && p[1] == NUL)
8292 ++col;
8293 # endif
8294 }
8295 }
8296 #endif
8297 }
8298 }
8299 rettv->vval.v_number = col;
8300 }
8301
8302 #if defined(FEAT_INS_EXPAND)
8303 /*
8304 * "complete()" function
8305 */
8306 static void
8307 f_complete(typval_T *argvars, typval_T *rettv UNUSED)
8308 {
8309 int startcol;
8310
8311 if ((State & INSERT) == 0)
8312 {
8313 EMSG(_("E785: complete() can only be used in Insert mode"));
8314 return;
8315 }
8316
8317 /* Check for undo allowed here, because if something was already inserted
8318 * the line was already saved for undo and this check isn't done. */
8319 if (!undo_allowed())
8320 return;
8321
8322 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
8323 {
8324 EMSG(_(e_invarg));
8325 return;
8326 }
8327
8328 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
8329 if (startcol <= 0)
8330 return;
8331
8332 set_completion(startcol - 1, argvars[1].vval.v_list);
8333 }
8334
8335 /*
8336 * "complete_add()" function
8337 */
8338 static void
8339 f_complete_add(typval_T *argvars, typval_T *rettv)
8340 {
8341 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
8342 }
8343
8344 /*
8345 * "complete_check()" function
8346 */
8347 static void
8348 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
8349 {
8350 int saved = RedrawingDisabled;
8351
8352 RedrawingDisabled = 0;
8353 ins_compl_check_keys(0);
8354 rettv->vval.v_number = compl_interrupted;
8355 RedrawingDisabled = saved;
8356 }
8357 #endif
8358
8359 /*
8360 * "confirm(message, buttons[, default [, type]])" function
8361 */
8362 static void
8363 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8364 {
8365 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
8366 char_u *message;
8367 char_u *buttons = NULL;
8368 char_u buf[NUMBUFLEN];
8369 char_u buf2[NUMBUFLEN];
8370 int def = 1;
8371 int type = VIM_GENERIC;
8372 char_u *typestr;
8373 int error = FALSE;
8374
8375 message = get_tv_string_chk(&argvars[0]);
8376 if (message == NULL)
8377 error = TRUE;
8378 if (argvars[1].v_type != VAR_UNKNOWN)
8379 {
8380 buttons = get_tv_string_buf_chk(&argvars[1], buf);
8381 if (buttons == NULL)
8382 error = TRUE;
8383 if (argvars[2].v_type != VAR_UNKNOWN)
8384 {
8385 def = (int)get_tv_number_chk(&argvars[2], &error);
8386 if (argvars[3].v_type != VAR_UNKNOWN)
8387 {
8388 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
8389 if (typestr == NULL)
8390 error = TRUE;
8391 else
8392 {
8393 switch (TOUPPER_ASC(*typestr))
8394 {
8395 case 'E': type = VIM_ERROR; break;
8396 case 'Q': type = VIM_QUESTION; break;
8397 case 'I': type = VIM_INFO; break;
8398 case 'W': type = VIM_WARNING; break;
8399 case 'G': type = VIM_GENERIC; break;
8400 }
8401 }
8402 }
8403 }
8404 }
8405
8406 if (buttons == NULL || *buttons == NUL)
8407 buttons = (char_u *)_("&Ok");
8408
8409 if (!error)
8410 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
8411 def, NULL, FALSE);
8412 #endif
8413 }
8414
8415 /*
8416 * "copy()" function
8417 */
8418 static void
8419 f_copy(typval_T *argvars, typval_T *rettv)
8420 {
8421 item_copy(&argvars[0], rettv, FALSE, 0);
8422 }
8423
8424 #ifdef FEAT_FLOAT
8425 /*
8426 * "cos()" function
8427 */
8428 static void
8429 f_cos(typval_T *argvars, typval_T *rettv)
8430 {
8431 float_T f = 0.0;
8432
8433 rettv->v_type = VAR_FLOAT;
8434 if (get_float_arg(argvars, &f) == OK)
8435 rettv->vval.v_float = cos(f);
8436 else
8437 rettv->vval.v_float = 0.0;
8438 }
8439
8440 /*
8441 * "cosh()" function
8442 */
8443 static void
8444 f_cosh(typval_T *argvars, typval_T *rettv)
8445 {
8446 float_T f = 0.0;
8447
8448 rettv->v_type = VAR_FLOAT;
8449 if (get_float_arg(argvars, &f) == OK)
8450 rettv->vval.v_float = cosh(f);
8451 else
8452 rettv->vval.v_float = 0.0;
8453 }
8454 #endif
8455
8456 /*
8457 * "count()" function
8458 */
8459 static void
8460 f_count(typval_T *argvars, typval_T *rettv)
8461 {
8462 long n = 0;
8463 int ic = FALSE;
8464
8465 if (argvars[0].v_type == VAR_LIST)
8466 {
8467 listitem_T *li;
8468 list_T *l;
8469 long idx;
8470
8471 if ((l = argvars[0].vval.v_list) != NULL)
8472 {
8473 li = l->lv_first;
8474 if (argvars[2].v_type != VAR_UNKNOWN)
8475 {
8476 int error = FALSE;
8477
8478 ic = (int)get_tv_number_chk(&argvars[2], &error);
8479 if (argvars[3].v_type != VAR_UNKNOWN)
8480 {
8481 idx = (long)get_tv_number_chk(&argvars[3], &error);
8482 if (!error)
8483 {
8484 li = list_find(l, idx);
8485 if (li == NULL)
8486 EMSGN(_(e_listidx), idx);
8487 }
8488 }
8489 if (error)
8490 li = NULL;
8491 }
8492
8493 for ( ; li != NULL; li = li->li_next)
8494 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
8495 ++n;
8496 }
8497 }
8498 else if (argvars[0].v_type == VAR_DICT)
8499 {
8500 int todo;
8501 dict_T *d;
8502 hashitem_T *hi;
8503
8504 if ((d = argvars[0].vval.v_dict) != NULL)
8505 {
8506 int error = FALSE;
8507
8508 if (argvars[2].v_type != VAR_UNKNOWN)
8509 {
8510 ic = (int)get_tv_number_chk(&argvars[2], &error);
8511 if (argvars[3].v_type != VAR_UNKNOWN)
8512 EMSG(_(e_invarg));
8513 }
8514
8515 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
8516 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8517 {
8518 if (!HASHITEM_EMPTY(hi))
8519 {
8520 --todo;
8521 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
8522 ++n;
8523 }
8524 }
8525 }
8526 }
8527 else
8528 EMSG2(_(e_listdictarg), "count()");
8529 rettv->vval.v_number = n;
8530 }
8531
8532 /*
8533 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
8534 *
8535 * Checks the existence of a cscope connection.
8536 */
8537 static void
8538 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8539 {
8540 #ifdef FEAT_CSCOPE
8541 int num = 0;
8542 char_u *dbpath = NULL;
8543 char_u *prepend = NULL;
8544 char_u buf[NUMBUFLEN];
8545
8546 if (argvars[0].v_type != VAR_UNKNOWN
8547 && argvars[1].v_type != VAR_UNKNOWN)
8548 {
8549 num = (int)get_tv_number(&argvars[0]);
8550 dbpath = get_tv_string(&argvars[1]);
8551 if (argvars[2].v_type != VAR_UNKNOWN)
8552 prepend = get_tv_string_buf(&argvars[2], buf);
8553 }
8554
8555 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
8556 #endif
8557 }
8558
8559 /*
8560 * "cursor(lnum, col)" function, or
8561 * "cursor(list)"
8562 *
8563 * Moves the cursor to the specified line and column.
8564 * Returns 0 when the position could be set, -1 otherwise.
8565 */
8566 static void
8567 f_cursor(typval_T *argvars, typval_T *rettv)
8568 {
8569 long line, col;
8570 #ifdef FEAT_VIRTUALEDIT
8571 long coladd = 0;
8572 #endif
8573 int set_curswant = TRUE;
8574
8575 rettv->vval.v_number = -1;
8576 if (argvars[1].v_type == VAR_UNKNOWN)
8577 {
8578 pos_T pos;
8579 colnr_T curswant = -1;
8580
8581 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
8582 {
8583 EMSG(_(e_invarg));
8584 return;
8585 }
8586 line = pos.lnum;
8587 col = pos.col;
8588 #ifdef FEAT_VIRTUALEDIT
8589 coladd = pos.coladd;
8590 #endif
8591 if (curswant >= 0)
8592 {
8593 curwin->w_curswant = curswant - 1;
8594 set_curswant = FALSE;
8595 }
8596 }
8597 else
8598 {
8599 line = get_tv_lnum(argvars);
8600 col = (long)get_tv_number_chk(&argvars[1], NULL);
8601 #ifdef FEAT_VIRTUALEDIT
8602 if (argvars[2].v_type != VAR_UNKNOWN)
8603 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
8604 #endif
8605 }
8606 if (line < 0 || col < 0
8607 #ifdef FEAT_VIRTUALEDIT
8608 || coladd < 0
8609 #endif
8610 )
8611 return; /* type error; errmsg already given */
8612 if (line > 0)
8613 curwin->w_cursor.lnum = line;
8614 if (col > 0)
8615 curwin->w_cursor.col = col - 1;
8616 #ifdef FEAT_VIRTUALEDIT
8617 curwin->w_cursor.coladd = coladd;
8618 #endif
8619
8620 /* Make sure the cursor is in a valid position. */
8621 check_cursor();
8622 #ifdef FEAT_MBYTE
8623 /* Correct cursor for multi-byte character. */
8624 if (has_mbyte)
8625 mb_adjust_cursor();
8626 #endif
8627
8628 curwin->w_set_curswant = set_curswant;
8629 rettv->vval.v_number = 0;
8630 }
8631
8632 /*
8633 * "deepcopy()" function
8634 */
8635 static void
8636 f_deepcopy(typval_T *argvars, typval_T *rettv)
8637 {
8638 int noref = 0;
8639
8640 if (argvars[1].v_type != VAR_UNKNOWN)
8641 noref = (int)get_tv_number_chk(&argvars[1], NULL);
8642 if (noref < 0 || noref > 1)
8643 EMSG(_(e_invarg));
8644 else
8645 {
8646 current_copyID += COPYID_INC;
8647 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? current_copyID : 0);
8648 }
8649 }
8650
8651 /*
8652 * "delete()" function
8653 */
8654 static void
8655 f_delete(typval_T *argvars, typval_T *rettv)
8656 {
8657 char_u nbuf[NUMBUFLEN];
8658 char_u *name;
8659 char_u *flags;
8660
8661 rettv->vval.v_number = -1;
8662 if (check_restricted() || check_secure())
8663 return;
8664
8665 name = get_tv_string(&argvars[0]);
8666 if (name == NULL || *name == NUL)
8667 {
8668 EMSG(_(e_invarg));
8669 return;
8670 }
8671
8672 if (argvars[1].v_type != VAR_UNKNOWN)
8673 flags = get_tv_string_buf(&argvars[1], nbuf);
8674 else
8675 flags = (char_u *)"";
8676
8677 if (*flags == NUL)
8678 /* delete a file */
8679 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
8680 else if (STRCMP(flags, "d") == 0)
8681 /* delete an empty directory */
8682 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
8683 else if (STRCMP(flags, "rf") == 0)
8684 /* delete a directory recursively */
8685 rettv->vval.v_number = delete_recursive(name);
8686 else
8687 EMSG2(_(e_invexpr2), flags);
8688 }
8689
8690 /*
8691 * "did_filetype()" function
8692 */
8693 static void
8694 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8695 {
8696 #ifdef FEAT_AUTOCMD
8697 rettv->vval.v_number = did_filetype;
8698 #endif
8699 }
8700
8701 /*
8702 * "diff_filler()" function
8703 */
8704 static void
8705 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8706 {
8707 #ifdef FEAT_DIFF
8708 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
8709 #endif
8710 }
8711
8712 /*
8713 * "diff_hlID()" function
8714 */
8715 static void
8716 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8717 {
8718 #ifdef FEAT_DIFF
8719 linenr_T lnum = get_tv_lnum(argvars);
8720 static linenr_T prev_lnum = 0;
8721 static int changedtick = 0;
8722 static int fnum = 0;
8723 static int change_start = 0;
8724 static int change_end = 0;
8725 static hlf_T hlID = (hlf_T)0;
8726 int filler_lines;
8727 int col;
8728
8729 if (lnum < 0) /* ignore type error in {lnum} arg */
8730 lnum = 0;
8731 if (lnum != prev_lnum
8732 || changedtick != curbuf->b_changedtick
8733 || fnum != curbuf->b_fnum)
8734 {
8735 /* New line, buffer, change: need to get the values. */
8736 filler_lines = diff_check(curwin, lnum);
8737 if (filler_lines < 0)
8738 {
8739 if (filler_lines == -1)
8740 {
8741 change_start = MAXCOL;
8742 change_end = -1;
8743 if (diff_find_change(curwin, lnum, &change_start, &change_end))
8744 hlID = HLF_ADD; /* added line */
8745 else
8746 hlID = HLF_CHD; /* changed line */
8747 }
8748 else
8749 hlID = HLF_ADD; /* added line */
8750 }
8751 else
8752 hlID = (hlf_T)0;
8753 prev_lnum = lnum;
8754 changedtick = curbuf->b_changedtick;
8755 fnum = curbuf->b_fnum;
8756 }
8757
8758 if (hlID == HLF_CHD || hlID == HLF_TXD)
8759 {
8760 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
8761 if (col >= change_start && col <= change_end)
8762 hlID = HLF_TXD; /* changed text */
8763 else
8764 hlID = HLF_CHD; /* changed line */
8765 }
8766 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
8767 #endif
8768 }
8769
8770 /*
8771 * "empty({expr})" function
8772 */
8773 static void
8774 f_empty(typval_T *argvars, typval_T *rettv)
8775 {
8776 int n = FALSE;
8777
8778 switch (argvars[0].v_type)
8779 {
8780 case VAR_STRING:
8781 case VAR_FUNC:
8782 n = argvars[0].vval.v_string == NULL
8783 || *argvars[0].vval.v_string == NUL;
8784 break;
8785 case VAR_PARTIAL:
8786 n = FALSE;
8787 break;
8788 case VAR_NUMBER:
8789 n = argvars[0].vval.v_number == 0;
8790 break;
8791 case VAR_FLOAT:
8792 #ifdef FEAT_FLOAT
8793 n = argvars[0].vval.v_float == 0.0;
8794 break;
8795 #endif
8796 case VAR_LIST:
8797 n = argvars[0].vval.v_list == NULL
8798 || argvars[0].vval.v_list->lv_first == NULL;
8799 break;
8800 case VAR_DICT:
8801 n = argvars[0].vval.v_dict == NULL
8802 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
8803 break;
8804 case VAR_SPECIAL:
8805 n = argvars[0].vval.v_number != VVAL_TRUE;
8806 break;
8807
8808 case VAR_JOB:
8809 #ifdef FEAT_JOB_CHANNEL
8810 n = argvars[0].vval.v_job == NULL
8811 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
8812 break;
8813 #endif
8814 case VAR_CHANNEL:
8815 #ifdef FEAT_JOB_CHANNEL
8816 n = argvars[0].vval.v_channel == NULL
8817 || !channel_is_open(argvars[0].vval.v_channel);
8818 break;
8819 #endif
8820 case VAR_UNKNOWN:
8821 EMSG2(_(e_intern2), "f_empty(UNKNOWN)");
8822 n = TRUE;
8823 break;
8824 }
8825
8826 rettv->vval.v_number = n;
8827 }
8828
8829 /*
8830 * "escape({string}, {chars})" function
8831 */
8832 static void
8833 f_escape(typval_T *argvars, typval_T *rettv)
8834 {
8835 char_u buf[NUMBUFLEN];
8836
8837 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
8838 get_tv_string_buf(&argvars[1], buf));
8839 rettv->v_type = VAR_STRING;
8840 }
8841
8842 /*
8843 * "eval()" function
8844 */
8845 static void
8846 f_eval(typval_T *argvars, typval_T *rettv)
8847 {
8848 char_u *s, *p;
8849
8850 s = get_tv_string_chk(&argvars[0]);
8851 if (s != NULL)
8852 s = skipwhite(s);
8853
8854 p = s;
8855 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
8856 {
8857 if (p != NULL && !aborting())
8858 EMSG2(_(e_invexpr2), p);
8859 need_clr_eos = FALSE;
8860 rettv->v_type = VAR_NUMBER;
8861 rettv->vval.v_number = 0;
8862 }
8863 else if (*s != NUL)
8864 EMSG(_(e_trailing));
8865 }
8866
8867 /*
8868 * "eventhandler()" function
8869 */
8870 static void
8871 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
8872 {
8873 rettv->vval.v_number = vgetc_busy;
8874 }
8875
8876 /*
8877 * "executable()" function
8878 */
8879 static void
8880 f_executable(typval_T *argvars, typval_T *rettv)
8881 {
8882 char_u *name = get_tv_string(&argvars[0]);
8883
8884 /* Check in $PATH and also check directly if there is a directory name. */
8885 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
8886 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
8887 }
8888
8889 static garray_T redir_execute_ga;
8890
8891 /*
8892 * Append "value[value_len]" to the execute() output.
8893 */
8894 void
8895 execute_redir_str(char_u *value, int value_len)
8896 {
8897 int len;
8898
8899 if (value_len == -1)
8900 len = (int)STRLEN(value); /* Append the entire string */
8901 else
8902 len = value_len; /* Append only "value_len" characters */
8903 if (ga_grow(&redir_execute_ga, len) == OK)
8904 {
8905 mch_memmove((char *)redir_execute_ga.ga_data
8906 + redir_execute_ga.ga_len, value, len);
8907 redir_execute_ga.ga_len += len;
8908 }
8909 }
8910
8911 /*
8912 * Get next line from a list.
8913 * Called by do_cmdline() to get the next line.
8914 * Returns allocated string, or NULL for end of function.
8915 */
8916
8917 static char_u *
8918 get_list_line(
8919 int c UNUSED,
8920 void *cookie,
8921 int indent UNUSED)
8922 {
8923 listitem_T **p = (listitem_T **)cookie;
8924 listitem_T *item = *p;
8925 char_u buf[NUMBUFLEN];
8926 char_u *s;
8927
8928 if (item == NULL)
8929 return NULL;
8930 s = get_tv_string_buf_chk(&item->li_tv, buf);
8931 *p = item->li_next;
8932 return s == NULL ? NULL : vim_strsave(s);
8933 }
8934
8935 /*
8936 * "execute()" function
8937 */
8938 static void
8939 f_execute(typval_T *argvars, typval_T *rettv)
8940 {
8941 char_u *cmd = NULL;
8942 list_T *list = NULL;
8943 int save_msg_silent = msg_silent;
8944 int save_emsg_silent = emsg_silent;
8945 int save_emsg_noredir = emsg_noredir;
8946 int save_redir_execute = redir_execute;
8947 garray_T save_ga;
8948
8949 rettv->vval.v_string = NULL;
8950 rettv->v_type = VAR_STRING;
8951
8952 if (argvars[0].v_type == VAR_LIST)
8953 {
8954 list = argvars[0].vval.v_list;
8955 if (list == NULL || list->lv_first == NULL)
8956 /* empty list, no commands, empty output */
8957 return;
8958 ++list->lv_refcount;
8959 }
8960 else
8961 {
8962 cmd = get_tv_string_chk(&argvars[0]);
8963 if (cmd == NULL)
8964 return;
8965 }
8966
8967 if (argvars[1].v_type != VAR_UNKNOWN)
8968 {
8969 char_u buf[NUMBUFLEN];
8970 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
8971
8972 if (s == NULL)
8973 return;
8974 if (STRNCMP(s, "silent", 6) == 0)
8975 ++msg_silent;
8976 if (STRCMP(s, "silent!") == 0)
8977 {
8978 emsg_silent = TRUE;
8979 emsg_noredir = TRUE;
8980 }
8981 }
8982 else
8983 ++msg_silent;
8984
8985 if (redir_execute)
8986 save_ga = redir_execute_ga;
8987 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
8988 redir_execute = TRUE;
8989
8990 if (cmd != NULL)
8991 do_cmdline_cmd(cmd);
8992 else
8993 {
8994 listitem_T *item = list->lv_first;
8995
8996 do_cmdline(NULL, get_list_line, (void *)&item,
8997 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
8998 --list->lv_refcount;
8999 }
9000
9001 rettv->vval.v_string = redir_execute_ga.ga_data;
9002 msg_silent = save_msg_silent;
9003 emsg_silent = save_emsg_silent;
9004 emsg_noredir = save_emsg_noredir;
9005
9006 redir_execute = save_redir_execute;
9007 if (redir_execute)
9008 redir_execute_ga = save_ga;
9009
9010 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
9011 * line. Put it back in the first column. */
9012 msg_col = 0;
9013 }
9014
9015 /*
9016 * "exepath()" function
9017 */
9018 static void
9019 f_exepath(typval_T *argvars, typval_T *rettv)
9020 {
9021 char_u *p = NULL;
9022
9023 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
9024 rettv->v_type = VAR_STRING;
9025 rettv->vval.v_string = p;
9026 }
9027
9028 /*
9029 * "exists()" function
9030 */
9031 static void
9032 f_exists(typval_T *argvars, typval_T *rettv)
9033 {
9034 char_u *p;
9035 char_u *name;
9036 int n = FALSE;
9037 int len = 0;
9038
9039 p = get_tv_string(&argvars[0]);
9040 if (*p == '$') /* environment variable */
9041 {
9042 /* first try "normal" environment variables (fast) */
9043 if (mch_getenv(p + 1) != NULL)
9044 n = TRUE;
9045 else
9046 {
9047 /* try expanding things like $VIM and ${HOME} */
9048 p = expand_env_save(p);
9049 if (p != NULL && *p != '$')
9050 n = TRUE;
9051 vim_free(p);
9052 }
9053 }
9054 else if (*p == '&' || *p == '+') /* option */
9055 {
9056 n = (get_option_tv(&p, NULL, TRUE) == OK);
9057 if (*skipwhite(p) != NUL)
9058 n = FALSE; /* trailing garbage */
9059 }
9060 else if (*p == '*') /* internal or user defined function */
9061 {
9062 n = function_exists(p + 1);
9063 }
9064 else if (*p == ':')
9065 {
9066 n = cmd_exists(p + 1);
9067 }
9068 else if (*p == '#')
9069 {
9070 #ifdef FEAT_AUTOCMD
9071 if (p[1] == '#')
9072 n = autocmd_supported(p + 2);
9073 else
9074 n = au_exists(p + 1);
9075 #endif
9076 }
9077 else /* internal variable */
9078 {
9079 char_u *tofree;
9080 typval_T tv;
9081
9082 /* get_name_len() takes care of expanding curly braces */
9083 name = p;
9084 len = get_name_len(&p, &tofree, TRUE, FALSE);
9085 if (len > 0)
9086 {
9087 if (tofree != NULL)
9088 name = tofree;
9089 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
9090 if (n)
9091 {
9092 /* handle d.key, l[idx], f(expr) */
9093 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
9094 if (n)
9095 clear_tv(&tv);
9096 }
9097 }
9098 if (*p != NUL)
9099 n = FALSE;
9100
9101 vim_free(tofree);
9102 }
9103
9104 rettv->vval.v_number = n;
9105 }
9106
9107 #ifdef FEAT_FLOAT
9108 /*
9109 * "exp()" function
9110 */
9111 static void
9112 f_exp(typval_T *argvars, typval_T *rettv)
9113 {
9114 float_T f = 0.0;
9115
9116 rettv->v_type = VAR_FLOAT;
9117 if (get_float_arg(argvars, &f) == OK)
9118 rettv->vval.v_float = exp(f);
9119 else
9120 rettv->vval.v_float = 0.0;
9121 }
9122 #endif
9123
9124 /*
9125 * "expand()" function
9126 */
9127 static void
9128 f_expand(typval_T *argvars, typval_T *rettv)
9129 {
9130 char_u *s;
9131 int len;
9132 char_u *errormsg;
9133 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
9134 expand_T xpc;
9135 int error = FALSE;
9136 char_u *result;
9137
9138 rettv->v_type = VAR_STRING;
9139 if (argvars[1].v_type != VAR_UNKNOWN
9140 && argvars[2].v_type != VAR_UNKNOWN
9141 && get_tv_number_chk(&argvars[2], &error)
9142 && !error)
9143 {
9144 rettv->v_type = VAR_LIST;
9145 rettv->vval.v_list = NULL;
9146 }
9147
9148 s = get_tv_string(&argvars[0]);
9149 if (*s == '%' || *s == '#' || *s == '<')
9150 {
9151 ++emsg_off;
9152 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
9153 --emsg_off;
9154 if (rettv->v_type == VAR_LIST)
9155 {
9156 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
9157 list_append_string(rettv->vval.v_list, result, -1);
9158 else
9159 vim_free(result);
9160 }
9161 else
9162 rettv->vval.v_string = result;
9163 }
9164 else
9165 {
9166 /* When the optional second argument is non-zero, don't remove matches
9167 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
9168 if (argvars[1].v_type != VAR_UNKNOWN
9169 && get_tv_number_chk(&argvars[1], &error))
9170 options |= WILD_KEEP_ALL;
9171 if (!error)
9172 {
9173 ExpandInit(&xpc);
9174 xpc.xp_context = EXPAND_FILES;
9175 if (p_wic)
9176 options += WILD_ICASE;
9177 if (rettv->v_type == VAR_STRING)
9178 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
9179 options, WILD_ALL);
9180 else if (rettv_list_alloc(rettv) != FAIL)
9181 {
9182 int i;
9183
9184 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
9185 for (i = 0; i < xpc.xp_numfiles; i++)
9186 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
9187 ExpandCleanup(&xpc);
9188 }
9189 }
9190 else
9191 rettv->vval.v_string = NULL;
9192 }
9193 }
9194
9195 /*
9196 * "extend(list, list [, idx])" function
9197 * "extend(dict, dict [, action])" function
9198 */
9199 static void
9200 f_extend(typval_T *argvars, typval_T *rettv)
9201 {
9202 char_u *arg_errmsg = (char_u *)N_("extend() argument");
9203
9204 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
9205 {
9206 list_T *l1, *l2;
9207 listitem_T *item;
9208 long before;
9209 int error = FALSE;
9210
9211 l1 = argvars[0].vval.v_list;
9212 l2 = argvars[1].vval.v_list;
9213 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
9214 && l2 != NULL)
9215 {
9216 if (argvars[2].v_type != VAR_UNKNOWN)
9217 {
9218 before = (long)get_tv_number_chk(&argvars[2], &error);
9219 if (error)
9220 return; /* type error; errmsg already given */
9221
9222 if (before == l1->lv_len)
9223 item = NULL;
9224 else
9225 {
9226 item = list_find(l1, before);
9227 if (item == NULL)
9228 {
9229 EMSGN(_(e_listidx), before);
9230 return;
9231 }
9232 }
9233 }
9234 else
9235 item = NULL;
9236 list_extend(l1, l2, item);
9237
9238 copy_tv(&argvars[0], rettv);
9239 }
9240 }
9241 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
9242 {
9243 dict_T *d1, *d2;
9244 char_u *action;
9245 int i;
9246
9247 d1 = argvars[0].vval.v_dict;
9248 d2 = argvars[1].vval.v_dict;
9249 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
9250 && d2 != NULL)
9251 {
9252 /* Check the third argument. */
9253 if (argvars[2].v_type != VAR_UNKNOWN)
9254 {
9255 static char *(av[]) = {"keep", "force", "error"};
9256
9257 action = get_tv_string_chk(&argvars[2]);
9258 if (action == NULL)
9259 return; /* type error; errmsg already given */
9260 for (i = 0; i < 3; ++i)
9261 if (STRCMP(action, av[i]) == 0)
9262 break;
9263 if (i == 3)
9264 {
9265 EMSG2(_(e_invarg2), action);
9266 return;
9267 }
9268 }
9269 else
9270 action = (char_u *)"force";
9271
9272 dict_extend(d1, d2, action);
9273
9274 copy_tv(&argvars[0], rettv);
9275 }
9276 }
9277 else
9278 EMSG2(_(e_listdictarg), "extend()");
9279 }
9280
9281 /*
9282 * "feedkeys()" function
9283 */
9284 static void
9285 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
9286 {
9287 int remap = TRUE;
9288 int insert = FALSE;
9289 char_u *keys, *flags;
9290 char_u nbuf[NUMBUFLEN];
9291 int typed = FALSE;
9292 int execute = FALSE;
9293 int dangerous = FALSE;
9294 char_u *keys_esc;
9295
9296 /* This is not allowed in the sandbox. If the commands would still be
9297 * executed in the sandbox it would be OK, but it probably happens later,
9298 * when "sandbox" is no longer set. */
9299 if (check_secure())
9300 return;
9301
9302 keys = get_tv_string(&argvars[0]);
9303
9304 if (argvars[1].v_type != VAR_UNKNOWN)
9305 {
9306 flags = get_tv_string_buf(&argvars[1], nbuf);
9307 for ( ; *flags != NUL; ++flags)
9308 {
9309 switch (*flags)
9310 {
9311 case 'n': remap = FALSE; break;
9312 case 'm': remap = TRUE; break;
9313 case 't': typed = TRUE; break;
9314 case 'i': insert = TRUE; break;
9315 case 'x': execute = TRUE; break;
9316 case '!': dangerous = TRUE; break;
9317 }
9318 }
9319 }
9320
9321 if (*keys != NUL || execute)
9322 {
9323 /* Need to escape K_SPECIAL and CSI before putting the string in the
9324 * typeahead buffer. */
9325 keys_esc = vim_strsave_escape_csi(keys);
9326 if (keys_esc != NULL)
9327 {
9328 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
9329 insert ? 0 : typebuf.tb_len, !typed, FALSE);
9330 vim_free(keys_esc);
9331 if (vgetc_busy)
9332 typebuf_was_filled = TRUE;
9333 if (execute)
9334 {
9335 int save_msg_scroll = msg_scroll;
9336
9337 /* Avoid a 1 second delay when the keys start Insert mode. */
9338 msg_scroll = FALSE;
9339
9340 if (!dangerous)
9341 ++ex_normal_busy;
9342 exec_normal(TRUE);
9343 if (!dangerous)
9344 --ex_normal_busy;
9345 msg_scroll |= save_msg_scroll;
9346 }
9347 }
9348 }
9349 }
9350
9351 /*
9352 * "filereadable()" function
9353 */
9354 static void
9355 f_filereadable(typval_T *argvars, typval_T *rettv)
9356 {
9357 int fd;
9358 char_u *p;
9359 int n;
9360
9361 #ifndef O_NONBLOCK
9362 # define O_NONBLOCK 0
9363 #endif
9364 p = get_tv_string(&argvars[0]);
9365 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
9366 O_RDONLY | O_NONBLOCK, 0)) >= 0)
9367 {
9368 n = TRUE;
9369 close(fd);
9370 }
9371 else
9372 n = FALSE;
9373
9374 rettv->vval.v_number = n;
9375 }
9376
9377 /*
9378 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
9379 * rights to write into.
9380 */
9381 static void
9382 f_filewritable(typval_T *argvars, typval_T *rettv)
9383 {
9384 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
9385 }
9386
9387 static void
9388 findfilendir(
9389 typval_T *argvars UNUSED,
9390 typval_T *rettv,
9391 int find_what UNUSED)
9392 {
9393 #ifdef FEAT_SEARCHPATH
9394 char_u *fname;
9395 char_u *fresult = NULL;
9396 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
9397 char_u *p;
9398 char_u pathbuf[NUMBUFLEN];
9399 int count = 1;
9400 int first = TRUE;
9401 int error = FALSE;
9402 #endif
9403
9404 rettv->vval.v_string = NULL;
9405 rettv->v_type = VAR_STRING;
9406
9407 #ifdef FEAT_SEARCHPATH
9408 fname = get_tv_string(&argvars[0]);
9409
9410 if (argvars[1].v_type != VAR_UNKNOWN)
9411 {
9412 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
9413 if (p == NULL)
9414 error = TRUE;
9415 else
9416 {
9417 if (*p != NUL)
9418 path = p;
9419
9420 if (argvars[2].v_type != VAR_UNKNOWN)
9421 count = (int)get_tv_number_chk(&argvars[2], &error);
9422 }
9423 }
9424
9425 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
9426 error = TRUE;
9427
9428 if (*fname != NUL && !error)
9429 {
9430 do
9431 {
9432 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
9433 vim_free(fresult);
9434 fresult = find_file_in_path_option(first ? fname : NULL,
9435 first ? (int)STRLEN(fname) : 0,
9436 0, first, path,
9437 find_what,
9438 curbuf->b_ffname,
9439 find_what == FINDFILE_DIR
9440 ? (char_u *)"" : curbuf->b_p_sua);
9441 first = FALSE;
9442
9443 if (fresult != NULL && rettv->v_type == VAR_LIST)
9444 list_append_string(rettv->vval.v_list, fresult, -1);
9445
9446 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
9447 }
9448
9449 if (rettv->v_type == VAR_STRING)
9450 rettv->vval.v_string = fresult;
9451 #endif
9452 }
9453
9454 static void filter_map(typval_T *argvars, typval_T *rettv, int map);
9455 static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp);
9456
9457 /*
9458 * Implementation of map() and filter().
9459 */
9460 static void
9461 filter_map(typval_T *argvars, typval_T *rettv, int map)
9462 {
9463 typval_T *expr;
9464 listitem_T *li, *nli;
9465 list_T *l = NULL;
9466 dictitem_T *di;
9467 hashtab_T *ht;
9468 hashitem_T *hi;
9469 dict_T *d = NULL;
9470 typval_T save_val;
9471 typval_T save_key;
9472 int rem;
9473 int todo;
9474 char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
9475 char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
9476 : N_("filter() argument"));
9477 int save_did_emsg;
9478 int idx = 0;
9479
9480 if (argvars[0].v_type == VAR_LIST)
9481 {
9482 if ((l = argvars[0].vval.v_list) == NULL
9483 || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE)))
9484 return;
9485 }
9486 else if (argvars[0].v_type == VAR_DICT)
9487 {
9488 if ((d = argvars[0].vval.v_dict) == NULL
9489 || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE)))
9490 return;
9491 }
9492 else
9493 {
9494 EMSG2(_(e_listdictarg), ermsg);
9495 return;
9496 }
9497
9498 expr = &argvars[1];
9499 /* On type errors, the preceding call has already displayed an error
9500 * message. Avoid a misleading error message for an empty string that
9501 * was not passed as argument. */
9502 if (expr->v_type != VAR_UNKNOWN)
9503 {
9504 prepare_vimvar(VV_VAL, &save_val);
9505
9506 /* We reset "did_emsg" to be able to detect whether an error
9507 * occurred during evaluation of the expression. */
9508 save_did_emsg = did_emsg;
9509 did_emsg = FALSE;
9510
9511 prepare_vimvar(VV_KEY, &save_key);
9512 if (argvars[0].v_type == VAR_DICT)
9513 {
9514 vimvars[VV_KEY].vv_type = VAR_STRING;
9515
9516 ht = &d->dv_hashtab;
9517 hash_lock(ht);
9518 todo = (int)ht->ht_used;
9519 for (hi = ht->ht_array; todo > 0; ++hi)
9520 {
9521 if (!HASHITEM_EMPTY(hi))
9522 {
9523 int r;
9524
9525 --todo;
9526 di = HI2DI(hi);
9527 if (map &&
9528 (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE)
9529 || var_check_ro(di->di_flags, arg_errmsg, TRUE)))
9530 break;
9531 vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
9532 r = filter_map_one(&di->di_tv, expr, map, &rem);
9533 clear_tv(&vimvars[VV_KEY].vv_tv);
9534 if (r == FAIL || did_emsg)
9535 break;
9536 if (!map && rem)
9537 {
9538 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9539 || var_check_ro(di->di_flags, arg_errmsg, TRUE))
9540 break;
9541 dictitem_remove(d, di);
9542 }
9543 }
9544 }
9545 hash_unlock(ht);
9546 }
9547 else
9548 {
9549 vimvars[VV_KEY].vv_type = VAR_NUMBER;
9550
9551 for (li = l->lv_first; li != NULL; li = nli)
9552 {
9553 if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
9554 break;
9555 nli = li->li_next;
9556 vimvars[VV_KEY].vv_nr = idx;
9557 if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
9558 || did_emsg)
9559 break;
9560 if (!map && rem)
9561 listitem_remove(l, li);
9562 ++idx;
9563 }
9564 }
9565
9566 restore_vimvar(VV_KEY, &save_key);
9567 restore_vimvar(VV_VAL, &save_val);
9568
9569 did_emsg |= save_did_emsg;
9570 }
9571
9572 copy_tv(&argvars[0], rettv);
9573 }
9574
9575 static int
9576 filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
9577 {
9578 typval_T rettv;
9579 typval_T argv[3];
9580 char_u buf[NUMBUFLEN];
9581 char_u *s;
9582 int retval = FAIL;
9583 int dummy;
9584
9585 copy_tv(tv, &vimvars[VV_VAL].vv_tv);
9586 argv[0] = vimvars[VV_KEY].vv_tv;
9587 argv[1] = vimvars[VV_VAL].vv_tv;
9588 if (expr->v_type == VAR_FUNC)
9589 {
9590 s = expr->vval.v_string;
9591 if (call_func(s, (int)STRLEN(s),
9592 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL)
9593 goto theend;
9594 }
9595 else if (expr->v_type == VAR_PARTIAL)
9596 {
9597 partial_T *partial = expr->vval.v_partial;
9598
9599 s = partial->pt_name;
9600 if (call_func(s, (int)STRLEN(s),
9601 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL)
9602 == FAIL)
9603 goto theend;
9604 }
9605 else
9606 {
9607 s = get_tv_string_buf_chk(expr, buf);
9608 if (s == NULL)
9609 goto theend;
9610 s = skipwhite(s);
9611 if (eval1(&s, &rettv, TRUE) == FAIL)
9612 goto theend;
9613 if (*s != NUL) /* check for trailing chars after expr */
9614 {
9615 EMSG2(_(e_invexpr2), s);
9616 goto theend;
9617 }
9618 }
9619 if (map)
9620 {
9621 /* map(): replace the list item value */
9622 clear_tv(tv);
9623 rettv.v_lock = 0;
9624 *tv = rettv;
9625 }
9626 else
9627 {
9628 int error = FALSE;
9629
9630 /* filter(): when expr is zero remove the item */
9631 *remp = (get_tv_number_chk(&rettv, &error) == 0);
9632 clear_tv(&rettv);
9633 /* On type error, nothing has been removed; return FAIL to stop the
9634 * loop. The error message was given by get_tv_number_chk(). */
9635 if (error)
9636 goto theend;
9637 }
9638 retval = OK;
9639 theend:
9640 clear_tv(&vimvars[VV_VAL].vv_tv);
9641 return retval;
9642 }
9643
9644 /*
9645 * "filter()" function
9646 */
9647 static void
9648 f_filter(typval_T *argvars, typval_T *rettv)
9649 {
9650 filter_map(argvars, rettv, FALSE);
9651 }
9652
9653 /*
9654 * "finddir({fname}[, {path}[, {count}]])" function
9655 */
9656 static void
9657 f_finddir(typval_T *argvars, typval_T *rettv)
9658 {
9659 findfilendir(argvars, rettv, FINDFILE_DIR);
9660 }
9661
9662 /*
9663 * "findfile({fname}[, {path}[, {count}]])" function
9664 */
9665 static void
9666 f_findfile(typval_T *argvars, typval_T *rettv)
9667 {
9668 findfilendir(argvars, rettv, FINDFILE_FILE);
9669 }
9670
9671 #ifdef FEAT_FLOAT
9672 /*
9673 * "float2nr({float})" function
9674 */
9675 static void
9676 f_float2nr(typval_T *argvars, typval_T *rettv)
9677 {
9678 float_T f = 0.0;
9679
9680 if (get_float_arg(argvars, &f) == OK)
9681 {
9682 # ifdef FEAT_NUM64
9683 if (f < -0x7fffffffffffffff)
9684 rettv->vval.v_number = -0x7fffffffffffffff;
9685 else if (f > 0x7fffffffffffffff)
9686 rettv->vval.v_number = 0x7fffffffffffffff;
9687 else
9688 rettv->vval.v_number = (varnumber_T)f;
9689 # else
9690 if (f < -0x7fffffff)
9691 rettv->vval.v_number = -0x7fffffff;
9692 else if (f > 0x7fffffff)
9693 rettv->vval.v_number = 0x7fffffff;
9694 else
9695 rettv->vval.v_number = (varnumber_T)f;
9696 # endif
9697 }
9698 }
9699
9700 /*
9701 * "floor({float})" function
9702 */
9703 static void
9704 f_floor(typval_T *argvars, typval_T *rettv)
9705 {
9706 float_T f = 0.0;
9707
9708 rettv->v_type = VAR_FLOAT;
9709 if (get_float_arg(argvars, &f) == OK)
9710 rettv->vval.v_float = floor(f);
9711 else
9712 rettv->vval.v_float = 0.0;
9713 }
9714
9715 /*
9716 * "fmod()" function
9717 */
9718 static void
9719 f_fmod(typval_T *argvars, typval_T *rettv)
9720 {
9721 float_T fx = 0.0, fy = 0.0;
9722
9723 rettv->v_type = VAR_FLOAT;
9724 if (get_float_arg(argvars, &fx) == OK
9725 && get_float_arg(&argvars[1], &fy) == OK)
9726 rettv->vval.v_float = fmod(fx, fy);
9727 else
9728 rettv->vval.v_float = 0.0;
9729 }
9730 #endif
9731
9732 /*
9733 * "fnameescape({string})" function
9734 */
9735 static void
9736 f_fnameescape(typval_T *argvars, typval_T *rettv)
9737 {
9738 rettv->vval.v_string = vim_strsave_fnameescape(
9739 get_tv_string(&argvars[0]), FALSE);
9740 rettv->v_type = VAR_STRING;
9741 }
9742
9743 /*
9744 * "fnamemodify({fname}, {mods})" function
9745 */
9746 static void
9747 f_fnamemodify(typval_T *argvars, typval_T *rettv)
9748 {
9749 char_u *fname;
9750 char_u *mods;
9751 int usedlen = 0;
9752 int len;
9753 char_u *fbuf = NULL;
9754 char_u buf[NUMBUFLEN];
9755
9756 fname = get_tv_string_chk(&argvars[0]);
9757 mods = get_tv_string_buf_chk(&argvars[1], buf);
9758 if (fname == NULL || mods == NULL)
9759 fname = NULL;
9760 else
9761 {
9762 len = (int)STRLEN(fname);
9763 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
9764 }
9765
9766 rettv->v_type = VAR_STRING;
9767 if (fname == NULL)
9768 rettv->vval.v_string = NULL;
9769 else
9770 rettv->vval.v_string = vim_strnsave(fname, len);
9771 vim_free(fbuf);
9772 }
9773
9774 static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
9775
9776 /*
9777 * "foldclosed()" function
9778 */
9779 static void
9780 foldclosed_both(
9781 typval_T *argvars UNUSED,
9782 typval_T *rettv,
9783 int end UNUSED)
9784 {
9785 #ifdef FEAT_FOLDING
9786 linenr_T lnum;
9787 linenr_T first, last;
9788
9789 lnum = get_tv_lnum(argvars);
9790 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
9791 {
9792 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
9793 {
9794 if (end)
9795 rettv->vval.v_number = (varnumber_T)last;
9796 else
9797 rettv->vval.v_number = (varnumber_T)first;
9798 return;
9799 }
9800 }
9801 #endif
9802 rettv->vval.v_number = -1;
9803 }
9804
9805 /*
9806 * "foldclosed()" function
9807 */
9808 static void
9809 f_foldclosed(typval_T *argvars, typval_T *rettv)
9810 {
9811 foldclosed_both(argvars, rettv, FALSE);
9812 }
9813
9814 /*
9815 * "foldclosedend()" function
9816 */
9817 static void
9818 f_foldclosedend(typval_T *argvars, typval_T *rettv)
9819 {
9820 foldclosed_both(argvars, rettv, TRUE);
9821 }
9822
9823 /*
9824 * "foldlevel()" function
9825 */
9826 static void
9827 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9828 {
9829 #ifdef FEAT_FOLDING
9830 linenr_T lnum;
9831
9832 lnum = get_tv_lnum(argvars);
9833 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
9834 rettv->vval.v_number = foldLevel(lnum);
9835 #endif
9836 }
9837
9838 /*
9839 * "foldtext()" function
9840 */
9841 static void
9842 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
9843 {
9844 #ifdef FEAT_FOLDING
9845 linenr_T lnum;
9846 char_u *s;
9847 char_u *r;
9848 int len;
9849 char *txt;
9850 #endif
9851
9852 rettv->v_type = VAR_STRING;
9853 rettv->vval.v_string = NULL;
9854 #ifdef FEAT_FOLDING
9855 if ((linenr_T)vimvars[VV_FOLDSTART].vv_nr > 0
9856 && (linenr_T)vimvars[VV_FOLDEND].vv_nr
9857 <= curbuf->b_ml.ml_line_count
9858 && vimvars[VV_FOLDDASHES].vv_str != NULL)
9859 {
9860 /* Find first non-empty line in the fold. */
9861 lnum = (linenr_T)vimvars[VV_FOLDSTART].vv_nr;
9862 while (lnum < (linenr_T)vimvars[VV_FOLDEND].vv_nr)
9863 {
9864 if (!linewhite(lnum))
9865 break;
9866 ++lnum;
9867 }
9868
9869 /* Find interesting text in this line. */
9870 s = skipwhite(ml_get(lnum));
9871 /* skip C comment-start */
9872 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
9873 {
9874 s = skipwhite(s + 2);
9875 if (*skipwhite(s) == NUL
9876 && lnum + 1 < (linenr_T)vimvars[VV_FOLDEND].vv_nr)
9877 {
9878 s = skipwhite(ml_get(lnum + 1));
9879 if (*s == '*')
9880 s = skipwhite(s + 1);
9881 }
9882 }
9883 txt = _("+-%s%3ld lines: ");
9884 r = alloc((unsigned)(STRLEN(txt)
9885 + STRLEN(vimvars[VV_FOLDDASHES].vv_str) /* for %s */
9886 + 20 /* for %3ld */
9887 + STRLEN(s))); /* concatenated */
9888 if (r != NULL)
9889 {
9890 sprintf((char *)r, txt, vimvars[VV_FOLDDASHES].vv_str,
9891 (long)((linenr_T)vimvars[VV_FOLDEND].vv_nr
9892 - (linenr_T)vimvars[VV_FOLDSTART].vv_nr + 1));
9893 len = (int)STRLEN(r);
9894 STRCAT(r, s);
9895 /* remove 'foldmarker' and 'commentstring' */
9896 foldtext_cleanup(r + len);
9897 rettv->vval.v_string = r;
9898 }
9899 }
9900 #endif
9901 }
9902
9903 /*
9904 * "foldtextresult(lnum)" function
9905 */
9906 static void
9907 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
9908 {
9909 #ifdef FEAT_FOLDING
9910 linenr_T lnum;
9911 char_u *text;
9912 char_u buf[51];
9913 foldinfo_T foldinfo;
9914 int fold_count;
9915 #endif
9916
9917 rettv->v_type = VAR_STRING;
9918 rettv->vval.v_string = NULL;
9919 #ifdef FEAT_FOLDING
9920 lnum = get_tv_lnum(argvars);
9921 /* treat illegal types and illegal string values for {lnum} the same */
9922 if (lnum < 0)
9923 lnum = 0;
9924 fold_count = foldedCount(curwin, lnum, &foldinfo);
9925 if (fold_count > 0)
9926 {
9927 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
9928 &foldinfo, buf);
9929 if (text == buf)
9930 text = vim_strsave(text);
9931 rettv->vval.v_string = text;
9932 }
9933 #endif
9934 }
9935
9936 /*
9937 * "foreground()" function
9938 */
9939 static void
9940 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9941 {
9942 #ifdef FEAT_GUI
9943 if (gui.in_use)
9944 gui_mch_set_foreground();
9945 #else
9946 # ifdef WIN32
9947 win32_set_foreground();
9948 # endif
9949 #endif
9950 }
9951
9952 /*
9953 * "function()" function
9954 */
9955 static void
9956 f_function(typval_T *argvars, typval_T *rettv)
9957 {
9958 char_u *s;
9959 char_u *name;
9960 int use_string = FALSE;
9961 partial_T *arg_pt = NULL;
9962
9963 if (argvars[0].v_type == VAR_FUNC)
9964 {
9965 /* function(MyFunc, [arg], dict) */
9966 s = argvars[0].vval.v_string;
9967 }
9968 else if (argvars[0].v_type == VAR_PARTIAL
9969 && argvars[0].vval.v_partial != NULL)
9970 {
9971 /* function(dict.MyFunc, [arg]) */
9972 arg_pt = argvars[0].vval.v_partial;
9973 s = arg_pt->pt_name;
9974 }
9975 else
9976 {
9977 /* function('MyFunc', [arg], dict) */
9978 s = get_tv_string(&argvars[0]);
9979 use_string = TRUE;
9980 }
9981
9982 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
9983 EMSG2(_(e_invarg2), s);
9984 /* Don't check an autoload name for existence here. */
9985 else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
9986 && !function_exists(s))
9987 EMSG2(_("E700: Unknown function: %s"), s);
9988 else
9989 {
9990 int dict_idx = 0;
9991 int arg_idx = 0;
9992 list_T *list = NULL;
9993
9994 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
9995 {
9996 char sid_buf[25];
9997 int off = *s == 's' ? 2 : 5;
9998
9999 /* Expand s: and <SID> into <SNR>nr_, so that the function can
10000 * also be called from another script. Using trans_function_name()
10001 * would also work, but some plugins depend on the name being
10002 * printable text. */
10003 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
10004 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
10005 if (name != NULL)
10006 {
10007 STRCPY(name, sid_buf);
10008 STRCAT(name, s + off);
10009 }
10010 }
10011 else
10012 name = vim_strsave(s);
10013
10014 if (argvars[1].v_type != VAR_UNKNOWN)
10015 {
10016 if (argvars[2].v_type != VAR_UNKNOWN)
10017 {
10018 /* function(name, [args], dict) */
10019 arg_idx = 1;
10020 dict_idx = 2;
10021 }
10022 else if (argvars[1].v_type == VAR_DICT)
10023 /* function(name, dict) */
10024 dict_idx = 1;
10025 else
10026 /* function(name, [args]) */
10027 arg_idx = 1;
10028 if (dict_idx > 0)
10029 {
10030 if (argvars[dict_idx].v_type != VAR_DICT)
10031 {
10032 EMSG(_("E922: expected a dict"));
10033 vim_free(name);
10034 return;
10035 }
10036 if (argvars[dict_idx].vval.v_dict == NULL)
10037 dict_idx = 0;
10038 }
10039 if (arg_idx > 0)
10040 {
10041 if (argvars[arg_idx].v_type != VAR_LIST)
10042 {
10043 EMSG(_("E923: Second argument of function() must be a list or a dict"));
10044 vim_free(name);
10045 return;
10046 }
10047 list = argvars[arg_idx].vval.v_list;
10048 if (list == NULL || list->lv_len == 0)
10049 arg_idx = 0;
10050 }
10051 }
10052 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL)
10053 {
10054 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
10055
10056 /* result is a VAR_PARTIAL */
10057 if (pt == NULL)
10058 vim_free(name);
10059 else
10060 {
10061 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
10062 {
10063 listitem_T *li;
10064 int i = 0;
10065 int arg_len = 0;
10066 int lv_len = 0;
10067
10068 if (arg_pt != NULL)
10069 arg_len = arg_pt->pt_argc;
10070 if (list != NULL)
10071 lv_len = list->lv_len;
10072 pt->pt_argc = arg_len + lv_len;
10073 pt->pt_argv = (typval_T *)alloc(
10074 sizeof(typval_T) * pt->pt_argc);
10075 if (pt->pt_argv == NULL)
10076 {
10077 vim_free(pt);
10078 vim_free(name);
10079 return;
10080 }
10081 else
10082 {
10083 for (i = 0; i < arg_len; i++)
10084 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
10085 if (lv_len > 0)
10086 for (li = list->lv_first; li != NULL;
10087 li = li->li_next)
10088 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
10089 }
10090 }
10091
10092 /* For "function(dict.func, [], dict)" and "func" is a partial
10093 * use "dict". That is backwards compatible. */
10094 if (dict_idx > 0)
10095 {
10096 /* The dict is bound explicitly, pt_auto is FALSE. */
10097 pt->pt_dict = argvars[dict_idx].vval.v_dict;
10098 ++pt->pt_dict->dv_refcount;
10099 }
10100 else if (arg_pt != NULL)
10101 {
10102 /* If the dict was bound automatically the result is also
10103 * bound automatically. */
10104 pt->pt_dict = arg_pt->pt_dict;
10105 pt->pt_auto = arg_pt->pt_auto;
10106 if (pt->pt_dict != NULL)
10107 ++pt->pt_dict->dv_refcount;
10108 }
10109
10110 pt->pt_refcount = 1;
10111 pt->pt_name = name;
10112 func_ref(pt->pt_name);
10113 }
10114 rettv->v_type = VAR_PARTIAL;
10115 rettv->vval.v_partial = pt;
10116 }
10117 else
10118 {
10119 /* result is a VAR_FUNC */
10120 rettv->v_type = VAR_FUNC;
10121 rettv->vval.v_string = name;
10122 func_ref(name);
10123 }
10124 }
10125 }
10126
10127 /*
10128 * "garbagecollect()" function
10129 */
10130 static void
10131 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
10132 {
10133 /* This is postponed until we are back at the toplevel, because we may be
10134 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
10135 want_garbage_collect = TRUE;
10136
10137 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
10138 garbage_collect_at_exit = TRUE;
10139 }
10140
10141 /*
10142 * "get()" function
10143 */
10144 static void
10145 f_get(typval_T *argvars, typval_T *rettv)
10146 {
10147 listitem_T *li;
10148 list_T *l;
10149 dictitem_T *di;
10150 dict_T *d;
10151 typval_T *tv = NULL;
10152
10153 if (argvars[0].v_type == VAR_LIST)
10154 {
10155 if ((l = argvars[0].vval.v_list) != NULL)
10156 {
10157 int error = FALSE;
10158
10159 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
10160 if (!error && li != NULL)
10161 tv = &li->li_tv;
10162 }
10163 }
10164 else if (argvars[0].v_type == VAR_DICT)
10165 {
10166 if ((d = argvars[0].vval.v_dict) != NULL)
10167 {
10168 di = dict_find(d, get_tv_string(&argvars[1]), -1);
10169 if (di != NULL)
10170 tv = &di->di_tv;
10171 }
10172 }
10173 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
10174 {
10175 partial_T *pt;
10176 partial_T fref_pt;
10177
10178 if (argvars[0].v_type == VAR_PARTIAL)
10179 pt = argvars[0].vval.v_partial;
10180 else
10181 {
10182 vim_memset(&fref_pt, 0, sizeof(fref_pt));
10183 fref_pt.pt_name = argvars[0].vval.v_string;
10184 pt = &fref_pt;
10185 }
10186
10187 if (pt != NULL)
10188 {
10189 char_u *what = get_tv_string(&argvars[1]);
10190
10191 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
10192 {
10193 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
10194 if (pt->pt_name == NULL)
10195 rettv->vval.v_string = NULL;
10196 else
10197 rettv->vval.v_string = vim_strsave(pt->pt_name);
10198 }
10199 else if (STRCMP(what, "dict") == 0)
10200 {
10201 rettv->v_type = VAR_DICT;
10202 rettv->vval.v_dict = pt->pt_dict;
10203 if (pt->pt_dict != NULL)
10204 ++pt->pt_dict->dv_refcount;
10205 }
10206 else if (STRCMP(what, "args") == 0)
10207 {
10208 rettv->v_type = VAR_LIST;
10209 if (rettv_list_alloc(rettv) == OK)
10210 {
10211 int i;
10212
10213 for (i = 0; i < pt->pt_argc; ++i)
10214 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
10215 }
10216 }
10217 else
10218 EMSG2(_(e_invarg2), what);
10219 return;
10220 }
10221 }
10222 else
10223 EMSG2(_(e_listdictarg), "get()");
10224
10225 if (tv == NULL)
10226 {
10227 if (argvars[2].v_type != VAR_UNKNOWN)
10228 copy_tv(&argvars[2], rettv);
10229 }
10230 else
10231 copy_tv(tv, rettv);
10232 }
10233
10234 static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
10235
10236 /*
10237 * Get line or list of lines from buffer "buf" into "rettv".
10238 * Return a range (from start to end) of lines in rettv from the specified
10239 * buffer.
10240 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
10241 */
10242 static void
10243 get_buffer_lines(
10244 buf_T *buf,
10245 linenr_T start,
10246 linenr_T end,
10247 int retlist,
10248 typval_T *rettv)
10249 {
10250 char_u *p;
10251
10252 rettv->v_type = VAR_STRING;
10253 rettv->vval.v_string = NULL;
10254 if (retlist && rettv_list_alloc(rettv) == FAIL)
10255 return;
10256
10257 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
10258 return;
10259
10260 if (!retlist)
10261 {
10262 if (start >= 1 && start <= buf->b_ml.ml_line_count)
10263 p = ml_get_buf(buf, start, FALSE);
10264 else
10265 p = (char_u *)"";
10266 rettv->vval.v_string = vim_strsave(p);
10267 }
10268 else
10269 {
10270 if (end < start)
10271 return;
10272
10273 if (start < 1)
10274 start = 1;
10275 if (end > buf->b_ml.ml_line_count)
10276 end = buf->b_ml.ml_line_count;
10277 while (start <= end)
10278 if (list_append_string(rettv->vval.v_list,
10279 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
10280 break;
10281 }
10282 }
10283
10284 /*
10285 * "getbufline()" function
10286 */
10287 static void
10288 f_getbufline(typval_T *argvars, typval_T *rettv)
10289 {
10290 linenr_T lnum;
10291 linenr_T end;
10292 buf_T *buf;
10293
10294 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10295 ++emsg_off;
10296 buf = get_buf_tv(&argvars[0], FALSE);
10297 --emsg_off;
10298
10299 lnum = get_tv_lnum_buf(&argvars[1], buf);
10300 if (argvars[2].v_type == VAR_UNKNOWN)
10301 end = lnum;
10302 else
10303 end = get_tv_lnum_buf(&argvars[2], buf);
10304
10305 get_buffer_lines(buf, lnum, end, TRUE, rettv);
10306 }
10307
10308 /*
10309 * "getbufvar()" function
10310 */
10311 static void
10312 f_getbufvar(typval_T *argvars, typval_T *rettv)
10313 {
10314 buf_T *buf;
10315 buf_T *save_curbuf;
10316 char_u *varname;
10317 dictitem_T *v;
10318 int done = FALSE;
10319
10320 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
10321 varname = get_tv_string_chk(&argvars[1]);
10322 ++emsg_off;
10323 buf = get_buf_tv(&argvars[0], FALSE);
10324
10325 rettv->v_type = VAR_STRING;
10326 rettv->vval.v_string = NULL;
10327
10328 if (buf != NULL && varname != NULL)
10329 {
10330 /* set curbuf to be our buf, temporarily */
10331 save_curbuf = curbuf;
10332 curbuf = buf;
10333
10334 if (*varname == '&') /* buffer-local-option */
10335 {
10336 if (get_option_tv(&varname, rettv, TRUE) == OK)
10337 done = TRUE;
10338 }
10339 else if (STRCMP(varname, "changedtick") == 0)
10340 {
10341 rettv->v_type = VAR_NUMBER;
10342 rettv->vval.v_number = curbuf->b_changedtick;
10343 done = TRUE;
10344 }
10345 else
10346 {
10347 /* Look up the variable. */
10348 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
10349 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
10350 'b', varname, FALSE);
10351 if (v != NULL)
10352 {
10353 copy_tv(&v->di_tv, rettv);
10354 done = TRUE;
10355 }
10356 }
10357
10358 /* restore previous notion of curbuf */
10359 curbuf = save_curbuf;
10360 }
10361
10362 if (!done && argvars[2].v_type != VAR_UNKNOWN)
10363 /* use the default value */
10364 copy_tv(&argvars[2], rettv);
10365
10366 --emsg_off;
10367 }
10368
10369 /*
10370 * "getchar()" function
10371 */
10372 static void
10373 f_getchar(typval_T *argvars, typval_T *rettv)
10374 {
10375 varnumber_T n;
10376 int error = FALSE;
10377
10378 /* Position the cursor. Needed after a message that ends in a space. */
10379 windgoto(msg_row, msg_col);
10380
10381 ++no_mapping;
10382 ++allow_keys;
10383 for (;;)
10384 {
10385 if (argvars[0].v_type == VAR_UNKNOWN)
10386 /* getchar(): blocking wait. */
10387 n = safe_vgetc();
10388 else if (get_tv_number_chk(&argvars[0], &error) == 1)
10389 /* getchar(1): only check if char avail */
10390 n = vpeekc_any();
10391 else if (error || vpeekc_any() == NUL)
10392 /* illegal argument or getchar(0) and no char avail: return zero */
10393 n = 0;
10394 else
10395 /* getchar(0) and char avail: return char */
10396 n = safe_vgetc();
10397
10398 if (n == K_IGNORE)
10399 continue;
10400 break;
10401 }
10402 --no_mapping;
10403 --allow_keys;
10404
10405 vimvars[VV_MOUSE_WIN].vv_nr = 0;
10406 vimvars[VV_MOUSE_WINID].vv_nr = 0;
10407 vimvars[VV_MOUSE_LNUM].vv_nr = 0;
10408 vimvars[VV_MOUSE_COL].vv_nr = 0;
10409
10410 rettv->vval.v_number = n;
10411 if (IS_SPECIAL(n) || mod_mask != 0)
10412 {
10413 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
10414 int i = 0;
10415
10416 /* Turn a special key into three bytes, plus modifier. */
10417 if (mod_mask != 0)
10418 {
10419 temp[i++] = K_SPECIAL;
10420 temp[i++] = KS_MODIFIER;
10421 temp[i++] = mod_mask;
10422 }
10423 if (IS_SPECIAL(n))
10424 {
10425 temp[i++] = K_SPECIAL;
10426 temp[i++] = K_SECOND(n);
10427 temp[i++] = K_THIRD(n);
10428 }
10429 #ifdef FEAT_MBYTE
10430 else if (has_mbyte)
10431 i += (*mb_char2bytes)(n, temp + i);
10432 #endif
10433 else
10434 temp[i++] = n;
10435 temp[i++] = NUL;
10436 rettv->v_type = VAR_STRING;
10437 rettv->vval.v_string = vim_strsave(temp);
10438
10439 #ifdef FEAT_MOUSE
10440 if (is_mouse_key(n))
10441 {
10442 int row = mouse_row;
10443 int col = mouse_col;
10444 win_T *win;
10445 linenr_T lnum;
10446 # ifdef FEAT_WINDOWS
10447 win_T *wp;
10448 # endif
10449 int winnr = 1;
10450
10451 if (row >= 0 && col >= 0)
10452 {
10453 /* Find the window at the mouse coordinates and compute the
10454 * text position. */
10455 win = mouse_find_win(&row, &col);
10456 (void)mouse_comp_pos(win, &row, &col, &lnum);
10457 # ifdef FEAT_WINDOWS
10458 for (wp = firstwin; wp != win; wp = wp->w_next)
10459 ++winnr;
10460 # endif
10461 vimvars[VV_MOUSE_WIN].vv_nr = winnr;
10462 vimvars[VV_MOUSE_WINID].vv_nr = win->w_id;
10463 vimvars[VV_MOUSE_LNUM].vv_nr = lnum;
10464 vimvars[VV_MOUSE_COL].vv_nr = col + 1;
10465 }
10466 }
10467 #endif
10468 }
10469 }
10470
10471 /*
10472 * "getcharmod()" function
10473 */
10474 static void
10475 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
10476 {
10477 rettv->vval.v_number = mod_mask;
10478 }
10479
10480 /*
10481 * "getcharsearch()" function
10482 */
10483 static void
10484 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
10485 {
10486 if (rettv_dict_alloc(rettv) != FAIL)
10487 {
10488 dict_T *dict = rettv->vval.v_dict;
10489
10490 dict_add_nr_str(dict, "char", 0L, last_csearch());
10491 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
10492 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
10493 }
10494 }
10495
10496 /*
10497 * "getcmdline()" function
10498 */
10499 static void
10500 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
10501 {
10502 rettv->v_type = VAR_STRING;
10503 rettv->vval.v_string = get_cmdline_str();
10504 }
10505
10506 /*
10507 * "getcmdpos()" function
10508 */
10509 static void
10510 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
10511 {
10512 rettv->vval.v_number = get_cmdline_pos() + 1;
10513 }
10514
10515 /*
10516 * "getcmdtype()" function
10517 */
10518 static void
10519 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
10520 {
10521 rettv->v_type = VAR_STRING;
10522 rettv->vval.v_string = alloc(2);
10523 if (rettv->vval.v_string != NULL)
10524 {
10525 rettv->vval.v_string[0] = get_cmdline_type();
10526 rettv->vval.v_string[1] = NUL;
10527 }
10528 }
10529
10530 /*
10531 * "getcmdwintype()" function
10532 */
10533 static void
10534 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
10535 {
10536 rettv->v_type = VAR_STRING;
10537 rettv->vval.v_string = NULL;
10538 #ifdef FEAT_CMDWIN
10539 rettv->vval.v_string = alloc(2);
10540 if (rettv->vval.v_string != NULL)
10541 {
10542 rettv->vval.v_string[0] = cmdwin_type;
10543 rettv->vval.v_string[1] = NUL;
10544 }
10545 #endif
10546 }
10547
10548 #if defined(FEAT_CMDL_COMPL)
10549 /*
10550 * "getcompletion()" function
10551 */
10552 static void
10553 f_getcompletion(typval_T *argvars, typval_T *rettv)
10554 {
10555 char_u *pat;
10556 expand_T xpc;
10557 int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL
10558 | WILD_LIST_NOTFOUND | WILD_NO_BEEP;
10559
10560 if (p_wic)
10561 options |= WILD_ICASE;
10562
10563 ExpandInit(&xpc);
10564 xpc.xp_pattern = get_tv_string(&argvars[0]);
10565 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
10566 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
10567 if (xpc.xp_context == EXPAND_NOTHING)
10568 {
10569 if (argvars[1].v_type == VAR_STRING)
10570 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
10571 else
10572 EMSG(_(e_invarg));
10573 return;
10574 }
10575
10576 # if defined(FEAT_MENU)
10577 if (xpc.xp_context == EXPAND_MENUS)
10578 {
10579 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
10580 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
10581 }
10582 # endif
10583
10584 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
10585 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
10586 {
10587 int i;
10588
10589 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
10590
10591 for (i = 0; i < xpc.xp_numfiles; i++)
10592 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
10593 }
10594 vim_free(pat);
10595 ExpandCleanup(&xpc);
10596 }
10597 #endif
10598
10599 /*
10600 * "getcwd()" function
10601 */
10602 static void
10603 f_getcwd(typval_T *argvars, typval_T *rettv)
10604 {
10605 win_T *wp = NULL;
10606 char_u *cwd;
10607
10608 rettv->v_type = VAR_STRING;
10609 rettv->vval.v_string = NULL;
10610
10611 wp = find_tabwin(&argvars[0], &argvars[1]);
10612 if (wp != NULL)
10613 {
10614 if (wp->w_localdir != NULL)
10615 rettv->vval.v_string = vim_strsave(wp->w_localdir);
10616 else if (globaldir != NULL)
10617 rettv->vval.v_string = vim_strsave(globaldir);
10618 else
10619 {
10620 cwd = alloc(MAXPATHL);
10621 if (cwd != NULL)
10622 {
10623 if (mch_dirname(cwd, MAXPATHL) != FAIL)
10624 rettv->vval.v_string = vim_strsave(cwd);
10625 vim_free(cwd);
10626 }
10627 }
10628 #ifdef BACKSLASH_IN_FILENAME
10629 if (rettv->vval.v_string != NULL)
10630 slash_adjust(rettv->vval.v_string);
10631 #endif
10632 }
10633 }
10634
10635 /*
10636 * "getfontname()" function
10637 */
10638 static void
10639 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
10640 {
10641 rettv->v_type = VAR_STRING;
10642 rettv->vval.v_string = NULL;
10643 #ifdef FEAT_GUI
10644 if (gui.in_use)
10645 {
10646 GuiFont font;
10647 char_u *name = NULL;
10648
10649 if (argvars[0].v_type == VAR_UNKNOWN)
10650 {
10651 /* Get the "Normal" font. Either the name saved by
10652 * hl_set_font_name() or from the font ID. */
10653 font = gui.norm_font;
10654 name = hl_get_font_name();
10655 }
10656 else
10657 {
10658 name = get_tv_string(&argvars[0]);
10659 if (STRCMP(name, "*") == 0) /* don't use font dialog */
10660 return;
10661 font = gui_mch_get_font(name, FALSE);
10662 if (font == NOFONT)
10663 return; /* Invalid font name, return empty string. */
10664 }
10665 rettv->vval.v_string = gui_mch_get_fontname(font, name);
10666 if (argvars[0].v_type != VAR_UNKNOWN)
10667 gui_mch_free_font(font);
10668 }
10669 #endif
10670 }
10671
10672 /*
10673 * "getfperm({fname})" function
10674 */
10675 static void
10676 f_getfperm(typval_T *argvars, typval_T *rettv)
10677 {
10678 char_u *fname;
10679 stat_T st;
10680 char_u *perm = NULL;
10681 char_u flags[] = "rwx";
10682 int i;
10683
10684 fname = get_tv_string(&argvars[0]);
10685
10686 rettv->v_type = VAR_STRING;
10687 if (mch_stat((char *)fname, &st) >= 0)
10688 {
10689 perm = vim_strsave((char_u *)"---------");
10690 if (perm != NULL)
10691 {
10692 for (i = 0; i < 9; i++)
10693 {
10694 if (st.st_mode & (1 << (8 - i)))
10695 perm[i] = flags[i % 3];
10696 }
10697 }
10698 }
10699 rettv->vval.v_string = perm;
10700 }
10701
10702 /*
10703 * "getfsize({fname})" function
10704 */
10705 static void
10706 f_getfsize(typval_T *argvars, typval_T *rettv)
10707 {
10708 char_u *fname;
10709 stat_T st;
10710
10711 fname = get_tv_string(&argvars[0]);
10712
10713 rettv->v_type = VAR_NUMBER;
10714
10715 if (mch_stat((char *)fname, &st) >= 0)
10716 {
10717 if (mch_isdir(fname))
10718 rettv->vval.v_number = 0;
10719 else
10720 {
10721 rettv->vval.v_number = (varnumber_T)st.st_size;
10722
10723 /* non-perfect check for overflow */
10724 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
10725 rettv->vval.v_number = -2;
10726 }
10727 }
10728 else
10729 rettv->vval.v_number = -1;
10730 }
10731
10732 /*
10733 * "getftime({fname})" function
10734 */
10735 static void
10736 f_getftime(typval_T *argvars, typval_T *rettv)
10737 {
10738 char_u *fname;
10739 stat_T st;
10740
10741 fname = get_tv_string(&argvars[0]);
10742
10743 if (mch_stat((char *)fname, &st) >= 0)
10744 rettv->vval.v_number = (varnumber_T)st.st_mtime;
10745 else
10746 rettv->vval.v_number = -1;
10747 }
10748
10749 /*
10750 * "getftype({fname})" function
10751 */
10752 static void
10753 f_getftype(typval_T *argvars, typval_T *rettv)
10754 {
10755 char_u *fname;
10756 stat_T st;
10757 char_u *type = NULL;
10758 char *t;
10759
10760 fname = get_tv_string(&argvars[0]);
10761
10762 rettv->v_type = VAR_STRING;
10763 if (mch_lstat((char *)fname, &st) >= 0)
10764 {
10765 #ifdef S_ISREG
10766 if (S_ISREG(st.st_mode))
10767 t = "file";
10768 else if (S_ISDIR(st.st_mode))
10769 t = "dir";
10770 # ifdef S_ISLNK
10771 else if (S_ISLNK(st.st_mode))
10772 t = "link";
10773 # endif
10774 # ifdef S_ISBLK
10775 else if (S_ISBLK(st.st_mode))
10776 t = "bdev";
10777 # endif
10778 # ifdef S_ISCHR
10779 else if (S_ISCHR(st.st_mode))
10780 t = "cdev";
10781 # endif
10782 # ifdef S_ISFIFO
10783 else if (S_ISFIFO(st.st_mode))
10784 t = "fifo";
10785 # endif
10786 # ifdef S_ISSOCK
10787 else if (S_ISSOCK(st.st_mode))
10788 t = "fifo";
10789 # endif
10790 else
10791 t = "other";
10792 #else
10793 # ifdef S_IFMT
10794 switch (st.st_mode & S_IFMT)
10795 {
10796 case S_IFREG: t = "file"; break;
10797 case S_IFDIR: t = "dir"; break;
10798 # ifdef S_IFLNK
10799 case S_IFLNK: t = "link"; break;
10800 # endif
10801 # ifdef S_IFBLK
10802 case S_IFBLK: t = "bdev"; break;
10803 # endif
10804 # ifdef S_IFCHR
10805 case S_IFCHR: t = "cdev"; break;
10806 # endif
10807 # ifdef S_IFIFO
10808 case S_IFIFO: t = "fifo"; break;
10809 # endif
10810 # ifdef S_IFSOCK
10811 case S_IFSOCK: t = "socket"; break;
10812 # endif
10813 default: t = "other";
10814 }
10815 # else
10816 if (mch_isdir(fname))
10817 t = "dir";
10818 else
10819 t = "file";
10820 # endif
10821 #endif
10822 type = vim_strsave((char_u *)t);
10823 }
10824 rettv->vval.v_string = type;
10825 }
10826
10827 /*
10828 * "getline(lnum, [end])" function
10829 */
10830 static void
10831 f_getline(typval_T *argvars, typval_T *rettv)
10832 {
10833 linenr_T lnum;
10834 linenr_T end;
10835 int retlist;
10836
10837 lnum = get_tv_lnum(argvars);
10838 if (argvars[1].v_type == VAR_UNKNOWN)
10839 {
10840 end = 0;
10841 retlist = FALSE;
10842 }
10843 else
10844 {
10845 end = get_tv_lnum(&argvars[1]);
10846 retlist = TRUE;
10847 }
10848
10849 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
10850 }
10851
10852 /*
10853 * "getmatches()" function
10854 */
10855 static void
10856 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10857 {
10858 #ifdef FEAT_SEARCH_EXTRA
10859 dict_T *dict;
10860 matchitem_T *cur = curwin->w_match_head;
10861 int i;
10862
10863 if (rettv_list_alloc(rettv) == OK)
10864 {
10865 while (cur != NULL)
10866 {
10867 dict = dict_alloc();
10868 if (dict == NULL)
10869 return;
10870 if (cur->match.regprog == NULL)
10871 {
10872 /* match added with matchaddpos() */
10873 for (i = 0; i < MAXPOSMATCH; ++i)
10874 {
10875 llpos_T *llpos;
10876 char buf[6];
10877 list_T *l;
10878
10879 llpos = &cur->pos.pos[i];
10880 if (llpos->lnum == 0)
10881 break;
10882 l = list_alloc();
10883 if (l == NULL)
10884 break;
10885 list_append_number(l, (varnumber_T)llpos->lnum);
10886 if (llpos->col > 0)
10887 {
10888 list_append_number(l, (varnumber_T)llpos->col);
10889 list_append_number(l, (varnumber_T)llpos->len);
10890 }
10891 sprintf(buf, "pos%d", i + 1);
10892 dict_add_list(dict, buf, l);
10893 }
10894 }
10895 else
10896 {
10897 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
10898 }
10899 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
10900 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
10901 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
10902 # if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
10903 if (cur->conceal_char)
10904 {
10905 char_u buf[MB_MAXBYTES + 1];
10906
10907 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
10908 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
10909 }
10910 # endif
10911 list_append_dict(rettv->vval.v_list, dict);
10912 cur = cur->next;
10913 }
10914 }
10915 #endif
10916 }
10917
10918 /*
10919 * "getpid()" function
10920 */
10921 static void
10922 f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
10923 {
10924 rettv->vval.v_number = mch_get_pid();
10925 }
10926
10927 static void
10928 getpos_both(
10929 typval_T *argvars,
10930 typval_T *rettv,
10931 int getcurpos)
10932 {
10933 pos_T *fp;
10934 list_T *l;
10935 int fnum = -1;
10936
10937 if (rettv_list_alloc(rettv) == OK)
10938 {
10939 l = rettv->vval.v_list;
10940 if (getcurpos)
10941 fp = &curwin->w_cursor;
10942 else
10943 fp = var2fpos(&argvars[0], TRUE, &fnum);
10944 if (fnum != -1)
10945 list_append_number(l, (varnumber_T)fnum);
10946 else
10947 list_append_number(l, (varnumber_T)0);
10948 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
10949 : (varnumber_T)0);
10950 list_append_number(l, (fp != NULL)
10951 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
10952 : (varnumber_T)0);
10953 list_append_number(l,
10954 #ifdef FEAT_VIRTUALEDIT
10955 (fp != NULL) ? (varnumber_T)fp->coladd :
10956 #endif
10957 (varnumber_T)0);
10958 if (getcurpos)
10959 {
10960 update_curswant();
10961 list_append_number(l, curwin->w_curswant == MAXCOL ?
10962 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
10963 }
10964 }
10965 else
10966 rettv->vval.v_number = FALSE;
10967 }
10968
10969
10970 /*
10971 * "getcurpos()" function
10972 */
10973 static void
10974 f_getcurpos(typval_T *argvars, typval_T *rettv)
10975 {
10976 getpos_both(argvars, rettv, TRUE);
10977 }
10978
10979 /*
10980 * "getpos(string)" function
10981 */
10982 static void
10983 f_getpos(typval_T *argvars, typval_T *rettv)
10984 {
10985 getpos_both(argvars, rettv, FALSE);
10986 }
10987
10988 /*
10989 * "getqflist()" and "getloclist()" functions
10990 */
10991 static void
10992 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10993 {
10994 #ifdef FEAT_QUICKFIX
10995 win_T *wp;
10996 #endif
10997
10998 #ifdef FEAT_QUICKFIX
10999 if (rettv_list_alloc(rettv) == OK)
11000 {
11001 wp = NULL;
11002 if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */
11003 {
11004 wp = find_win_by_nr(&argvars[0], NULL);
11005 if (wp == NULL)
11006 return;
11007 }
11008
11009 (void)get_errorlist(wp, rettv->vval.v_list);
11010 }
11011 #endif
11012 }
11013
11014 /*
11015 * "getreg()" function
11016 */
11017 static void
11018 f_getreg(typval_T *argvars, typval_T *rettv)
11019 {
11020 char_u *strregname;
11021 int regname;
11022 int arg2 = FALSE;
11023 int return_list = FALSE;
11024 int error = FALSE;
11025
11026 if (argvars[0].v_type != VAR_UNKNOWN)
11027 {
11028 strregname = get_tv_string_chk(&argvars[0]);
11029 error = strregname == NULL;
11030 if (argvars[1].v_type != VAR_UNKNOWN)
11031 {
11032 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
11033 if (!error && argvars[2].v_type != VAR_UNKNOWN)
11034 return_list = (int)get_tv_number_chk(&argvars[2], &error);
11035 }
11036 }
11037 else
11038 strregname = vimvars[VV_REG].vv_str;
11039
11040 if (error)
11041 return;
11042
11043 regname = (strregname == NULL ? '"' : *strregname);
11044 if (regname == 0)
11045 regname = '"';
11046
11047 if (return_list)
11048 {
11049 rettv->v_type = VAR_LIST;
11050 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
11051 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
11052 if (rettv->vval.v_list == NULL)
11053 (void)rettv_list_alloc(rettv);
11054 else
11055 ++rettv->vval.v_list->lv_refcount;
11056 }
11057 else
11058 {
11059 rettv->v_type = VAR_STRING;
11060 rettv->vval.v_string = get_reg_contents(regname,
11061 arg2 ? GREG_EXPR_SRC : 0);
11062 }
11063 }
11064
11065 /*
11066 * "getregtype()" function
11067 */
11068 static void
11069 f_getregtype(typval_T *argvars, typval_T *rettv)
11070 {
11071 char_u *strregname;
11072 int regname;
11073 char_u buf[NUMBUFLEN + 2];
11074 long reglen = 0;
11075
11076 if (argvars[0].v_type != VAR_UNKNOWN)
11077 {
11078 strregname = get_tv_string_chk(&argvars[0]);
11079 if (strregname == NULL) /* type error; errmsg already given */
11080 {
11081 rettv->v_type = VAR_STRING;
11082 rettv->vval.v_string = NULL;
11083 return;
11084 }
11085 }
11086 else
11087 /* Default to v:register */
11088 strregname = vimvars[VV_REG].vv_str;
11089
11090 regname = (strregname == NULL ? '"' : *strregname);
11091 if (regname == 0)
11092 regname = '"';
11093
11094 buf[0] = NUL;
11095 buf[1] = NUL;
11096 switch (get_reg_type(regname, &reglen))
11097 {
11098 case MLINE: buf[0] = 'V'; break;
11099 case MCHAR: buf[0] = 'v'; break;
11100 case MBLOCK:
11101 buf[0] = Ctrl_V;
11102 sprintf((char *)buf + 1, "%ld", reglen + 1);
11103 break;
11104 }
11105 rettv->v_type = VAR_STRING;
11106 rettv->vval.v_string = vim_strsave(buf);
11107 }
11108
11109 /*
11110 * "gettabvar()" function
11111 */
11112 static void
11113 f_gettabvar(typval_T *argvars, typval_T *rettv)
11114 {
11115 win_T *oldcurwin;
11116 tabpage_T *tp, *oldtabpage;
11117 dictitem_T *v;
11118 char_u *varname;
11119 int done = FALSE;
11120
11121 rettv->v_type = VAR_STRING;
11122 rettv->vval.v_string = NULL;
11123
11124 varname = get_tv_string_chk(&argvars[1]);
11125 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
11126 if (tp != NULL && varname != NULL)
11127 {
11128 /* Set tp to be our tabpage, temporarily. Also set the window to the
11129 * first window in the tabpage, otherwise the window is not valid. */
11130 if (switch_win(&oldcurwin, &oldtabpage,
11131 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE)
11132 == OK)
11133 {
11134 /* look up the variable */
11135 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
11136 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
11137 if (v != NULL)
11138 {
11139 copy_tv(&v->di_tv, rettv);
11140 done = TRUE;
11141 }
11142 }
11143
11144 /* restore previous notion of curwin */
11145 restore_win(oldcurwin, oldtabpage, TRUE);
11146 }
11147
11148 if (!done && argvars[2].v_type != VAR_UNKNOWN)
11149 copy_tv(&argvars[2], rettv);
11150 }
11151
11152 /*
11153 * "gettabwinvar()" function
11154 */
11155 static void
11156 f_gettabwinvar(typval_T *argvars, typval_T *rettv)
11157 {
11158 getwinvar(argvars, rettv, 1);
11159 }
11160
11161 /*
11162 * "getwinposx()" function
11163 */
11164 static void
11165 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
11166 {
11167 rettv->vval.v_number = -1;
11168 #ifdef FEAT_GUI
11169 if (gui.in_use)
11170 {
11171 int x, y;
11172
11173 if (gui_mch_get_winpos(&x, &y) == OK)
11174 rettv->vval.v_number = x;
11175 }
11176 #endif
11177 }
11178
11179 /*
11180 * "win_findbuf()" function
11181 */
11182 static void
11183 f_win_findbuf(typval_T *argvars, typval_T *rettv)
11184 {
11185 if (rettv_list_alloc(rettv) != FAIL)
11186 win_findbuf(argvars, rettv->vval.v_list);
11187 }
11188
11189 /*
11190 * "win_getid()" function
11191 */
11192 static void
11193 f_win_getid(typval_T *argvars, typval_T *rettv)
11194 {
11195 rettv->vval.v_number = win_getid(argvars);
11196 }
11197
11198 /*
11199 * "win_gotoid()" function
11200 */
11201 static void
11202 f_win_gotoid(typval_T *argvars, typval_T *rettv)
11203 {
11204 rettv->vval.v_number = win_gotoid(argvars);
11205 }
11206
11207 /*
11208 * "win_id2tabwin()" function
11209 */
11210 static void
11211 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
11212 {
11213 if (rettv_list_alloc(rettv) != FAIL)
11214 win_id2tabwin(argvars, rettv->vval.v_list);
11215 }
11216
11217 /*
11218 * "win_id2win()" function
11219 */
11220 static void
11221 f_win_id2win(typval_T *argvars, typval_T *rettv)
11222 {
11223 rettv->vval.v_number = win_id2win(argvars);
11224 }
11225
11226 /*
11227 * "getwinposy()" function
11228 */
11229 static void
11230 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
11231 {
11232 rettv->vval.v_number = -1;
11233 #ifdef FEAT_GUI
11234 if (gui.in_use)
11235 {
11236 int x, y;
11237
11238 if (gui_mch_get_winpos(&x, &y) == OK)
11239 rettv->vval.v_number = y;
11240 }
11241 #endif
11242 }
11243
11244 /*
11245 * Find window specified by "vp" in tabpage "tp".
11246 */
11247 static win_T *
11248 find_win_by_nr(
11249 typval_T *vp,
11250 tabpage_T *tp UNUSED) /* NULL for current tab page */
11251 {
11252 #ifdef FEAT_WINDOWS
11253 win_T *wp;
11254 #endif
11255 int nr;
11256
11257 nr = (int)get_tv_number_chk(vp, NULL);
11258
11259 #ifdef FEAT_WINDOWS
11260 if (nr < 0)
11261 return NULL;
11262 if (nr == 0)
11263 return curwin;
11264
11265 for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin;
11266 wp != NULL; wp = wp->w_next)
11267 if (nr >= LOWEST_WIN_ID)
11268 {
11269 if (wp->w_id == nr)
11270 return wp;
11271 }
11272 else if (--nr <= 0)
11273 break;
11274 if (nr >= LOWEST_WIN_ID)
11275 return NULL;
11276 return wp;
11277 #else
11278 if (nr == 0 || nr == 1 || nr == curwin->w_id)
11279 return curwin;
11280 return NULL;
11281 #endif
11282 }
11283
11284 /*
11285 * Find window specified by "wvp" in tabpage "tvp".
11286 */
11287 static win_T *
11288 find_tabwin(
11289 typval_T *wvp, /* VAR_UNKNOWN for current window */
11290 typval_T *tvp) /* VAR_UNKNOWN for current tab page */
11291 {
11292 win_T *wp = NULL;
11293 tabpage_T *tp = NULL;
11294 long n;
11295
11296 if (wvp->v_type != VAR_UNKNOWN)
11297 {
11298 if (tvp->v_type != VAR_UNKNOWN)
11299 {
11300 n = (long)get_tv_number(tvp);
11301 if (n >= 0)
11302 tp = find_tabpage(n);
11303 }
11304 else
11305 tp = curtab;
11306
11307 if (tp != NULL)
11308 wp = find_win_by_nr(wvp, tp);
11309 }
11310 else
11311 wp = curwin;
11312
11313 return wp;
11314 }
11315
11316 /*
11317 * "getwinvar()" function
11318 */
11319 static void
11320 f_getwinvar(typval_T *argvars, typval_T *rettv)
11321 {
11322 getwinvar(argvars, rettv, 0);
11323 }
11324
11325 /*
11326 * getwinvar() and gettabwinvar()
11327 */
11328 static void
11329 getwinvar(
11330 typval_T *argvars,
11331 typval_T *rettv,
11332 int off) /* 1 for gettabwinvar() */
11333 {
11334 win_T *win;
11335 char_u *varname;
11336 dictitem_T *v;
11337 tabpage_T *tp = NULL;
11338 int done = FALSE;
11339 #ifdef FEAT_WINDOWS
11340 win_T *oldcurwin;
11341 tabpage_T *oldtabpage;
11342 int need_switch_win;
11343 #endif
11344
11345 #ifdef FEAT_WINDOWS
11346 if (off == 1)
11347 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
11348 else
11349 tp = curtab;
11350 #endif
11351 win = find_win_by_nr(&argvars[off], tp);
11352 varname = get_tv_string_chk(&argvars[off + 1]);
11353 ++emsg_off;
11354
11355 rettv->v_type = VAR_STRING;
11356 rettv->vval.v_string = NULL;
11357
11358 if (win != NULL && varname != NULL)
11359 {
11360 #ifdef FEAT_WINDOWS
11361 /* Set curwin to be our win, temporarily. Also set the tabpage,
11362 * otherwise the window is not valid. Only do this when needed,
11363 * autocommands get blocked. */
11364 need_switch_win = !(tp == curtab && win == curwin);
11365 if (!need_switch_win
11366 || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK)
11367 #endif
11368 {
11369 if (*varname == '&') /* window-local-option */
11370 {
11371 if (get_option_tv(&varname, rettv, 1) == OK)
11372 done = TRUE;
11373 }
11374 else
11375 {
11376 /* Look up the variable. */
11377 /* Let getwinvar({nr}, "") return the "w:" dictionary. */
11378 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
11379 varname, FALSE);
11380 if (v != NULL)
11381 {
11382 copy_tv(&v->di_tv, rettv);
11383 done = TRUE;
11384 }
11385 }
11386 }
11387
11388 #ifdef FEAT_WINDOWS
11389 if (need_switch_win)
11390 /* restore previous notion of curwin */
11391 restore_win(oldcurwin, oldtabpage, TRUE);
11392 #endif
11393 }
11394
11395 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
11396 /* use the default return value */
11397 copy_tv(&argvars[off + 2], rettv);
11398
11399 --emsg_off;
11400 }
11401
11402 /*
11403 * "glob()" function
11404 */
11405 static void
11406 f_glob(typval_T *argvars, typval_T *rettv)
11407 {
11408 int options = WILD_SILENT|WILD_USE_NL;
11409 expand_T xpc;
11410 int error = FALSE;
11411
11412 /* When the optional second argument is non-zero, don't remove matches
11413 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
11414 rettv->v_type = VAR_STRING;
11415 if (argvars[1].v_type != VAR_UNKNOWN)
11416 {
11417 if (get_tv_number_chk(&argvars[1], &error))
11418 options |= WILD_KEEP_ALL;
11419 if (argvars[2].v_type != VAR_UNKNOWN)
11420 {
11421 if (get_tv_number_chk(&argvars[2], &error))
11422 {
11423 rettv->v_type = VAR_LIST;
11424 rettv->vval.v_list = NULL;
11425 }
11426 if (argvars[3].v_type != VAR_UNKNOWN
11427 && get_tv_number_chk(&argvars[3], &error))
11428 options |= WILD_ALLLINKS;
11429 }
11430 }
11431 if (!error)
11432 {
11433 ExpandInit(&xpc);
11434 xpc.xp_context = EXPAND_FILES;
11435 if (p_wic)
11436 options += WILD_ICASE;
11437 if (rettv->v_type == VAR_STRING)
11438 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
11439 NULL, options, WILD_ALL);
11440 else if (rettv_list_alloc(rettv) != FAIL)
11441 {
11442 int i;
11443
11444 ExpandOne(&xpc, get_tv_string(&argvars[0]),
11445 NULL, options, WILD_ALL_KEEP);
11446 for (i = 0; i < xpc.xp_numfiles; i++)
11447 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
11448
11449 ExpandCleanup(&xpc);
11450 }
11451 }
11452 else
11453 rettv->vval.v_string = NULL;
11454 }
11455
11456 /*
11457 * "globpath()" function
11458 */
11459 static void
11460 f_globpath(typval_T *argvars, typval_T *rettv)
11461 {
11462 int flags = 0;
11463 char_u buf1[NUMBUFLEN];
11464 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
11465 int error = FALSE;
11466 garray_T ga;
11467 int i;
11468
11469 /* When the optional second argument is non-zero, don't remove matches
11470 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
11471 rettv->v_type = VAR_STRING;
11472 if (argvars[2].v_type != VAR_UNKNOWN)
11473 {
11474 if (get_tv_number_chk(&argvars[2], &error))
11475 flags |= WILD_KEEP_ALL;
11476 if (argvars[3].v_type != VAR_UNKNOWN)
11477 {
11478 if (get_tv_number_chk(&argvars[3], &error))
11479 {
11480 rettv->v_type = VAR_LIST;
11481 rettv->vval.v_list = NULL;
11482 }
11483 if (argvars[4].v_type != VAR_UNKNOWN
11484 && get_tv_number_chk(&argvars[4], &error))
11485 flags |= WILD_ALLLINKS;
11486 }
11487 }
11488 if (file != NULL && !error)
11489 {
11490 ga_init2(&ga, (int)sizeof(char_u *), 10);
11491 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
11492 if (rettv->v_type == VAR_STRING)
11493 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
11494 else if (rettv_list_alloc(rettv) != FAIL)
11495 for (i = 0; i < ga.ga_len; ++i)
11496 list_append_string(rettv->vval.v_list,
11497 ((char_u **)(ga.ga_data))[i], -1);
11498 ga_clear_strings(&ga);
11499 }
11500 else
11501 rettv->vval.v_string = NULL;
11502 }
11503
11504 /*
11505 * "glob2regpat()" function
11506 */
11507 static void
11508 f_glob2regpat(typval_T *argvars, typval_T *rettv)
11509 {
11510 char_u *pat = get_tv_string_chk(&argvars[0]);
11511
11512 rettv->v_type = VAR_STRING;
11513 rettv->vval.v_string = (pat == NULL)
11514 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
11515 }
11516
11517 /*
11518 * "has()" function
11519 */
11520 static void
11521 f_has(typval_T *argvars, typval_T *rettv)
11522 {
11523 int i;
11524 char_u *name;
11525 int n = FALSE;
11526 static char *(has_list[]) =
11527 {
11528 #ifdef AMIGA
11529 "amiga",
11530 # ifdef FEAT_ARP
11531 "arp",
11532 # endif
11533 #endif
11534 #ifdef __BEOS__
11535 "beos",
11536 #endif
11537 #ifdef MACOS
11538 "mac",
11539 #endif
11540 #if defined(MACOS_X_UNIX)
11541 "macunix", /* built with 'darwin' enabled */
11542 #endif
11543 #if defined(__APPLE__) && __APPLE__ == 1
11544 "osx", /* built with or without 'darwin' enabled */
11545 #endif
11546 #ifdef __QNX__
11547 "qnx",
11548 #endif
11549 #ifdef UNIX
11550 "unix",
11551 #endif
11552 #ifdef VMS
11553 "vms",
11554 #endif
11555 #ifdef WIN32
11556 "win32",
11557 #endif
11558 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
11559 "win32unix",
11560 #endif
11561 #if defined(WIN64) || defined(_WIN64)
11562 "win64",
11563 #endif
11564 #ifdef EBCDIC
11565 "ebcdic",
11566 #endif
11567 #ifndef CASE_INSENSITIVE_FILENAME
11568 "fname_case",
11569 #endif
11570 #ifdef HAVE_ACL
11571 "acl",
11572 #endif
11573 #ifdef FEAT_ARABIC
11574 "arabic",
11575 #endif
11576 #ifdef FEAT_AUTOCMD
11577 "autocmd",
11578 #endif
11579 #ifdef FEAT_BEVAL
11580 "balloon_eval",
11581 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
11582 "balloon_multiline",
11583 # endif
11584 #endif
11585 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
11586 "builtin_terms",
11587 # ifdef ALL_BUILTIN_TCAPS
11588 "all_builtin_terms",
11589 # endif
11590 #endif
11591 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
11592 || defined(FEAT_GUI_W32) \
11593 || defined(FEAT_GUI_MOTIF))
11594 "browsefilter",
11595 #endif
11596 #ifdef FEAT_BYTEOFF
11597 "byte_offset",
11598 #endif
11599 #ifdef FEAT_JOB_CHANNEL
11600 "channel",
11601 #endif
11602 #ifdef FEAT_CINDENT
11603 "cindent",
11604 #endif
11605 #ifdef FEAT_CLIENTSERVER
11606 "clientserver",
11607 #endif
11608 #ifdef FEAT_CLIPBOARD
11609 "clipboard",
11610 #endif
11611 #ifdef FEAT_CMDL_COMPL
11612 "cmdline_compl",
11613 #endif
11614 #ifdef FEAT_CMDHIST
11615 "cmdline_hist",
11616 #endif
11617 #ifdef FEAT_COMMENTS
11618 "comments",
11619 #endif
11620 #ifdef FEAT_CONCEAL
11621 "conceal",
11622 #endif
11623 #ifdef FEAT_CRYPT
11624 "cryptv",
11625 "crypt-blowfish",
11626 "crypt-blowfish2",
11627 #endif
11628 #ifdef FEAT_CSCOPE
11629 "cscope",
11630 #endif
11631 #ifdef FEAT_CURSORBIND
11632 "cursorbind",
11633 #endif
11634 #ifdef CURSOR_SHAPE
11635 "cursorshape",
11636 #endif
11637 #ifdef DEBUG
11638 "debug",
11639 #endif
11640 #ifdef FEAT_CON_DIALOG
11641 "dialog_con",
11642 #endif
11643 #ifdef FEAT_GUI_DIALOG
11644 "dialog_gui",
11645 #endif
11646 #ifdef FEAT_DIFF
11647 "diff",
11648 #endif
11649 #ifdef FEAT_DIGRAPHS
11650 "digraphs",
11651 #endif
11652 #ifdef FEAT_DIRECTX
11653 "directx",
11654 #endif
11655 #ifdef FEAT_DND
11656 "dnd",
11657 #endif
11658 #ifdef FEAT_EMACS_TAGS
11659 "emacs_tags",
11660 #endif
11661 "eval", /* always present, of course! */
11662 "ex_extra", /* graduated feature */
11663 #ifdef FEAT_SEARCH_EXTRA
11664 "extra_search",
11665 #endif
11666 #ifdef FEAT_FKMAP
11667 "farsi",
11668 #endif
11669 #ifdef FEAT_SEARCHPATH
11670 "file_in_path",
11671 #endif
11672 #ifdef FEAT_FILTERPIPE
11673 "filterpipe",
11674 #endif
11675 #ifdef FEAT_FIND_ID
11676 "find_in_path",
11677 #endif
11678 #ifdef FEAT_FLOAT
11679 "float",
11680 #endif
11681 #ifdef FEAT_FOLDING
11682 "folding",
11683 #endif
11684 #ifdef FEAT_FOOTER
11685 "footer",
11686 #endif
11687 #if !defined(USE_SYSTEM) && defined(UNIX)
11688 "fork",
11689 #endif
11690 #ifdef FEAT_GETTEXT
11691 "gettext",
11692 #endif
11693 #ifdef FEAT_GUI
11694 "gui",
11695 #endif
11696 #ifdef FEAT_GUI_ATHENA
11697 # ifdef FEAT_GUI_NEXTAW
11698 "gui_neXtaw",
11699 # else
11700 "gui_athena",
11701 # endif
11702 #endif
11703 #ifdef FEAT_GUI_GTK
11704 "gui_gtk",
11705 # ifdef USE_GTK3
11706 "gui_gtk3",
11707 # else
11708 "gui_gtk2",
11709 # endif
11710 #endif
11711 #ifdef FEAT_GUI_GNOME
11712 "gui_gnome",
11713 #endif
11714 #ifdef FEAT_GUI_MAC
11715 "gui_mac",
11716 #endif
11717 #ifdef FEAT_GUI_MOTIF
11718 "gui_motif",
11719 #endif
11720 #ifdef FEAT_GUI_PHOTON
11721 "gui_photon",
11722 #endif
11723 #ifdef FEAT_GUI_W32
11724 "gui_win32",
11725 #endif
11726 #ifdef FEAT_HANGULIN
11727 "hangul_input",
11728 #endif
11729 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
11730 "iconv",
11731 #endif
11732 #ifdef FEAT_INS_EXPAND
11733 "insert_expand",
11734 #endif
11735 #ifdef FEAT_JOB_CHANNEL
11736 "job",
11737 #endif
11738 #ifdef FEAT_JUMPLIST
11739 "jumplist",
11740 #endif
11741 #ifdef FEAT_KEYMAP
11742 "keymap",
11743 #endif
11744 #ifdef FEAT_LANGMAP
11745 "langmap",
11746 #endif
11747 #ifdef FEAT_LIBCALL
11748 "libcall",
11749 #endif
11750 #ifdef FEAT_LINEBREAK
11751 "linebreak",
11752 #endif
11753 #ifdef FEAT_LISP
11754 "lispindent",
11755 #endif
11756 #ifdef FEAT_LISTCMDS
11757 "listcmds",
11758 #endif
11759 #ifdef FEAT_LOCALMAP
11760 "localmap",
11761 #endif
11762 #ifdef FEAT_LUA
11763 # ifndef DYNAMIC_LUA
11764 "lua",
11765 # endif
11766 #endif
11767 #ifdef FEAT_MENU
11768 "menu",
11769 #endif
11770 #ifdef FEAT_SESSION
11771 "mksession",
11772 #endif
11773 #ifdef FEAT_MODIFY_FNAME
11774 "modify_fname",
11775 #endif
11776 #ifdef FEAT_MOUSE
11777 "mouse",
11778 #endif
11779 #ifdef FEAT_MOUSESHAPE
11780 "mouseshape",
11781 #endif
11782 #if defined(UNIX) || defined(VMS)
11783 # ifdef FEAT_MOUSE_DEC
11784 "mouse_dec",
11785 # endif
11786 # ifdef FEAT_MOUSE_GPM
11787 "mouse_gpm",
11788 # endif
11789 # ifdef FEAT_MOUSE_JSB
11790 "mouse_jsbterm",
11791 # endif
11792 # ifdef FEAT_MOUSE_NET
11793 "mouse_netterm",
11794 # endif
11795 # ifdef FEAT_MOUSE_PTERM
11796 "mouse_pterm",
11797 # endif
11798 # ifdef FEAT_MOUSE_SGR
11799 "mouse_sgr",
11800 # endif
11801 # ifdef FEAT_SYSMOUSE
11802 "mouse_sysmouse",
11803 # endif
11804 # ifdef FEAT_MOUSE_URXVT
11805 "mouse_urxvt",
11806 # endif
11807 # ifdef FEAT_MOUSE_XTERM
11808 "mouse_xterm",
11809 # endif
11810 #endif
11811 #ifdef FEAT_MBYTE
11812 "multi_byte",
11813 #endif
11814 #ifdef FEAT_MBYTE_IME
11815 "multi_byte_ime",
11816 #endif
11817 #ifdef FEAT_MULTI_LANG
11818 "multi_lang",
11819 #endif
11820 #ifdef FEAT_MZSCHEME
11821 #ifndef DYNAMIC_MZSCHEME
11822 "mzscheme",
11823 #endif
11824 #endif
11825 #ifdef FEAT_NUM64
11826 "num64",
11827 #endif
11828 #ifdef FEAT_OLE
11829 "ole",
11830 #endif
11831 "packages",
11832 #ifdef FEAT_PATH_EXTRA
11833 "path_extra",
11834 #endif
11835 #ifdef FEAT_PERL
11836 #ifndef DYNAMIC_PERL
11837 "perl",
11838 #endif
11839 #endif
11840 #ifdef FEAT_PERSISTENT_UNDO
11841 "persistent_undo",
11842 #endif
11843 #ifdef FEAT_PYTHON
11844 #ifndef DYNAMIC_PYTHON
11845 "python",
11846 #endif
11847 #endif
11848 #ifdef FEAT_PYTHON3
11849 #ifndef DYNAMIC_PYTHON3
11850 "python3",
11851 #endif
11852 #endif
11853 #ifdef FEAT_POSTSCRIPT
11854 "postscript",
11855 #endif
11856 #ifdef FEAT_PRINTER
11857 "printer",
11858 #endif
11859 #ifdef FEAT_PROFILE
11860 "profile",
11861 #endif
11862 #ifdef FEAT_RELTIME
11863 "reltime",
11864 #endif
11865 #ifdef FEAT_QUICKFIX
11866 "quickfix",
11867 #endif
11868 #ifdef FEAT_RIGHTLEFT
11869 "rightleft",
11870 #endif
11871 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
11872 "ruby",
11873 #endif
11874 #ifdef FEAT_SCROLLBIND
11875 "scrollbind",
11876 #endif
11877 #ifdef FEAT_CMDL_INFO
11878 "showcmd",
11879 "cmdline_info",
11880 #endif
11881 #ifdef FEAT_SIGNS
11882 "signs",
11883 #endif
11884 #ifdef FEAT_SMARTINDENT
11885 "smartindent",
11886 #endif
11887 #ifdef STARTUPTIME
11888 "startuptime",
11889 #endif
11890 #ifdef FEAT_STL_OPT
11891 "statusline",
11892 #endif
11893 #ifdef FEAT_SUN_WORKSHOP
11894 "sun_workshop",
11895 #endif
11896 #ifdef FEAT_NETBEANS_INTG
11897 "netbeans_intg",
11898 #endif
11899 #ifdef FEAT_SPELL
11900 "spell",
11901 #endif
11902 #ifdef FEAT_SYN_HL
11903 "syntax",
11904 #endif
11905 #if defined(USE_SYSTEM) || !defined(UNIX)
11906 "system",
11907 #endif
11908 #ifdef FEAT_TAG_BINS
11909 "tag_binary",
11910 #endif
11911 #ifdef FEAT_TAG_OLDSTATIC
11912 "tag_old_static",
11913 #endif
11914 #ifdef FEAT_TAG_ANYWHITE
11915 "tag_any_white",
11916 #endif
11917 #ifdef FEAT_TCL
11918 # ifndef DYNAMIC_TCL
11919 "tcl",
11920 # endif
11921 #endif
11922 #ifdef FEAT_TERMGUICOLORS
11923 "termguicolors",
11924 #endif
11925 #ifdef TERMINFO
11926 "terminfo",
11927 #endif
11928 #ifdef FEAT_TERMRESPONSE
11929 "termresponse",
11930 #endif
11931 #ifdef FEAT_TEXTOBJ
11932 "textobjects",
11933 #endif
11934 #ifdef HAVE_TGETENT
11935 "tgetent",
11936 #endif
11937 #ifdef FEAT_TIMERS
11938 "timers",
11939 #endif
11940 #ifdef FEAT_TITLE
11941 "title",
11942 #endif
11943 #ifdef FEAT_TOOLBAR
11944 "toolbar",
11945 #endif
11946 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
11947 "unnamedplus",
11948 #endif
11949 #ifdef FEAT_USR_CMDS
11950 "user-commands", /* was accidentally included in 5.4 */
11951 "user_commands",
11952 #endif
11953 #ifdef FEAT_VIMINFO
11954 "viminfo",
11955 #endif
11956 #ifdef FEAT_WINDOWS
11957 "vertsplit",
11958 #endif
11959 #ifdef FEAT_VIRTUALEDIT
11960 "virtualedit",
11961 #endif
11962 "visual",
11963 #ifdef FEAT_VISUALEXTRA
11964 "visualextra",
11965 #endif
11966 #ifdef FEAT_VREPLACE
11967 "vreplace",
11968 #endif
11969 #ifdef FEAT_WILDIGN
11970 "wildignore",
11971 #endif
11972 #ifdef FEAT_WILDMENU
11973 "wildmenu",
11974 #endif
11975 #ifdef FEAT_WINDOWS
11976 "windows",
11977 #endif
11978 #ifdef FEAT_WAK
11979 "winaltkeys",
11980 #endif
11981 #ifdef FEAT_WRITEBACKUP
11982 "writebackup",
11983 #endif
11984 #ifdef FEAT_XIM
11985 "xim",
11986 #endif
11987 #ifdef FEAT_XFONTSET
11988 "xfontset",
11989 #endif
11990 #ifdef FEAT_XPM_W32
11991 "xpm",
11992 "xpm_w32", /* for backward compatibility */
11993 #else
11994 # if defined(HAVE_XPM)
11995 "xpm",
11996 # endif
11997 #endif
11998 #ifdef USE_XSMP
11999 "xsmp",
12000 #endif
12001 #ifdef USE_XSMP_INTERACT
12002 "xsmp_interact",
12003 #endif
12004 #ifdef FEAT_XCLIPBOARD
12005 "xterm_clipboard",
12006 #endif
12007 #ifdef FEAT_XTERM_SAVE
12008 "xterm_save",
12009 #endif
12010 #if defined(UNIX) && defined(FEAT_X11)
12011 "X11",
12012 #endif
12013 NULL
12014 };
12015
12016 name = get_tv_string(&argvars[0]);
12017 for (i = 0; has_list[i] != NULL; ++i)
12018 if (STRICMP(name, has_list[i]) == 0)
12019 {
12020 n = TRUE;
12021 break;
12022 }
12023
12024 if (n == FALSE)
12025 {
12026 if (STRNICMP(name, "patch", 5) == 0)
12027 {
12028 if (name[5] == '-'
12029 && STRLEN(name) >= 11
12030 && vim_isdigit(name[6])
12031 && vim_isdigit(name[8])
12032 && vim_isdigit(name[10]))
12033 {
12034 int major = atoi((char *)name + 6);
12035 int minor = atoi((char *)name + 8);
12036
12037 /* Expect "patch-9.9.01234". */
12038 n = (major < VIM_VERSION_MAJOR
12039 || (major == VIM_VERSION_MAJOR
12040 && (minor < VIM_VERSION_MINOR
12041 || (minor == VIM_VERSION_MINOR
12042 && has_patch(atoi((char *)name + 10))))));
12043 }
12044 else
12045 n = has_patch(atoi((char *)name + 5));
12046 }
12047 else if (STRICMP(name, "vim_starting") == 0)
12048 n = (starting != 0);
12049 #ifdef FEAT_MBYTE
12050 else if (STRICMP(name, "multi_byte_encoding") == 0)
12051 n = has_mbyte;
12052 #endif
12053 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
12054 else if (STRICMP(name, "balloon_multiline") == 0)
12055 n = multiline_balloon_available();
12056 #endif
12057 #ifdef DYNAMIC_TCL
12058 else if (STRICMP(name, "tcl") == 0)
12059 n = tcl_enabled(FALSE);
12060 #endif
12061 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
12062 else if (STRICMP(name, "iconv") == 0)
12063 n = iconv_enabled(FALSE);
12064 #endif
12065 #ifdef DYNAMIC_LUA
12066 else if (STRICMP(name, "lua") == 0)
12067 n = lua_enabled(FALSE);
12068 #endif
12069 #ifdef DYNAMIC_MZSCHEME
12070 else if (STRICMP(name, "mzscheme") == 0)
12071 n = mzscheme_enabled(FALSE);
12072 #endif
12073 #ifdef DYNAMIC_RUBY
12074 else if (STRICMP(name, "ruby") == 0)
12075 n = ruby_enabled(FALSE);
12076 #endif
12077 #ifdef FEAT_PYTHON
12078 #ifdef DYNAMIC_PYTHON
12079 else if (STRICMP(name, "python") == 0)
12080 n = python_enabled(FALSE);
12081 #endif
12082 #endif
12083 #ifdef FEAT_PYTHON3
12084 #ifdef DYNAMIC_PYTHON3
12085 else if (STRICMP(name, "python3") == 0)
12086 n = python3_enabled(FALSE);
12087 #endif
12088 #endif
12089 #ifdef DYNAMIC_PERL
12090 else if (STRICMP(name, "perl") == 0)
12091 n = perl_enabled(FALSE);
12092 #endif
12093 #ifdef FEAT_GUI
12094 else if (STRICMP(name, "gui_running") == 0)
12095 n = (gui.in_use || gui.starting);
12096 # ifdef FEAT_GUI_W32
12097 else if (STRICMP(name, "gui_win32s") == 0)
12098 n = gui_is_win32s();
12099 # endif
12100 # ifdef FEAT_BROWSE
12101 else if (STRICMP(name, "browse") == 0)
12102 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
12103 # endif
12104 #endif
12105 #ifdef FEAT_SYN_HL
12106 else if (STRICMP(name, "syntax_items") == 0)
12107 n = syntax_present(curwin);
12108 #endif
12109 #if defined(WIN3264)
12110 else if (STRICMP(name, "win95") == 0)
12111 n = mch_windows95();
12112 #endif
12113 #ifdef FEAT_NETBEANS_INTG
12114 else if (STRICMP(name, "netbeans_enabled") == 0)
12115 n = netbeans_active();
12116 #endif
12117 }
12118
12119 rettv->vval.v_number = n;
12120 }
12121
12122 /*
12123 * "has_key()" function
12124 */
12125 static void
12126 f_has_key(typval_T *argvars, typval_T *rettv)
12127 {
12128 if (argvars[0].v_type != VAR_DICT)
12129 {
12130 EMSG(_(e_dictreq));
12131 return;
12132 }
12133 if (argvars[0].vval.v_dict == NULL)
12134 return;
12135
12136 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
12137 get_tv_string(&argvars[1]), -1) != NULL;
12138 }
12139
12140 /*
12141 * "haslocaldir()" function
12142 */
12143 static void
12144 f_haslocaldir(typval_T *argvars, typval_T *rettv)
12145 {
12146 win_T *wp = NULL;
12147
12148 wp = find_tabwin(&argvars[0], &argvars[1]);
12149 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
12150 }
12151
12152 /*
12153 * "hasmapto()" function
12154 */
12155 static void
12156 f_hasmapto(typval_T *argvars, typval_T *rettv)
12157 {
12158 char_u *name;
12159 char_u *mode;
12160 char_u buf[NUMBUFLEN];
12161 int abbr = FALSE;
12162
12163 name = get_tv_string(&argvars[0]);
12164 if (argvars[1].v_type == VAR_UNKNOWN)
12165 mode = (char_u *)"nvo";
12166 else
12167 {
12168 mode = get_tv_string_buf(&argvars[1], buf);
12169 if (argvars[2].v_type != VAR_UNKNOWN)
12170 abbr = (int)get_tv_number(&argvars[2]);
12171 }
12172
12173 if (map_to_exists(name, mode, abbr))
12174 rettv->vval.v_number = TRUE;
12175 else
12176 rettv->vval.v_number = FALSE;
12177 }
12178
12179 /*
12180 * "histadd()" function
12181 */
12182 static void
12183 f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
12184 {
12185 #ifdef FEAT_CMDHIST
12186 int histype;
12187 char_u *str;
12188 char_u buf[NUMBUFLEN];
12189 #endif
12190
12191 rettv->vval.v_number = FALSE;
12192 if (check_restricted() || check_secure())
12193 return;
12194 #ifdef FEAT_CMDHIST
12195 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
12196 histype = str != NULL ? get_histtype(str) : -1;
12197 if (histype >= 0)
12198 {
12199 str = get_tv_string_buf(&argvars[1], buf);
12200 if (*str != NUL)
12201 {
12202 init_history();
12203 add_to_history(histype, str, FALSE, NUL);
12204 rettv->vval.v_number = TRUE;
12205 return;
12206 }
12207 }
12208 #endif
12209 }
12210
12211 /*
12212 * "histdel()" function
12213 */
12214 static void
12215 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12216 {
12217 #ifdef FEAT_CMDHIST
12218 int n;
12219 char_u buf[NUMBUFLEN];
12220 char_u *str;
12221
12222 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
12223 if (str == NULL)
12224 n = 0;
12225 else if (argvars[1].v_type == VAR_UNKNOWN)
12226 /* only one argument: clear entire history */
12227 n = clr_history(get_histtype(str));
12228 else if (argvars[1].v_type == VAR_NUMBER)
12229 /* index given: remove that entry */
12230 n = del_history_idx(get_histtype(str),
12231 (int)get_tv_number(&argvars[1]));
12232 else
12233 /* string given: remove all matching entries */
12234 n = del_history_entry(get_histtype(str),
12235 get_tv_string_buf(&argvars[1], buf));
12236 rettv->vval.v_number = n;
12237 #endif
12238 }
12239
12240 /*
12241 * "histget()" function
12242 */
12243 static void
12244 f_histget(typval_T *argvars UNUSED, typval_T *rettv)
12245 {
12246 #ifdef FEAT_CMDHIST
12247 int type;
12248 int idx;
12249 char_u *str;
12250
12251 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
12252 if (str == NULL)
12253 rettv->vval.v_string = NULL;
12254 else
12255 {
12256 type = get_histtype(str);
12257 if (argvars[1].v_type == VAR_UNKNOWN)
12258 idx = get_history_idx(type);
12259 else
12260 idx = (int)get_tv_number_chk(&argvars[1], NULL);
12261 /* -1 on type error */
12262 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
12263 }
12264 #else
12265 rettv->vval.v_string = NULL;
12266 #endif
12267 rettv->v_type = VAR_STRING;
12268 }
12269
12270 /*
12271 * "histnr()" function
12272 */
12273 static void
12274 f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
12275 {
12276 int i;
12277
12278 #ifdef FEAT_CMDHIST
12279 char_u *history = get_tv_string_chk(&argvars[0]);
12280
12281 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
12282 if (i >= HIST_CMD && i < HIST_COUNT)
12283 i = get_history_idx(i);
12284 else
12285 #endif
12286 i = -1;
12287 rettv->vval.v_number = i;
12288 }
12289
12290 /*
12291 * "highlightID(name)" function
12292 */
12293 static void
12294 f_hlID(typval_T *argvars, typval_T *rettv)
12295 {
12296 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
12297 }
12298
12299 /*
12300 * "highlight_exists()" function
12301 */
12302 static void
12303 f_hlexists(typval_T *argvars, typval_T *rettv)
12304 {
12305 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
12306 }
12307
12308 /*
12309 * "hostname()" function
12310 */
12311 static void
12312 f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
12313 {
12314 char_u hostname[256];
12315
12316 mch_get_host_name(hostname, 256);
12317 rettv->v_type = VAR_STRING;
12318 rettv->vval.v_string = vim_strsave(hostname);
12319 }
12320
12321 /*
12322 * iconv() function
12323 */
12324 static void
12325 f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
12326 {
12327 #ifdef FEAT_MBYTE
12328 char_u buf1[NUMBUFLEN];
12329 char_u buf2[NUMBUFLEN];
12330 char_u *from, *to, *str;
12331 vimconv_T vimconv;
12332 #endif
12333
12334 rettv->v_type = VAR_STRING;
12335 rettv->vval.v_string = NULL;
12336
12337 #ifdef FEAT_MBYTE
12338 str = get_tv_string(&argvars[0]);
12339 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
12340 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
12341 vimconv.vc_type = CONV_NONE;
12342 convert_setup(&vimconv, from, to);
12343
12344 /* If the encodings are equal, no conversion needed. */
12345 if (vimconv.vc_type == CONV_NONE)
12346 rettv->vval.v_string = vim_strsave(str);
12347 else
12348 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
12349
12350 convert_setup(&vimconv, NULL, NULL);
12351 vim_free(from);
12352 vim_free(to);
12353 #endif
12354 }
12355
12356 /*
12357 * "indent()" function
12358 */
12359 static void
12360 f_indent(typval_T *argvars, typval_T *rettv)
12361 {
12362 linenr_T lnum;
12363
12364 lnum = get_tv_lnum(argvars);
12365 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
12366 rettv->vval.v_number = get_indent_lnum(lnum);
12367 else
12368 rettv->vval.v_number = -1;
12369 }
12370
12371 /*
12372 * "index()" function
12373 */
12374 static void
12375 f_index(typval_T *argvars, typval_T *rettv)
12376 {
12377 list_T *l;
12378 listitem_T *item;
12379 long idx = 0;
12380 int ic = FALSE;
12381
12382 rettv->vval.v_number = -1;
12383 if (argvars[0].v_type != VAR_LIST)
12384 {
12385 EMSG(_(e_listreq));
12386 return;
12387 }
12388 l = argvars[0].vval.v_list;
12389 if (l != NULL)
12390 {
12391 item = l->lv_first;
12392 if (argvars[2].v_type != VAR_UNKNOWN)
12393 {
12394 int error = FALSE;
12395
12396 /* Start at specified item. Use the cached index that list_find()
12397 * sets, so that a negative number also works. */
12398 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
12399 idx = l->lv_idx;
12400 if (argvars[3].v_type != VAR_UNKNOWN)
12401 ic = (int)get_tv_number_chk(&argvars[3], &error);
12402 if (error)
12403 item = NULL;
12404 }
12405
12406 for ( ; item != NULL; item = item->li_next, ++idx)
12407 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
12408 {
12409 rettv->vval.v_number = idx;
12410 break;
12411 }
12412 }
12413 }
12414
12415 static int inputsecret_flag = 0;
12416
12417 static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog);
12418
12419 /*
12420 * This function is used by f_input() and f_inputdialog() functions. The third
12421 * argument to f_input() specifies the type of completion to use at the
12422 * prompt. The third argument to f_inputdialog() specifies the value to return
12423 * when the user cancels the prompt.
12424 */
12425 static void
12426 get_user_input(
12427 typval_T *argvars,
12428 typval_T *rettv,
12429 int inputdialog)
12430 {
12431 char_u *prompt = get_tv_string_chk(&argvars[0]);
12432 char_u *p = NULL;
12433 int c;
12434 char_u buf[NUMBUFLEN];
12435 int cmd_silent_save = cmd_silent;
12436 char_u *defstr = (char_u *)"";
12437 int xp_type = EXPAND_NOTHING;
12438 char_u *xp_arg = NULL;
12439
12440 rettv->v_type = VAR_STRING;
12441 rettv->vval.v_string = NULL;
12442
12443 #ifdef NO_CONSOLE_INPUT
12444 /* While starting up, there is no place to enter text. */
12445 if (no_console_input())
12446 return;
12447 #endif
12448
12449 cmd_silent = FALSE; /* Want to see the prompt. */
12450 if (prompt != NULL)
12451 {
12452 /* Only the part of the message after the last NL is considered as
12453 * prompt for the command line */
12454 p = vim_strrchr(prompt, '\n');
12455 if (p == NULL)
12456 p = prompt;
12457 else
12458 {
12459 ++p;
12460 c = *p;
12461 *p = NUL;
12462 msg_start();
12463 msg_clr_eos();
12464 msg_puts_attr(prompt, echo_attr);
12465 msg_didout = FALSE;
12466 msg_starthere();
12467 *p = c;
12468 }
12469 cmdline_row = msg_row;
12470
12471 if (argvars[1].v_type != VAR_UNKNOWN)
12472 {
12473 defstr = get_tv_string_buf_chk(&argvars[1], buf);
12474 if (defstr != NULL)
12475 stuffReadbuffSpec(defstr);
12476
12477 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
12478 {
12479 char_u *xp_name;
12480 int xp_namelen;
12481 long argt;
12482
12483 /* input() with a third argument: completion */
12484 rettv->vval.v_string = NULL;
12485
12486 xp_name = get_tv_string_buf_chk(&argvars[2], buf);
12487 if (xp_name == NULL)
12488 return;
12489
12490 xp_namelen = (int)STRLEN(xp_name);
12491
12492 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
12493 &xp_arg) == FAIL)
12494 return;
12495 }
12496 }
12497
12498 if (defstr != NULL)
12499 {
12500 int save_ex_normal_busy = ex_normal_busy;
12501 ex_normal_busy = 0;
12502 rettv->vval.v_string =
12503 getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr,
12504 xp_type, xp_arg);
12505 ex_normal_busy = save_ex_normal_busy;
12506 }
12507 if (inputdialog && rettv->vval.v_string == NULL
12508 && argvars[1].v_type != VAR_UNKNOWN
12509 && argvars[2].v_type != VAR_UNKNOWN)
12510 rettv->vval.v_string = vim_strsave(get_tv_string_buf(
12511 &argvars[2], buf));
12512
12513 vim_free(xp_arg);
12514
12515 /* since the user typed this, no need to wait for return */
12516 need_wait_return = FALSE;
12517 msg_didout = FALSE;
12518 }
12519 cmd_silent = cmd_silent_save;
12520 }
12521
12522 /*
12523 * "input()" function
12524 * Also handles inputsecret() when inputsecret is set.
12525 */
12526 static void
12527 f_input(typval_T *argvars, typval_T *rettv)
12528 {
12529 get_user_input(argvars, rettv, FALSE);
12530 }
12531
12532 /*
12533 * "inputdialog()" function
12534 */
12535 static void
12536 f_inputdialog(typval_T *argvars, typval_T *rettv)
12537 {
12538 #if defined(FEAT_GUI_TEXTDIALOG)
12539 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
12540 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
12541 {
12542 char_u *message;
12543 char_u buf[NUMBUFLEN];
12544 char_u *defstr = (char_u *)"";
12545
12546 message = get_tv_string_chk(&argvars[0]);
12547 if (argvars[1].v_type != VAR_UNKNOWN
12548 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
12549 vim_strncpy(IObuff, defstr, IOSIZE - 1);
12550 else
12551 IObuff[0] = NUL;
12552 if (message != NULL && defstr != NULL
12553 && do_dialog(VIM_QUESTION, NULL, message,
12554 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
12555 rettv->vval.v_string = vim_strsave(IObuff);
12556 else
12557 {
12558 if (message != NULL && defstr != NULL
12559 && argvars[1].v_type != VAR_UNKNOWN
12560 && argvars[2].v_type != VAR_UNKNOWN)
12561 rettv->vval.v_string = vim_strsave(
12562 get_tv_string_buf(&argvars[2], buf));
12563 else
12564 rettv->vval.v_string = NULL;
12565 }
12566 rettv->v_type = VAR_STRING;
12567 }
12568 else
12569 #endif
12570 get_user_input(argvars, rettv, TRUE);
12571 }
12572
12573 /*
12574 * "inputlist()" function
12575 */
12576 static void
12577 f_inputlist(typval_T *argvars, typval_T *rettv)
12578 {
12579 listitem_T *li;
12580 int selected;
12581 int mouse_used;
12582
12583 #ifdef NO_CONSOLE_INPUT
12584 /* While starting up, there is no place to enter text. */
12585 if (no_console_input())
12586 return;
12587 #endif
12588 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
12589 {
12590 EMSG2(_(e_listarg), "inputlist()");
12591 return;
12592 }
12593
12594 msg_start();
12595 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
12596 lines_left = Rows; /* avoid more prompt */
12597 msg_scroll = TRUE;
12598 msg_clr_eos();
12599
12600 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
12601 {
12602 msg_puts(get_tv_string(&li->li_tv));
12603 msg_putchar('\n');
12604 }
12605
12606 /* Ask for choice. */
12607 selected = prompt_for_number(&mouse_used);
12608 if (mouse_used)
12609 selected -= lines_left;
12610
12611 rettv->vval.v_number = selected;
12612 }
12613
12614
12615 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
12616
12617 /*
12618 * "inputrestore()" function
12619 */
12620 static void
12621 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
12622 {
12623 if (ga_userinput.ga_len > 0)
12624 {
12625 --ga_userinput.ga_len;
12626 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
12627 + ga_userinput.ga_len);
12628 /* default return is zero == OK */
12629 }
12630 else if (p_verbose > 1)
12631 {
12632 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
12633 rettv->vval.v_number = 1; /* Failed */
12634 }
12635 }
12636
12637 /*
12638 * "inputsave()" function
12639 */
12640 static void
12641 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
12642 {
12643 /* Add an entry to the stack of typeahead storage. */
12644 if (ga_grow(&ga_userinput, 1) == OK)
12645 {
12646 save_typeahead((tasave_T *)(ga_userinput.ga_data)
12647 + ga_userinput.ga_len);
12648 ++ga_userinput.ga_len;
12649 /* default return is zero == OK */
12650 }
12651 else
12652 rettv->vval.v_number = 1; /* Failed */
12653 }
12654
12655 /*
12656 * "inputsecret()" function
12657 */
12658 static void
12659 f_inputsecret(typval_T *argvars, typval_T *rettv)
12660 {
12661 ++cmdline_star;
12662 ++inputsecret_flag;
12663 f_input(argvars, rettv);
12664 --cmdline_star;
12665 --inputsecret_flag;
12666 }
12667
12668 /*
12669 * "insert()" function
12670 */
12671 static void
12672 f_insert(typval_T *argvars, typval_T *rettv)
12673 {
12674 long before = 0;
12675 listitem_T *item;
12676 list_T *l;
12677 int error = FALSE;
12678
12679 if (argvars[0].v_type != VAR_LIST)
12680 EMSG2(_(e_listarg), "insert()");
12681 else if ((l = argvars[0].vval.v_list) != NULL
12682 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
12683 {
12684 if (argvars[2].v_type != VAR_UNKNOWN)
12685 before = (long)get_tv_number_chk(&argvars[2], &error);
12686 if (error)
12687 return; /* type error; errmsg already given */
12688
12689 if (before == l->lv_len)
12690 item = NULL;
12691 else
12692 {
12693 item = list_find(l, before);
12694 if (item == NULL)
12695 {
12696 EMSGN(_(e_listidx), before);
12697 l = NULL;
12698 }
12699 }
12700 if (l != NULL)
12701 {
12702 list_insert_tv(l, &argvars[1], item);
12703 copy_tv(&argvars[0], rettv);
12704 }
12705 }
12706 }
12707
12708 /*
12709 * "invert(expr)" function
12710 */
12711 static void
12712 f_invert(typval_T *argvars, typval_T *rettv)
12713 {
12714 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
12715 }
12716
12717 /*
12718 * "isdirectory()" function
12719 */
12720 static void
12721 f_isdirectory(typval_T *argvars, typval_T *rettv)
12722 {
12723 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
12724 }
12725
12726 /*
12727 * "islocked()" function
12728 */
12729 static void
12730 f_islocked(typval_T *argvars, typval_T *rettv)
12731 {
12732 lval_T lv;
12733 char_u *end;
12734 dictitem_T *di;
12735
12736 rettv->vval.v_number = -1;
12737 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
12738 GLV_NO_AUTOLOAD, FNE_CHECK_START);
12739 if (end != NULL && lv.ll_name != NULL)
12740 {
12741 if (*end != NUL)
12742 EMSG(_(e_trailing));
12743 else
12744 {
12745 if (lv.ll_tv == NULL)
12746 {
12747 if (check_changedtick(lv.ll_name))
12748 rettv->vval.v_number = 1; /* always locked */
12749 else
12750 {
12751 di = find_var(lv.ll_name, NULL, TRUE);
12752 if (di != NULL)
12753 {
12754 /* Consider a variable locked when:
12755 * 1. the variable itself is locked
12756 * 2. the value of the variable is locked.
12757 * 3. the List or Dict value is locked.
12758 */
12759 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
12760 || tv_islocked(&di->di_tv));
12761 }
12762 }
12763 }
12764 else if (lv.ll_range)
12765 EMSG(_("E786: Range not allowed"));
12766 else if (lv.ll_newkey != NULL)
12767 EMSG2(_(e_dictkey), lv.ll_newkey);
12768 else if (lv.ll_list != NULL)
12769 /* List item. */
12770 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
12771 else
12772 /* Dictionary item. */
12773 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
12774 }
12775 }
12776
12777 clear_lval(&lv);
12778 }
12779
12780 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
12781 /*
12782 * "isnan()" function
12783 */
12784 static void
12785 f_isnan(typval_T *argvars, typval_T *rettv)
12786 {
12787 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
12788 && isnan(argvars[0].vval.v_float);
12789 }
12790 #endif
12791
12792 /*
12793 * "items(dict)" function
12794 */
12795 static void
12796 f_items(typval_T *argvars, typval_T *rettv)
12797 {
12798 dict_list(argvars, rettv, 2);
12799 }
12800
12801 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
12802 /*
12803 * Get the job from the argument.
12804 * Returns NULL if the job is invalid.
12805 */
12806 static job_T *
12807 get_job_arg(typval_T *tv)
12808 {
12809 job_T *job;
12810
12811 if (tv->v_type != VAR_JOB)
12812 {
12813 EMSG2(_(e_invarg2), get_tv_string(tv));
12814 return NULL;
12815 }
12816 job = tv->vval.v_job;
12817
12818 if (job == NULL)
12819 EMSG(_("E916: not a valid job"));
12820 return job;
12821 }
12822
12823 /*
12824 * "job_getchannel()" function
12825 */
12826 static void
12827 f_job_getchannel(typval_T *argvars, typval_T *rettv)
12828 {
12829 job_T *job = get_job_arg(&argvars[0]);
12830
12831 if (job != NULL)
12832 {
12833 rettv->v_type = VAR_CHANNEL;
12834 rettv->vval.v_channel = job->jv_channel;
12835 if (job->jv_channel != NULL)
12836 ++job->jv_channel->ch_refcount;
12837 }
12838 }
12839
12840 /*
12841 * "job_info()" function
12842 */
12843 static void
12844 f_job_info(typval_T *argvars, typval_T *rettv)
12845 {
12846 job_T *job = get_job_arg(&argvars[0]);
12847
12848 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
12849 job_info(job, rettv->vval.v_dict);
12850 }
12851
12852 /*
12853 * "job_setoptions()" function
12854 */
12855 static void
12856 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
12857 {
12858 job_T *job = get_job_arg(&argvars[0]);
12859 jobopt_T opt;
12860
12861 if (job == NULL)
12862 return;
12863 clear_job_options(&opt);
12864 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
12865 job_set_options(job, &opt);
12866 free_job_options(&opt);
12867 }
12868
12869 /*
12870 * "job_start()" function
12871 */
12872 static void
12873 f_job_start(typval_T *argvars, typval_T *rettv)
12874 {
12875 rettv->v_type = VAR_JOB;
12876 if (check_restricted() || check_secure())
12877 return;
12878 rettv->vval.v_job = job_start(argvars);
12879 }
12880
12881 /*
12882 * "job_status()" function
12883 */
12884 static void
12885 f_job_status(typval_T *argvars, typval_T *rettv)
12886 {
12887 job_T *job = get_job_arg(&argvars[0]);
12888
12889 if (job != NULL)
12890 {
12891 rettv->v_type = VAR_STRING;
12892 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
12893 }
12894 }
12895
12896 /*
12897 * "job_stop()" function
12898 */
12899 static void
12900 f_job_stop(typval_T *argvars, typval_T *rettv)
12901 {
12902 job_T *job = get_job_arg(&argvars[0]);
12903
12904 if (job != NULL)
12905 rettv->vval.v_number = job_stop(job, argvars);
12906 }
12907 #endif
12908
12909 /*
12910 * "join()" function
12911 */
12912 static void
12913 f_join(typval_T *argvars, typval_T *rettv)
12914 {
12915 garray_T ga;
12916 char_u *sep;
12917
12918 if (argvars[0].v_type != VAR_LIST)
12919 {
12920 EMSG(_(e_listreq));
12921 return;
12922 }
12923 if (argvars[0].vval.v_list == NULL)
12924 return;
12925 if (argvars[1].v_type == VAR_UNKNOWN)
12926 sep = (char_u *)" ";
12927 else
12928 sep = get_tv_string_chk(&argvars[1]);
12929
12930 rettv->v_type = VAR_STRING;
12931
12932 if (sep != NULL)
12933 {
12934 ga_init2(&ga, (int)sizeof(char), 80);
12935 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
12936 ga_append(&ga, NUL);
12937 rettv->vval.v_string = (char_u *)ga.ga_data;
12938 }
12939 else
12940 rettv->vval.v_string = NULL;
12941 }
12942
12943 /*
12944 * "js_decode()" function
12945 */
12946 static void
12947 f_js_decode(typval_T *argvars, typval_T *rettv)
12948 {
12949 js_read_T reader;
12950
12951 reader.js_buf = get_tv_string(&argvars[0]);
12952 reader.js_fill = NULL;
12953 reader.js_used = 0;
12954 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
12955 EMSG(_(e_invarg));
12956 }
12957
12958 /*
12959 * "js_encode()" function
12960 */
12961 static void
12962 f_js_encode(typval_T *argvars, typval_T *rettv)
12963 {
12964 rettv->v_type = VAR_STRING;
12965 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
12966 }
12967
12968 /*
12969 * "json_decode()" function
12970 */
12971 static void
12972 f_json_decode(typval_T *argvars, typval_T *rettv)
12973 {
12974 js_read_T reader;
12975
12976 reader.js_buf = get_tv_string(&argvars[0]);
12977 reader.js_fill = NULL;
12978 reader.js_used = 0;
12979 if (json_decode_all(&reader, rettv, 0) != OK)
12980 EMSG(_(e_invarg));
12981 }
12982
12983 /*
12984 * "json_encode()" function
12985 */
12986 static void
12987 f_json_encode(typval_T *argvars, typval_T *rettv)
12988 {
12989 rettv->v_type = VAR_STRING;
12990 rettv->vval.v_string = json_encode(&argvars[0], 0);
12991 }
12992
12993 /*
12994 * "keys()" function
12995 */
12996 static void
12997 f_keys(typval_T *argvars, typval_T *rettv)
12998 {
12999 dict_list(argvars, rettv, 0);
13000 }
13001
13002 /*
13003 * "last_buffer_nr()" function.
13004 */
13005 static void
13006 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
13007 {
13008 int n = 0;
13009 buf_T *buf;
13010
13011 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
13012 if (n < buf->b_fnum)
13013 n = buf->b_fnum;
13014
13015 rettv->vval.v_number = n;
13016 }
13017
13018 /*
13019 * "len()" function
13020 */
13021 static void
13022 f_len(typval_T *argvars, typval_T *rettv)
13023 {
13024 switch (argvars[0].v_type)
13025 {
13026 case VAR_STRING:
13027 case VAR_NUMBER:
13028 rettv->vval.v_number = (varnumber_T)STRLEN(
13029 get_tv_string(&argvars[0]));
13030 break;
13031 case VAR_LIST:
13032 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
13033 break;
13034 case VAR_DICT:
13035 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
13036 break;
13037 case VAR_UNKNOWN:
13038 case VAR_SPECIAL:
13039 case VAR_FLOAT:
13040 case VAR_FUNC:
13041 case VAR_PARTIAL:
13042 case VAR_JOB:
13043 case VAR_CHANNEL:
13044 EMSG(_("E701: Invalid type for len()"));
13045 break;
13046 }
13047 }
13048
13049 static void libcall_common(typval_T *argvars, typval_T *rettv, int type);
13050
13051 static void
13052 libcall_common(typval_T *argvars, typval_T *rettv, int type)
13053 {
13054 #ifdef FEAT_LIBCALL
13055 char_u *string_in;
13056 char_u **string_result;
13057 int nr_result;
13058 #endif
13059
13060 rettv->v_type = type;
13061 if (type != VAR_NUMBER)
13062 rettv->vval.v_string = NULL;
13063
13064 if (check_restricted() || check_secure())
13065 return;
13066
13067 #ifdef FEAT_LIBCALL
13068 /* The first two args must be strings, otherwise its meaningless */
13069 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
13070 {
13071 string_in = NULL;
13072 if (argvars[2].v_type == VAR_STRING)
13073 string_in = argvars[2].vval.v_string;
13074 if (type == VAR_NUMBER)
13075 string_result = NULL;
13076 else
13077 string_result = &rettv->vval.v_string;
13078 if (mch_libcall(argvars[0].vval.v_string,
13079 argvars[1].vval.v_string,
13080 string_in,
13081 argvars[2].vval.v_number,
13082 string_result,
13083 &nr_result) == OK
13084 && type == VAR_NUMBER)
13085 rettv->vval.v_number = nr_result;
13086 }
13087 #endif
13088 }
13089
13090 /*
13091 * "libcall()" function
13092 */
13093 static void
13094 f_libcall(typval_T *argvars, typval_T *rettv)
13095 {
13096 libcall_common(argvars, rettv, VAR_STRING);
13097 }
13098
13099 /*
13100 * "libcallnr()" function
13101 */
13102 static void
13103 f_libcallnr(typval_T *argvars, typval_T *rettv)
13104 {
13105 libcall_common(argvars, rettv, VAR_NUMBER);
13106 }
13107
13108 /*
13109 * "line(string)" function
13110 */
13111 static void
13112 f_line(typval_T *argvars, typval_T *rettv)
13113 {
13114 linenr_T lnum = 0;
13115 pos_T *fp;
13116 int fnum;
13117
13118 fp = var2fpos(&argvars[0], TRUE, &fnum);
13119 if (fp != NULL)
13120 lnum = fp->lnum;
13121 rettv->vval.v_number = lnum;
13122 }
13123
13124 /*
13125 * "line2byte(lnum)" function
13126 */
13127 static void
13128 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
13129 {
13130 #ifndef FEAT_BYTEOFF
13131 rettv->vval.v_number = -1;
13132 #else
13133 linenr_T lnum;
13134
13135 lnum = get_tv_lnum(argvars);
13136 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
13137 rettv->vval.v_number = -1;
13138 else
13139 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
13140 if (rettv->vval.v_number >= 0)
13141 ++rettv->vval.v_number;
13142 #endif
13143 }
13144
13145 /*
13146 * "lispindent(lnum)" function
13147 */
13148 static void
13149 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
13150 {
13151 #ifdef FEAT_LISP
13152 pos_T pos;
13153 linenr_T lnum;
13154
13155 pos = curwin->w_cursor;
13156 lnum = get_tv_lnum(argvars);
13157 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
13158 {
13159 curwin->w_cursor.lnum = lnum;
13160 rettv->vval.v_number = get_lisp_indent();
13161 curwin->w_cursor = pos;
13162 }
13163 else
13164 #endif
13165 rettv->vval.v_number = -1;
13166 }
13167
13168 /*
13169 * "localtime()" function
13170 */
13171 static void
13172 f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
13173 {
13174 rettv->vval.v_number = (varnumber_T)time(NULL);
13175 }
13176
13177 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
13178
13179 static void
13180 get_maparg(typval_T *argvars, typval_T *rettv, int exact)
13181 {
13182 char_u *keys;
13183 char_u *which;
13184 char_u buf[NUMBUFLEN];
13185 char_u *keys_buf = NULL;
13186 char_u *rhs;
13187 int mode;
13188 int abbr = FALSE;
13189 int get_dict = FALSE;
13190 mapblock_T *mp;
13191 int buffer_local;
13192
13193 /* return empty string for failure */
13194 rettv->v_type = VAR_STRING;
13195 rettv->vval.v_string = NULL;
13196
13197 keys = get_tv_string(&argvars[0]);
13198 if (*keys == NUL)
13199 return;
13200
13201 if (argvars[1].v_type != VAR_UNKNOWN)
13202 {
13203 which = get_tv_string_buf_chk(&argvars[1], buf);
13204 if (argvars[2].v_type != VAR_UNKNOWN)
13205 {
13206 abbr = (int)get_tv_number(&argvars[2]);
13207 if (argvars[3].v_type != VAR_UNKNOWN)
13208 get_dict = (int)get_tv_number(&argvars[3]);
13209 }
13210 }
13211 else
13212 which = (char_u *)"";
13213 if (which == NULL)
13214 return;
13215
13216 mode = get_map_mode(&which, 0);
13217
13218 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
13219 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
13220 vim_free(keys_buf);
13221
13222 if (!get_dict)
13223 {
13224 /* Return a string. */
13225 if (rhs != NULL)
13226 rettv->vval.v_string = str2special_save(rhs, FALSE);
13227
13228 }
13229 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
13230 {
13231 /* Return a dictionary. */
13232 char_u *lhs = str2special_save(mp->m_keys, TRUE);
13233 char_u *mapmode = map_mode_to_chars(mp->m_mode);
13234 dict_T *dict = rettv->vval.v_dict;
13235
13236 dict_add_nr_str(dict, "lhs", 0L, lhs);
13237 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
13238 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
13239 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
13240 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
13241 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
13242 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
13243 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
13244 dict_add_nr_str(dict, "mode", 0L, mapmode);
13245
13246 vim_free(lhs);
13247 vim_free(mapmode);
13248 }
13249 }
13250
13251 #ifdef FEAT_FLOAT
13252 /*
13253 * "log()" function
13254 */
13255 static void
13256 f_log(typval_T *argvars, typval_T *rettv)
13257 {
13258 float_T f = 0.0;
13259
13260 rettv->v_type = VAR_FLOAT;
13261 if (get_float_arg(argvars, &f) == OK)
13262 rettv->vval.v_float = log(f);
13263 else
13264 rettv->vval.v_float = 0.0;
13265 }
13266
13267 /*
13268 * "log10()" function
13269 */
13270 static void
13271 f_log10(typval_T *argvars, typval_T *rettv)
13272 {
13273 float_T f = 0.0;
13274
13275 rettv->v_type = VAR_FLOAT;
13276 if (get_float_arg(argvars, &f) == OK)
13277 rettv->vval.v_float = log10(f);
13278 else
13279 rettv->vval.v_float = 0.0;
13280 }
13281 #endif
13282
13283 #ifdef FEAT_LUA
13284 /*
13285 * "luaeval()" function
13286 */
13287 static void
13288 f_luaeval(typval_T *argvars, typval_T *rettv)
13289 {
13290 char_u *str;
13291 char_u buf[NUMBUFLEN];
13292
13293 str = get_tv_string_buf(&argvars[0], buf);
13294 do_luaeval(str, argvars + 1, rettv);
13295 }
13296 #endif
13297
13298 /*
13299 * "map()" function
13300 */
13301 static void
13302 f_map(typval_T *argvars, typval_T *rettv)
13303 {
13304 filter_map(argvars, rettv, TRUE);
13305 }
13306
13307 /*
13308 * "maparg()" function
13309 */
13310 static void
13311 f_maparg(typval_T *argvars, typval_T *rettv)
13312 {
13313 get_maparg(argvars, rettv, TRUE);
13314 }
13315
13316 /*
13317 * "mapcheck()" function
13318 */
13319 static void
13320 f_mapcheck(typval_T *argvars, typval_T *rettv)
13321 {
13322 get_maparg(argvars, rettv, FALSE);
13323 }
13324
13325 static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
13326
13327 static void
13328 find_some_match(typval_T *argvars, typval_T *rettv, int type)
13329 {
13330 char_u *str = NULL;
13331 long len = 0;
13332 char_u *expr = NULL;
13333 char_u *pat;
13334 regmatch_T regmatch;
13335 char_u patbuf[NUMBUFLEN];
13336 char_u strbuf[NUMBUFLEN];
13337 char_u *save_cpo;
13338 long start = 0;
13339 long nth = 1;
13340 colnr_T startcol = 0;
13341 int match = 0;
13342 list_T *l = NULL;
13343 listitem_T *li = NULL;
13344 long idx = 0;
13345 char_u *tofree = NULL;
13346
13347 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
13348 save_cpo = p_cpo;
13349 p_cpo = (char_u *)"";
13350
13351 rettv->vval.v_number = -1;
13352 if (type == 3 || type == 4)
13353 {
13354 /* type 3: return empty list when there are no matches.
13355 * type 4: return ["", -1, -1, -1] */
13356 if (rettv_list_alloc(rettv) == FAIL)
13357 goto theend;
13358 if (type == 4
13359 && (list_append_string(rettv->vval.v_list,
13360 (char_u *)"", 0) == FAIL
13361 || list_append_number(rettv->vval.v_list,
13362 (varnumber_T)-1) == FAIL
13363 || list_append_number(rettv->vval.v_list,
13364 (varnumber_T)-1) == FAIL
13365 || list_append_number(rettv->vval.v_list,
13366 (varnumber_T)-1) == FAIL))
13367 {
13368 list_free(rettv->vval.v_list);
13369 rettv->vval.v_list = NULL;
13370 goto theend;
13371 }
13372 }
13373 else if (type == 2)
13374 {
13375 rettv->v_type = VAR_STRING;
13376 rettv->vval.v_string = NULL;
13377 }
13378
13379 if (argvars[0].v_type == VAR_LIST)
13380 {
13381 if ((l = argvars[0].vval.v_list) == NULL)
13382 goto theend;
13383 li = l->lv_first;
13384 }
13385 else
13386 {
13387 expr = str = get_tv_string(&argvars[0]);
13388 len = (long)STRLEN(str);
13389 }
13390
13391 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
13392 if (pat == NULL)
13393 goto theend;
13394
13395 if (argvars[2].v_type != VAR_UNKNOWN)
13396 {
13397 int error = FALSE;
13398
13399 start = (long)get_tv_number_chk(&argvars[2], &error);
13400 if (error)
13401 goto theend;
13402 if (l != NULL)
13403 {
13404 li = list_find(l, start);
13405 if (li == NULL)
13406 goto theend;
13407 idx = l->lv_idx; /* use the cached index */
13408 }
13409 else
13410 {
13411 if (start < 0)
13412 start = 0;
13413 if (start > len)
13414 goto theend;
13415 /* When "count" argument is there ignore matches before "start",
13416 * otherwise skip part of the string. Differs when pattern is "^"
13417 * or "\<". */
13418 if (argvars[3].v_type != VAR_UNKNOWN)
13419 startcol = start;
13420 else
13421 {
13422 str += start;
13423 len -= start;
13424 }
13425 }
13426
13427 if (argvars[3].v_type != VAR_UNKNOWN)
13428 nth = (long)get_tv_number_chk(&argvars[3], &error);
13429 if (error)
13430 goto theend;
13431 }
13432
13433 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
13434 if (regmatch.regprog != NULL)
13435 {
13436 regmatch.rm_ic = p_ic;
13437
13438 for (;;)
13439 {
13440 if (l != NULL)
13441 {
13442 if (li == NULL)
13443 {
13444 match = FALSE;
13445 break;
13446 }
13447 vim_free(tofree);
13448 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
13449 if (str == NULL)
13450 break;
13451 }
13452
13453 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
13454
13455 if (match && --nth <= 0)
13456 break;
13457 if (l == NULL && !match)
13458 break;
13459
13460 /* Advance to just after the match. */
13461 if (l != NULL)
13462 {
13463 li = li->li_next;
13464 ++idx;
13465 }
13466 else
13467 {
13468 #ifdef FEAT_MBYTE
13469 startcol = (colnr_T)(regmatch.startp[0]
13470 + (*mb_ptr2len)(regmatch.startp[0]) - str);
13471 #else
13472 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
13473 #endif
13474 if (startcol > (colnr_T)len
13475 || str + startcol <= regmatch.startp[0])
13476 {
13477 match = FALSE;
13478 break;
13479 }
13480 }
13481 }
13482
13483 if (match)
13484 {
13485 if (type == 4)
13486 {
13487 listitem_T *li1 = rettv->vval.v_list->lv_first;
13488 listitem_T *li2 = li1->li_next;
13489 listitem_T *li3 = li2->li_next;
13490 listitem_T *li4 = li3->li_next;
13491
13492 vim_free(li1->li_tv.vval.v_string);
13493 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
13494 (int)(regmatch.endp[0] - regmatch.startp[0]));
13495 li3->li_tv.vval.v_number =
13496 (varnumber_T)(regmatch.startp[0] - expr);
13497 li4->li_tv.vval.v_number =
13498 (varnumber_T)(regmatch.endp[0] - expr);
13499 if (l != NULL)
13500 li2->li_tv.vval.v_number = (varnumber_T)idx;
13501 }
13502 else if (type == 3)
13503 {
13504 int i;
13505
13506 /* return list with matched string and submatches */
13507 for (i = 0; i < NSUBEXP; ++i)
13508 {
13509 if (regmatch.endp[i] == NULL)
13510 {
13511 if (list_append_string(rettv->vval.v_list,
13512 (char_u *)"", 0) == FAIL)
13513 break;
13514 }
13515 else if (list_append_string(rettv->vval.v_list,
13516 regmatch.startp[i],
13517 (int)(regmatch.endp[i] - regmatch.startp[i]))
13518 == FAIL)
13519 break;
13520 }
13521 }
13522 else if (type == 2)
13523 {
13524 /* return matched string */
13525 if (l != NULL)
13526 copy_tv(&li->li_tv, rettv);
13527 else
13528 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
13529 (int)(regmatch.endp[0] - regmatch.startp[0]));
13530 }
13531 else if (l != NULL)
13532 rettv->vval.v_number = idx;
13533 else
13534 {
13535 if (type != 0)
13536 rettv->vval.v_number =
13537 (varnumber_T)(regmatch.startp[0] - str);
13538 else
13539 rettv->vval.v_number =
13540 (varnumber_T)(regmatch.endp[0] - str);
13541 rettv->vval.v_number += (varnumber_T)(str - expr);
13542 }
13543 }
13544 vim_regfree(regmatch.regprog);
13545 }
13546
13547 if (type == 4 && l == NULL)
13548 /* matchstrpos() without a list: drop the second item. */
13549 listitem_remove(rettv->vval.v_list,
13550 rettv->vval.v_list->lv_first->li_next);
13551
13552 theend:
13553 vim_free(tofree);
13554 p_cpo = save_cpo;
13555 }
13556
13557 /*
13558 * "match()" function
13559 */
13560 static void
13561 f_match(typval_T *argvars, typval_T *rettv)
13562 {
13563 find_some_match(argvars, rettv, 1);
13564 }
13565
13566 /*
13567 * "matchadd()" function
13568 */
13569 static void
13570 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13571 {
13572 #ifdef FEAT_SEARCH_EXTRA
13573 char_u buf[NUMBUFLEN];
13574 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
13575 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
13576 int prio = 10; /* default priority */
13577 int id = -1;
13578 int error = FALSE;
13579 char_u *conceal_char = NULL;
13580
13581 rettv->vval.v_number = -1;
13582
13583 if (grp == NULL || pat == NULL)
13584 return;
13585 if (argvars[2].v_type != VAR_UNKNOWN)
13586 {
13587 prio = (int)get_tv_number_chk(&argvars[2], &error);
13588 if (argvars[3].v_type != VAR_UNKNOWN)
13589 {
13590 id = (int)get_tv_number_chk(&argvars[3], &error);
13591 if (argvars[4].v_type != VAR_UNKNOWN)
13592 {
13593 if (argvars[4].v_type != VAR_DICT)
13594 {
13595 EMSG(_(e_dictreq));
13596 return;
13597 }
13598 if (dict_find(argvars[4].vval.v_dict,
13599 (char_u *)"conceal", -1) != NULL)
13600 conceal_char = get_dict_string(argvars[4].vval.v_dict,
13601 (char_u *)"conceal", FALSE);
13602 }
13603 }
13604 }
13605 if (error == TRUE)
13606 return;
13607 if (id >= 1 && id <= 3)
13608 {
13609 EMSGN("E798: ID is reserved for \":match\": %ld", id);
13610 return;
13611 }
13612
13613 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
13614 conceal_char);
13615 #endif
13616 }
13617
13618 /*
13619 * "matchaddpos()" function
13620 */
13621 static void
13622 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13623 {
13624 #ifdef FEAT_SEARCH_EXTRA
13625 char_u buf[NUMBUFLEN];
13626 char_u *group;
13627 int prio = 10;
13628 int id = -1;
13629 int error = FALSE;
13630 list_T *l;
13631 char_u *conceal_char = NULL;
13632
13633 rettv->vval.v_number = -1;
13634
13635 group = get_tv_string_buf_chk(&argvars[0], buf);
13636 if (group == NULL)
13637 return;
13638
13639 if (argvars[1].v_type != VAR_LIST)
13640 {
13641 EMSG2(_(e_listarg), "matchaddpos()");
13642 return;
13643 }
13644 l = argvars[1].vval.v_list;
13645 if (l == NULL)
13646 return;
13647
13648 if (argvars[2].v_type != VAR_UNKNOWN)
13649 {
13650 prio = (int)get_tv_number_chk(&argvars[2], &error);
13651 if (argvars[3].v_type != VAR_UNKNOWN)
13652 {
13653 id = (int)get_tv_number_chk(&argvars[3], &error);
13654 if (argvars[4].v_type != VAR_UNKNOWN)
13655 {
13656 if (argvars[4].v_type != VAR_DICT)
13657 {
13658 EMSG(_(e_dictreq));
13659 return;
13660 }
13661 if (dict_find(argvars[4].vval.v_dict,
13662 (char_u *)"conceal", -1) != NULL)
13663 conceal_char = get_dict_string(argvars[4].vval.v_dict,
13664 (char_u *)"conceal", FALSE);
13665 }
13666 }
13667 }
13668 if (error == TRUE)
13669 return;
13670
13671 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
13672 if (id == 1 || id == 2)
13673 {
13674 EMSGN("E798: ID is reserved for \":match\": %ld", id);
13675 return;
13676 }
13677
13678 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
13679 conceal_char);
13680 #endif
13681 }
13682
13683 /*
13684 * "matcharg()" function
13685 */
13686 static void
13687 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
13688 {
13689 if (rettv_list_alloc(rettv) == OK)
13690 {
13691 #ifdef FEAT_SEARCH_EXTRA
13692 int id = (int)get_tv_number(&argvars[0]);
13693 matchitem_T *m;
13694
13695 if (id >= 1 && id <= 3)
13696 {
13697 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
13698 {
13699 list_append_string(rettv->vval.v_list,
13700 syn_id2name(m->hlg_id), -1);
13701 list_append_string(rettv->vval.v_list, m->pattern, -1);
13702 }
13703 else
13704 {
13705 list_append_string(rettv->vval.v_list, NULL, -1);
13706 list_append_string(rettv->vval.v_list, NULL, -1);
13707 }
13708 }
13709 #endif
13710 }
13711 }
13712
13713 /*
13714 * "matchdelete()" function
13715 */
13716 static void
13717 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13718 {
13719 #ifdef FEAT_SEARCH_EXTRA
13720 rettv->vval.v_number = match_delete(curwin,
13721 (int)get_tv_number(&argvars[0]), TRUE);
13722 #endif
13723 }
13724
13725 /*
13726 * "matchend()" function
13727 */
13728 static void
13729 f_matchend(typval_T *argvars, typval_T *rettv)
13730 {
13731 find_some_match(argvars, rettv, 0);
13732 }
13733
13734 /*
13735 * "matchlist()" function
13736 */
13737 static void
13738 f_matchlist(typval_T *argvars, typval_T *rettv)
13739 {
13740 find_some_match(argvars, rettv, 3);
13741 }
13742
13743 /*
13744 * "matchstr()" function
13745 */
13746 static void
13747 f_matchstr(typval_T *argvars, typval_T *rettv)
13748 {
13749 find_some_match(argvars, rettv, 2);
13750 }
13751
13752 /*
13753 * "matchstrpos()" function
13754 */
13755 static void
13756 f_matchstrpos(typval_T *argvars, typval_T *rettv)
13757 {
13758 find_some_match(argvars, rettv, 4);
13759 }
13760
13761 static void max_min(typval_T *argvars, typval_T *rettv, int domax);
13762
13763 static void
13764 max_min(typval_T *argvars, typval_T *rettv, int domax)
13765 {
13766 varnumber_T n = 0;
13767 varnumber_T i;
13768 int error = FALSE;
13769
13770 if (argvars[0].v_type == VAR_LIST)
13771 {
13772 list_T *l;
13773 listitem_T *li;
13774
13775 l = argvars[0].vval.v_list;
13776 if (l != NULL)
13777 {
13778 li = l->lv_first;
13779 if (li != NULL)
13780 {
13781 n = get_tv_number_chk(&li->li_tv, &error);
13782 for (;;)
13783 {
13784 li = li->li_next;
13785 if (li == NULL)
13786 break;
13787 i = get_tv_number_chk(&li->li_tv, &error);
13788 if (domax ? i > n : i < n)
13789 n = i;
13790 }
13791 }
13792 }
13793 }
13794 else if (argvars[0].v_type == VAR_DICT)
13795 {
13796 dict_T *d;
13797 int first = TRUE;
13798 hashitem_T *hi;
13799 int todo;
13800
13801 d = argvars[0].vval.v_dict;
13802 if (d != NULL)
13803 {
13804 todo = (int)d->dv_hashtab.ht_used;
13805 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
13806 {
13807 if (!HASHITEM_EMPTY(hi))
13808 {
13809 --todo;
13810 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
13811 if (first)
13812 {
13813 n = i;
13814 first = FALSE;
13815 }
13816 else if (domax ? i > n : i < n)
13817 n = i;
13818 }
13819 }
13820 }
13821 }
13822 else
13823 EMSG(_(e_listdictarg));
13824 rettv->vval.v_number = error ? 0 : n;
13825 }
13826
13827 /*
13828 * "max()" function
13829 */
13830 static void
13831 f_max(typval_T *argvars, typval_T *rettv)
13832 {
13833 max_min(argvars, rettv, TRUE);
13834 }
13835
13836 /*
13837 * "min()" function
13838 */
13839 static void
13840 f_min(typval_T *argvars, typval_T *rettv)
13841 {
13842 max_min(argvars, rettv, FALSE);
13843 }
13844
13845 static int mkdir_recurse(char_u *dir, int prot);
13846
13847 /*
13848 * Create the directory in which "dir" is located, and higher levels when
13849 * needed.
13850 */
13851 static int
13852 mkdir_recurse(char_u *dir, int prot)
13853 {
13854 char_u *p;
13855 char_u *updir;
13856 int r = FAIL;
13857
13858 /* Get end of directory name in "dir".
13859 * We're done when it's "/" or "c:/". */
13860 p = gettail_sep(dir);
13861 if (p <= get_past_head(dir))
13862 return OK;
13863
13864 /* If the directory exists we're done. Otherwise: create it.*/
13865 updir = vim_strnsave(dir, (int)(p - dir));
13866 if (updir == NULL)
13867 return FAIL;
13868 if (mch_isdir(updir))
13869 r = OK;
13870 else if (mkdir_recurse(updir, prot) == OK)
13871 r = vim_mkdir_emsg(updir, prot);
13872 vim_free(updir);
13873 return r;
13874 }
13875
13876 #ifdef vim_mkdir
13877 /*
13878 * "mkdir()" function
13879 */
13880 static void
13881 f_mkdir(typval_T *argvars, typval_T *rettv)
13882 {
13883 char_u *dir;
13884 char_u buf[NUMBUFLEN];
13885 int prot = 0755;
13886
13887 rettv->vval.v_number = FAIL;
13888 if (check_restricted() || check_secure())
13889 return;
13890
13891 dir = get_tv_string_buf(&argvars[0], buf);
13892 if (*dir == NUL)
13893 rettv->vval.v_number = FAIL;
13894 else
13895 {
13896 if (*gettail(dir) == NUL)
13897 /* remove trailing slashes */
13898 *gettail_sep(dir) = NUL;
13899
13900 if (argvars[1].v_type != VAR_UNKNOWN)
13901 {
13902 if (argvars[2].v_type != VAR_UNKNOWN)
13903 prot = (int)get_tv_number_chk(&argvars[2], NULL);
13904 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
13905 mkdir_recurse(dir, prot);
13906 }
13907 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
13908 }
13909 }
13910 #endif
13911
13912 /*
13913 * "mode()" function
13914 */
13915 static void
13916 f_mode(typval_T *argvars, typval_T *rettv)
13917 {
13918 char_u buf[3];
13919
13920 buf[1] = NUL;
13921 buf[2] = NUL;
13922
13923 if (time_for_testing == 93784)
13924 {
13925 /* Testing the two-character code. */
13926 buf[0] = 'x';
13927 buf[1] = '!';
13928 }
13929 else if (VIsual_active)
13930 {
13931 if (VIsual_select)
13932 buf[0] = VIsual_mode + 's' - 'v';
13933 else
13934 buf[0] = VIsual_mode;
13935 }
13936 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
13937 || State == CONFIRM)
13938 {
13939 buf[0] = 'r';
13940 if (State == ASKMORE)
13941 buf[1] = 'm';
13942 else if (State == CONFIRM)
13943 buf[1] = '?';
13944 }
13945 else if (State == EXTERNCMD)
13946 buf[0] = '!';
13947 else if (State & INSERT)
13948 {
13949 #ifdef FEAT_VREPLACE
13950 if (State & VREPLACE_FLAG)
13951 {
13952 buf[0] = 'R';
13953 buf[1] = 'v';
13954 }
13955 else
13956 #endif
13957 if (State & REPLACE_FLAG)
13958 buf[0] = 'R';
13959 else
13960 buf[0] = 'i';
13961 }
13962 else if (State & CMDLINE)
13963 {
13964 buf[0] = 'c';
13965 if (exmode_active)
13966 buf[1] = 'v';
13967 }
13968 else if (exmode_active)
13969 {
13970 buf[0] = 'c';
13971 buf[1] = 'e';
13972 }
13973 else
13974 {
13975 buf[0] = 'n';
13976 if (finish_op)
13977 buf[1] = 'o';
13978 }
13979
13980 /* Clear out the minor mode when the argument is not a non-zero number or
13981 * non-empty string. */
13982 if (!non_zero_arg(&argvars[0]))
13983 buf[1] = NUL;
13984
13985 rettv->vval.v_string = vim_strsave(buf);
13986 rettv->v_type = VAR_STRING;
13987 }
13988
13989 #if defined(FEAT_MZSCHEME) || defined(PROTO)
13990 /*
13991 * "mzeval()" function
13992 */
13993 static void
13994 f_mzeval(typval_T *argvars, typval_T *rettv)
13995 {
13996 char_u *str;
13997 char_u buf[NUMBUFLEN];
13998
13999 str = get_tv_string_buf(&argvars[0], buf);
14000 do_mzeval(str, rettv);
14001 }
14002
14003 void
14004 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
14005 {
14006 typval_T argvars[3];
14007
14008 argvars[0].v_type = VAR_STRING;
14009 argvars[0].vval.v_string = name;
14010 copy_tv(args, &argvars[1]);
14011 argvars[2].v_type = VAR_UNKNOWN;
14012 f_call(argvars, rettv);
14013 clear_tv(&argvars[1]);
14014 }
14015 #endif
14016
14017 /*
14018 * "nextnonblank()" function
14019 */
14020 static void
14021 f_nextnonblank(typval_T *argvars, typval_T *rettv)
14022 {
14023 linenr_T lnum;
14024
14025 for (lnum = get_tv_lnum(argvars); ; ++lnum)
14026 {
14027 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
14028 {
14029 lnum = 0;
14030 break;
14031 }
14032 if (*skipwhite(ml_get(lnum)) != NUL)
14033 break;
14034 }
14035 rettv->vval.v_number = lnum;
14036 }
14037
14038 /*
14039 * "nr2char()" function
14040 */
14041 static void
14042 f_nr2char(typval_T *argvars, typval_T *rettv)
14043 {
14044 char_u buf[NUMBUFLEN];
14045
14046 #ifdef FEAT_MBYTE
14047 if (has_mbyte)
14048 {
14049 int utf8 = 0;
14050
14051 if (argvars[1].v_type != VAR_UNKNOWN)
14052 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
14053 if (utf8)
14054 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
14055 else
14056 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
14057 }
14058 else
14059 #endif
14060 {
14061 buf[0] = (char_u)get_tv_number(&argvars[0]);
14062 buf[1] = NUL;
14063 }
14064 rettv->v_type = VAR_STRING;
14065 rettv->vval.v_string = vim_strsave(buf);
14066 }
14067
14068 /*
14069 * "or(expr, expr)" function
14070 */
14071 static void
14072 f_or(typval_T *argvars, typval_T *rettv)
14073 {
14074 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
14075 | get_tv_number_chk(&argvars[1], NULL);
14076 }
14077
14078 /*
14079 * "pathshorten()" function
14080 */
14081 static void
14082 f_pathshorten(typval_T *argvars, typval_T *rettv)
14083 {
14084 char_u *p;
14085
14086 rettv->v_type = VAR_STRING;
14087 p = get_tv_string_chk(&argvars[0]);
14088 if (p == NULL)
14089 rettv->vval.v_string = NULL;
14090 else
14091 {
14092 p = vim_strsave(p);
14093 rettv->vval.v_string = p;
14094 if (p != NULL)
14095 shorten_dir(p);
14096 }
14097 }
14098
14099 #ifdef FEAT_PERL
14100 /*
14101 * "perleval()" function
14102 */
14103 static void
14104 f_perleval(typval_T *argvars, typval_T *rettv)
14105 {
14106 char_u *str;
14107 char_u buf[NUMBUFLEN];
14108
14109 str = get_tv_string_buf(&argvars[0], buf);
14110 do_perleval(str, rettv);
14111 }
14112 #endif
14113
14114 #ifdef FEAT_FLOAT
14115 /*
14116 * "pow()" function
14117 */
14118 static void
14119 f_pow(typval_T *argvars, typval_T *rettv)
14120 {
14121 float_T fx = 0.0, fy = 0.0;
14122
14123 rettv->v_type = VAR_FLOAT;
14124 if (get_float_arg(argvars, &fx) == OK
14125 && get_float_arg(&argvars[1], &fy) == OK)
14126 rettv->vval.v_float = pow(fx, fy);
14127 else
14128 rettv->vval.v_float = 0.0;
14129 }
14130 #endif
14131
14132 /*
14133 * "prevnonblank()" function
14134 */
14135 static void
14136 f_prevnonblank(typval_T *argvars, typval_T *rettv)
14137 {
14138 linenr_T lnum;
14139
14140 lnum = get_tv_lnum(argvars);
14141 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
14142 lnum = 0;
14143 else
14144 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
14145 --lnum;
14146 rettv->vval.v_number = lnum;
14147 }
14148
14149 /* This dummy va_list is here because:
14150 * - passing a NULL pointer doesn't work when va_list isn't a pointer
14151 * - locally in the function results in a "used before set" warning
14152 * - using va_start() to initialize it gives "function with fixed args" error */
14153 static va_list ap;
14154
14155 /*
14156 * "printf()" function
14157 */
14158 static void
14159 f_printf(typval_T *argvars, typval_T *rettv)
14160 {
14161 char_u buf[NUMBUFLEN];
14162 int len;
14163 char_u *s;
14164 int saved_did_emsg = did_emsg;
14165 char *fmt;
14166
14167 rettv->v_type = VAR_STRING;
14168 rettv->vval.v_string = NULL;
14169
14170 /* Get the required length, allocate the buffer and do it for real. */
14171 did_emsg = FALSE;
14172 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
14173 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
14174 if (!did_emsg)
14175 {
14176 s = alloc(len + 1);
14177 if (s != NULL)
14178 {
14179 rettv->vval.v_string = s;
14180 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
14181 }
14182 }
14183 did_emsg |= saved_did_emsg;
14184 }
14185
14186 /*
14187 * "pumvisible()" function
14188 */
14189 static void
14190 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14191 {
14192 #ifdef FEAT_INS_EXPAND
14193 if (pum_visible())
14194 rettv->vval.v_number = 1;
14195 #endif
14196 }
14197
14198 #ifdef FEAT_PYTHON3
14199 /*
14200 * "py3eval()" function
14201 */
14202 static void
14203 f_py3eval(typval_T *argvars, typval_T *rettv)
14204 {
14205 char_u *str;
14206 char_u buf[NUMBUFLEN];
14207
14208 str = get_tv_string_buf(&argvars[0], buf);
14209 do_py3eval(str, rettv);
14210 }
14211 #endif
14212
14213 #ifdef FEAT_PYTHON
14214 /*
14215 * "pyeval()" function
14216 */
14217 static void
14218 f_pyeval(typval_T *argvars, typval_T *rettv)
14219 {
14220 char_u *str;
14221 char_u buf[NUMBUFLEN];
14222
14223 str = get_tv_string_buf(&argvars[0], buf);
14224 do_pyeval(str, rettv);
14225 }
14226 #endif
14227
14228 /*
14229 * "range()" function
14230 */
14231 static void
14232 f_range(typval_T *argvars, typval_T *rettv)
14233 {
14234 varnumber_T start;
14235 varnumber_T end;
14236 varnumber_T stride = 1;
14237 varnumber_T i;
14238 int error = FALSE;
14239
14240 start = get_tv_number_chk(&argvars[0], &error);
14241 if (argvars[1].v_type == VAR_UNKNOWN)
14242 {
14243 end = start - 1;
14244 start = 0;
14245 }
14246 else
14247 {
14248 end = get_tv_number_chk(&argvars[1], &error);
14249 if (argvars[2].v_type != VAR_UNKNOWN)
14250 stride = get_tv_number_chk(&argvars[2], &error);
14251 }
14252
14253 if (error)
14254 return; /* type error; errmsg already given */
14255 if (stride == 0)
14256 EMSG(_("E726: Stride is zero"));
14257 else if (stride > 0 ? end + 1 < start : end - 1 > start)
14258 EMSG(_("E727: Start past end"));
14259 else
14260 {
14261 if (rettv_list_alloc(rettv) == OK)
14262 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
14263 if (list_append_number(rettv->vval.v_list,
14264 (varnumber_T)i) == FAIL)
14265 break;
14266 }
14267 }
14268
14269 /*
14270 * "readfile()" function
14271 */
14272 static void
14273 f_readfile(typval_T *argvars, typval_T *rettv)
14274 {
14275 int binary = FALSE;
14276 int failed = FALSE;
14277 char_u *fname;
14278 FILE *fd;
14279 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
14280 int io_size = sizeof(buf);
14281 int readlen; /* size of last fread() */
14282 char_u *prev = NULL; /* previously read bytes, if any */
14283 long prevlen = 0; /* length of data in prev */
14284 long prevsize = 0; /* size of prev buffer */
14285 long maxline = MAXLNUM;
14286 long cnt = 0;
14287 char_u *p; /* position in buf */
14288 char_u *start; /* start of current line */
14289
14290 if (argvars[1].v_type != VAR_UNKNOWN)
14291 {
14292 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
14293 binary = TRUE;
14294 if (argvars[2].v_type != VAR_UNKNOWN)
14295 maxline = (long)get_tv_number(&argvars[2]);
14296 }
14297
14298 if (rettv_list_alloc(rettv) == FAIL)
14299 return;
14300
14301 /* Always open the file in binary mode, library functions have a mind of
14302 * their own about CR-LF conversion. */
14303 fname = get_tv_string(&argvars[0]);
14304 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
14305 {
14306 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
14307 return;
14308 }
14309
14310 while (cnt < maxline || maxline < 0)
14311 {
14312 readlen = (int)fread(buf, 1, io_size, fd);
14313
14314 /* This for loop processes what was read, but is also entered at end
14315 * of file so that either:
14316 * - an incomplete line gets written
14317 * - a "binary" file gets an empty line at the end if it ends in a
14318 * newline. */
14319 for (p = buf, start = buf;
14320 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
14321 ++p)
14322 {
14323 if (*p == '\n' || readlen <= 0)
14324 {
14325 listitem_T *li;
14326 char_u *s = NULL;
14327 long_u len = p - start;
14328
14329 /* Finished a line. Remove CRs before NL. */
14330 if (readlen > 0 && !binary)
14331 {
14332 while (len > 0 && start[len - 1] == '\r')
14333 --len;
14334 /* removal may cross back to the "prev" string */
14335 if (len == 0)
14336 while (prevlen > 0 && prev[prevlen - 1] == '\r')
14337 --prevlen;
14338 }
14339 if (prevlen == 0)
14340 s = vim_strnsave(start, (int)len);
14341 else
14342 {
14343 /* Change "prev" buffer to be the right size. This way
14344 * the bytes are only copied once, and very long lines are
14345 * allocated only once. */
14346 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
14347 {
14348 mch_memmove(s + prevlen, start, len);
14349 s[prevlen + len] = NUL;
14350 prev = NULL; /* the list will own the string */
14351 prevlen = prevsize = 0;
14352 }
14353 }
14354 if (s == NULL)
14355 {
14356 do_outofmem_msg((long_u) prevlen + len + 1);
14357 failed = TRUE;
14358 break;
14359 }
14360
14361 if ((li = listitem_alloc()) == NULL)
14362 {
14363 vim_free(s);
14364 failed = TRUE;
14365 break;
14366 }
14367 li->li_tv.v_type = VAR_STRING;
14368 li->li_tv.v_lock = 0;
14369 li->li_tv.vval.v_string = s;
14370 list_append(rettv->vval.v_list, li);
14371
14372 start = p + 1; /* step over newline */
14373 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
14374 break;
14375 }
14376 else if (*p == NUL)
14377 *p = '\n';
14378 #ifdef FEAT_MBYTE
14379 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
14380 * when finding the BF and check the previous two bytes. */
14381 else if (*p == 0xbf && enc_utf8 && !binary)
14382 {
14383 /* Find the two bytes before the 0xbf. If p is at buf, or buf
14384 * + 1, these may be in the "prev" string. */
14385 char_u back1 = p >= buf + 1 ? p[-1]
14386 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
14387 char_u back2 = p >= buf + 2 ? p[-2]
14388 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
14389 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
14390
14391 if (back2 == 0xef && back1 == 0xbb)
14392 {
14393 char_u *dest = p - 2;
14394
14395 /* Usually a BOM is at the beginning of a file, and so at
14396 * the beginning of a line; then we can just step over it.
14397 */
14398 if (start == dest)
14399 start = p + 1;
14400 else
14401 {
14402 /* have to shuffle buf to close gap */
14403 int adjust_prevlen = 0;
14404
14405 if (dest < buf)
14406 {
14407 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
14408 dest = buf;
14409 }
14410 if (readlen > p - buf + 1)
14411 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
14412 readlen -= 3 - adjust_prevlen;
14413 prevlen -= adjust_prevlen;
14414 p = dest - 1;
14415 }
14416 }
14417 }
14418 #endif
14419 } /* for */
14420
14421 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
14422 break;
14423 if (start < p)
14424 {
14425 /* There's part of a line in buf, store it in "prev". */
14426 if (p - start + prevlen >= prevsize)
14427 {
14428 /* need bigger "prev" buffer */
14429 char_u *newprev;
14430
14431 /* A common use case is ordinary text files and "prev" gets a
14432 * fragment of a line, so the first allocation is made
14433 * small, to avoid repeatedly 'allocing' large and
14434 * 'reallocing' small. */
14435 if (prevsize == 0)
14436 prevsize = (long)(p - start);
14437 else
14438 {
14439 long grow50pc = (prevsize * 3) / 2;
14440 long growmin = (long)((p - start) * 2 + prevlen);
14441 prevsize = grow50pc > growmin ? grow50pc : growmin;
14442 }
14443 newprev = prev == NULL ? alloc(prevsize)
14444 : vim_realloc(prev, prevsize);
14445 if (newprev == NULL)
14446 {
14447 do_outofmem_msg((long_u)prevsize);
14448 failed = TRUE;
14449 break;
14450 }
14451 prev = newprev;
14452 }
14453 /* Add the line part to end of "prev". */
14454 mch_memmove(prev + prevlen, start, p - start);
14455 prevlen += (long)(p - start);
14456 }
14457 } /* while */
14458
14459 /*
14460 * For a negative line count use only the lines at the end of the file,
14461 * free the rest.
14462 */
14463 if (!failed && maxline < 0)
14464 while (cnt > -maxline)
14465 {
14466 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
14467 --cnt;
14468 }
14469
14470 if (failed)
14471 {
14472 list_free(rettv->vval.v_list);
14473 /* readfile doc says an empty list is returned on error */
14474 rettv->vval.v_list = list_alloc();
14475 }
14476
14477 vim_free(prev);
14478 fclose(fd);
14479 }
14480
14481 #if defined(FEAT_RELTIME)
14482 static int list2proftime(typval_T *arg, proftime_T *tm);
14483
14484 /*
14485 * Convert a List to proftime_T.
14486 * Return FAIL when there is something wrong.
14487 */
14488 static int
14489 list2proftime(typval_T *arg, proftime_T *tm)
14490 {
14491 long n1, n2;
14492 int error = FALSE;
14493
14494 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
14495 || arg->vval.v_list->lv_len != 2)
14496 return FAIL;
14497 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
14498 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
14499 # ifdef WIN3264
14500 tm->HighPart = n1;
14501 tm->LowPart = n2;
14502 # else
14503 tm->tv_sec = n1;
14504 tm->tv_usec = n2;
14505 # endif
14506 return error ? FAIL : OK;
14507 }
14508 #endif /* FEAT_RELTIME */
14509
14510 /*
14511 * "reltime()" function
14512 */
14513 static void
14514 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14515 {
14516 #ifdef FEAT_RELTIME
14517 proftime_T res;
14518 proftime_T start;
14519
14520 if (argvars[0].v_type == VAR_UNKNOWN)
14521 {
14522 /* No arguments: get current time. */
14523 profile_start(&res);
14524 }
14525 else if (argvars[1].v_type == VAR_UNKNOWN)
14526 {
14527 if (list2proftime(&argvars[0], &res) == FAIL)
14528 return;
14529 profile_end(&res);
14530 }
14531 else
14532 {
14533 /* Two arguments: compute the difference. */
14534 if (list2proftime(&argvars[0], &start) == FAIL
14535 || list2proftime(&argvars[1], &res) == FAIL)
14536 return;
14537 profile_sub(&res, &start);
14538 }
14539
14540 if (rettv_list_alloc(rettv) == OK)
14541 {
14542 long n1, n2;
14543
14544 # ifdef WIN3264
14545 n1 = res.HighPart;
14546 n2 = res.LowPart;
14547 # else
14548 n1 = res.tv_sec;
14549 n2 = res.tv_usec;
14550 # endif
14551 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
14552 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
14553 }
14554 #endif
14555 }
14556
14557 #ifdef FEAT_FLOAT
14558 /*
14559 * "reltimefloat()" function
14560 */
14561 static void
14562 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
14563 {
14564 # ifdef FEAT_RELTIME
14565 proftime_T tm;
14566 # endif
14567
14568 rettv->v_type = VAR_FLOAT;
14569 rettv->vval.v_float = 0;
14570 # ifdef FEAT_RELTIME
14571 if (list2proftime(&argvars[0], &tm) == OK)
14572 rettv->vval.v_float = profile_float(&tm);
14573 # endif
14574 }
14575 #endif
14576
14577 /*
14578 * "reltimestr()" function
14579 */
14580 static void
14581 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
14582 {
14583 #ifdef FEAT_RELTIME
14584 proftime_T tm;
14585 #endif
14586
14587 rettv->v_type = VAR_STRING;
14588 rettv->vval.v_string = NULL;
14589 #ifdef FEAT_RELTIME
14590 if (list2proftime(&argvars[0], &tm) == OK)
14591 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
14592 #endif
14593 }
14594
14595 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
14596 static void make_connection(void);
14597 static int check_connection(void);
14598
14599 static void
14600 make_connection(void)
14601 {
14602 if (X_DISPLAY == NULL
14603 # ifdef FEAT_GUI
14604 && !gui.in_use
14605 # endif
14606 )
14607 {
14608 x_force_connect = TRUE;
14609 setup_term_clip();
14610 x_force_connect = FALSE;
14611 }
14612 }
14613
14614 static int
14615 check_connection(void)
14616 {
14617 make_connection();
14618 if (X_DISPLAY == NULL)
14619 {
14620 EMSG(_("E240: No connection to Vim server"));
14621 return FAIL;
14622 }
14623 return OK;
14624 }
14625 #endif
14626
14627 #ifdef FEAT_CLIENTSERVER
14628 static void
14629 remote_common(typval_T *argvars, typval_T *rettv, int expr)
14630 {
14631 char_u *server_name;
14632 char_u *keys;
14633 char_u *r = NULL;
14634 char_u buf[NUMBUFLEN];
14635 # ifdef WIN32
14636 HWND w;
14637 # else
14638 Window w;
14639 # endif
14640
14641 if (check_restricted() || check_secure())
14642 return;
14643
14644 # ifdef FEAT_X11
14645 if (check_connection() == FAIL)
14646 return;
14647 # endif
14648
14649 server_name = get_tv_string_chk(&argvars[0]);
14650 if (server_name == NULL)
14651 return; /* type error; errmsg already given */
14652 keys = get_tv_string_buf(&argvars[1], buf);
14653 # ifdef WIN32
14654 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
14655 # else
14656 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
14657 < 0)
14658 # endif
14659 {
14660 if (r != NULL)
14661 EMSG(r); /* sending worked but evaluation failed */
14662 else
14663 EMSG2(_("E241: Unable to send to %s"), server_name);
14664 return;
14665 }
14666
14667 rettv->vval.v_string = r;
14668
14669 if (argvars[2].v_type != VAR_UNKNOWN)
14670 {
14671 dictitem_T v;
14672 char_u str[30];
14673 char_u *idvar;
14674
14675 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
14676 v.di_tv.v_type = VAR_STRING;
14677 v.di_tv.vval.v_string = vim_strsave(str);
14678 idvar = get_tv_string_chk(&argvars[2]);
14679 if (idvar != NULL)
14680 set_var(idvar, &v.di_tv, FALSE);
14681 vim_free(v.di_tv.vval.v_string);
14682 }
14683 }
14684 #endif
14685
14686 /*
14687 * "remote_expr()" function
14688 */
14689 static void
14690 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
14691 {
14692 rettv->v_type = VAR_STRING;
14693 rettv->vval.v_string = NULL;
14694 #ifdef FEAT_CLIENTSERVER
14695 remote_common(argvars, rettv, TRUE);
14696 #endif
14697 }
14698
14699 /*
14700 * "remote_foreground()" function
14701 */
14702 static void
14703 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14704 {
14705 #ifdef FEAT_CLIENTSERVER
14706 # ifdef WIN32
14707 /* On Win32 it's done in this application. */
14708 {
14709 char_u *server_name = get_tv_string_chk(&argvars[0]);
14710
14711 if (server_name != NULL)
14712 serverForeground(server_name);
14713 }
14714 # else
14715 /* Send a foreground() expression to the server. */
14716 argvars[1].v_type = VAR_STRING;
14717 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
14718 argvars[2].v_type = VAR_UNKNOWN;
14719 remote_common(argvars, rettv, TRUE);
14720 vim_free(argvars[1].vval.v_string);
14721 # endif
14722 #endif
14723 }
14724
14725 static void
14726 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
14727 {
14728 #ifdef FEAT_CLIENTSERVER
14729 dictitem_T v;
14730 char_u *s = NULL;
14731 # ifdef WIN32
14732 long_u n = 0;
14733 # endif
14734 char_u *serverid;
14735
14736 if (check_restricted() || check_secure())
14737 {
14738 rettv->vval.v_number = -1;
14739 return;
14740 }
14741 serverid = get_tv_string_chk(&argvars[0]);
14742 if (serverid == NULL)
14743 {
14744 rettv->vval.v_number = -1;
14745 return; /* type error; errmsg already given */
14746 }
14747 # ifdef WIN32
14748 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
14749 if (n == 0)
14750 rettv->vval.v_number = -1;
14751 else
14752 {
14753 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
14754 rettv->vval.v_number = (s != NULL);
14755 }
14756 # else
14757 if (check_connection() == FAIL)
14758 return;
14759
14760 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
14761 serverStrToWin(serverid), &s);
14762 # endif
14763
14764 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
14765 {
14766 char_u *retvar;
14767
14768 v.di_tv.v_type = VAR_STRING;
14769 v.di_tv.vval.v_string = vim_strsave(s);
14770 retvar = get_tv_string_chk(&argvars[1]);
14771 if (retvar != NULL)
14772 set_var(retvar, &v.di_tv, FALSE);
14773 vim_free(v.di_tv.vval.v_string);
14774 }
14775 #else
14776 rettv->vval.v_number = -1;
14777 #endif
14778 }
14779
14780 static void
14781 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
14782 {
14783 char_u *r = NULL;
14784
14785 #ifdef FEAT_CLIENTSERVER
14786 char_u *serverid = get_tv_string_chk(&argvars[0]);
14787
14788 if (serverid != NULL && !check_restricted() && !check_secure())
14789 {
14790 # ifdef WIN32
14791 /* The server's HWND is encoded in the 'id' parameter */
14792 long_u n = 0;
14793
14794 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
14795 if (n != 0)
14796 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
14797 if (r == NULL)
14798 # else
14799 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
14800 serverStrToWin(serverid), &r, FALSE) < 0)
14801 # endif
14802 EMSG(_("E277: Unable to read a server reply"));
14803 }
14804 #endif
14805 rettv->v_type = VAR_STRING;
14806 rettv->vval.v_string = r;
14807 }
14808
14809 /*
14810 * "remote_send()" function
14811 */
14812 static void
14813 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
14814 {
14815 rettv->v_type = VAR_STRING;
14816 rettv->vval.v_string = NULL;
14817 #ifdef FEAT_CLIENTSERVER
14818 remote_common(argvars, rettv, FALSE);
14819 #endif
14820 }
14821
14822 /*
14823 * "remove()" function
14824 */
14825 static void
14826 f_remove(typval_T *argvars, typval_T *rettv)
14827 {
14828 list_T *l;
14829 listitem_T *item, *item2;
14830 listitem_T *li;
14831 long idx;
14832 long end;
14833 char_u *key;
14834 dict_T *d;
14835 dictitem_T *di;
14836 char_u *arg_errmsg = (char_u *)N_("remove() argument");
14837
14838 if (argvars[0].v_type == VAR_DICT)
14839 {
14840 if (argvars[2].v_type != VAR_UNKNOWN)
14841 EMSG2(_(e_toomanyarg), "remove()");
14842 else if ((d = argvars[0].vval.v_dict) != NULL
14843 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
14844 {
14845 key = get_tv_string_chk(&argvars[1]);
14846 if (key != NULL)
14847 {
14848 di = dict_find(d, key, -1);
14849 if (di == NULL)
14850 EMSG2(_(e_dictkey), key);
14851 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
14852 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
14853 {
14854 *rettv = di->di_tv;
14855 init_tv(&di->di_tv);
14856 dictitem_remove(d, di);
14857 }
14858 }
14859 }
14860 }
14861 else if (argvars[0].v_type != VAR_LIST)
14862 EMSG2(_(e_listdictarg), "remove()");
14863 else if ((l = argvars[0].vval.v_list) != NULL
14864 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
14865 {
14866 int error = FALSE;
14867
14868 idx = (long)get_tv_number_chk(&argvars[1], &error);
14869 if (error)
14870 ; /* type error: do nothing, errmsg already given */
14871 else if ((item = list_find(l, idx)) == NULL)
14872 EMSGN(_(e_listidx), idx);
14873 else
14874 {
14875 if (argvars[2].v_type == VAR_UNKNOWN)
14876 {
14877 /* Remove one item, return its value. */
14878 vimlist_remove(l, item, item);
14879 *rettv = item->li_tv;
14880 vim_free(item);
14881 }
14882 else
14883 {
14884 /* Remove range of items, return list with values. */
14885 end = (long)get_tv_number_chk(&argvars[2], &error);
14886 if (error)
14887 ; /* type error: do nothing */
14888 else if ((item2 = list_find(l, end)) == NULL)
14889 EMSGN(_(e_listidx), end);
14890 else
14891 {
14892 int cnt = 0;
14893
14894 for (li = item; li != NULL; li = li->li_next)
14895 {
14896 ++cnt;
14897 if (li == item2)
14898 break;
14899 }
14900 if (li == NULL) /* didn't find "item2" after "item" */
14901 EMSG(_(e_invrange));
14902 else
14903 {
14904 vimlist_remove(l, item, item2);
14905 if (rettv_list_alloc(rettv) == OK)
14906 {
14907 l = rettv->vval.v_list;
14908 l->lv_first = item;
14909 l->lv_last = item2;
14910 item->li_prev = NULL;
14911 item2->li_next = NULL;
14912 l->lv_len = cnt;
14913 }
14914 }
14915 }
14916 }
14917 }
14918 }
14919 }
14920
14921 /*
14922 * "rename({from}, {to})" function
14923 */
14924 static void
14925 f_rename(typval_T *argvars, typval_T *rettv)
14926 {
14927 char_u buf[NUMBUFLEN];
14928
14929 if (check_restricted() || check_secure())
14930 rettv->vval.v_number = -1;
14931 else
14932 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
14933 get_tv_string_buf(&argvars[1], buf));
14934 }
14935
14936 /*
14937 * "repeat()" function
14938 */
14939 static void
14940 f_repeat(typval_T *argvars, typval_T *rettv)
14941 {
14942 char_u *p;
14943 int n;
14944 int slen;
14945 int len;
14946 char_u *r;
14947 int i;
14948
14949 n = (int)get_tv_number(&argvars[1]);
14950 if (argvars[0].v_type == VAR_LIST)
14951 {
14952 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
14953 while (n-- > 0)
14954 if (list_extend(rettv->vval.v_list,
14955 argvars[0].vval.v_list, NULL) == FAIL)
14956 break;
14957 }
14958 else
14959 {
14960 p = get_tv_string(&argvars[0]);
14961 rettv->v_type = VAR_STRING;
14962 rettv->vval.v_string = NULL;
14963
14964 slen = (int)STRLEN(p);
14965 len = slen * n;
14966 if (len <= 0)
14967 return;
14968
14969 r = alloc(len + 1);
14970 if (r != NULL)
14971 {
14972 for (i = 0; i < n; i++)
14973 mch_memmove(r + i * slen, p, (size_t)slen);
14974 r[len] = NUL;
14975 }
14976
14977 rettv->vval.v_string = r;
14978 }
14979 }
14980
14981 /*
14982 * "resolve()" function
14983 */
14984 static void
14985 f_resolve(typval_T *argvars, typval_T *rettv)
14986 {
14987 char_u *p;
14988 #ifdef HAVE_READLINK
14989 char_u *buf = NULL;
14990 #endif
14991
14992 p = get_tv_string(&argvars[0]);
14993 #ifdef FEAT_SHORTCUT
14994 {
14995 char_u *v = NULL;
14996
14997 v = mch_resolve_shortcut(p);
14998 if (v != NULL)
14999 rettv->vval.v_string = v;
15000 else
15001 rettv->vval.v_string = vim_strsave(p);
15002 }
15003 #else
15004 # ifdef HAVE_READLINK
15005 {
15006 char_u *cpy;
15007 int len;
15008 char_u *remain = NULL;
15009 char_u *q;
15010 int is_relative_to_current = FALSE;
15011 int has_trailing_pathsep = FALSE;
15012 int limit = 100;
15013
15014 p = vim_strsave(p);
15015
15016 if (p[0] == '.' && (vim_ispathsep(p[1])
15017 || (p[1] == '.' && (vim_ispathsep(p[2])))))
15018 is_relative_to_current = TRUE;
15019
15020 len = STRLEN(p);
15021 if (len > 0 && after_pathsep(p, p + len))
15022 {
15023 has_trailing_pathsep = TRUE;
15024 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
15025 }
15026
15027 q = getnextcomp(p);
15028 if (*q != NUL)
15029 {
15030 /* Separate the first path component in "p", and keep the
15031 * remainder (beginning with the path separator). */
15032 remain = vim_strsave(q - 1);
15033 q[-1] = NUL;
15034 }
15035
15036 buf = alloc(MAXPATHL + 1);
15037 if (buf == NULL)
15038 goto fail;
15039
15040 for (;;)
15041 {
15042 for (;;)
15043 {
15044 len = readlink((char *)p, (char *)buf, MAXPATHL);
15045 if (len <= 0)
15046 break;
15047 buf[len] = NUL;
15048
15049 if (limit-- == 0)
15050 {
15051 vim_free(p);
15052 vim_free(remain);
15053 EMSG(_("E655: Too many symbolic links (cycle?)"));
15054 rettv->vval.v_string = NULL;
15055 goto fail;
15056 }
15057
15058 /* Ensure that the result will have a trailing path separator
15059 * if the argument has one. */
15060 if (remain == NULL && has_trailing_pathsep)
15061 add_pathsep(buf);
15062
15063 /* Separate the first path component in the link value and
15064 * concatenate the remainders. */
15065 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
15066 if (*q != NUL)
15067 {
15068 if (remain == NULL)
15069 remain = vim_strsave(q - 1);
15070 else
15071 {
15072 cpy = concat_str(q - 1, remain);
15073 if (cpy != NULL)
15074 {
15075 vim_free(remain);
15076 remain = cpy;
15077 }
15078 }
15079 q[-1] = NUL;
15080 }
15081
15082 q = gettail(p);
15083 if (q > p && *q == NUL)
15084 {
15085 /* Ignore trailing path separator. */
15086 q[-1] = NUL;
15087 q = gettail(p);
15088 }
15089 if (q > p && !mch_isFullName(buf))
15090 {
15091 /* symlink is relative to directory of argument */
15092 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
15093 if (cpy != NULL)
15094 {
15095 STRCPY(cpy, p);
15096 STRCPY(gettail(cpy), buf);
15097 vim_free(p);
15098 p = cpy;
15099 }
15100 }
15101 else
15102 {
15103 vim_free(p);
15104 p = vim_strsave(buf);
15105 }
15106 }
15107
15108 if (remain == NULL)
15109 break;
15110
15111 /* Append the first path component of "remain" to "p". */
15112 q = getnextcomp(remain + 1);
15113 len = q - remain - (*q != NUL);
15114 cpy = vim_strnsave(p, STRLEN(p) + len);
15115 if (cpy != NULL)
15116 {
15117 STRNCAT(cpy, remain, len);
15118 vim_free(p);
15119 p = cpy;
15120 }
15121 /* Shorten "remain". */
15122 if (*q != NUL)
15123 STRMOVE(remain, q - 1);
15124 else
15125 {
15126 vim_free(remain);
15127 remain = NULL;
15128 }
15129 }
15130
15131 /* If the result is a relative path name, make it explicitly relative to
15132 * the current directory if and only if the argument had this form. */
15133 if (!vim_ispathsep(*p))
15134 {
15135 if (is_relative_to_current
15136 && *p != NUL
15137 && !(p[0] == '.'
15138 && (p[1] == NUL
15139 || vim_ispathsep(p[1])
15140 || (p[1] == '.'
15141 && (p[2] == NUL
15142 || vim_ispathsep(p[2]))))))
15143 {
15144 /* Prepend "./". */
15145 cpy = concat_str((char_u *)"./", p);
15146 if (cpy != NULL)
15147 {
15148 vim_free(p);
15149 p = cpy;
15150 }
15151 }
15152 else if (!is_relative_to_current)
15153 {
15154 /* Strip leading "./". */
15155 q = p;
15156 while (q[0] == '.' && vim_ispathsep(q[1]))
15157 q += 2;
15158 if (q > p)
15159 STRMOVE(p, p + 2);
15160 }
15161 }
15162
15163 /* Ensure that the result will have no trailing path separator
15164 * if the argument had none. But keep "/" or "//". */
15165 if (!has_trailing_pathsep)
15166 {
15167 q = p + STRLEN(p);
15168 if (after_pathsep(p, q))
15169 *gettail_sep(p) = NUL;
15170 }
15171
15172 rettv->vval.v_string = p;
15173 }
15174 # else
15175 rettv->vval.v_string = vim_strsave(p);
15176 # endif
15177 #endif
15178
15179 simplify_filename(rettv->vval.v_string);
15180
15181 #ifdef HAVE_READLINK
15182 fail:
15183 vim_free(buf);
15184 #endif
15185 rettv->v_type = VAR_STRING;
15186 }
15187
15188 /*
15189 * "reverse({list})" function
15190 */
15191 static void
15192 f_reverse(typval_T *argvars, typval_T *rettv)
15193 {
15194 list_T *l;
15195 listitem_T *li, *ni;
15196
15197 if (argvars[0].v_type != VAR_LIST)
15198 EMSG2(_(e_listarg), "reverse()");
15199 else if ((l = argvars[0].vval.v_list) != NULL
15200 && !tv_check_lock(l->lv_lock,
15201 (char_u *)N_("reverse() argument"), TRUE))
15202 {
15203 li = l->lv_last;
15204 l->lv_first = l->lv_last = NULL;
15205 l->lv_len = 0;
15206 while (li != NULL)
15207 {
15208 ni = li->li_prev;
15209 list_append(l, li);
15210 li = ni;
15211 }
15212 rettv->vval.v_list = l;
15213 rettv->v_type = VAR_LIST;
15214 ++l->lv_refcount;
15215 l->lv_idx = l->lv_len - l->lv_idx - 1;
15216 }
15217 }
15218
15219 #define SP_NOMOVE 0x01 /* don't move cursor */
15220 #define SP_REPEAT 0x02 /* repeat to find outer pair */
15221 #define SP_RETCOUNT 0x04 /* return matchcount */
15222 #define SP_SETPCMARK 0x08 /* set previous context mark */
15223 #define SP_START 0x10 /* accept match at start position */
15224 #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
15225 #define SP_END 0x40 /* leave cursor at end of match */
15226 #define SP_COLUMN 0x80 /* start at cursor column */
15227
15228 static int get_search_arg(typval_T *varp, int *flagsp);
15229
15230 /*
15231 * Get flags for a search function.
15232 * Possibly sets "p_ws".
15233 * Returns BACKWARD, FORWARD or zero (for an error).
15234 */
15235 static int
15236 get_search_arg(typval_T *varp, int *flagsp)
15237 {
15238 int dir = FORWARD;
15239 char_u *flags;
15240 char_u nbuf[NUMBUFLEN];
15241 int mask;
15242
15243 if (varp->v_type != VAR_UNKNOWN)
15244 {
15245 flags = get_tv_string_buf_chk(varp, nbuf);
15246 if (flags == NULL)
15247 return 0; /* type error; errmsg already given */
15248 while (*flags != NUL)
15249 {
15250 switch (*flags)
15251 {
15252 case 'b': dir = BACKWARD; break;
15253 case 'w': p_ws = TRUE; break;
15254 case 'W': p_ws = FALSE; break;
15255 default: mask = 0;
15256 if (flagsp != NULL)
15257 switch (*flags)
15258 {
15259 case 'c': mask = SP_START; break;
15260 case 'e': mask = SP_END; break;
15261 case 'm': mask = SP_RETCOUNT; break;
15262 case 'n': mask = SP_NOMOVE; break;
15263 case 'p': mask = SP_SUBPAT; break;
15264 case 'r': mask = SP_REPEAT; break;
15265 case 's': mask = SP_SETPCMARK; break;
15266 case 'z': mask = SP_COLUMN; break;
15267 }
15268 if (mask == 0)
15269 {
15270 EMSG2(_(e_invarg2), flags);
15271 dir = 0;
15272 }
15273 else
15274 *flagsp |= mask;
15275 }
15276 if (dir == 0)
15277 break;
15278 ++flags;
15279 }
15280 }
15281 return dir;
15282 }
15283
15284 /*
15285 * Shared by search() and searchpos() functions.
15286 */
15287 static int
15288 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
15289 {
15290 int flags;
15291 char_u *pat;
15292 pos_T pos;
15293 pos_T save_cursor;
15294 int save_p_ws = p_ws;
15295 int dir;
15296 int retval = 0; /* default: FAIL */
15297 long lnum_stop = 0;
15298 proftime_T tm;
15299 #ifdef FEAT_RELTIME
15300 long time_limit = 0;
15301 #endif
15302 int options = SEARCH_KEEP;
15303 int subpatnum;
15304
15305 pat = get_tv_string(&argvars[0]);
15306 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
15307 if (dir == 0)
15308 goto theend;
15309 flags = *flagsp;
15310 if (flags & SP_START)
15311 options |= SEARCH_START;
15312 if (flags & SP_END)
15313 options |= SEARCH_END;
15314 if (flags & SP_COLUMN)
15315 options |= SEARCH_COL;
15316
15317 /* Optional arguments: line number to stop searching and timeout. */
15318 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
15319 {
15320 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
15321 if (lnum_stop < 0)
15322 goto theend;
15323 #ifdef FEAT_RELTIME
15324 if (argvars[3].v_type != VAR_UNKNOWN)
15325 {
15326 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
15327 if (time_limit < 0)
15328 goto theend;
15329 }
15330 #endif
15331 }
15332
15333 #ifdef FEAT_RELTIME
15334 /* Set the time limit, if there is one. */
15335 profile_setlimit(time_limit, &tm);
15336 #endif
15337
15338 /*
15339 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
15340 * Check to make sure only those flags are set.
15341 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
15342 * flags cannot be set. Check for that condition also.
15343 */
15344 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
15345 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
15346 {
15347 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
15348 goto theend;
15349 }
15350
15351 pos = save_cursor = curwin->w_cursor;
15352 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
15353 options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
15354 if (subpatnum != FAIL)
15355 {
15356 if (flags & SP_SUBPAT)
15357 retval = subpatnum;
15358 else
15359 retval = pos.lnum;
15360 if (flags & SP_SETPCMARK)
15361 setpcmark();
15362 curwin->w_cursor = pos;
15363 if (match_pos != NULL)
15364 {
15365 /* Store the match cursor position */
15366 match_pos->lnum = pos.lnum;
15367 match_pos->col = pos.col + 1;
15368 }
15369 /* "/$" will put the cursor after the end of the line, may need to
15370 * correct that here */
15371 check_cursor();
15372 }
15373
15374 /* If 'n' flag is used: restore cursor position. */
15375 if (flags & SP_NOMOVE)
15376 curwin->w_cursor = save_cursor;
15377 else
15378 curwin->w_set_curswant = TRUE;
15379 theend:
15380 p_ws = save_p_ws;
15381
15382 return retval;
15383 }
15384
15385 #ifdef FEAT_FLOAT
15386
15387 /*
15388 * round() is not in C90, use ceil() or floor() instead.
15389 */
15390 float_T
15391 vim_round(float_T f)
15392 {
15393 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
15394 }
15395
15396 /*
15397 * "round({float})" function
15398 */
15399 static void
15400 f_round(typval_T *argvars, typval_T *rettv)
15401 {
15402 float_T f = 0.0;
15403
15404 rettv->v_type = VAR_FLOAT;
15405 if (get_float_arg(argvars, &f) == OK)
15406 rettv->vval.v_float = vim_round(f);
15407 else
15408 rettv->vval.v_float = 0.0;
15409 }
15410 #endif
15411
15412 /*
15413 * "screenattr()" function
15414 */
15415 static void
15416 f_screenattr(typval_T *argvars, typval_T *rettv)
15417 {
15418 int row;
15419 int col;
15420 int c;
15421
15422 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
15423 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
15424 if (row < 0 || row >= screen_Rows
15425 || col < 0 || col >= screen_Columns)
15426 c = -1;
15427 else
15428 c = ScreenAttrs[LineOffset[row] + col];
15429 rettv->vval.v_number = c;
15430 }
15431
15432 /*
15433 * "screenchar()" function
15434 */
15435 static void
15436 f_screenchar(typval_T *argvars, typval_T *rettv)
15437 {
15438 int row;
15439 int col;
15440 int off;
15441 int c;
15442
15443 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
15444 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
15445 if (row < 0 || row >= screen_Rows
15446 || col < 0 || col >= screen_Columns)
15447 c = -1;
15448 else
15449 {
15450 off = LineOffset[row] + col;
15451 #ifdef FEAT_MBYTE
15452 if (enc_utf8 && ScreenLinesUC[off] != 0)
15453 c = ScreenLinesUC[off];
15454 else
15455 #endif
15456 c = ScreenLines[off];
15457 }
15458 rettv->vval.v_number = c;
15459 }
15460
15461 /*
15462 * "screencol()" function
15463 *
15464 * First column is 1 to be consistent with virtcol().
15465 */
15466 static void
15467 f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
15468 {
15469 rettv->vval.v_number = screen_screencol() + 1;
15470 }
15471
15472 /*
15473 * "screenrow()" function
15474 */
15475 static void
15476 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
15477 {
15478 rettv->vval.v_number = screen_screenrow() + 1;
15479 }
15480
15481 /*
15482 * "search()" function
15483 */
15484 static void
15485 f_search(typval_T *argvars, typval_T *rettv)
15486 {
15487 int flags = 0;
15488
15489 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
15490 }
15491
15492 /*
15493 * "searchdecl()" function
15494 */
15495 static void
15496 f_searchdecl(typval_T *argvars, typval_T *rettv)
15497 {
15498 int locally = 1;
15499 int thisblock = 0;
15500 int error = FALSE;
15501 char_u *name;
15502
15503 rettv->vval.v_number = 1; /* default: FAIL */
15504
15505 name = get_tv_string_chk(&argvars[0]);
15506 if (argvars[1].v_type != VAR_UNKNOWN)
15507 {
15508 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
15509 if (!error && argvars[2].v_type != VAR_UNKNOWN)
15510 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
15511 }
15512 if (!error && name != NULL)
15513 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
15514 locally, thisblock, SEARCH_KEEP) == FAIL;
15515 }
15516
15517 /*
15518 * Used by searchpair() and searchpairpos()
15519 */
15520 static int
15521 searchpair_cmn(typval_T *argvars, pos_T *match_pos)
15522 {
15523 char_u *spat, *mpat, *epat;
15524 char_u *skip;
15525 int save_p_ws = p_ws;
15526 int dir;
15527 int flags = 0;
15528 char_u nbuf1[NUMBUFLEN];
15529 char_u nbuf2[NUMBUFLEN];
15530 char_u nbuf3[NUMBUFLEN];
15531 int retval = 0; /* default: FAIL */
15532 long lnum_stop = 0;
15533 long time_limit = 0;
15534
15535 /* Get the three pattern arguments: start, middle, end. */
15536 spat = get_tv_string_chk(&argvars[0]);
15537 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
15538 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
15539 if (spat == NULL || mpat == NULL || epat == NULL)
15540 goto theend; /* type error */
15541
15542 /* Handle the optional fourth argument: flags */
15543 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
15544 if (dir == 0)
15545 goto theend;
15546
15547 /* Don't accept SP_END or SP_SUBPAT.
15548 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
15549 */
15550 if ((flags & (SP_END | SP_SUBPAT)) != 0
15551 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
15552 {
15553 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
15554 goto theend;
15555 }
15556
15557 /* Using 'r' implies 'W', otherwise it doesn't work. */
15558 if (flags & SP_REPEAT)
15559 p_ws = FALSE;
15560
15561 /* Optional fifth argument: skip expression */
15562 if (argvars[3].v_type == VAR_UNKNOWN
15563 || argvars[4].v_type == VAR_UNKNOWN)
15564 skip = (char_u *)"";
15565 else
15566 {
15567 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
15568 if (argvars[5].v_type != VAR_UNKNOWN)
15569 {
15570 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
15571 if (lnum_stop < 0)
15572 goto theend;
15573 #ifdef FEAT_RELTIME
15574 if (argvars[6].v_type != VAR_UNKNOWN)
15575 {
15576 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
15577 if (time_limit < 0)
15578 goto theend;
15579 }
15580 #endif
15581 }
15582 }
15583 if (skip == NULL)
15584 goto theend; /* type error */
15585
15586 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
15587 match_pos, lnum_stop, time_limit);
15588
15589 theend:
15590 p_ws = save_p_ws;
15591
15592 return retval;
15593 }
15594
15595 /*
15596 * "searchpair()" function
15597 */
15598 static void
15599 f_searchpair(typval_T *argvars, typval_T *rettv)
15600 {
15601 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
15602 }
15603
15604 /*
15605 * "searchpairpos()" function
15606 */
15607 static void
15608 f_searchpairpos(typval_T *argvars, typval_T *rettv)
15609 {
15610 pos_T match_pos;
15611 int lnum = 0;
15612 int col = 0;
15613
15614 if (rettv_list_alloc(rettv) == FAIL)
15615 return;
15616
15617 if (searchpair_cmn(argvars, &match_pos) > 0)
15618 {
15619 lnum = match_pos.lnum;
15620 col = match_pos.col;
15621 }
15622
15623 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
15624 list_append_number(rettv->vval.v_list, (varnumber_T)col);
15625 }
15626
15627 /*
15628 * Search for a start/middle/end thing.
15629 * Used by searchpair(), see its documentation for the details.
15630 * Returns 0 or -1 for no match,
15631 */
15632 long
15633 do_searchpair(
15634 char_u *spat, /* start pattern */
15635 char_u *mpat, /* middle pattern */
15636 char_u *epat, /* end pattern */
15637 int dir, /* BACKWARD or FORWARD */
15638 char_u *skip, /* skip expression */
15639 int flags, /* SP_SETPCMARK and other SP_ values */
15640 pos_T *match_pos,
15641 linenr_T lnum_stop, /* stop at this line if not zero */
15642 long time_limit UNUSED) /* stop after this many msec */
15643 {
15644 char_u *save_cpo;
15645 char_u *pat, *pat2 = NULL, *pat3 = NULL;
15646 long retval = 0;
15647 pos_T pos;
15648 pos_T firstpos;
15649 pos_T foundpos;
15650 pos_T save_cursor;
15651 pos_T save_pos;
15652 int n;
15653 int r;
15654 int nest = 1;
15655 int err;
15656 int options = SEARCH_KEEP;
15657 proftime_T tm;
15658
15659 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
15660 save_cpo = p_cpo;
15661 p_cpo = empty_option;
15662
15663 #ifdef FEAT_RELTIME
15664 /* Set the time limit, if there is one. */
15665 profile_setlimit(time_limit, &tm);
15666 #endif
15667
15668 /* Make two search patterns: start/end (pat2, for in nested pairs) and
15669 * start/middle/end (pat3, for the top pair). */
15670 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15));
15671 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23));
15672 if (pat2 == NULL || pat3 == NULL)
15673 goto theend;
15674 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
15675 if (*mpat == NUL)
15676 STRCPY(pat3, pat2);
15677 else
15678 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
15679 spat, epat, mpat);
15680 if (flags & SP_START)
15681 options |= SEARCH_START;
15682
15683 save_cursor = curwin->w_cursor;
15684 pos = curwin->w_cursor;
15685 clearpos(&firstpos);
15686 clearpos(&foundpos);
15687 pat = pat3;
15688 for (;;)
15689 {
15690 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
15691 options, RE_SEARCH, lnum_stop, &tm);
15692 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
15693 /* didn't find it or found the first match again: FAIL */
15694 break;
15695
15696 if (firstpos.lnum == 0)
15697 firstpos = pos;
15698 if (equalpos(pos, foundpos))
15699 {
15700 /* Found the same position again. Can happen with a pattern that
15701 * has "\zs" at the end and searching backwards. Advance one
15702 * character and try again. */
15703 if (dir == BACKWARD)
15704 decl(&pos);
15705 else
15706 incl(&pos);
15707 }
15708 foundpos = pos;
15709
15710 /* clear the start flag to avoid getting stuck here */
15711 options &= ~SEARCH_START;
15712
15713 /* If the skip pattern matches, ignore this match. */
15714 if (*skip != NUL)
15715 {
15716 save_pos = curwin->w_cursor;
15717 curwin->w_cursor = pos;
15718 r = eval_to_bool(skip, &err, NULL, FALSE);
15719 curwin->w_cursor = save_pos;
15720 if (err)
15721 {
15722 /* Evaluating {skip} caused an error, break here. */
15723 curwin->w_cursor = save_cursor;
15724 retval = -1;
15725 break;
15726 }
15727 if (r)
15728 continue;
15729 }
15730
15731 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
15732 {
15733 /* Found end when searching backwards or start when searching
15734 * forward: nested pair. */
15735 ++nest;
15736 pat = pat2; /* nested, don't search for middle */
15737 }
15738 else
15739 {
15740 /* Found end when searching forward or start when searching
15741 * backward: end of (nested) pair; or found middle in outer pair. */
15742 if (--nest == 1)
15743 pat = pat3; /* outer level, search for middle */
15744 }
15745
15746 if (nest == 0)
15747 {
15748 /* Found the match: return matchcount or line number. */
15749 if (flags & SP_RETCOUNT)
15750 ++retval;
15751 else
15752 retval = pos.lnum;
15753 if (flags & SP_SETPCMARK)
15754 setpcmark();
15755 curwin->w_cursor = pos;
15756 if (!(flags & SP_REPEAT))
15757 break;
15758 nest = 1; /* search for next unmatched */
15759 }
15760 }
15761
15762 if (match_pos != NULL)
15763 {
15764 /* Store the match cursor position */
15765 match_pos->lnum = curwin->w_cursor.lnum;
15766 match_pos->col = curwin->w_cursor.col + 1;
15767 }
15768
15769 /* If 'n' flag is used or search failed: restore cursor position. */
15770 if ((flags & SP_NOMOVE) || retval == 0)
15771 curwin->w_cursor = save_cursor;
15772
15773 theend:
15774 vim_free(pat2);
15775 vim_free(pat3);
15776 if (p_cpo == empty_option)
15777 p_cpo = save_cpo;
15778 else
15779 /* Darn, evaluating the {skip} expression changed the value. */
15780 free_string_option(save_cpo);
15781
15782 return retval;
15783 }
15784
15785 /*
15786 * "searchpos()" function
15787 */
15788 static void
15789 f_searchpos(typval_T *argvars, typval_T *rettv)
15790 {
15791 pos_T match_pos;
15792 int lnum = 0;
15793 int col = 0;
15794 int n;
15795 int flags = 0;
15796
15797 if (rettv_list_alloc(rettv) == FAIL)
15798 return;
15799
15800 n = search_cmn(argvars, &match_pos, &flags);
15801 if (n > 0)
15802 {
15803 lnum = match_pos.lnum;
15804 col = match_pos.col;
15805 }
15806
15807 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
15808 list_append_number(rettv->vval.v_list, (varnumber_T)col);
15809 if (flags & SP_SUBPAT)
15810 list_append_number(rettv->vval.v_list, (varnumber_T)n);
15811 }
15812
15813 static void
15814 f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
15815 {
15816 #ifdef FEAT_CLIENTSERVER
15817 char_u buf[NUMBUFLEN];
15818 char_u *server = get_tv_string_chk(&argvars[0]);
15819 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
15820
15821 rettv->vval.v_number = -1;
15822 if (server == NULL || reply == NULL)
15823 return;
15824 if (check_restricted() || check_secure())
15825 return;
15826 # ifdef FEAT_X11
15827 if (check_connection() == FAIL)
15828 return;
15829 # endif
15830
15831 if (serverSendReply(server, reply) < 0)
15832 {
15833 EMSG(_("E258: Unable to send to client"));
15834 return;
15835 }
15836 rettv->vval.v_number = 0;
15837 #else
15838 rettv->vval.v_number = -1;
15839 #endif
15840 }
15841
15842 static void
15843 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
15844 {
15845 char_u *r = NULL;
15846
15847 #ifdef FEAT_CLIENTSERVER
15848 # ifdef WIN32
15849 r = serverGetVimNames();
15850 # else
15851 make_connection();
15852 if (X_DISPLAY != NULL)
15853 r = serverGetVimNames(X_DISPLAY);
15854 # endif
15855 #endif
15856 rettv->v_type = VAR_STRING;
15857 rettv->vval.v_string = r;
15858 }
15859
15860 /*
15861 * "setbufvar()" function
15862 */
15863 static void
15864 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
15865 {
15866 buf_T *buf;
15867 char_u *varname, *bufvarname;
15868 typval_T *varp;
15869 char_u nbuf[NUMBUFLEN];
15870
15871 if (check_restricted() || check_secure())
15872 return;
15873 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
15874 varname = get_tv_string_chk(&argvars[1]);
15875 buf = get_buf_tv(&argvars[0], FALSE);
15876 varp = &argvars[2];
15877
15878 if (buf != NULL && varname != NULL && varp != NULL)
15879 {
15880 if (*varname == '&')
15881 {
15882 long numval;
15883 char_u *strval;
15884 int error = FALSE;
15885 aco_save_T aco;
15886
15887 /* set curbuf to be our buf, temporarily */
15888 aucmd_prepbuf(&aco, buf);
15889
15890 ++varname;
15891 numval = (long)get_tv_number_chk(varp, &error);
15892 strval = get_tv_string_buf_chk(varp, nbuf);
15893 if (!error && strval != NULL)
15894 set_option_value(varname, numval, strval, OPT_LOCAL);
15895
15896 /* reset notion of buffer */
15897 aucmd_restbuf(&aco);
15898 }
15899 else
15900 {
15901 buf_T *save_curbuf = curbuf;
15902
15903 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
15904 if (bufvarname != NULL)
15905 {
15906 curbuf = buf;
15907 STRCPY(bufvarname, "b:");
15908 STRCPY(bufvarname + 2, varname);
15909 set_var(bufvarname, varp, TRUE);
15910 vim_free(bufvarname);
15911 curbuf = save_curbuf;
15912 }
15913 }
15914 }
15915 }
15916
15917 static void
15918 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
15919 {
15920 dict_T *d;
15921 dictitem_T *di;
15922 char_u *csearch;
15923
15924 if (argvars[0].v_type != VAR_DICT)
15925 {
15926 EMSG(_(e_dictreq));
15927 return;
15928 }
15929
15930 if ((d = argvars[0].vval.v_dict) != NULL)
15931 {
15932 csearch = get_dict_string(d, (char_u *)"char", FALSE);
15933 if (csearch != NULL)
15934 {
15935 #ifdef FEAT_MBYTE
15936 if (enc_utf8)
15937 {
15938 int pcc[MAX_MCO];
15939 int c = utfc_ptr2char(csearch, pcc);
15940
15941 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
15942 }
15943 else
15944 #endif
15945 set_last_csearch(PTR2CHAR(csearch),
15946 csearch, MB_PTR2LEN(csearch));
15947 }
15948
15949 di = dict_find(d, (char_u *)"forward", -1);
15950 if (di != NULL)
15951 set_csearch_direction((int)get_tv_number(&di->di_tv)
15952 ? FORWARD : BACKWARD);
15953
15954 di = dict_find(d, (char_u *)"until", -1);
15955 if (di != NULL)
15956 set_csearch_until(!!get_tv_number(&di->di_tv));
15957 }
15958 }
15959
15960 /*
15961 * "setcmdpos()" function
15962 */
15963 static void
15964 f_setcmdpos(typval_T *argvars, typval_T *rettv)
15965 {
15966 int pos = (int)get_tv_number(&argvars[0]) - 1;
15967
15968 if (pos >= 0)
15969 rettv->vval.v_number = set_cmdline_pos(pos);
15970 }
15971
15972 /*
15973 * "setfperm({fname}, {mode})" function
15974 */
15975 static void
15976 f_setfperm(typval_T *argvars, typval_T *rettv)
15977 {
15978 char_u *fname;
15979 char_u modebuf[NUMBUFLEN];
15980 char_u *mode_str;
15981 int i;
15982 int mask;
15983 int mode = 0;
15984
15985 rettv->vval.v_number = 0;
15986 fname = get_tv_string_chk(&argvars[0]);
15987 if (fname == NULL)
15988 return;
15989 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
15990 if (mode_str == NULL)
15991 return;
15992 if (STRLEN(mode_str) != 9)
15993 {
15994 EMSG2(_(e_invarg2), mode_str);
15995 return;
15996 }
15997
15998 mask = 1;
15999 for (i = 8; i >= 0; --i)
16000 {
16001 if (mode_str[i] != '-')
16002 mode |= mask;
16003 mask = mask << 1;
16004 }
16005 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
16006 }
16007
16008 /*
16009 * "setline()" function
16010 */
16011 static void
16012 f_setline(typval_T *argvars, typval_T *rettv)
16013 {
16014 linenr_T lnum;
16015 char_u *line = NULL;
16016 list_T *l = NULL;
16017 listitem_T *li = NULL;
16018 long added = 0;
16019 linenr_T lcount = curbuf->b_ml.ml_line_count;
16020
16021 lnum = get_tv_lnum(&argvars[0]);
16022 if (argvars[1].v_type == VAR_LIST)
16023 {
16024 l = argvars[1].vval.v_list;
16025 li = l->lv_first;
16026 }
16027 else
16028 line = get_tv_string_chk(&argvars[1]);
16029
16030 /* default result is zero == OK */
16031 for (;;)
16032 {
16033 if (l != NULL)
16034 {
16035 /* list argument, get next string */
16036 if (li == NULL)
16037 break;
16038 line = get_tv_string_chk(&li->li_tv);
16039 li = li->li_next;
16040 }
16041
16042 rettv->vval.v_number = 1; /* FAIL */
16043 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
16044 break;
16045
16046 /* When coming here from Insert mode, sync undo, so that this can be
16047 * undone separately from what was previously inserted. */
16048 if (u_sync_once == 2)
16049 {
16050 u_sync_once = 1; /* notify that u_sync() was called */
16051 u_sync(TRUE);
16052 }
16053
16054 if (lnum <= curbuf->b_ml.ml_line_count)
16055 {
16056 /* existing line, replace it */
16057 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
16058 {
16059 changed_bytes(lnum, 0);
16060 if (lnum == curwin->w_cursor.lnum)
16061 check_cursor_col();
16062 rettv->vval.v_number = 0; /* OK */
16063 }
16064 }
16065 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
16066 {
16067 /* lnum is one past the last line, append the line */
16068 ++added;
16069 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
16070 rettv->vval.v_number = 0; /* OK */
16071 }
16072
16073 if (l == NULL) /* only one string argument */
16074 break;
16075 ++lnum;
16076 }
16077
16078 if (added > 0)
16079 appended_lines_mark(lcount, added);
16080 }
16081
16082 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv);
16083
16084 /*
16085 * Used by "setqflist()" and "setloclist()" functions
16086 */
16087 static void
16088 set_qf_ll_list(
16089 win_T *wp UNUSED,
16090 typval_T *list_arg UNUSED,
16091 typval_T *action_arg UNUSED,
16092 typval_T *rettv)
16093 {
16094 #ifdef FEAT_QUICKFIX
16095 static char *e_invact = N_("E927: Invalid action: '%s'");
16096 char_u *act;
16097 int action = 0;
16098 #endif
16099
16100 rettv->vval.v_number = -1;
16101
16102 #ifdef FEAT_QUICKFIX
16103 if (list_arg->v_type != VAR_LIST)
16104 EMSG(_(e_listreq));
16105 else
16106 {
16107 list_T *l = list_arg->vval.v_list;
16108
16109 if (action_arg->v_type == VAR_STRING)
16110 {
16111 act = get_tv_string_chk(action_arg);
16112 if (act == NULL)
16113 return; /* type error; errmsg already given */
16114 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL)
16115 action = *act;
16116 else
16117 EMSG2(_(e_invact), act);
16118 }
16119 else if (action_arg->v_type == VAR_UNKNOWN)
16120 action = ' ';
16121 else
16122 EMSG(_(e_stringreq));
16123
16124 if (l != NULL && action && set_errorlist(wp, l, action,
16125 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK)
16126 rettv->vval.v_number = 0;
16127 }
16128 #endif
16129 }
16130
16131 /*
16132 * "setloclist()" function
16133 */
16134 static void
16135 f_setloclist(typval_T *argvars, typval_T *rettv)
16136 {
16137 win_T *win;
16138
16139 rettv->vval.v_number = -1;
16140
16141 win = find_win_by_nr(&argvars[0], NULL);
16142 if (win != NULL)
16143 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv);
16144 }
16145
16146 /*
16147 * "setmatches()" function
16148 */
16149 static void
16150 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
16151 {
16152 #ifdef FEAT_SEARCH_EXTRA
16153 list_T *l;
16154 listitem_T *li;
16155 dict_T *d;
16156 list_T *s = NULL;
16157
16158 rettv->vval.v_number = -1;
16159 if (argvars[0].v_type != VAR_LIST)
16160 {
16161 EMSG(_(e_listreq));
16162 return;
16163 }
16164 if ((l = argvars[0].vval.v_list) != NULL)
16165 {
16166
16167 /* To some extent make sure that we are dealing with a list from
16168 * "getmatches()". */
16169 li = l->lv_first;
16170 while (li != NULL)
16171 {
16172 if (li->li_tv.v_type != VAR_DICT
16173 || (d = li->li_tv.vval.v_dict) == NULL)
16174 {
16175 EMSG(_(e_invarg));
16176 return;
16177 }
16178 if (!(dict_find(d, (char_u *)"group", -1) != NULL
16179 && (dict_find(d, (char_u *)"pattern", -1) != NULL
16180 || dict_find(d, (char_u *)"pos1", -1) != NULL)
16181 && dict_find(d, (char_u *)"priority", -1) != NULL
16182 && dict_find(d, (char_u *)"id", -1) != NULL))
16183 {
16184 EMSG(_(e_invarg));
16185 return;
16186 }
16187 li = li->li_next;
16188 }
16189
16190 clear_matches(curwin);
16191 li = l->lv_first;
16192 while (li != NULL)
16193 {
16194 int i = 0;
16195 char_u buf[5];
16196 dictitem_T *di;
16197 char_u *group;
16198 int priority;
16199 int id;
16200 char_u *conceal;
16201
16202 d = li->li_tv.vval.v_dict;
16203 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
16204 {
16205 if (s == NULL)
16206 {
16207 s = list_alloc();
16208 if (s == NULL)
16209 return;
16210 }
16211
16212 /* match from matchaddpos() */
16213 for (i = 1; i < 9; i++)
16214 {
16215 sprintf((char *)buf, (char *)"pos%d", i);
16216 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
16217 {
16218 if (di->di_tv.v_type != VAR_LIST)
16219 return;
16220
16221 list_append_tv(s, &di->di_tv);
16222 s->lv_refcount++;
16223 }
16224 else
16225 break;
16226 }
16227 }
16228
16229 group = get_dict_string(d, (char_u *)"group", FALSE);
16230 priority = (int)get_dict_number(d, (char_u *)"priority");
16231 id = (int)get_dict_number(d, (char_u *)"id");
16232 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
16233 ? get_dict_string(d, (char_u *)"conceal", FALSE)
16234 : NULL;
16235 if (i == 0)
16236 {
16237 match_add(curwin, group,
16238 get_dict_string(d, (char_u *)"pattern", FALSE),
16239 priority, id, NULL, conceal);
16240 }
16241 else
16242 {
16243 match_add(curwin, group, NULL, priority, id, s, conceal);
16244 list_unref(s);
16245 s = NULL;
16246 }
16247
16248 li = li->li_next;
16249 }
16250 rettv->vval.v_number = 0;
16251 }
16252 #endif
16253 }
16254
16255 /*
16256 * "setpos()" function
16257 */
16258 static void
16259 f_setpos(typval_T *argvars, typval_T *rettv)
16260 {
16261 pos_T pos;
16262 int fnum;
16263 char_u *name;
16264 colnr_T curswant = -1;
16265
16266 rettv->vval.v_number = -1;
16267 name = get_tv_string_chk(argvars);
16268 if (name != NULL)
16269 {
16270 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
16271 {
16272 if (--pos.col < 0)
16273 pos.col = 0;
16274 if (name[0] == '.' && name[1] == NUL)
16275 {
16276 /* set cursor */
16277 if (fnum == curbuf->b_fnum)
16278 {
16279 curwin->w_cursor = pos;
16280 if (curswant >= 0)
16281 {
16282 curwin->w_curswant = curswant - 1;
16283 curwin->w_set_curswant = FALSE;
16284 }
16285 check_cursor();
16286 rettv->vval.v_number = 0;
16287 }
16288 else
16289 EMSG(_(e_invarg));
16290 }
16291 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
16292 {
16293 /* set mark */
16294 if (setmark_pos(name[1], &pos, fnum) == OK)
16295 rettv->vval.v_number = 0;
16296 }
16297 else
16298 EMSG(_(e_invarg));
16299 }
16300 }
16301 }
16302
16303 /*
16304 * "setqflist()" function
16305 */
16306 static void
16307 f_setqflist(typval_T *argvars, typval_T *rettv)
16308 {
16309 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv);
16310 }
16311
16312 /*
16313 * "setreg()" function
16314 */
16315 static void
16316 f_setreg(typval_T *argvars, typval_T *rettv)
16317 {
16318 int regname;
16319 char_u *strregname;
16320 char_u *stropt;
16321 char_u *strval;
16322 int append;
16323 char_u yank_type;
16324 long block_len;
16325
16326 block_len = -1;
16327 yank_type = MAUTO;
16328 append = FALSE;
16329
16330 strregname = get_tv_string_chk(argvars);
16331 rettv->vval.v_number = 1; /* FAIL is default */
16332
16333 if (strregname == NULL)
16334 return; /* type error; errmsg already given */
16335 regname = *strregname;
16336 if (regname == 0 || regname == '@')
16337 regname = '"';
16338
16339 if (argvars[2].v_type != VAR_UNKNOWN)
16340 {
16341 stropt = get_tv_string_chk(&argvars[2]);
16342 if (stropt == NULL)
16343 return; /* type error */
16344 for (; *stropt != NUL; ++stropt)
16345 switch (*stropt)
16346 {
16347 case 'a': case 'A': /* append */
16348 append = TRUE;
16349 break;
16350 case 'v': case 'c': /* character-wise selection */
16351 yank_type = MCHAR;
16352 break;
16353 case 'V': case 'l': /* line-wise selection */
16354 yank_type = MLINE;
16355 break;
16356 case 'b': case Ctrl_V: /* block-wise selection */
16357 yank_type = MBLOCK;
16358 if (VIM_ISDIGIT(stropt[1]))
16359 {
16360 ++stropt;
16361 block_len = getdigits(&stropt) - 1;
16362 --stropt;
16363 }
16364 break;
16365 }
16366 }
16367
16368 if (argvars[1].v_type == VAR_LIST)
16369 {
16370 char_u **lstval;
16371 char_u **allocval;
16372 char_u buf[NUMBUFLEN];
16373 char_u **curval;
16374 char_u **curallocval;
16375 list_T *ll = argvars[1].vval.v_list;
16376 listitem_T *li;
16377 int len;
16378
16379 /* If the list is NULL handle like an empty list. */
16380 len = ll == NULL ? 0 : ll->lv_len;
16381
16382 /* First half: use for pointers to result lines; second half: use for
16383 * pointers to allocated copies. */
16384 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
16385 if (lstval == NULL)
16386 return;
16387 curval = lstval;
16388 allocval = lstval + len + 2;
16389 curallocval = allocval;
16390
16391 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
16392 li = li->li_next)
16393 {
16394 strval = get_tv_string_buf_chk(&li->li_tv, buf);
16395 if (strval == NULL)
16396 goto free_lstval;
16397 if (strval == buf)
16398 {
16399 /* Need to make a copy, next get_tv_string_buf_chk() will
16400 * overwrite the string. */
16401 strval = vim_strsave(buf);
16402 if (strval == NULL)
16403 goto free_lstval;
16404 *curallocval++ = strval;
16405 }
16406 *curval++ = strval;
16407 }
16408 *curval++ = NULL;
16409
16410 write_reg_contents_lst(regname, lstval, -1,
16411 append, yank_type, block_len);
16412 free_lstval:
16413 while (curallocval > allocval)
16414 vim_free(*--curallocval);
16415 vim_free(lstval);
16416 }
16417 else
16418 {
16419 strval = get_tv_string_chk(&argvars[1]);
16420 if (strval == NULL)
16421 return;
16422 write_reg_contents_ex(regname, strval, -1,
16423 append, yank_type, block_len);
16424 }
16425 rettv->vval.v_number = 0;
16426 }
16427
16428 /*
16429 * "settabvar()" function
16430 */
16431 static void
16432 f_settabvar(typval_T *argvars, typval_T *rettv)
16433 {
16434 #ifdef FEAT_WINDOWS
16435 tabpage_T *save_curtab;
16436 tabpage_T *tp;
16437 #endif
16438 char_u *varname, *tabvarname;
16439 typval_T *varp;
16440
16441 rettv->vval.v_number = 0;
16442
16443 if (check_restricted() || check_secure())
16444 return;
16445
16446 #ifdef FEAT_WINDOWS
16447 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
16448 #endif
16449 varname = get_tv_string_chk(&argvars[1]);
16450 varp = &argvars[2];
16451
16452 if (varname != NULL && varp != NULL
16453 #ifdef FEAT_WINDOWS
16454 && tp != NULL
16455 #endif
16456 )
16457 {
16458 #ifdef FEAT_WINDOWS
16459 save_curtab = curtab;
16460 goto_tabpage_tp(tp, FALSE, FALSE);
16461 #endif
16462
16463 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
16464 if (tabvarname != NULL)
16465 {
16466 STRCPY(tabvarname, "t:");
16467 STRCPY(tabvarname + 2, varname);
16468 set_var(tabvarname, varp, TRUE);
16469 vim_free(tabvarname);
16470 }
16471
16472 #ifdef FEAT_WINDOWS
16473 /* Restore current tabpage */
16474 if (valid_tabpage(save_curtab))
16475 goto_tabpage_tp(save_curtab, FALSE, FALSE);
16476 #endif
16477 }
16478 }
16479
16480 /*
16481 * "settabwinvar()" function
16482 */
16483 static void
16484 f_settabwinvar(typval_T *argvars, typval_T *rettv)
16485 {
16486 setwinvar(argvars, rettv, 1);
16487 }
16488
16489 /*
16490 * "setwinvar()" function
16491 */
16492 static void
16493 f_setwinvar(typval_T *argvars, typval_T *rettv)
16494 {
16495 setwinvar(argvars, rettv, 0);
16496 }
16497
16498 /*
16499 * "setwinvar()" and "settabwinvar()" functions
16500 */
16501
16502 static void
16503 setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off)
16504 {
16505 win_T *win;
16506 #ifdef FEAT_WINDOWS
16507 win_T *save_curwin;
16508 tabpage_T *save_curtab;
16509 int need_switch_win;
16510 #endif
16511 char_u *varname, *winvarname;
16512 typval_T *varp;
16513 char_u nbuf[NUMBUFLEN];
16514 tabpage_T *tp = NULL;
16515
16516 if (check_restricted() || check_secure())
16517 return;
16518
16519 #ifdef FEAT_WINDOWS
16520 if (off == 1)
16521 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
16522 else
16523 tp = curtab;
16524 #endif
16525 win = find_win_by_nr(&argvars[off], tp);
16526 varname = get_tv_string_chk(&argvars[off + 1]);
16527 varp = &argvars[off + 2];
16528
16529 if (win != NULL && varname != NULL && varp != NULL)
16530 {
16531 #ifdef FEAT_WINDOWS
16532 need_switch_win = !(tp == curtab && win == curwin);
16533 if (!need_switch_win
16534 || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK)
16535 #endif
16536 {
16537 if (*varname == '&')
16538 {
16539 long numval;
16540 char_u *strval;
16541 int error = FALSE;
16542
16543 ++varname;
16544 numval = (long)get_tv_number_chk(varp, &error);
16545 strval = get_tv_string_buf_chk(varp, nbuf);
16546 if (!error && strval != NULL)
16547 set_option_value(varname, numval, strval, OPT_LOCAL);
16548 }
16549 else
16550 {
16551 winvarname = alloc((unsigned)STRLEN(varname) + 3);
16552 if (winvarname != NULL)
16553 {
16554 STRCPY(winvarname, "w:");
16555 STRCPY(winvarname + 2, varname);
16556 set_var(winvarname, varp, TRUE);
16557 vim_free(winvarname);
16558 }
16559 }
16560 }
16561 #ifdef FEAT_WINDOWS
16562 if (need_switch_win)
16563 restore_win(save_curwin, save_curtab, TRUE);
16564 #endif
16565 }
16566 }
16567
16568 #ifdef FEAT_CRYPT
16569 /*
16570 * "sha256({string})" function
16571 */
16572 static void
16573 f_sha256(typval_T *argvars, typval_T *rettv)
16574 {
16575 char_u *p;
16576
16577 p = get_tv_string(&argvars[0]);
16578 rettv->vval.v_string = vim_strsave(
16579 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
16580 rettv->v_type = VAR_STRING;
16581 }
16582 #endif /* FEAT_CRYPT */
16583
16584 /*
16585 * "shellescape({string})" function
16586 */
16587 static void
16588 f_shellescape(typval_T *argvars, typval_T *rettv)
16589 {
16590 rettv->vval.v_string = vim_strsave_shellescape(
16591 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
16592 rettv->v_type = VAR_STRING;
16593 }
16594
16595 /*
16596 * shiftwidth() function
16597 */
16598 static void
16599 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
16600 {
16601 rettv->vval.v_number = get_sw_value(curbuf);
16602 }
16603
16604 /*
16605 * "simplify()" function
16606 */
16607 static void
16608 f_simplify(typval_T *argvars, typval_T *rettv)
16609 {
16610 char_u *p;
16611
16612 p = get_tv_string(&argvars[0]);
16613 rettv->vval.v_string = vim_strsave(p);
16614 simplify_filename(rettv->vval.v_string); /* simplify in place */
16615 rettv->v_type = VAR_STRING;
16616 }
16617
16618 #ifdef FEAT_FLOAT
16619 /*
16620 * "sin()" function
16621 */
16622 static void
16623 f_sin(typval_T *argvars, typval_T *rettv)
16624 {
16625 float_T f = 0.0;
16626
16627 rettv->v_type = VAR_FLOAT;
16628 if (get_float_arg(argvars, &f) == OK)
16629 rettv->vval.v_float = sin(f);
16630 else
16631 rettv->vval.v_float = 0.0;
16632 }
16633
16634 /*
16635 * "sinh()" function
16636 */
16637 static void
16638 f_sinh(typval_T *argvars, typval_T *rettv)
16639 {
16640 float_T f = 0.0;
16641
16642 rettv->v_type = VAR_FLOAT;
16643 if (get_float_arg(argvars, &f) == OK)
16644 rettv->vval.v_float = sinh(f);
16645 else
16646 rettv->vval.v_float = 0.0;
16647 }
16648 #endif
16649
16650 static int
16651 #ifdef __BORLANDC__
16652 _RTLENTRYF
16653 #endif
16654 item_compare(const void *s1, const void *s2);
16655 static int
16656 #ifdef __BORLANDC__
16657 _RTLENTRYF
16658 #endif
16659 item_compare2(const void *s1, const void *s2);
16660
16661 /* struct used in the array that's given to qsort() */
16662 typedef struct
16663 {
16664 listitem_T *item;
16665 int idx;
16666 } sortItem_T;
16667
16668 /* struct storing information about current sort */
16669 typedef struct
16670 {
16671 int item_compare_ic;
16672 int item_compare_numeric;
16673 int item_compare_numbers;
16674 #ifdef FEAT_FLOAT
16675 int item_compare_float;
16676 #endif
16677 char_u *item_compare_func;
16678 partial_T *item_compare_partial;
16679 dict_T *item_compare_selfdict;
16680 int item_compare_func_err;
16681 int item_compare_keep_zero;
16682 } sortinfo_T;
16683 static sortinfo_T *sortinfo = NULL;
16684 static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
16685 #define ITEM_COMPARE_FAIL 999
16686
16687 /*
16688 * Compare functions for f_sort() and f_uniq() below.
16689 */
16690 static int
16691 #ifdef __BORLANDC__
16692 _RTLENTRYF
16693 #endif
16694 item_compare(const void *s1, const void *s2)
16695 {
16696 sortItem_T *si1, *si2;
16697 typval_T *tv1, *tv2;
16698 char_u *p1, *p2;
16699 char_u *tofree1 = NULL, *tofree2 = NULL;
16700 int res;
16701 char_u numbuf1[NUMBUFLEN];
16702 char_u numbuf2[NUMBUFLEN];
16703
16704 si1 = (sortItem_T *)s1;
16705 si2 = (sortItem_T *)s2;
16706 tv1 = &si1->item->li_tv;
16707 tv2 = &si2->item->li_tv;
16708
16709 if (sortinfo->item_compare_numbers)
16710 {
16711 varnumber_T v1 = get_tv_number(tv1);
16712 varnumber_T v2 = get_tv_number(tv2);
16713
16714 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
16715 }
16716
16717 #ifdef FEAT_FLOAT
16718 if (sortinfo->item_compare_float)
16719 {
16720 float_T v1 = get_tv_float(tv1);
16721 float_T v2 = get_tv_float(tv2);
16722
16723 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
16724 }
16725 #endif
16726
16727 /* tv2string() puts quotes around a string and allocates memory. Don't do
16728 * that for string variables. Use a single quote when comparing with a
16729 * non-string to do what the docs promise. */
16730 if (tv1->v_type == VAR_STRING)
16731 {
16732 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
16733 p1 = (char_u *)"'";
16734 else
16735 p1 = tv1->vval.v_string;
16736 }
16737 else
16738 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
16739 if (tv2->v_type == VAR_STRING)
16740 {
16741 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
16742 p2 = (char_u *)"'";
16743 else
16744 p2 = tv2->vval.v_string;
16745 }
16746 else
16747 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
16748 if (p1 == NULL)
16749 p1 = (char_u *)"";
16750 if (p2 == NULL)
16751 p2 = (char_u *)"";
16752 if (!sortinfo->item_compare_numeric)
16753 {
16754 if (sortinfo->item_compare_ic)
16755 res = STRICMP(p1, p2);
16756 else
16757 res = STRCMP(p1, p2);
16758 }
16759 else
16760 {
16761 double n1, n2;
16762 n1 = strtod((char *)p1, (char **)&p1);
16763 n2 = strtod((char *)p2, (char **)&p2);
16764 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
16765 }
16766
16767 /* When the result would be zero, compare the item indexes. Makes the
16768 * sort stable. */
16769 if (res == 0 && !sortinfo->item_compare_keep_zero)
16770 res = si1->idx > si2->idx ? 1 : -1;
16771
16772 vim_free(tofree1);
16773 vim_free(tofree2);
16774 return res;
16775 }
16776
16777 static int
16778 #ifdef __BORLANDC__
16779 _RTLENTRYF
16780 #endif
16781 item_compare2(const void *s1, const void *s2)
16782 {
16783 sortItem_T *si1, *si2;
16784 int res;
16785 typval_T rettv;
16786 typval_T argv[3];
16787 int dummy;
16788 char_u *func_name;
16789 partial_T *partial = sortinfo->item_compare_partial;
16790
16791 /* shortcut after failure in previous call; compare all items equal */
16792 if (sortinfo->item_compare_func_err)
16793 return 0;
16794
16795 si1 = (sortItem_T *)s1;
16796 si2 = (sortItem_T *)s2;
16797
16798 if (partial == NULL)
16799 func_name = sortinfo->item_compare_func;
16800 else
16801 func_name = partial->pt_name;
16802
16803 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
16804 * in the copy without changing the original list items. */
16805 copy_tv(&si1->item->li_tv, &argv[0]);
16806 copy_tv(&si2->item->li_tv, &argv[1]);
16807
16808 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
16809 res = call_func(func_name, (int)STRLEN(func_name),
16810 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
16811 partial, sortinfo->item_compare_selfdict);
16812 clear_tv(&argv[0]);
16813 clear_tv(&argv[1]);
16814
16815 if (res == FAIL)
16816 res = ITEM_COMPARE_FAIL;
16817 else
16818 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
16819 if (sortinfo->item_compare_func_err)
16820 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
16821 clear_tv(&rettv);
16822
16823 /* When the result would be zero, compare the pointers themselves. Makes
16824 * the sort stable. */
16825 if (res == 0 && !sortinfo->item_compare_keep_zero)
16826 res = si1->idx > si2->idx ? 1 : -1;
16827
16828 return res;
16829 }
16830
16831 /*
16832 * "sort({list})" function
16833 */
16834 static void
16835 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
16836 {
16837 list_T *l;
16838 listitem_T *li;
16839 sortItem_T *ptrs;
16840 sortinfo_T *old_sortinfo;
16841 sortinfo_T info;
16842 long len;
16843 long i;
16844
16845 /* Pointer to current info struct used in compare function. Save and
16846 * restore the current one for nested calls. */
16847 old_sortinfo = sortinfo;
16848 sortinfo = &info;
16849
16850 if (argvars[0].v_type != VAR_LIST)
16851 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
16852 else
16853 {
16854 l = argvars[0].vval.v_list;
16855 if (l == NULL || tv_check_lock(l->lv_lock,
16856 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
16857 TRUE))
16858 goto theend;
16859 rettv->vval.v_list = l;
16860 rettv->v_type = VAR_LIST;
16861 ++l->lv_refcount;
16862
16863 len = list_len(l);
16864 if (len <= 1)
16865 goto theend; /* short list sorts pretty quickly */
16866
16867 info.item_compare_ic = FALSE;
16868 info.item_compare_numeric = FALSE;
16869 info.item_compare_numbers = FALSE;
16870 #ifdef FEAT_FLOAT
16871 info.item_compare_float = FALSE;
16872 #endif
16873 info.item_compare_func = NULL;
16874 info.item_compare_partial = NULL;
16875 info.item_compare_selfdict = NULL;
16876 if (argvars[1].v_type != VAR_UNKNOWN)
16877 {
16878 /* optional second argument: {func} */
16879 if (argvars[1].v_type == VAR_FUNC)
16880 info.item_compare_func = argvars[1].vval.v_string;
16881 else if (argvars[1].v_type == VAR_PARTIAL)
16882 info.item_compare_partial = argvars[1].vval.v_partial;
16883 else
16884 {
16885 int error = FALSE;
16886
16887 i = (long)get_tv_number_chk(&argvars[1], &error);
16888 if (error)
16889 goto theend; /* type error; errmsg already given */
16890 if (i == 1)
16891 info.item_compare_ic = TRUE;
16892 else if (argvars[1].v_type != VAR_NUMBER)
16893 info.item_compare_func = get_tv_string(&argvars[1]);
16894 else if (i != 0)
16895 {
16896 EMSG(_(e_invarg));
16897 goto theend;
16898 }
16899 if (info.item_compare_func != NULL)
16900 {
16901 if (*info.item_compare_func == NUL)
16902 {
16903 /* empty string means default sort */
16904 info.item_compare_func = NULL;
16905 }
16906 else if (STRCMP(info.item_compare_func, "n") == 0)
16907 {
16908 info.item_compare_func = NULL;
16909 info.item_compare_numeric = TRUE;
16910 }
16911 else if (STRCMP(info.item_compare_func, "N") == 0)
16912 {
16913 info.item_compare_func = NULL;
16914 info.item_compare_numbers = TRUE;
16915 }
16916 #ifdef FEAT_FLOAT
16917 else if (STRCMP(info.item_compare_func, "f") == 0)
16918 {
16919 info.item_compare_func = NULL;
16920 info.item_compare_float = TRUE;
16921 }
16922 #endif
16923 else if (STRCMP(info.item_compare_func, "i") == 0)
16924 {
16925 info.item_compare_func = NULL;
16926 info.item_compare_ic = TRUE;
16927 }
16928 }
16929 }
16930
16931 if (argvars[2].v_type != VAR_UNKNOWN)
16932 {
16933 /* optional third argument: {dict} */
16934 if (argvars[2].v_type != VAR_DICT)
16935 {
16936 EMSG(_(e_dictreq));
16937 goto theend;
16938 }
16939 info.item_compare_selfdict = argvars[2].vval.v_dict;
16940 }
16941 }
16942
16943 /* Make an array with each entry pointing to an item in the List. */
16944 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
16945 if (ptrs == NULL)
16946 goto theend;
16947
16948 i = 0;
16949 if (sort)
16950 {
16951 /* sort(): ptrs will be the list to sort */
16952 for (li = l->lv_first; li != NULL; li = li->li_next)
16953 {
16954 ptrs[i].item = li;
16955 ptrs[i].idx = i;
16956 ++i;
16957 }
16958
16959 info.item_compare_func_err = FALSE;
16960 info.item_compare_keep_zero = FALSE;
16961 /* test the compare function */
16962 if ((info.item_compare_func != NULL
16963 || info.item_compare_partial != NULL)
16964 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
16965 == ITEM_COMPARE_FAIL)
16966 EMSG(_("E702: Sort compare function failed"));
16967 else
16968 {
16969 /* Sort the array with item pointers. */
16970 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
16971 info.item_compare_func == NULL
16972 && info.item_compare_partial == NULL
16973 ? item_compare : item_compare2);
16974
16975 if (!info.item_compare_func_err)
16976 {
16977 /* Clear the List and append the items in sorted order. */
16978 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
16979 l->lv_len = 0;
16980 for (i = 0; i < len; ++i)
16981 list_append(l, ptrs[i].item);
16982 }
16983 }
16984 }
16985 else
16986 {
16987 int (*item_compare_func_ptr)(const void *, const void *);
16988
16989 /* f_uniq(): ptrs will be a stack of items to remove */
16990 info.item_compare_func_err = FALSE;
16991 info.item_compare_keep_zero = TRUE;
16992 item_compare_func_ptr = info.item_compare_func != NULL
16993 || info.item_compare_partial != NULL
16994 ? item_compare2 : item_compare;
16995
16996 for (li = l->lv_first; li != NULL && li->li_next != NULL;
16997 li = li->li_next)
16998 {
16999 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
17000 == 0)
17001 ptrs[i++].item = li;
17002 if (info.item_compare_func_err)
17003 {
17004 EMSG(_("E882: Uniq compare function failed"));
17005 break;
17006 }
17007 }
17008
17009 if (!info.item_compare_func_err)
17010 {
17011 while (--i >= 0)
17012 {
17013 li = ptrs[i].item->li_next;
17014 ptrs[i].item->li_next = li->li_next;
17015 if (li->li_next != NULL)
17016 li->li_next->li_prev = ptrs[i].item;
17017 else
17018 l->lv_last = ptrs[i].item;
17019 list_fix_watch(l, li);
17020 listitem_free(li);
17021 l->lv_len--;
17022 }
17023 }
17024 }
17025
17026 vim_free(ptrs);
17027 }
17028 theend:
17029 sortinfo = old_sortinfo;
17030 }
17031
17032 /*
17033 * "sort({list})" function
17034 */
17035 static void
17036 f_sort(typval_T *argvars, typval_T *rettv)
17037 {
17038 do_sort_uniq(argvars, rettv, TRUE);
17039 }
17040
17041 /*
17042 * "uniq({list})" function
17043 */
17044 static void
17045 f_uniq(typval_T *argvars, typval_T *rettv)
17046 {
17047 do_sort_uniq(argvars, rettv, FALSE);
17048 }
17049
17050 /*
17051 * "soundfold({word})" function
17052 */
17053 static void
17054 f_soundfold(typval_T *argvars, typval_T *rettv)
17055 {
17056 char_u *s;
17057
17058 rettv->v_type = VAR_STRING;
17059 s = get_tv_string(&argvars[0]);
17060 #ifdef FEAT_SPELL
17061 rettv->vval.v_string = eval_soundfold(s);
17062 #else
17063 rettv->vval.v_string = vim_strsave(s);
17064 #endif
17065 }
17066
17067 /*
17068 * "spellbadword()" function
17069 */
17070 static void
17071 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
17072 {
17073 char_u *word = (char_u *)"";
17074 hlf_T attr = HLF_COUNT;
17075 int len = 0;
17076
17077 if (rettv_list_alloc(rettv) == FAIL)
17078 return;
17079
17080 #ifdef FEAT_SPELL
17081 if (argvars[0].v_type == VAR_UNKNOWN)
17082 {
17083 /* Find the start and length of the badly spelled word. */
17084 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
17085 if (len != 0)
17086 word = ml_get_cursor();
17087 }
17088 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
17089 {
17090 char_u *str = get_tv_string_chk(&argvars[0]);
17091 int capcol = -1;
17092
17093 if (str != NULL)
17094 {
17095 /* Check the argument for spelling. */
17096 while (*str != NUL)
17097 {
17098 len = spell_check(curwin, str, &attr, &capcol, FALSE);
17099 if (attr != HLF_COUNT)
17100 {
17101 word = str;
17102 break;
17103 }
17104 str += len;
17105 }
17106 }
17107 }
17108 #endif
17109
17110 list_append_string(rettv->vval.v_list, word, len);
17111 list_append_string(rettv->vval.v_list, (char_u *)(
17112 attr == HLF_SPB ? "bad" :
17113 attr == HLF_SPR ? "rare" :
17114 attr == HLF_SPL ? "local" :
17115 attr == HLF_SPC ? "caps" :
17116 ""), -1);
17117 }
17118
17119 /*
17120 * "spellsuggest()" function
17121 */
17122 static void
17123 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
17124 {
17125 #ifdef FEAT_SPELL
17126 char_u *str;
17127 int typeerr = FALSE;
17128 int maxcount;
17129 garray_T ga;
17130 int i;
17131 listitem_T *li;
17132 int need_capital = FALSE;
17133 #endif
17134
17135 if (rettv_list_alloc(rettv) == FAIL)
17136 return;
17137
17138 #ifdef FEAT_SPELL
17139 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
17140 {
17141 str = get_tv_string(&argvars[0]);
17142 if (argvars[1].v_type != VAR_UNKNOWN)
17143 {
17144 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
17145 if (maxcount <= 0)
17146 return;
17147 if (argvars[2].v_type != VAR_UNKNOWN)
17148 {
17149 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
17150 if (typeerr)
17151 return;
17152 }
17153 }
17154 else
17155 maxcount = 25;
17156
17157 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
17158
17159 for (i = 0; i < ga.ga_len; ++i)
17160 {
17161 str = ((char_u **)ga.ga_data)[i];
17162
17163 li = listitem_alloc();
17164 if (li == NULL)
17165 vim_free(str);
17166 else
17167 {
17168 li->li_tv.v_type = VAR_STRING;
17169 li->li_tv.v_lock = 0;
17170 li->li_tv.vval.v_string = str;
17171 list_append(rettv->vval.v_list, li);
17172 }
17173 }
17174 ga_clear(&ga);
17175 }
17176 #endif
17177 }
17178
17179 static void
17180 f_split(typval_T *argvars, typval_T *rettv)
17181 {
17182 char_u *str;
17183 char_u *end;
17184 char_u *pat = NULL;
17185 regmatch_T regmatch;
17186 char_u patbuf[NUMBUFLEN];
17187 char_u *save_cpo;
17188 int match;
17189 colnr_T col = 0;
17190 int keepempty = FALSE;
17191 int typeerr = FALSE;
17192
17193 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
17194 save_cpo = p_cpo;
17195 p_cpo = (char_u *)"";
17196
17197 str = get_tv_string(&argvars[0]);
17198 if (argvars[1].v_type != VAR_UNKNOWN)
17199 {
17200 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
17201 if (pat == NULL)
17202 typeerr = TRUE;
17203 if (argvars[2].v_type != VAR_UNKNOWN)
17204 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
17205 }
17206 if (pat == NULL || *pat == NUL)
17207 pat = (char_u *)"[\\x01- ]\\+";
17208
17209 if (rettv_list_alloc(rettv) == FAIL)
17210 return;
17211 if (typeerr)
17212 return;
17213
17214 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
17215 if (regmatch.regprog != NULL)
17216 {
17217 regmatch.rm_ic = FALSE;
17218 while (*str != NUL || keepempty)
17219 {
17220 if (*str == NUL)
17221 match = FALSE; /* empty item at the end */
17222 else
17223 match = vim_regexec_nl(&regmatch, str, col);
17224 if (match)
17225 end = regmatch.startp[0];
17226 else
17227 end = str + STRLEN(str);
17228 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
17229 && *str != NUL && match && end < regmatch.endp[0]))
17230 {
17231 if (list_append_string(rettv->vval.v_list, str,
17232 (int)(end - str)) == FAIL)
17233 break;
17234 }
17235 if (!match)
17236 break;
17237 /* Advance to just after the match. */
17238 if (regmatch.endp[0] > str)
17239 col = 0;
17240 else
17241 {
17242 /* Don't get stuck at the same match. */
17243 #ifdef FEAT_MBYTE
17244 col = (*mb_ptr2len)(regmatch.endp[0]);
17245 #else
17246 col = 1;
17247 #endif
17248 }
17249 str = regmatch.endp[0];
17250 }
17251
17252 vim_regfree(regmatch.regprog);
17253 }
17254
17255 p_cpo = save_cpo;
17256 }
17257
17258 #ifdef FEAT_FLOAT
17259 /*
17260 * "sqrt()" function
17261 */
17262 static void
17263 f_sqrt(typval_T *argvars, typval_T *rettv)
17264 {
17265 float_T f = 0.0;
17266
17267 rettv->v_type = VAR_FLOAT;
17268 if (get_float_arg(argvars, &f) == OK)
17269 rettv->vval.v_float = sqrt(f);
17270 else
17271 rettv->vval.v_float = 0.0;
17272 }
17273
17274 /*
17275 * "str2float()" function
17276 */
17277 static void
17278 f_str2float(typval_T *argvars, typval_T *rettv)
17279 {
17280 char_u *p = skipwhite(get_tv_string(&argvars[0]));
17281
17282 if (*p == '+')
17283 p = skipwhite(p + 1);
17284 (void)string2float(p, &rettv->vval.v_float);
17285 rettv->v_type = VAR_FLOAT;
17286 }
17287 #endif
17288
17289 /*
17290 * "str2nr()" function
17291 */
17292 static void
17293 f_str2nr(typval_T *argvars, typval_T *rettv)
17294 {
17295 int base = 10;
17296 char_u *p;
17297 varnumber_T n;
17298 int what;
17299
17300 if (argvars[1].v_type != VAR_UNKNOWN)
17301 {
17302 base = (int)get_tv_number(&argvars[1]);
17303 if (base != 2 && base != 8 && base != 10 && base != 16)
17304 {
17305 EMSG(_(e_invarg));
17306 return;
17307 }
17308 }
17309
17310 p = skipwhite(get_tv_string(&argvars[0]));
17311 if (*p == '+')
17312 p = skipwhite(p + 1);
17313 switch (base)
17314 {
17315 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
17316 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
17317 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
17318 default: what = 0;
17319 }
17320 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
17321 rettv->vval.v_number = n;
17322 }
17323
17324 #ifdef HAVE_STRFTIME
17325 /*
17326 * "strftime({format}[, {time}])" function
17327 */
17328 static void
17329 f_strftime(typval_T *argvars, typval_T *rettv)
17330 {
17331 char_u result_buf[256];
17332 struct tm *curtime;
17333 time_t seconds;
17334 char_u *p;
17335
17336 rettv->v_type = VAR_STRING;
17337
17338 p = get_tv_string(&argvars[0]);
17339 if (argvars[1].v_type == VAR_UNKNOWN)
17340 seconds = time(NULL);
17341 else
17342 seconds = (time_t)get_tv_number(&argvars[1]);
17343 curtime = localtime(&seconds);
17344 /* MSVC returns NULL for an invalid value of seconds. */
17345 if (curtime == NULL)
17346 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
17347 else
17348 {
17349 # ifdef FEAT_MBYTE
17350 vimconv_T conv;
17351 char_u *enc;
17352
17353 conv.vc_type = CONV_NONE;
17354 enc = enc_locale();
17355 convert_setup(&conv, p_enc, enc);
17356 if (conv.vc_type != CONV_NONE)
17357 p = string_convert(&conv, p, NULL);
17358 # endif
17359 if (p != NULL)
17360 (void)strftime((char *)result_buf, sizeof(result_buf),
17361 (char *)p, curtime);
17362 else
17363 result_buf[0] = NUL;
17364
17365 # ifdef FEAT_MBYTE
17366 if (conv.vc_type != CONV_NONE)
17367 vim_free(p);
17368 convert_setup(&conv, enc, p_enc);
17369 if (conv.vc_type != CONV_NONE)
17370 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
17371 else
17372 # endif
17373 rettv->vval.v_string = vim_strsave(result_buf);
17374
17375 # ifdef FEAT_MBYTE
17376 /* Release conversion descriptors */
17377 convert_setup(&conv, NULL, NULL);
17378 vim_free(enc);
17379 # endif
17380 }
17381 }
17382 #endif
17383
17384 /*
17385 * "strgetchar()" function
17386 */
17387 static void
17388 f_strgetchar(typval_T *argvars, typval_T *rettv)
17389 {
17390 char_u *str;
17391 int len;
17392 int error = FALSE;
17393 int charidx;
17394
17395 rettv->vval.v_number = -1;
17396 str = get_tv_string_chk(&argvars[0]);
17397 if (str == NULL)
17398 return;
17399 len = (int)STRLEN(str);
17400 charidx = (int)get_tv_number_chk(&argvars[1], &error);
17401 if (error)
17402 return;
17403 #ifdef FEAT_MBYTE
17404 {
17405 int byteidx = 0;
17406
17407 while (charidx >= 0 && byteidx < len)
17408 {
17409 if (charidx == 0)
17410 {
17411 rettv->vval.v_number = mb_ptr2char(str + byteidx);
17412 break;
17413 }
17414 --charidx;
17415 byteidx += mb_cptr2len(str + byteidx);
17416 }
17417 }
17418 #else
17419 if (charidx < len)
17420 rettv->vval.v_number = str[charidx];
17421 #endif
17422 }
17423
17424 /*
17425 * "stridx()" function
17426 */
17427 static void
17428 f_stridx(typval_T *argvars, typval_T *rettv)
17429 {
17430 char_u buf[NUMBUFLEN];
17431 char_u *needle;
17432 char_u *haystack;
17433 char_u *save_haystack;
17434 char_u *pos;
17435 int start_idx;
17436
17437 needle = get_tv_string_chk(&argvars[1]);
17438 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
17439 rettv->vval.v_number = -1;
17440 if (needle == NULL || haystack == NULL)
17441 return; /* type error; errmsg already given */
17442
17443 if (argvars[2].v_type != VAR_UNKNOWN)
17444 {
17445 int error = FALSE;
17446
17447 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
17448 if (error || start_idx >= (int)STRLEN(haystack))
17449 return;
17450 if (start_idx >= 0)
17451 haystack += start_idx;
17452 }
17453
17454 pos = (char_u *)strstr((char *)haystack, (char *)needle);
17455 if (pos != NULL)
17456 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
17457 }
17458
17459 /*
17460 * "string()" function
17461 */
17462 static void
17463 f_string(typval_T *argvars, typval_T *rettv)
17464 {
17465 char_u *tofree;
17466 char_u numbuf[NUMBUFLEN];
17467
17468 rettv->v_type = VAR_STRING;
17469 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
17470 get_copyID());
17471 /* Make a copy if we have a value but it's not in allocated memory. */
17472 if (rettv->vval.v_string != NULL && tofree == NULL)
17473 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
17474 }
17475
17476 /*
17477 * "strlen()" function
17478 */
17479 static void
17480 f_strlen(typval_T *argvars, typval_T *rettv)
17481 {
17482 rettv->vval.v_number = (varnumber_T)(STRLEN(
17483 get_tv_string(&argvars[0])));
17484 }
17485
17486 /*
17487 * "strchars()" function
17488 */
17489 static void
17490 f_strchars(typval_T *argvars, typval_T *rettv)
17491 {
17492 char_u *s = get_tv_string(&argvars[0]);
17493 int skipcc = 0;
17494 #ifdef FEAT_MBYTE
17495 varnumber_T len = 0;
17496 int (*func_mb_ptr2char_adv)(char_u **pp);
17497 #endif
17498
17499 if (argvars[1].v_type != VAR_UNKNOWN)
17500 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
17501 if (skipcc < 0 || skipcc > 1)
17502 EMSG(_(e_invarg));
17503 else
17504 {
17505 #ifdef FEAT_MBYTE
17506 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
17507 while (*s != NUL)
17508 {
17509 func_mb_ptr2char_adv(&s);
17510 ++len;
17511 }
17512 rettv->vval.v_number = len;
17513 #else
17514 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
17515 #endif
17516 }
17517 }
17518
17519 /*
17520 * "strdisplaywidth()" function
17521 */
17522 static void
17523 f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
17524 {
17525 char_u *s = get_tv_string(&argvars[0]);
17526 int col = 0;
17527
17528 if (argvars[1].v_type != VAR_UNKNOWN)
17529 col = (int)get_tv_number(&argvars[1]);
17530
17531 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
17532 }
17533
17534 /*
17535 * "strwidth()" function
17536 */
17537 static void
17538 f_strwidth(typval_T *argvars, typval_T *rettv)
17539 {
17540 char_u *s = get_tv_string(&argvars[0]);
17541
17542 rettv->vval.v_number = (varnumber_T)(
17543 #ifdef FEAT_MBYTE
17544 mb_string2cells(s, -1)
17545 #else
17546 STRLEN(s)
17547 #endif
17548 );
17549 }
17550
17551 /*
17552 * "strcharpart()" function
17553 */
17554 static void
17555 f_strcharpart(typval_T *argvars, typval_T *rettv)
17556 {
17557 #ifdef FEAT_MBYTE
17558 char_u *p;
17559 int nchar;
17560 int nbyte = 0;
17561 int charlen;
17562 int len = 0;
17563 int slen;
17564 int error = FALSE;
17565
17566 p = get_tv_string(&argvars[0]);
17567 slen = (int)STRLEN(p);
17568
17569 nchar = (int)get_tv_number_chk(&argvars[1], &error);
17570 if (!error)
17571 {
17572 if (nchar > 0)
17573 while (nchar > 0 && nbyte < slen)
17574 {
17575 nbyte += mb_cptr2len(p + nbyte);
17576 --nchar;
17577 }
17578 else
17579 nbyte = nchar;
17580 if (argvars[2].v_type != VAR_UNKNOWN)
17581 {
17582 charlen = (int)get_tv_number(&argvars[2]);
17583 while (charlen > 0 && nbyte + len < slen)
17584 {
17585 int off = nbyte + len;
17586
17587 if (off < 0)
17588 len += 1;
17589 else
17590 len += mb_cptr2len(p + off);
17591 --charlen;
17592 }
17593 }
17594 else
17595 len = slen - nbyte; /* default: all bytes that are available. */
17596 }
17597
17598 /*
17599 * Only return the overlap between the specified part and the actual
17600 * string.
17601 */
17602 if (nbyte < 0)
17603 {
17604 len += nbyte;
17605 nbyte = 0;
17606 }
17607 else if (nbyte > slen)
17608 nbyte = slen;
17609 if (len < 0)
17610 len = 0;
17611 else if (nbyte + len > slen)
17612 len = slen - nbyte;
17613
17614 rettv->v_type = VAR_STRING;
17615 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
17616 #else
17617 f_strpart(argvars, rettv);
17618 #endif
17619 }
17620
17621 /*
17622 * "strpart()" function
17623 */
17624 static void
17625 f_strpart(typval_T *argvars, typval_T *rettv)
17626 {
17627 char_u *p;
17628 int n;
17629 int len;
17630 int slen;
17631 int error = FALSE;
17632
17633 p = get_tv_string(&argvars[0]);
17634 slen = (int)STRLEN(p);
17635
17636 n = (int)get_tv_number_chk(&argvars[1], &error);
17637 if (error)
17638 len = 0;
17639 else if (argvars[2].v_type != VAR_UNKNOWN)
17640 len = (int)get_tv_number(&argvars[2]);
17641 else
17642 len = slen - n; /* default len: all bytes that are available. */
17643
17644 /*
17645 * Only return the overlap between the specified part and the actual
17646 * string.
17647 */
17648 if (n < 0)
17649 {
17650 len += n;
17651 n = 0;
17652 }
17653 else if (n > slen)
17654 n = slen;
17655 if (len < 0)
17656 len = 0;
17657 else if (n + len > slen)
17658 len = slen - n;
17659
17660 rettv->v_type = VAR_STRING;
17661 rettv->vval.v_string = vim_strnsave(p + n, len);
17662 }
17663
17664 /*
17665 * "strridx()" function
17666 */
17667 static void
17668 f_strridx(typval_T *argvars, typval_T *rettv)
17669 {
17670 char_u buf[NUMBUFLEN];
17671 char_u *needle;
17672 char_u *haystack;
17673 char_u *rest;
17674 char_u *lastmatch = NULL;
17675 int haystack_len, end_idx;
17676
17677 needle = get_tv_string_chk(&argvars[1]);
17678 haystack = get_tv_string_buf_chk(&argvars[0], buf);
17679
17680 rettv->vval.v_number = -1;
17681 if (needle == NULL || haystack == NULL)
17682 return; /* type error; errmsg already given */
17683
17684 haystack_len = (int)STRLEN(haystack);
17685 if (argvars[2].v_type != VAR_UNKNOWN)
17686 {
17687 /* Third argument: upper limit for index */
17688 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
17689 if (end_idx < 0)
17690 return; /* can never find a match */
17691 }
17692 else
17693 end_idx = haystack_len;
17694
17695 if (*needle == NUL)
17696 {
17697 /* Empty string matches past the end. */
17698 lastmatch = haystack + end_idx;
17699 }
17700 else
17701 {
17702 for (rest = haystack; *rest != '\0'; ++rest)
17703 {
17704 rest = (char_u *)strstr((char *)rest, (char *)needle);
17705 if (rest == NULL || rest > haystack + end_idx)
17706 break;
17707 lastmatch = rest;
17708 }
17709 }
17710
17711 if (lastmatch == NULL)
17712 rettv->vval.v_number = -1;
17713 else
17714 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
17715 }
17716
17717 /*
17718 * "strtrans()" function
17719 */
17720 static void
17721 f_strtrans(typval_T *argvars, typval_T *rettv)
17722 {
17723 rettv->v_type = VAR_STRING;
17724 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
17725 }
17726
17727 /*
17728 * "submatch()" function
17729 */
17730 static void
17731 f_submatch(typval_T *argvars, typval_T *rettv)
17732 {
17733 int error = FALSE;
17734 int no;
17735 int retList = 0;
17736
17737 no = (int)get_tv_number_chk(&argvars[0], &error);
17738 if (error)
17739 return;
17740 error = FALSE;
17741 if (argvars[1].v_type != VAR_UNKNOWN)
17742 retList = (int)get_tv_number_chk(&argvars[1], &error);
17743 if (error)
17744 return;
17745
17746 if (retList == 0)
17747 {
17748 rettv->v_type = VAR_STRING;
17749 rettv->vval.v_string = reg_submatch(no);
17750 }
17751 else
17752 {
17753 rettv->v_type = VAR_LIST;
17754 rettv->vval.v_list = reg_submatch_list(no);
17755 }
17756 }
17757
17758 /*
17759 * "substitute()" function
17760 */
17761 static void
17762 f_substitute(typval_T *argvars, typval_T *rettv)
17763 {
17764 char_u patbuf[NUMBUFLEN];
17765 char_u subbuf[NUMBUFLEN];
17766 char_u flagsbuf[NUMBUFLEN];
17767
17768 char_u *str = get_tv_string_chk(&argvars[0]);
17769 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
17770 char_u *sub = get_tv_string_buf_chk(&argvars[2], subbuf);
17771 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
17772
17773 rettv->v_type = VAR_STRING;
17774 if (str == NULL || pat == NULL || sub == NULL || flg == NULL)
17775 rettv->vval.v_string = NULL;
17776 else
17777 rettv->vval.v_string = do_string_sub(str, pat, sub, flg);
17778 }
17779
17780 /*
17781 * "synID(lnum, col, trans)" function
17782 */
17783 static void
17784 f_synID(typval_T *argvars UNUSED, typval_T *rettv)
17785 {
17786 int id = 0;
17787 #ifdef FEAT_SYN_HL
17788 linenr_T lnum;
17789 colnr_T col;
17790 int trans;
17791 int transerr = FALSE;
17792
17793 lnum = get_tv_lnum(argvars); /* -1 on type error */
17794 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
17795 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
17796
17797 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
17798 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
17799 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
17800 #endif
17801
17802 rettv->vval.v_number = id;
17803 }
17804
17805 /*
17806 * "synIDattr(id, what [, mode])" function
17807 */
17808 static void
17809 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
17810 {
17811 char_u *p = NULL;
17812 #ifdef FEAT_SYN_HL
17813 int id;
17814 char_u *what;
17815 char_u *mode;
17816 char_u modebuf[NUMBUFLEN];
17817 int modec;
17818
17819 id = (int)get_tv_number(&argvars[0]);
17820 what = get_tv_string(&argvars[1]);
17821 if (argvars[2].v_type != VAR_UNKNOWN)
17822 {
17823 mode = get_tv_string_buf(&argvars[2], modebuf);
17824 modec = TOLOWER_ASC(mode[0]);
17825 if (modec != 't' && modec != 'c' && modec != 'g')
17826 modec = 0; /* replace invalid with current */
17827 }
17828 else
17829 {
17830 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
17831 if (USE_24BIT)
17832 modec = 'g';
17833 else
17834 #endif
17835 if (t_colors > 1)
17836 modec = 'c';
17837 else
17838 modec = 't';
17839 }
17840
17841
17842 switch (TOLOWER_ASC(what[0]))
17843 {
17844 case 'b':
17845 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
17846 p = highlight_color(id, what, modec);
17847 else /* bold */
17848 p = highlight_has_attr(id, HL_BOLD, modec);
17849 break;
17850
17851 case 'f': /* fg[#] or font */
17852 p = highlight_color(id, what, modec);
17853 break;
17854
17855 case 'i':
17856 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
17857 p = highlight_has_attr(id, HL_INVERSE, modec);
17858 else /* italic */
17859 p = highlight_has_attr(id, HL_ITALIC, modec);
17860 break;
17861
17862 case 'n': /* name */
17863 p = get_highlight_name(NULL, id - 1);
17864 break;
17865
17866 case 'r': /* reverse */
17867 p = highlight_has_attr(id, HL_INVERSE, modec);
17868 break;
17869
17870 case 's':
17871 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
17872 p = highlight_color(id, what, modec);
17873 else /* standout */
17874 p = highlight_has_attr(id, HL_STANDOUT, modec);
17875 break;
17876
17877 case 'u':
17878 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
17879 /* underline */
17880 p = highlight_has_attr(id, HL_UNDERLINE, modec);
17881 else
17882 /* undercurl */
17883 p = highlight_has_attr(id, HL_UNDERCURL, modec);
17884 break;
17885 }
17886
17887 if (p != NULL)
17888 p = vim_strsave(p);
17889 #endif
17890 rettv->v_type = VAR_STRING;
17891 rettv->vval.v_string = p;
17892 }
17893
17894 /*
17895 * "synIDtrans(id)" function
17896 */
17897 static void
17898 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
17899 {
17900 int id;
17901
17902 #ifdef FEAT_SYN_HL
17903 id = (int)get_tv_number(&argvars[0]);
17904
17905 if (id > 0)
17906 id = syn_get_final_id(id);
17907 else
17908 #endif
17909 id = 0;
17910
17911 rettv->vval.v_number = id;
17912 }
17913
17914 /*
17915 * "synconcealed(lnum, col)" function
17916 */
17917 static void
17918 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
17919 {
17920 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
17921 linenr_T lnum;
17922 colnr_T col;
17923 int syntax_flags = 0;
17924 int cchar;
17925 int matchid = 0;
17926 char_u str[NUMBUFLEN];
17927 #endif
17928
17929 rettv->v_type = VAR_LIST;
17930 rettv->vval.v_list = NULL;
17931
17932 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
17933 lnum = get_tv_lnum(argvars); /* -1 on type error */
17934 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
17935
17936 vim_memset(str, NUL, sizeof(str));
17937
17938 if (rettv_list_alloc(rettv) != FAIL)
17939 {
17940 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
17941 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
17942 && curwin->w_p_cole > 0)
17943 {
17944 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
17945 syntax_flags = get_syntax_info(&matchid);
17946
17947 /* get the conceal character */
17948 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
17949 {
17950 cchar = syn_get_sub_char();
17951 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
17952 cchar = lcs_conceal;
17953 if (cchar != NUL)
17954 {
17955 # ifdef FEAT_MBYTE
17956 if (has_mbyte)
17957 (*mb_char2bytes)(cchar, str);
17958 else
17959 # endif
17960 str[0] = cchar;
17961 }
17962 }
17963 }
17964
17965 list_append_number(rettv->vval.v_list,
17966 (syntax_flags & HL_CONCEAL) != 0);
17967 /* -1 to auto-determine strlen */
17968 list_append_string(rettv->vval.v_list, str, -1);
17969 list_append_number(rettv->vval.v_list, matchid);
17970 }
17971 #endif
17972 }
17973
17974 /*
17975 * "synstack(lnum, col)" function
17976 */
17977 static void
17978 f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
17979 {
17980 #ifdef FEAT_SYN_HL
17981 linenr_T lnum;
17982 colnr_T col;
17983 int i;
17984 int id;
17985 #endif
17986
17987 rettv->v_type = VAR_LIST;
17988 rettv->vval.v_list = NULL;
17989
17990 #ifdef FEAT_SYN_HL
17991 lnum = get_tv_lnum(argvars); /* -1 on type error */
17992 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
17993
17994 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
17995 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
17996 && rettv_list_alloc(rettv) != FAIL)
17997 {
17998 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
17999 for (i = 0; ; ++i)
18000 {
18001 id = syn_get_stack_item(i);
18002 if (id < 0)
18003 break;
18004 if (list_append_number(rettv->vval.v_list, id) == FAIL)
18005 break;
18006 }
18007 }
18008 #endif
18009 }
18010
18011 static void
18012 get_cmd_output_as_rettv(
18013 typval_T *argvars,
18014 typval_T *rettv,
18015 int retlist)
18016 {
18017 char_u *res = NULL;
18018 char_u *p;
18019 char_u *infile = NULL;
18020 char_u buf[NUMBUFLEN];
18021 int err = FALSE;
18022 FILE *fd;
18023 list_T *list = NULL;
18024 int flags = SHELL_SILENT;
18025
18026 rettv->v_type = VAR_STRING;
18027 rettv->vval.v_string = NULL;
18028 if (check_restricted() || check_secure())
18029 goto errret;
18030
18031 if (argvars[1].v_type != VAR_UNKNOWN)
18032 {
18033 /*
18034 * Write the string to a temp file, to be used for input of the shell
18035 * command.
18036 */
18037 if ((infile = vim_tempname('i', TRUE)) == NULL)
18038 {
18039 EMSG(_(e_notmp));
18040 goto errret;
18041 }
18042
18043 fd = mch_fopen((char *)infile, WRITEBIN);
18044 if (fd == NULL)
18045 {
18046 EMSG2(_(e_notopen), infile);
18047 goto errret;
18048 }
18049 if (argvars[1].v_type == VAR_LIST)
18050 {
18051 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
18052 err = TRUE;
18053 }
18054 else
18055 {
18056 size_t len;
18057
18058 p = get_tv_string_buf_chk(&argvars[1], buf);
18059 if (p == NULL)
18060 {
18061 fclose(fd);
18062 goto errret; /* type error; errmsg already given */
18063 }
18064 len = STRLEN(p);
18065 if (len > 0 && fwrite(p, len, 1, fd) != 1)
18066 err = TRUE;
18067 }
18068 if (fclose(fd) != 0)
18069 err = TRUE;
18070 if (err)
18071 {
18072 EMSG(_("E677: Error writing temp file"));
18073 goto errret;
18074 }
18075 }
18076
18077 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
18078 * echoes typeahead, that messes up the display. */
18079 if (!msg_silent)
18080 flags += SHELL_COOKED;
18081
18082 if (retlist)
18083 {
18084 int len;
18085 listitem_T *li;
18086 char_u *s = NULL;
18087 char_u *start;
18088 char_u *end;
18089 int i;
18090
18091 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
18092 if (res == NULL)
18093 goto errret;
18094
18095 list = list_alloc();
18096 if (list == NULL)
18097 goto errret;
18098
18099 for (i = 0; i < len; ++i)
18100 {
18101 start = res + i;
18102 while (i < len && res[i] != NL)
18103 ++i;
18104 end = res + i;
18105
18106 s = alloc((unsigned)(end - start + 1));
18107 if (s == NULL)
18108 goto errret;
18109
18110 for (p = s; start < end; ++p, ++start)
18111 *p = *start == NUL ? NL : *start;
18112 *p = NUL;
18113
18114 li = listitem_alloc();
18115 if (li == NULL)
18116 {
18117 vim_free(s);
18118 goto errret;
18119 }
18120 li->li_tv.v_type = VAR_STRING;
18121 li->li_tv.v_lock = 0;
18122 li->li_tv.vval.v_string = s;
18123 list_append(list, li);
18124 }
18125
18126 ++list->lv_refcount;
18127 rettv->v_type = VAR_LIST;
18128 rettv->vval.v_list = list;
18129 list = NULL;
18130 }
18131 else
18132 {
18133 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
18134 #ifdef USE_CR
18135 /* translate <CR> into <NL> */
18136 if (res != NULL)
18137 {
18138 char_u *s;
18139
18140 for (s = res; *s; ++s)
18141 {
18142 if (*s == CAR)
18143 *s = NL;
18144 }
18145 }
18146 #else
18147 # ifdef USE_CRNL
18148 /* translate <CR><NL> into <NL> */
18149 if (res != NULL)
18150 {
18151 char_u *s, *d;
18152
18153 d = res;
18154 for (s = res; *s; ++s)
18155 {
18156 if (s[0] == CAR && s[1] == NL)
18157 ++s;
18158 *d++ = *s;
18159 }
18160 *d = NUL;
18161 }
18162 # endif
18163 #endif
18164 rettv->vval.v_string = res;
18165 res = NULL;
18166 }
18167
18168 errret:
18169 if (infile != NULL)
18170 {
18171 mch_remove(infile);
18172 vim_free(infile);
18173 }
18174 if (res != NULL)
18175 vim_free(res);
18176 if (list != NULL)
18177 list_free(list);
18178 }
18179
18180 /*
18181 * "system()" function
18182 */
18183 static void
18184 f_system(typval_T *argvars, typval_T *rettv)
18185 {
18186 get_cmd_output_as_rettv(argvars, rettv, FALSE);
18187 }
18188
18189 /*
18190 * "systemlist()" function
18191 */
18192 static void
18193 f_systemlist(typval_T *argvars, typval_T *rettv)
18194 {
18195 get_cmd_output_as_rettv(argvars, rettv, TRUE);
18196 }
18197
18198 /*
18199 * "tabpagebuflist()" function
18200 */
18201 static void
18202 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
18203 {
18204 #ifdef FEAT_WINDOWS
18205 tabpage_T *tp;
18206 win_T *wp = NULL;
18207
18208 if (argvars[0].v_type == VAR_UNKNOWN)
18209 wp = firstwin;
18210 else
18211 {
18212 tp = find_tabpage((int)get_tv_number(&argvars[0]));
18213 if (tp != NULL)
18214 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
18215 }
18216 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
18217 {
18218 for (; wp != NULL; wp = wp->w_next)
18219 if (list_append_number(rettv->vval.v_list,
18220 wp->w_buffer->b_fnum) == FAIL)
18221 break;
18222 }
18223 #endif
18224 }
18225
18226
18227 /*
18228 * "tabpagenr()" function
18229 */
18230 static void
18231 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
18232 {
18233 int nr = 1;
18234 #ifdef FEAT_WINDOWS
18235 char_u *arg;
18236
18237 if (argvars[0].v_type != VAR_UNKNOWN)
18238 {
18239 arg = get_tv_string_chk(&argvars[0]);
18240 nr = 0;
18241 if (arg != NULL)
18242 {
18243 if (STRCMP(arg, "$") == 0)
18244 nr = tabpage_index(NULL) - 1;
18245 else
18246 EMSG2(_(e_invexpr2), arg);
18247 }
18248 }
18249 else
18250 nr = tabpage_index(curtab);
18251 #endif
18252 rettv->vval.v_number = nr;
18253 }
18254
18255
18256 #ifdef FEAT_WINDOWS
18257 static int get_winnr(tabpage_T *tp, typval_T *argvar);
18258
18259 /*
18260 * Common code for tabpagewinnr() and winnr().
18261 */
18262 static int
18263 get_winnr(tabpage_T *tp, typval_T *argvar)
18264 {
18265 win_T *twin;
18266 int nr = 1;
18267 win_T *wp;
18268 char_u *arg;
18269
18270 twin = (tp == curtab) ? curwin : tp->tp_curwin;
18271 if (argvar->v_type != VAR_UNKNOWN)
18272 {
18273 arg = get_tv_string_chk(argvar);
18274 if (arg == NULL)
18275 nr = 0; /* type error; errmsg already given */
18276 else if (STRCMP(arg, "$") == 0)
18277 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
18278 else if (STRCMP(arg, "#") == 0)
18279 {
18280 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
18281 if (twin == NULL)
18282 nr = 0;
18283 }
18284 else
18285 {
18286 EMSG2(_(e_invexpr2), arg);
18287 nr = 0;
18288 }
18289 }
18290
18291 if (nr > 0)
18292 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
18293 wp != twin; wp = wp->w_next)
18294 {
18295 if (wp == NULL)
18296 {
18297 /* didn't find it in this tabpage */
18298 nr = 0;
18299 break;
18300 }
18301 ++nr;
18302 }
18303 return nr;
18304 }
18305 #endif
18306
18307 /*
18308 * "tabpagewinnr()" function
18309 */
18310 static void
18311 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
18312 {
18313 int nr = 1;
18314 #ifdef FEAT_WINDOWS
18315 tabpage_T *tp;
18316
18317 tp = find_tabpage((int)get_tv_number(&argvars[0]));
18318 if (tp == NULL)
18319 nr = 0;
18320 else
18321 nr = get_winnr(tp, &argvars[1]);
18322 #endif
18323 rettv->vval.v_number = nr;
18324 }
18325
18326
18327 /*
18328 * "tagfiles()" function
18329 */
18330 static void
18331 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
18332 {
18333 char_u *fname;
18334 tagname_T tn;
18335 int first;
18336
18337 if (rettv_list_alloc(rettv) == FAIL)
18338 return;
18339 fname = alloc(MAXPATHL);
18340 if (fname == NULL)
18341 return;
18342
18343 for (first = TRUE; ; first = FALSE)
18344 if (get_tagfname(&tn, first, fname) == FAIL
18345 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
18346 break;
18347 tagname_free(&tn);
18348 vim_free(fname);
18349 }
18350
18351 /*
18352 * "taglist()" function
18353 */
18354 static void
18355 f_taglist(typval_T *argvars, typval_T *rettv)
18356 {
18357 char_u *tag_pattern;
18358
18359 tag_pattern = get_tv_string(&argvars[0]);
18360
18361 rettv->vval.v_number = FALSE;
18362 if (*tag_pattern == NUL)
18363 return;
18364
18365 if (rettv_list_alloc(rettv) == OK)
18366 (void)get_tags(rettv->vval.v_list, tag_pattern);
18367 }
18368
18369 /*
18370 * "tempname()" function
18371 */
18372 static void
18373 f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
18374 {
18375 static int x = 'A';
18376
18377 rettv->v_type = VAR_STRING;
18378 rettv->vval.v_string = vim_tempname(x, FALSE);
18379
18380 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
18381 * names. Skip 'I' and 'O', they are used for shell redirection. */
18382 do
18383 {
18384 if (x == 'Z')
18385 x = '0';
18386 else if (x == '9')
18387 x = 'A';
18388 else
18389 {
18390 #ifdef EBCDIC
18391 if (x == 'I')
18392 x = 'J';
18393 else if (x == 'R')
18394 x = 'S';
18395 else
18396 #endif
18397 ++x;
18398 }
18399 } while (x == 'I' || x == 'O');
18400 }
18401
18402 #ifdef FEAT_FLOAT
18403 /*
18404 * "tan()" function
18405 */
18406 static void
18407 f_tan(typval_T *argvars, typval_T *rettv)
18408 {
18409 float_T f = 0.0;
18410
18411 rettv->v_type = VAR_FLOAT;
18412 if (get_float_arg(argvars, &f) == OK)
18413 rettv->vval.v_float = tan(f);
18414 else
18415 rettv->vval.v_float = 0.0;
18416 }
18417
18418 /*
18419 * "tanh()" function
18420 */
18421 static void
18422 f_tanh(typval_T *argvars, typval_T *rettv)
18423 {
18424 float_T f = 0.0;
18425
18426 rettv->v_type = VAR_FLOAT;
18427 if (get_float_arg(argvars, &f) == OK)
18428 rettv->vval.v_float = tanh(f);
18429 else
18430 rettv->vval.v_float = 0.0;
18431 }
18432 #endif
18433
18434 /*
18435 * "test_alloc_fail(id, countdown, repeat)" function
18436 */
18437 static void
18438 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
18439 {
18440 if (argvars[0].v_type != VAR_NUMBER
18441 || argvars[0].vval.v_number <= 0
18442 || argvars[1].v_type != VAR_NUMBER
18443 || argvars[1].vval.v_number < 0
18444 || argvars[2].v_type != VAR_NUMBER)
18445 EMSG(_(e_invarg));
18446 else
18447 {
18448 alloc_fail_id = argvars[0].vval.v_number;
18449 if (alloc_fail_id >= aid_last)
18450 EMSG(_(e_invarg));
18451 alloc_fail_countdown = argvars[1].vval.v_number;
18452 alloc_fail_repeat = argvars[2].vval.v_number;
18453 did_outofmem_msg = FALSE;
18454 }
18455 }
18456
18457 /*
18458 * "test_autochdir()"
18459 */
18460 static void
18461 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
18462 {
18463 #if defined(FEAT_AUTOCHDIR)
18464 test_autochdir = TRUE;
18465 #endif
18466 }
18467
18468 /*
18469 * "test_disable_char_avail({expr})" function
18470 */
18471 static void
18472 f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED)
18473 {
18474 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]);
18475 }
18476
18477 /*
18478 * "test_garbagecollect_now()" function
18479 */
18480 static void
18481 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
18482 {
18483 /* This is dangerous, any Lists and Dicts used internally may be freed
18484 * while still in use. */
18485 garbage_collect(TRUE);
18486 }
18487
18488 #ifdef FEAT_JOB_CHANNEL
18489 static void
18490 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
18491 {
18492 rettv->v_type = VAR_CHANNEL;
18493 rettv->vval.v_channel = NULL;
18494 }
18495 #endif
18496
18497 static void
18498 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
18499 {
18500 rettv->v_type = VAR_DICT;
18501 rettv->vval.v_dict = NULL;
18502 }
18503
18504 #ifdef FEAT_JOB_CHANNEL
18505 static void
18506 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
18507 {
18508 rettv->v_type = VAR_JOB;
18509 rettv->vval.v_job = NULL;
18510 }
18511 #endif
18512
18513 static void
18514 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
18515 {
18516 rettv->v_type = VAR_LIST;
18517 rettv->vval.v_list = NULL;
18518 }
18519
18520 static void
18521 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
18522 {
18523 rettv->v_type = VAR_PARTIAL;
18524 rettv->vval.v_partial = NULL;
18525 }
18526
18527 static void
18528 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
18529 {
18530 rettv->v_type = VAR_STRING;
18531 rettv->vval.v_string = NULL;
18532 }
18533
18534 static void
18535 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
18536 {
18537 time_for_testing = (time_t)get_tv_number(&argvars[0]);
18538 }
18539
18540 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
18541 /*
18542 * Get a callback from "arg". It can be a Funcref or a function name.
18543 * When "arg" is zero return an empty string.
18544 * Return NULL for an invalid argument.
18545 */
18546 char_u *
18547 get_callback(typval_T *arg, partial_T **pp)
18548 {
18549 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
18550 {
18551 *pp = arg->vval.v_partial;
18552 ++(*pp)->pt_refcount;
18553 return (*pp)->pt_name;
18554 }
18555 *pp = NULL;
18556 if (arg->v_type == VAR_FUNC)
18557 {
18558 func_ref(arg->vval.v_string);
18559 return arg->vval.v_string;
18560 }
18561 if (arg->v_type == VAR_STRING)
18562 return arg->vval.v_string;
18563 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
18564 return (char_u *)"";
18565 EMSG(_("E921: Invalid callback argument"));
18566 return NULL;
18567 }
18568
18569 /*
18570 * Unref/free "callback" and "partial" retured by get_callback().
18571 */
18572 void
18573 free_callback(char_u *callback, partial_T *partial)
18574 {
18575 if (partial != NULL)
18576 partial_unref(partial);
18577 else if (callback != NULL)
18578 {
18579 func_unref(callback);
18580 vim_free(callback);
18581 }
18582 }
18583 #endif
18584
18585 #ifdef FEAT_TIMERS
18586 /*
18587 * "timer_start(time, callback [, options])" function
18588 */
18589 static void
18590 f_timer_start(typval_T *argvars, typval_T *rettv)
18591 {
18592 long msec = (long)get_tv_number(&argvars[0]);
18593 timer_T *timer;
18594 int repeat = 0;
18595 char_u *callback;
18596 dict_T *dict;
18597
18598 if (check_secure())
18599 return;
18600 if (argvars[2].v_type != VAR_UNKNOWN)
18601 {
18602 if (argvars[2].v_type != VAR_DICT
18603 || (dict = argvars[2].vval.v_dict) == NULL)
18604 {
18605 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
18606 return;
18607 }
18608 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
18609 repeat = get_dict_number(dict, (char_u *)"repeat");
18610 }
18611
18612 timer = create_timer(msec, repeat);
18613 callback = get_callback(&argvars[1], &timer->tr_partial);
18614 if (callback == NULL)
18615 {
18616 stop_timer(timer);
18617 rettv->vval.v_number = -1;
18618 }
18619 else
18620 {
18621 timer->tr_callback = vim_strsave(callback);
18622 rettv->vval.v_number = timer->tr_id;
18623 }
18624 }
18625
18626 /*
18627 * "timer_stop(timer)" function
18628 */
18629 static void
18630 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
18631 {
18632 timer_T *timer;
18633
18634 if (argvars[0].v_type != VAR_NUMBER)
18635 {
18636 EMSG(_(e_number_exp));
18637 return;
18638 }
18639 timer = find_timer((int)get_tv_number(&argvars[0]));
18640 if (timer != NULL)
18641 stop_timer(timer);
18642 }
18643 #endif
18644
18645 /*
18646 * "tolower(string)" function
18647 */
18648 static void
18649 f_tolower(typval_T *argvars, typval_T *rettv)
18650 {
18651 char_u *p;
18652
18653 p = vim_strsave(get_tv_string(&argvars[0]));
18654 rettv->v_type = VAR_STRING;
18655 rettv->vval.v_string = p;
18656
18657 if (p != NULL)
18658 while (*p != NUL)
18659 {
18660 #ifdef FEAT_MBYTE
18661 int l;
18662
18663 if (enc_utf8)
18664 {
18665 int c, lc;
18666
18667 c = utf_ptr2char(p);
18668 lc = utf_tolower(c);
18669 l = utf_ptr2len(p);
18670 /* TODO: reallocate string when byte count changes. */
18671 if (utf_char2len(lc) == l)
18672 utf_char2bytes(lc, p);
18673 p += l;
18674 }
18675 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
18676 p += l; /* skip multi-byte character */
18677 else
18678 #endif
18679 {
18680 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
18681 ++p;
18682 }
18683 }
18684 }
18685
18686 /*
18687 * "toupper(string)" function
18688 */
18689 static void
18690 f_toupper(typval_T *argvars, typval_T *rettv)
18691 {
18692 rettv->v_type = VAR_STRING;
18693 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
18694 }
18695
18696 /*
18697 * "tr(string, fromstr, tostr)" function
18698 */
18699 static void
18700 f_tr(typval_T *argvars, typval_T *rettv)
18701 {
18702 char_u *in_str;
18703 char_u *fromstr;
18704 char_u *tostr;
18705 char_u *p;
18706 #ifdef FEAT_MBYTE
18707 int inlen;
18708 int fromlen;
18709 int tolen;
18710 int idx;
18711 char_u *cpstr;
18712 int cplen;
18713 int first = TRUE;
18714 #endif
18715 char_u buf[NUMBUFLEN];
18716 char_u buf2[NUMBUFLEN];
18717 garray_T ga;
18718
18719 in_str = get_tv_string(&argvars[0]);
18720 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
18721 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
18722
18723 /* Default return value: empty string. */
18724 rettv->v_type = VAR_STRING;
18725 rettv->vval.v_string = NULL;
18726 if (fromstr == NULL || tostr == NULL)
18727 return; /* type error; errmsg already given */
18728 ga_init2(&ga, (int)sizeof(char), 80);
18729
18730 #ifdef FEAT_MBYTE
18731 if (!has_mbyte)
18732 #endif
18733 /* not multi-byte: fromstr and tostr must be the same length */
18734 if (STRLEN(fromstr) != STRLEN(tostr))
18735 {
18736 #ifdef FEAT_MBYTE
18737 error:
18738 #endif
18739 EMSG2(_(e_invarg2), fromstr);
18740 ga_clear(&ga);
18741 return;
18742 }
18743
18744 /* fromstr and tostr have to contain the same number of chars */
18745 while (*in_str != NUL)
18746 {
18747 #ifdef FEAT_MBYTE
18748 if (has_mbyte)
18749 {
18750 inlen = (*mb_ptr2len)(in_str);
18751 cpstr = in_str;
18752 cplen = inlen;
18753 idx = 0;
18754 for (p = fromstr; *p != NUL; p += fromlen)
18755 {
18756 fromlen = (*mb_ptr2len)(p);
18757 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
18758 {
18759 for (p = tostr; *p != NUL; p += tolen)
18760 {
18761 tolen = (*mb_ptr2len)(p);
18762 if (idx-- == 0)
18763 {
18764 cplen = tolen;
18765 cpstr = p;
18766 break;
18767 }
18768 }
18769 if (*p == NUL) /* tostr is shorter than fromstr */
18770 goto error;
18771 break;
18772 }
18773 ++idx;
18774 }
18775
18776 if (first && cpstr == in_str)
18777 {
18778 /* Check that fromstr and tostr have the same number of
18779 * (multi-byte) characters. Done only once when a character
18780 * of in_str doesn't appear in fromstr. */
18781 first = FALSE;
18782 for (p = tostr; *p != NUL; p += tolen)
18783 {
18784 tolen = (*mb_ptr2len)(p);
18785 --idx;
18786 }
18787 if (idx != 0)
18788 goto error;
18789 }
18790
18791 (void)ga_grow(&ga, cplen);
18792 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
18793 ga.ga_len += cplen;
18794
18795 in_str += inlen;
18796 }
18797 else
18798 #endif
18799 {
18800 /* When not using multi-byte chars we can do it faster. */
18801 p = vim_strchr(fromstr, *in_str);
18802 if (p != NULL)
18803 ga_append(&ga, tostr[p - fromstr]);
18804 else
18805 ga_append(&ga, *in_str);
18806 ++in_str;
18807 }
18808 }
18809
18810 /* add a terminating NUL */
18811 (void)ga_grow(&ga, 1);
18812 ga_append(&ga, NUL);
18813
18814 rettv->vval.v_string = ga.ga_data;
18815 }
18816
18817 #ifdef FEAT_FLOAT
18818 /*
18819 * "trunc({float})" function
18820 */
18821 static void
18822 f_trunc(typval_T *argvars, typval_T *rettv)
18823 {
18824 float_T f = 0.0;
18825
18826 rettv->v_type = VAR_FLOAT;
18827 if (get_float_arg(argvars, &f) == OK)
18828 /* trunc() is not in C90, use floor() or ceil() instead. */
18829 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
18830 else
18831 rettv->vval.v_float = 0.0;
18832 }
18833 #endif
18834
18835 /*
18836 * "type(expr)" function
18837 */
18838 static void
18839 f_type(typval_T *argvars, typval_T *rettv)
18840 {
18841 int n = -1;
18842
18843 switch (argvars[0].v_type)
18844 {
18845 case VAR_NUMBER: n = 0; break;
18846 case VAR_STRING: n = 1; break;
18847 case VAR_PARTIAL:
18848 case VAR_FUNC: n = 2; break;
18849 case VAR_LIST: n = 3; break;
18850 case VAR_DICT: n = 4; break;
18851 case VAR_FLOAT: n = 5; break;
18852 case VAR_SPECIAL:
18853 if (argvars[0].vval.v_number == VVAL_FALSE
18854 || argvars[0].vval.v_number == VVAL_TRUE)
18855 n = 6;
18856 else
18857 n = 7;
18858 break;
18859 case VAR_JOB: n = 8; break;
18860 case VAR_CHANNEL: n = 9; break;
18861 case VAR_UNKNOWN:
18862 EMSG2(_(e_intern2), "f_type(UNKNOWN)");
18863 n = -1;
18864 break;
18865 }
18866 rettv->vval.v_number = n;
18867 }
18868
18869 /*
18870 * "undofile(name)" function
18871 */
18872 static void
18873 f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
18874 {
18875 rettv->v_type = VAR_STRING;
18876 #ifdef FEAT_PERSISTENT_UNDO
18877 {
18878 char_u *fname = get_tv_string(&argvars[0]);
18879
18880 if (*fname == NUL)
18881 {
18882 /* If there is no file name there will be no undo file. */
18883 rettv->vval.v_string = NULL;
18884 }
18885 else
18886 {
18887 char_u *ffname = FullName_save(fname, FALSE);
18888
18889 if (ffname != NULL)
18890 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
18891 vim_free(ffname);
18892 }
18893 }
18894 #else
18895 rettv->vval.v_string = NULL;
18896 #endif
18897 }
18898
18899 /*
18900 * "undotree()" function
18901 */
18902 static void
18903 f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
18904 {
18905 if (rettv_dict_alloc(rettv) == OK)
18906 {
18907 dict_T *dict = rettv->vval.v_dict;
18908 list_T *list;
18909
18910 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
18911 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
18912 dict_add_nr_str(dict, "save_last",
18913 (long)curbuf->b_u_save_nr_last, NULL);
18914 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
18915 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
18916 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
18917
18918 list = list_alloc();
18919 if (list != NULL)
18920 {
18921 u_eval_tree(curbuf->b_u_oldhead, list);
18922 dict_add_list(dict, "entries", list);
18923 }
18924 }
18925 }
18926
18927 /*
18928 * "values(dict)" function
18929 */
18930 static void
18931 f_values(typval_T *argvars, typval_T *rettv)
18932 {
18933 dict_list(argvars, rettv, 1);
18934 }
18935
18936 /*
18937 * "virtcol(string)" function
18938 */
18939 static void
18940 f_virtcol(typval_T *argvars, typval_T *rettv)
18941 {
18942 colnr_T vcol = 0;
18943 pos_T *fp;
18944 int fnum = curbuf->b_fnum;
18945
18946 fp = var2fpos(&argvars[0], FALSE, &fnum);
18947 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
18948 && fnum == curbuf->b_fnum)
18949 {
18950 getvvcol(curwin, fp, NULL, NULL, &vcol);
18951 ++vcol;
18952 }
18953
18954 rettv->vval.v_number = vcol;
18955 }
18956
18957 /*
18958 * "visualmode()" function
18959 */
18960 static void
18961 f_visualmode(typval_T *argvars, typval_T *rettv)
18962 {
18963 char_u str[2];
18964
18965 rettv->v_type = VAR_STRING;
18966 str[0] = curbuf->b_visual_mode_eval;
18967 str[1] = NUL;
18968 rettv->vval.v_string = vim_strsave(str);
18969
18970 /* A non-zero number or non-empty string argument: reset mode. */
18971 if (non_zero_arg(&argvars[0]))
18972 curbuf->b_visual_mode_eval = NUL;
18973 }
18974
18975 /*
18976 * "wildmenumode()" function
18977 */
18978 static void
18979 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
18980 {
18981 #ifdef FEAT_WILDMENU
18982 if (wild_menu_showing)
18983 rettv->vval.v_number = 1;
18984 #endif
18985 }
18986
18987 /*
18988 * "winbufnr(nr)" function
18989 */
18990 static void
18991 f_winbufnr(typval_T *argvars, typval_T *rettv)
18992 {
18993 win_T *wp;
18994
18995 wp = find_win_by_nr(&argvars[0], NULL);
18996 if (wp == NULL)
18997 rettv->vval.v_number = -1;
18998 else
18999 rettv->vval.v_number = wp->w_buffer->b_fnum;
19000 }
19001
19002 /*
19003 * "wincol()" function
19004 */
19005 static void
19006 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
19007 {
19008 validate_cursor();
19009 rettv->vval.v_number = curwin->w_wcol + 1;
19010 }
19011
19012 /*
19013 * "winheight(nr)" function
19014 */
19015 static void
19016 f_winheight(typval_T *argvars, typval_T *rettv)
19017 {
19018 win_T *wp;
19019
19020 wp = find_win_by_nr(&argvars[0], NULL);
19021 if (wp == NULL)
19022 rettv->vval.v_number = -1;
19023 else
19024 rettv->vval.v_number = wp->w_height;
19025 }
19026
19027 /*
19028 * "winline()" function
19029 */
19030 static void
19031 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
19032 {
19033 validate_cursor();
19034 rettv->vval.v_number = curwin->w_wrow + 1;
19035 }
19036
19037 /*
19038 * "winnr()" function
19039 */
19040 static void
19041 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
19042 {
19043 int nr = 1;
19044
19045 #ifdef FEAT_WINDOWS
19046 nr = get_winnr(curtab, &argvars[0]);
19047 #endif
19048 rettv->vval.v_number = nr;
19049 }
19050
19051 /*
19052 * "winrestcmd()" function
19053 */
19054 static void
19055 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
19056 {
19057 #ifdef FEAT_WINDOWS
19058 win_T *wp;
19059 int winnr = 1;
19060 garray_T ga;
19061 char_u buf[50];
19062
19063 ga_init2(&ga, (int)sizeof(char), 70);
19064 for (wp = firstwin; wp != NULL; wp = wp->w_next)
19065 {
19066 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
19067 ga_concat(&ga, buf);
19068 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
19069 ga_concat(&ga, buf);
19070 ++winnr;
19071 }
19072 ga_append(&ga, NUL);
19073
19074 rettv->vval.v_string = ga.ga_data;
19075 #else
19076 rettv->vval.v_string = NULL;
19077 #endif
19078 rettv->v_type = VAR_STRING;
19079 }
19080
19081 /*
19082 * "winrestview()" function
19083 */
19084 static void
19085 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
19086 {
19087 dict_T *dict;
19088
19089 if (argvars[0].v_type != VAR_DICT
19090 || (dict = argvars[0].vval.v_dict) == NULL)
19091 EMSG(_(e_invarg));
19092 else
19093 {
19094 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
19095 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
19096 if (dict_find(dict, (char_u *)"col", -1) != NULL)
19097 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
19098 #ifdef FEAT_VIRTUALEDIT
19099 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
19100 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
19101 #endif
19102 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
19103 {
19104 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
19105 curwin->w_set_curswant = FALSE;
19106 }
19107
19108 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
19109 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
19110 #ifdef FEAT_DIFF
19111 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
19112 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
19113 #endif
19114 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
19115 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
19116 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
19117 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
19118
19119 check_cursor();
19120 win_new_height(curwin, curwin->w_height);
19121 # ifdef FEAT_WINDOWS
19122 win_new_width(curwin, W_WIDTH(curwin));
19123 # endif
19124 changed_window_setting();
19125
19126 if (curwin->w_topline <= 0)
19127 curwin->w_topline = 1;
19128 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
19129 curwin->w_topline = curbuf->b_ml.ml_line_count;
19130 #ifdef FEAT_DIFF
19131 check_topfill(curwin, TRUE);
19132 #endif
19133 }
19134 }
19135
19136 /*
19137 * "winsaveview()" function
19138 */
19139 static void
19140 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
19141 {
19142 dict_T *dict;
19143
19144 if (rettv_dict_alloc(rettv) == FAIL)
19145 return;
19146 dict = rettv->vval.v_dict;
19147
19148 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
19149 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
19150 #ifdef FEAT_VIRTUALEDIT
19151 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
19152 #endif
19153 update_curswant();
19154 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
19155
19156 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
19157 #ifdef FEAT_DIFF
19158 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
19159 #endif
19160 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
19161 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
19162 }
19163
19164 /*
19165 * "winwidth(nr)" function
19166 */
19167 static void
19168 f_winwidth(typval_T *argvars, typval_T *rettv)
19169 {
19170 win_T *wp;
19171
19172 wp = find_win_by_nr(&argvars[0], NULL);
19173 if (wp == NULL)
19174 rettv->vval.v_number = -1;
19175 else
19176 #ifdef FEAT_WINDOWS
19177 rettv->vval.v_number = wp->w_width;
19178 #else
19179 rettv->vval.v_number = Columns;
19180 #endif
19181 }
19182
19183 /*
19184 * "wordcount()" function
19185 */
19186 static void
19187 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
19188 {
19189 if (rettv_dict_alloc(rettv) == FAIL)
19190 return;
19191 cursor_pos_info(rettv->vval.v_dict);
19192 }
19193
19194 /*
19195 * Write list of strings to file
19196 */
19197 static int
19198 write_list(FILE *fd, list_T *list, int binary)
19199 {
19200 listitem_T *li;
19201 int c;
19202 int ret = OK;
19203 char_u *s;
19204
19205 for (li = list->lv_first; li != NULL; li = li->li_next)
19206 {
19207 for (s = get_tv_string(&li->li_tv); *s != NUL; ++s)
19208 {
19209 if (*s == '\n')
19210 c = putc(NUL, fd);
19211 else
19212 c = putc(*s, fd);
19213 if (c == EOF)
19214 {
19215 ret = FAIL;
19216 break;
19217 }
19218 }
19219 if (!binary || li->li_next != NULL)
19220 if (putc('\n', fd) == EOF)
19221 {
19222 ret = FAIL;
19223 break;
19224 }
19225 if (ret == FAIL)
19226 {
19227 EMSG(_(e_write));
19228 break;
19229 }
19230 }
19231 return ret;
19232 }
19233
19234 /*
19235 * "writefile()" function
19236 */
19237 static void
19238 f_writefile(typval_T *argvars, typval_T *rettv)
19239 {
19240 int binary = FALSE;
19241 int append = FALSE;
19242 char_u *fname;
19243 FILE *fd;
19244 int ret = 0;
19245
19246 if (check_restricted() || check_secure())
19247 return;
19248
19249 if (argvars[0].v_type != VAR_LIST)
19250 {
19251 EMSG2(_(e_listarg), "writefile()");
19252 return;
19253 }
19254 if (argvars[0].vval.v_list == NULL)
19255 return;
19256
19257 if (argvars[2].v_type != VAR_UNKNOWN)
19258 {
19259 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL)
19260 binary = TRUE;
19261 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL)
19262 append = TRUE;
19263 }
19264
19265 /* Always open the file in binary mode, library functions have a mind of
19266 * their own about CR-LF conversion. */
19267 fname = get_tv_string(&argvars[1]);
19268 if (*fname == NUL || (fd = mch_fopen((char *)fname,
19269 append ? APPENDBIN : WRITEBIN)) == NULL)
19270 {
19271 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
19272 ret = -1;
19273 }
19274 else
19275 {
19276 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL)
19277 ret = -1;
19278 fclose(fd);
19279 }
19280
19281 rettv->vval.v_number = ret;
19282 }
19283
19284 /*
19285 * "xor(expr, expr)" function
19286 */
19287 static void
19288 f_xor(typval_T *argvars, typval_T *rettv)
19289 {
19290 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
19291 ^ get_tv_number_chk(&argvars[1], NULL);
19292 }
19293 5973
19294 5974
19295 /* 5975 /*
19296 * Translate a String variable into a position. 5976 * Translate a String variable into a position.
19297 * Returns NULL when there is an error. 5977 * Returns NULL when there is an error.
19298 */ 5978 */
19299 static pos_T * 5979 pos_T *
19300 var2fpos( 5980 var2fpos(
19301 typval_T *varp, 5981 typval_T *varp,
19302 int dollar_lnum, /* TRUE when $ is last line */ 5982 int dollar_lnum, /* TRUE when $ is last line */
19303 int *fnum) /* set to fnum for '0, 'A, etc. */ 5983 int *fnum) /* set to fnum for '0, 'A, etc. */
19304 { 5984 {
19413 * Note that the column is passed on as-is, the caller may want to decrement 6093 * Note that the column is passed on as-is, the caller may want to decrement
19414 * it to use 1 for the first column. 6094 * it to use 1 for the first column.
19415 * Return FAIL when conversion is not possible, doesn't check the position for 6095 * Return FAIL when conversion is not possible, doesn't check the position for
19416 * validity. 6096 * validity.
19417 */ 6097 */
19418 static int 6098 int
19419 list2fpos( 6099 list2fpos(
19420 typval_T *arg, 6100 typval_T *arg,
19421 pos_T *posp, 6101 pos_T *posp,
19422 int *fnump, 6102 int *fnump,
19423 colnr_T *curswantp) 6103 colnr_T *curswantp)
19529 * Return -1 if curly braces expansion failed. 6209 * Return -1 if curly braces expansion failed.
19530 * Return 0 if something else is wrong. 6210 * Return 0 if something else is wrong.
19531 * If the name contains 'magic' {}'s, expand them and return the 6211 * If the name contains 'magic' {}'s, expand them and return the
19532 * expanded name in an allocated string via 'alias' - caller must free. 6212 * expanded name in an allocated string via 'alias' - caller must free.
19533 */ 6213 */
19534 static int 6214 int
19535 get_name_len( 6215 get_name_len(
19536 char_u **arg, 6216 char_u **arg,
19537 char_u **alias, 6217 char_u **alias,
19538 int evaluate, 6218 int evaluate,
19539 int verbose) 6219 int verbose)
20030 6710
20031 /* 6711 /*
20032 * Get the value of internal variable "name". 6712 * Get the value of internal variable "name".
20033 * Return OK or FAIL. 6713 * Return OK or FAIL.
20034 */ 6714 */
20035 static int 6715 int
20036 get_var_tv( 6716 get_var_tv(
20037 char_u *name, 6717 char_u *name,
20038 int len, /* length of "name" */ 6718 int len, /* length of "name" */
20039 typval_T *rettv, /* NULL when only checking existence */ 6719 typval_T *rettv, /* NULL when only checking existence */
20040 dictitem_T **dip, /* non-NULL when typval's dict item is needed */ 6720 dictitem_T **dip, /* non-NULL when typval's dict item is needed */
20322 } 7002 }
20323 7003
20324 /* 7004 /*
20325 * Set the value of a variable to NULL without freeing items. 7005 * Set the value of a variable to NULL without freeing items.
20326 */ 7006 */
20327 static void 7007 void
20328 init_tv(typval_T *varp) 7008 init_tv(typval_T *varp)
20329 { 7009 {
20330 if (varp != NULL) 7010 if (varp != NULL)
20331 vim_memset(varp, 0, sizeof(typval_T)); 7011 vim_memset(varp, 0, sizeof(typval_T));
20332 } 7012 }
20399 *denote = TRUE; 7079 *denote = TRUE;
20400 return n; 7080 return n;
20401 } 7081 }
20402 7082
20403 #ifdef FEAT_FLOAT 7083 #ifdef FEAT_FLOAT
20404 static float_T 7084 float_T
20405 get_tv_float(typval_T *varp) 7085 get_tv_float(typval_T *varp)
20406 { 7086 {
20407 switch (varp->v_type) 7087 switch (varp->v_type)
20408 { 7088 {
20409 case VAR_NUMBER: 7089 case VAR_NUMBER:
20443 return 0; 7123 return 0;
20444 } 7124 }
20445 #endif 7125 #endif
20446 7126
20447 /* 7127 /*
20448 * Get the lnum from the first argument.
20449 * Also accepts ".", "$", etc., but that only works for the current buffer.
20450 * Returns -1 on error.
20451 */
20452 static linenr_T
20453 get_tv_lnum(typval_T *argvars)
20454 {
20455 typval_T rettv;
20456 linenr_T lnum;
20457
20458 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
20459 if (lnum == 0) /* no valid number, try using line() */
20460 {
20461 rettv.v_type = VAR_NUMBER;
20462 f_line(argvars, &rettv);
20463 lnum = (linenr_T)rettv.vval.v_number;
20464 clear_tv(&rettv);
20465 }
20466 return lnum;
20467 }
20468
20469 /*
20470 * Get the lnum from the first argument.
20471 * Also accepts "$", then "buf" is used.
20472 * Returns 0 on error.
20473 */
20474 static linenr_T
20475 get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
20476 {
20477 if (argvars[0].v_type == VAR_STRING
20478 && argvars[0].vval.v_string != NULL
20479 && argvars[0].vval.v_string[0] == '$'
20480 && buf != NULL)
20481 return buf->b_ml.ml_line_count;
20482 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
20483 }
20484
20485 /*
20486 * Get the string value of a variable. 7128 * Get the string value of a variable.
20487 * If it is a Number variable, the number is converted into a string. 7129 * If it is a Number variable, the number is converted into a string.
20488 * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE! 7130 * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
20489 * get_tv_string_buf() uses a given buffer. 7131 * get_tv_string_buf() uses a given buffer.
20490 * If the String variable has never been set, return an empty string. 7132 * If the String variable has never been set, return an empty string.
20622 7264
20623 /* 7265 /*
20624 * Find variable "varname" in hashtab "ht" with name "htname". 7266 * Find variable "varname" in hashtab "ht" with name "htname".
20625 * Returns NULL if not found. 7267 * Returns NULL if not found.
20626 */ 7268 */
20627 static dictitem_T * 7269 dictitem_T *
20628 find_var_in_ht( 7270 find_var_in_ht(
20629 hashtab_T *ht, 7271 hashtab_T *ht,
20630 int htname, 7272 int htname,
20631 char_u *varname, 7273 char_u *varname,
20632 int no_autoload) 7274 int no_autoload)
20934 /* 7576 /*
20935 * Set variable "name" to value in "tv". 7577 * Set variable "name" to value in "tv".
20936 * If the variable already exists, the value is updated. 7578 * If the variable already exists, the value is updated.
20937 * Otherwise the variable is created. 7579 * Otherwise the variable is created.
20938 */ 7580 */
20939 static void 7581 void
20940 set_var( 7582 set_var(
20941 char_u *name, 7583 char_u *name,
20942 typval_T *tv, 7584 typval_T *tv,
20943 int copy) /* make copy of value in "tv" */ 7585 int copy) /* make copy of value in "tv" */
20944 { 7586 {
21062 7704
21063 /* 7705 /*
21064 * Return TRUE if di_flags "flags" indicates variable "name" is fixed. 7706 * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
21065 * Also give an error message. 7707 * Also give an error message.
21066 */ 7708 */
21067 static int 7709 int
21068 var_check_fixed(int flags, char_u *name, int use_gettext) 7710 var_check_fixed(int flags, char_u *name, int use_gettext)
21069 { 7711 {
21070 if (flags & DI_FLAGS_FIX) 7712 if (flags & DI_FLAGS_FIX)
21071 { 7713 {
21072 EMSG2(_("E795: Cannot delete variable %s"), 7714 EMSG2(_("E795: Cannot delete variable %s"),
21305 EMSG2(_(e_intern2), "item_copy(UNKNOWN)"); 7947 EMSG2(_(e_intern2), "item_copy(UNKNOWN)");
21306 ret = FAIL; 7948 ret = FAIL;
21307 } 7949 }
21308 --recurse; 7950 --recurse;
21309 return ret; 7951 return ret;
7952 }
7953
7954 /*
7955 * This function is used by f_input() and f_inputdialog() functions. The third
7956 * argument to f_input() specifies the type of completion to use at the
7957 * prompt. The third argument to f_inputdialog() specifies the value to return
7958 * when the user cancels the prompt.
7959 */
7960 void
7961 get_user_input(
7962 typval_T *argvars,
7963 typval_T *rettv,
7964 int inputdialog,
7965 int secret)
7966 {
7967 char_u *prompt = get_tv_string_chk(&argvars[0]);
7968 char_u *p = NULL;
7969 int c;
7970 char_u buf[NUMBUFLEN];
7971 int cmd_silent_save = cmd_silent;
7972 char_u *defstr = (char_u *)"";
7973 int xp_type = EXPAND_NOTHING;
7974 char_u *xp_arg = NULL;
7975
7976 rettv->v_type = VAR_STRING;
7977 rettv->vval.v_string = NULL;
7978
7979 #ifdef NO_CONSOLE_INPUT
7980 /* While starting up, there is no place to enter text. */
7981 if (no_console_input())
7982 return;
7983 #endif
7984
7985 cmd_silent = FALSE; /* Want to see the prompt. */
7986 if (prompt != NULL)
7987 {
7988 /* Only the part of the message after the last NL is considered as
7989 * prompt for the command line */
7990 p = vim_strrchr(prompt, '\n');
7991 if (p == NULL)
7992 p = prompt;
7993 else
7994 {
7995 ++p;
7996 c = *p;
7997 *p = NUL;
7998 msg_start();
7999 msg_clr_eos();
8000 msg_puts_attr(prompt, echo_attr);
8001 msg_didout = FALSE;
8002 msg_starthere();
8003 *p = c;
8004 }
8005 cmdline_row = msg_row;
8006
8007 if (argvars[1].v_type != VAR_UNKNOWN)
8008 {
8009 defstr = get_tv_string_buf_chk(&argvars[1], buf);
8010 if (defstr != NULL)
8011 stuffReadbuffSpec(defstr);
8012
8013 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
8014 {
8015 char_u *xp_name;
8016 int xp_namelen;
8017 long argt;
8018
8019 /* input() with a third argument: completion */
8020 rettv->vval.v_string = NULL;
8021
8022 xp_name = get_tv_string_buf_chk(&argvars[2], buf);
8023 if (xp_name == NULL)
8024 return;
8025
8026 xp_namelen = (int)STRLEN(xp_name);
8027
8028 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
8029 &xp_arg) == FAIL)
8030 return;
8031 }
8032 }
8033
8034 if (defstr != NULL)
8035 {
8036 int save_ex_normal_busy = ex_normal_busy;
8037 ex_normal_busy = 0;
8038 rettv->vval.v_string =
8039 getcmdline_prompt(secret ? NUL : '@', p, echo_attr,
8040 xp_type, xp_arg);
8041 ex_normal_busy = save_ex_normal_busy;
8042 }
8043 if (inputdialog && rettv->vval.v_string == NULL
8044 && argvars[1].v_type != VAR_UNKNOWN
8045 && argvars[2].v_type != VAR_UNKNOWN)
8046 rettv->vval.v_string = vim_strsave(get_tv_string_buf(
8047 &argvars[2], buf));
8048
8049 vim_free(xp_arg);
8050
8051 /* since the user typed this, no need to wait for return */
8052 need_wait_return = FALSE;
8053 msg_didout = FALSE;
8054 }
8055 cmd_silent = cmd_silent_save;
21310 } 8056 }
21311 8057
21312 /* 8058 /*
21313 * ":echo expr1 ..." print each argument separated with a space, add a 8059 * ":echo expr1 ..." print each argument separated with a space, add a
21314 * newline at the end. 8060 * newline at the end.
21511 8257
21512 if (eap->skip) 8258 if (eap->skip)
21513 --emsg_skip; 8259 --emsg_skip;
21514 8260
21515 eap->nextcmd = check_nextcmd(arg); 8261 eap->nextcmd = check_nextcmd(arg);
8262 }
8263
8264 /*
8265 * Find window specified by "vp" in tabpage "tp".
8266 */
8267 win_T *
8268 find_win_by_nr(
8269 typval_T *vp,
8270 tabpage_T *tp UNUSED) /* NULL for current tab page */
8271 {
8272 #ifdef FEAT_WINDOWS
8273 win_T *wp;
8274 #endif
8275 int nr;
8276
8277 nr = (int)get_tv_number_chk(vp, NULL);
8278
8279 #ifdef FEAT_WINDOWS
8280 if (nr < 0)
8281 return NULL;
8282 if (nr == 0)
8283 return curwin;
8284
8285 for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin;
8286 wp != NULL; wp = wp->w_next)
8287 if (nr >= LOWEST_WIN_ID)
8288 {
8289 if (wp->w_id == nr)
8290 return wp;
8291 }
8292 else if (--nr <= 0)
8293 break;
8294 if (nr >= LOWEST_WIN_ID)
8295 return NULL;
8296 return wp;
8297 #else
8298 if (nr == 0 || nr == 1 || nr == curwin->w_id)
8299 return curwin;
8300 return NULL;
8301 #endif
8302 }
8303
8304 /*
8305 * Find window specified by "wvp" in tabpage "tvp".
8306 */
8307 win_T *
8308 find_tabwin(
8309 typval_T *wvp, /* VAR_UNKNOWN for current window */
8310 typval_T *tvp) /* VAR_UNKNOWN for current tab page */
8311 {
8312 win_T *wp = NULL;
8313 tabpage_T *tp = NULL;
8314 long n;
8315
8316 if (wvp->v_type != VAR_UNKNOWN)
8317 {
8318 if (tvp->v_type != VAR_UNKNOWN)
8319 {
8320 n = (long)get_tv_number(tvp);
8321 if (n >= 0)
8322 tp = find_tabpage(n);
8323 }
8324 else
8325 tp = curtab;
8326
8327 if (tp != NULL)
8328 wp = find_win_by_nr(wvp, tp);
8329 }
8330 else
8331 wp = curwin;
8332
8333 return wp;
8334 }
8335
8336 /*
8337 * getwinvar() and gettabwinvar()
8338 */
8339 void
8340 getwinvar(
8341 typval_T *argvars,
8342 typval_T *rettv,
8343 int off) /* 1 for gettabwinvar() */
8344 {
8345 win_T *win;
8346 char_u *varname;
8347 dictitem_T *v;
8348 tabpage_T *tp = NULL;
8349 int done = FALSE;
8350 #ifdef FEAT_WINDOWS
8351 win_T *oldcurwin;
8352 tabpage_T *oldtabpage;
8353 int need_switch_win;
8354 #endif
8355
8356 #ifdef FEAT_WINDOWS
8357 if (off == 1)
8358 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
8359 else
8360 tp = curtab;
8361 #endif
8362 win = find_win_by_nr(&argvars[off], tp);
8363 varname = get_tv_string_chk(&argvars[off + 1]);
8364 ++emsg_off;
8365
8366 rettv->v_type = VAR_STRING;
8367 rettv->vval.v_string = NULL;
8368
8369 if (win != NULL && varname != NULL)
8370 {
8371 #ifdef FEAT_WINDOWS
8372 /* Set curwin to be our win, temporarily. Also set the tabpage,
8373 * otherwise the window is not valid. Only do this when needed,
8374 * autocommands get blocked. */
8375 need_switch_win = !(tp == curtab && win == curwin);
8376 if (!need_switch_win
8377 || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK)
8378 #endif
8379 {
8380 if (*varname == '&') /* window-local-option */
8381 {
8382 if (get_option_tv(&varname, rettv, 1) == OK)
8383 done = TRUE;
8384 }
8385 else
8386 {
8387 /* Look up the variable. */
8388 /* Let getwinvar({nr}, "") return the "w:" dictionary. */
8389 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
8390 varname, FALSE);
8391 if (v != NULL)
8392 {
8393 copy_tv(&v->di_tv, rettv);
8394 done = TRUE;
8395 }
8396 }
8397 }
8398
8399 #ifdef FEAT_WINDOWS
8400 if (need_switch_win)
8401 /* restore previous notion of curwin */
8402 restore_win(oldcurwin, oldtabpage, TRUE);
8403 #endif
8404 }
8405
8406 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
8407 /* use the default return value */
8408 copy_tv(&argvars[off + 2], rettv);
8409
8410 --emsg_off;
8411 }
8412
8413 /*
8414 * "setwinvar()" and "settabwinvar()" functions
8415 */
8416 void
8417 setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off)
8418 {
8419 win_T *win;
8420 #ifdef FEAT_WINDOWS
8421 win_T *save_curwin;
8422 tabpage_T *save_curtab;
8423 int need_switch_win;
8424 #endif
8425 char_u *varname, *winvarname;
8426 typval_T *varp;
8427 char_u nbuf[NUMBUFLEN];
8428 tabpage_T *tp = NULL;
8429
8430 if (check_restricted() || check_secure())
8431 return;
8432
8433 #ifdef FEAT_WINDOWS
8434 if (off == 1)
8435 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
8436 else
8437 tp = curtab;
8438 #endif
8439 win = find_win_by_nr(&argvars[off], tp);
8440 varname = get_tv_string_chk(&argvars[off + 1]);
8441 varp = &argvars[off + 2];
8442
8443 if (win != NULL && varname != NULL && varp != NULL)
8444 {
8445 #ifdef FEAT_WINDOWS
8446 need_switch_win = !(tp == curtab && win == curwin);
8447 if (!need_switch_win
8448 || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK)
8449 #endif
8450 {
8451 if (*varname == '&')
8452 {
8453 long numval;
8454 char_u *strval;
8455 int error = FALSE;
8456
8457 ++varname;
8458 numval = (long)get_tv_number_chk(varp, &error);
8459 strval = get_tv_string_buf_chk(varp, nbuf);
8460 if (!error && strval != NULL)
8461 set_option_value(varname, numval, strval, OPT_LOCAL);
8462 }
8463 else
8464 {
8465 winvarname = alloc((unsigned)STRLEN(varname) + 3);
8466 if (winvarname != NULL)
8467 {
8468 STRCPY(winvarname, "w:");
8469 STRCPY(winvarname + 2, varname);
8470 set_var(winvarname, varp, TRUE);
8471 vim_free(winvarname);
8472 }
8473 }
8474 }
8475 #ifdef FEAT_WINDOWS
8476 if (need_switch_win)
8477 restore_win(save_curwin, save_curtab, TRUE);
8478 #endif
8479 }
21516 } 8480 }
21517 8481
21518 /* 8482 /*
21519 * Skip over the name of an option: "&option", "&g:option" or "&l:option". 8483 * Skip over the name of an option: "&option", "&g:option" or "&l:option".
21520 * "arg" points to the "&" or '+' when called, to "option" when returning. 8484 * "arg" points to the "&" or '+' when called, to "option" when returning.
21928 reset_v_option_vars(void) 8892 reset_v_option_vars(void)
21929 { 8893 {
21930 set_vim_var_string(VV_OPTION_NEW, NULL, -1); 8894 set_vim_var_string(VV_OPTION_NEW, NULL, -1);
21931 set_vim_var_string(VV_OPTION_OLD, NULL, -1); 8895 set_vim_var_string(VV_OPTION_OLD, NULL, -1);
21932 set_vim_var_string(VV_OPTION_TYPE, NULL, -1); 8896 set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
8897 }
8898
8899 /*
8900 * Prepare "gap" for an assert error and add the sourcing position.
8901 */
8902 void
8903 prepare_assert_error(garray_T *gap)
8904 {
8905 char buf[NUMBUFLEN];
8906
8907 ga_init2(gap, 1, 100);
8908 if (sourcing_name != NULL)
8909 {
8910 ga_concat(gap, sourcing_name);
8911 if (sourcing_lnum > 0)
8912 ga_concat(gap, (char_u *)" ");
8913 }
8914 if (sourcing_lnum > 0)
8915 {
8916 sprintf(buf, "line %ld", (long)sourcing_lnum);
8917 ga_concat(gap, (char_u *)buf);
8918 }
8919 if (sourcing_name != NULL || sourcing_lnum > 0)
8920 ga_concat(gap, (char_u *)": ");
8921 }
8922
8923 /*
8924 * Add an assert error to v:errors.
8925 */
8926 void
8927 assert_error(garray_T *gap)
8928 {
8929 struct vimvar *vp = &vimvars[VV_ERRORS];
8930
8931 if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
8932 /* Make sure v:errors is a list. */
8933 set_vim_var_list(VV_ERRORS, list_alloc());
8934 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
8935 }
8936
8937 void
8938 assert_equal_common(typval_T *argvars, assert_type_T atype)
8939 {
8940 garray_T ga;
8941
8942 if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE)
8943 != (atype == ASSERT_EQUAL))
8944 {
8945 prepare_assert_error(&ga);
8946 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
8947 atype);
8948 assert_error(&ga);
8949 ga_clear(&ga);
8950 }
8951 }
8952
8953 void
8954 assert_match_common(typval_T *argvars, assert_type_T atype)
8955 {
8956 garray_T ga;
8957 char_u buf1[NUMBUFLEN];
8958 char_u buf2[NUMBUFLEN];
8959 char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1);
8960 char_u *text = get_tv_string_buf_chk(&argvars[1], buf2);
8961
8962 if (pat == NULL || text == NULL)
8963 EMSG(_(e_invarg));
8964 else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH))
8965 {
8966 prepare_assert_error(&ga);
8967 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1],
8968 atype);
8969 assert_error(&ga);
8970 ga_clear(&ga);
8971 }
8972 }
8973
8974 /*
8975 * Common for assert_true() and assert_false().
8976 */
8977 void
8978 assert_bool(typval_T *argvars, int isTrue)
8979 {
8980 int error = FALSE;
8981 garray_T ga;
8982
8983 if (argvars[0].v_type == VAR_SPECIAL
8984 && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE))
8985 return;
8986 if (argvars[0].v_type != VAR_NUMBER
8987 || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue
8988 || error)
8989 {
8990 prepare_assert_error(&ga);
8991 fill_assert_error(&ga, &argvars[1],
8992 (char_u *)(isTrue ? "True" : "False"),
8993 NULL, &argvars[0], ASSERT_OTHER);
8994 assert_error(&ga);
8995 ga_clear(&ga);
8996 }
8997 }
8998
8999 void
9000 assert_exception(typval_T *argvars)
9001 {
9002 garray_T ga;
9003 char_u *error = get_tv_string_chk(&argvars[0]);
9004
9005 if (vimvars[VV_EXCEPTION].vv_str == NULL)
9006 {
9007 prepare_assert_error(&ga);
9008 ga_concat(&ga, (char_u *)"v:exception is not set");
9009 assert_error(&ga);
9010 ga_clear(&ga);
9011 }
9012 else if (error != NULL
9013 && strstr((char *)vimvars[VV_EXCEPTION].vv_str, (char *)error) == NULL)
9014 {
9015 prepare_assert_error(&ga);
9016 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
9017 &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER);
9018 assert_error(&ga);
9019 ga_clear(&ga);
9020 }
9021 }
9022
9023 void
9024 assert_fails(typval_T *argvars)
9025 {
9026 char_u *cmd = get_tv_string_chk(&argvars[0]);
9027 garray_T ga;
9028
9029 called_emsg = FALSE;
9030 suppress_errthrow = TRUE;
9031 emsg_silent = TRUE;
9032 do_cmdline_cmd(cmd);
9033 if (!called_emsg)
9034 {
9035 prepare_assert_error(&ga);
9036 ga_concat(&ga, (char_u *)"command did not fail: ");
9037 ga_concat(&ga, cmd);
9038 assert_error(&ga);
9039 ga_clear(&ga);
9040 }
9041 else if (argvars[1].v_type != VAR_UNKNOWN)
9042 {
9043 char_u buf[NUMBUFLEN];
9044 char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf);
9045
9046 if (error == NULL
9047 || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL)
9048 {
9049 prepare_assert_error(&ga);
9050 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
9051 &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
9052 assert_error(&ga);
9053 ga_clear(&ga);
9054 }
9055 }
9056
9057 called_emsg = FALSE;
9058 suppress_errthrow = FALSE;
9059 emsg_silent = FALSE;
9060 emsg_on_display = FALSE;
9061 set_vim_var_string(VV_ERRMSG, NULL, 0);
9062 }
9063
9064 /*
9065 * Append "str" to "gap", escaping unprintable characters.
9066 * Changes NL to \n, CR to \r, etc.
9067 */
9068 static void
9069 ga_concat_esc(garray_T *gap, char_u *str)
9070 {
9071 char_u *p;
9072 char_u buf[NUMBUFLEN];
9073
9074 if (str == NULL)
9075 {
9076 ga_concat(gap, (char_u *)"NULL");
9077 return;
9078 }
9079
9080 for (p = str; *p != NUL; ++p)
9081 switch (*p)
9082 {
9083 case BS: ga_concat(gap, (char_u *)"\\b"); break;
9084 case ESC: ga_concat(gap, (char_u *)"\\e"); break;
9085 case FF: ga_concat(gap, (char_u *)"\\f"); break;
9086 case NL: ga_concat(gap, (char_u *)"\\n"); break;
9087 case TAB: ga_concat(gap, (char_u *)"\\t"); break;
9088 case CAR: ga_concat(gap, (char_u *)"\\r"); break;
9089 case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
9090 default:
9091 if (*p < ' ')
9092 {
9093 vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
9094 ga_concat(gap, buf);
9095 }
9096 else
9097 ga_append(gap, *p);
9098 break;
9099 }
9100 }
9101
9102 /*
9103 * Fill "gap" with information about an assert error.
9104 */
9105 void
9106 fill_assert_error(
9107 garray_T *gap,
9108 typval_T *opt_msg_tv,
9109 char_u *exp_str,
9110 typval_T *exp_tv,
9111 typval_T *got_tv,
9112 assert_type_T atype)
9113 {
9114 char_u numbuf[NUMBUFLEN];
9115 char_u *tofree;
9116
9117 if (opt_msg_tv->v_type != VAR_UNKNOWN)
9118 {
9119 ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0));
9120 vim_free(tofree);
9121 }
9122 else
9123 {
9124 if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH)
9125 ga_concat(gap, (char_u *)"Pattern ");
9126 else
9127 ga_concat(gap, (char_u *)"Expected ");
9128 if (exp_str == NULL)
9129 {
9130 ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0));
9131 vim_free(tofree);
9132 }
9133 else
9134 ga_concat_esc(gap, exp_str);
9135 if (atype == ASSERT_MATCH)
9136 ga_concat(gap, (char_u *)" does not match ");
9137 else if (atype == ASSERT_NOTMATCH)
9138 ga_concat(gap, (char_u *)" does match ");
9139 else if (atype == ASSERT_NOTEQUAL)
9140 ga_concat(gap, (char_u *)" differs from ");
9141 else
9142 ga_concat(gap, (char_u *)" but got ");
9143 ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
9144 vim_free(tofree);
9145 }
21933 } 9146 }
21934 9147
21935 9148
21936 #endif /* FEAT_EVAL */ 9149 #endif /* FEAT_EVAL */
21937 9150
22676 free_string_option(save_cpo); 9889 free_string_option(save_cpo);
22677 9890
22678 return ret; 9891 return ret;
22679 } 9892 }
22680 9893
9894 static int
9895 filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
9896 {
9897 typval_T rettv;
9898 typval_T argv[3];
9899 char_u buf[NUMBUFLEN];
9900 char_u *s;
9901 int retval = FAIL;
9902 int dummy;
9903
9904 copy_tv(tv, &vimvars[VV_VAL].vv_tv);
9905 argv[0] = vimvars[VV_KEY].vv_tv;
9906 argv[1] = vimvars[VV_VAL].vv_tv;
9907 if (expr->v_type == VAR_FUNC)
9908 {
9909 s = expr->vval.v_string;
9910 if (call_func(s, (int)STRLEN(s),
9911 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL)
9912 goto theend;
9913 }
9914 else if (expr->v_type == VAR_PARTIAL)
9915 {
9916 partial_T *partial = expr->vval.v_partial;
9917
9918 s = partial->pt_name;
9919 if (call_func(s, (int)STRLEN(s),
9920 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL)
9921 == FAIL)
9922 goto theend;
9923 }
9924 else
9925 {
9926 s = get_tv_string_buf_chk(expr, buf);
9927 if (s == NULL)
9928 goto theend;
9929 s = skipwhite(s);
9930 if (eval1(&s, &rettv, TRUE) == FAIL)
9931 goto theend;
9932 if (*s != NUL) /* check for trailing chars after expr */
9933 {
9934 EMSG2(_(e_invexpr2), s);
9935 goto theend;
9936 }
9937 }
9938 if (map)
9939 {
9940 /* map(): replace the list item value */
9941 clear_tv(tv);
9942 rettv.v_lock = 0;
9943 *tv = rettv;
9944 }
9945 else
9946 {
9947 int error = FALSE;
9948
9949 /* filter(): when expr is zero remove the item */
9950 *remp = (get_tv_number_chk(&rettv, &error) == 0);
9951 clear_tv(&rettv);
9952 /* On type error, nothing has been removed; return FAIL to stop the
9953 * loop. The error message was given by get_tv_number_chk(). */
9954 if (error)
9955 goto theend;
9956 }
9957 retval = OK;
9958 theend:
9959 clear_tv(&vimvars[VV_VAL].vv_tv);
9960 return retval;
9961 }
9962
9963
9964 /*
9965 * Implementation of map() and filter().
9966 */
9967 void
9968 filter_map(typval_T *argvars, typval_T *rettv, int map)
9969 {
9970 typval_T *expr;
9971 listitem_T *li, *nli;
9972 list_T *l = NULL;
9973 dictitem_T *di;
9974 hashtab_T *ht;
9975 hashitem_T *hi;
9976 dict_T *d = NULL;
9977 typval_T save_val;
9978 typval_T save_key;
9979 int rem;
9980 int todo;
9981 char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
9982 char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
9983 : N_("filter() argument"));
9984 int save_did_emsg;
9985 int idx = 0;
9986
9987 if (argvars[0].v_type == VAR_LIST)
9988 {
9989 if ((l = argvars[0].vval.v_list) == NULL
9990 || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE)))
9991 return;
9992 }
9993 else if (argvars[0].v_type == VAR_DICT)
9994 {
9995 if ((d = argvars[0].vval.v_dict) == NULL
9996 || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE)))
9997 return;
9998 }
9999 else
10000 {
10001 EMSG2(_(e_listdictarg), ermsg);
10002 return;
10003 }
10004
10005 expr = &argvars[1];
10006 /* On type errors, the preceding call has already displayed an error
10007 * message. Avoid a misleading error message for an empty string that
10008 * was not passed as argument. */
10009 if (expr->v_type != VAR_UNKNOWN)
10010 {
10011 prepare_vimvar(VV_VAL, &save_val);
10012
10013 /* We reset "did_emsg" to be able to detect whether an error
10014 * occurred during evaluation of the expression. */
10015 save_did_emsg = did_emsg;
10016 did_emsg = FALSE;
10017
10018 prepare_vimvar(VV_KEY, &save_key);
10019 if (argvars[0].v_type == VAR_DICT)
10020 {
10021 vimvars[VV_KEY].vv_type = VAR_STRING;
10022
10023 ht = &d->dv_hashtab;
10024 hash_lock(ht);
10025 todo = (int)ht->ht_used;
10026 for (hi = ht->ht_array; todo > 0; ++hi)
10027 {
10028 if (!HASHITEM_EMPTY(hi))
10029 {
10030 int r;
10031
10032 --todo;
10033 di = HI2DI(hi);
10034 if (map &&
10035 (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE)
10036 || var_check_ro(di->di_flags, arg_errmsg, TRUE)))
10037 break;
10038 vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
10039 r = filter_map_one(&di->di_tv, expr, map, &rem);
10040 clear_tv(&vimvars[VV_KEY].vv_tv);
10041 if (r == FAIL || did_emsg)
10042 break;
10043 if (!map && rem)
10044 {
10045 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
10046 || var_check_ro(di->di_flags, arg_errmsg, TRUE))
10047 break;
10048 dictitem_remove(d, di);
10049 }
10050 }
10051 }
10052 hash_unlock(ht);
10053 }
10054 else
10055 {
10056 vimvars[VV_KEY].vv_type = VAR_NUMBER;
10057
10058 for (li = l->lv_first; li != NULL; li = nli)
10059 {
10060 if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
10061 break;
10062 nli = li->li_next;
10063 vimvars[VV_KEY].vv_nr = idx;
10064 if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
10065 || did_emsg)
10066 break;
10067 if (!map && rem)
10068 listitem_remove(l, li);
10069 ++idx;
10070 }
10071 }
10072
10073 restore_vimvar(VV_KEY, &save_key);
10074 restore_vimvar(VV_VAL, &save_val);
10075
10076 did_emsg |= save_did_emsg;
10077 }
10078
10079 copy_tv(&argvars[0], rettv);
10080 }
10081
22681 #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */ 10082 #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */