Mercurial > vim
diff 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 |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -16,29 +16,15 @@ #if defined(FEAT_EVAL) || defined(PROTO) -#ifdef AMIGA -# include <time.h> /* for strftime() */ -#endif - #ifdef VMS # include <float.h> #endif -#ifdef MACOS -# include <time.h> /* for time_t */ -#endif - #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ static char *e_letunexp = N_("E18: Unexpected characters in :let"); static char *e_undefvar = N_("E121: Undefined variable: %s"); static char *e_missbrac = N_("E111: Missing ']'"); -static char *e_listarg = N_("E686: Argument of %s must be a List"); -static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionary"); -static char *e_listreq = N_("E714: List required"); -#ifdef FEAT_QUICKFIX -static char *e_stringreq = N_("E928: String required"); -#endif static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_letwrong = N_("E734: Wrong variable type for %s="); static char *e_illvar = N_("E461: Illegal variable name: %s"); @@ -101,7 +87,6 @@ typedef struct * The reason to use this table anyway is for very quick access to the * variables with the VV_ defines. */ -#include "version.h" /* values for vv_flags: */ #define VV_COMPAT 1 /* compatible, also used without "v:" */ @@ -206,8 +191,6 @@ static struct vimvar static dictitem_T vimvars_var; /* variable used for v: */ #define vimvarht vimvardict.dv_hashtab -static void prepare_vimvar(int idx, typval_T *save_tv); -static void restore_vimvar(int idx, typval_T *save_tv); static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars); static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon); static char_u *skip_var_one(char_u *arg); @@ -221,14 +204,12 @@ static void list_vim_vars(int *first); static void list_script_vars(int *first); static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op); -static int check_changedtick(char_u *arg); static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op); static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep); static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit); static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock); static void item_lock(typval_T *tv, int deep, int lock); -static int tv_islocked(typval_T *tv); static int eval2(char_u **arg, typval_T *rettv, int evaluate); static int eval3(char_u **arg, typval_T *rettv, int evaluate); @@ -238,445 +219,29 @@ static int eval6(char_u **arg, typval_T static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); -static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); static int free_unref_items(int copyID); static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); -static int non_zero_arg(typval_T *argvars); - -#ifdef FEAT_FLOAT -static void f_abs(typval_T *argvars, typval_T *rettv); -static void f_acos(typval_T *argvars, typval_T *rettv); -#endif -static void f_add(typval_T *argvars, typval_T *rettv); -static void f_and(typval_T *argvars, typval_T *rettv); -static void f_append(typval_T *argvars, typval_T *rettv); -static void f_argc(typval_T *argvars, typval_T *rettv); -static void f_argidx(typval_T *argvars, typval_T *rettv); -static void f_arglistid(typval_T *argvars, typval_T *rettv); -static void f_argv(typval_T *argvars, typval_T *rettv); -static void f_assert_equal(typval_T *argvars, typval_T *rettv); -static void f_assert_exception(typval_T *argvars, typval_T *rettv); -static void f_assert_fails(typval_T *argvars, typval_T *rettv); -static void f_assert_false(typval_T *argvars, typval_T *rettv); -static void f_assert_match(typval_T *argvars, typval_T *rettv); -static void f_assert_notequal(typval_T *argvars, typval_T *rettv); -static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); -static void f_assert_true(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_asin(typval_T *argvars, typval_T *rettv); -static void f_atan(typval_T *argvars, typval_T *rettv); -static void f_atan2(typval_T *argvars, typval_T *rettv); -#endif -static void f_browse(typval_T *argvars, typval_T *rettv); -static void f_browsedir(typval_T *argvars, typval_T *rettv); -static void f_bufexists(typval_T *argvars, typval_T *rettv); -static void f_buflisted(typval_T *argvars, typval_T *rettv); -static void f_bufloaded(typval_T *argvars, typval_T *rettv); -static void f_bufname(typval_T *argvars, typval_T *rettv); -static void f_bufnr(typval_T *argvars, typval_T *rettv); -static void f_bufwinid(typval_T *argvars, typval_T *rettv); -static void f_bufwinnr(typval_T *argvars, typval_T *rettv); -static void f_byte2line(typval_T *argvars, typval_T *rettv); -static void byteidx(typval_T *argvars, typval_T *rettv, int comp); -static void f_byteidx(typval_T *argvars, typval_T *rettv); -static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); -static void f_call(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_ceil(typval_T *argvars, typval_T *rettv); -#endif -#ifdef FEAT_JOB_CHANNEL -static void f_ch_close(typval_T *argvars, typval_T *rettv); -static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); -static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); -static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); -static void f_ch_getjob(typval_T *argvars, typval_T *rettv); -static void f_ch_info(typval_T *argvars, typval_T *rettv); -static void f_ch_log(typval_T *argvars, typval_T *rettv); -static void f_ch_logfile(typval_T *argvars, typval_T *rettv); -static void f_ch_open(typval_T *argvars, typval_T *rettv); -static void f_ch_read(typval_T *argvars, typval_T *rettv); -static void f_ch_readraw(typval_T *argvars, typval_T *rettv); -static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); -static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); -static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); -static void f_ch_status(typval_T *argvars, typval_T *rettv); -#endif -static void f_changenr(typval_T *argvars, typval_T *rettv); -static void f_char2nr(typval_T *argvars, typval_T *rettv); -static void f_cindent(typval_T *argvars, typval_T *rettv); -static void f_clearmatches(typval_T *argvars, typval_T *rettv); -static void f_col(typval_T *argvars, typval_T *rettv); -#if defined(FEAT_INS_EXPAND) -static void f_complete(typval_T *argvars, typval_T *rettv); -static void f_complete_add(typval_T *argvars, typval_T *rettv); -static void f_complete_check(typval_T *argvars, typval_T *rettv); -#endif -static void f_confirm(typval_T *argvars, typval_T *rettv); -static void f_copy(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_cos(typval_T *argvars, typval_T *rettv); -static void f_cosh(typval_T *argvars, typval_T *rettv); -#endif -static void f_count(typval_T *argvars, typval_T *rettv); -static void f_cscope_connection(typval_T *argvars, typval_T *rettv); -static void f_cursor(typval_T *argsvars, typval_T *rettv); -static void f_deepcopy(typval_T *argvars, typval_T *rettv); -static void f_delete(typval_T *argvars, typval_T *rettv); -static void f_did_filetype(typval_T *argvars, typval_T *rettv); -static void f_diff_filler(typval_T *argvars, typval_T *rettv); -static void f_diff_hlID(typval_T *argvars, typval_T *rettv); -static void f_empty(typval_T *argvars, typval_T *rettv); -static void f_escape(typval_T *argvars, typval_T *rettv); -static void f_eval(typval_T *argvars, typval_T *rettv); -static void f_eventhandler(typval_T *argvars, typval_T *rettv); -static void f_executable(typval_T *argvars, typval_T *rettv); -static void f_execute(typval_T *argvars, typval_T *rettv); -static void f_exepath(typval_T *argvars, typval_T *rettv); -static void f_exists(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_exp(typval_T *argvars, typval_T *rettv); -#endif -static void f_expand(typval_T *argvars, typval_T *rettv); -static void f_extend(typval_T *argvars, typval_T *rettv); -static void f_feedkeys(typval_T *argvars, typval_T *rettv); -static void f_filereadable(typval_T *argvars, typval_T *rettv); -static void f_filewritable(typval_T *argvars, typval_T *rettv); -static void f_filter(typval_T *argvars, typval_T *rettv); -static void f_finddir(typval_T *argvars, typval_T *rettv); -static void f_findfile(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_float2nr(typval_T *argvars, typval_T *rettv); -static void f_floor(typval_T *argvars, typval_T *rettv); -static void f_fmod(typval_T *argvars, typval_T *rettv); -#endif -static void f_fnameescape(typval_T *argvars, typval_T *rettv); -static void f_fnamemodify(typval_T *argvars, typval_T *rettv); -static void f_foldclosed(typval_T *argvars, typval_T *rettv); -static void f_foldclosedend(typval_T *argvars, typval_T *rettv); -static void f_foldlevel(typval_T *argvars, typval_T *rettv); -static void f_foldtext(typval_T *argvars, typval_T *rettv); -static void f_foldtextresult(typval_T *argvars, typval_T *rettv); -static void f_foreground(typval_T *argvars, typval_T *rettv); -static void f_function(typval_T *argvars, typval_T *rettv); -static void f_garbagecollect(typval_T *argvars, typval_T *rettv); -static void f_get(typval_T *argvars, typval_T *rettv); -static void f_getbufline(typval_T *argvars, typval_T *rettv); -static void f_getbufvar(typval_T *argvars, typval_T *rettv); -static void f_getchar(typval_T *argvars, typval_T *rettv); -static void f_getcharmod(typval_T *argvars, typval_T *rettv); -static void f_getcharsearch(typval_T *argvars, typval_T *rettv); -static void f_getcmdline(typval_T *argvars, typval_T *rettv); -#if defined(FEAT_CMDL_COMPL) -static void f_getcompletion(typval_T *argvars, typval_T *rettv); -#endif -static void f_getcmdpos(typval_T *argvars, typval_T *rettv); -static void f_getcmdtype(typval_T *argvars, typval_T *rettv); -static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); -static void f_getcwd(typval_T *argvars, typval_T *rettv); -static void f_getfontname(typval_T *argvars, typval_T *rettv); -static void f_getfperm(typval_T *argvars, typval_T *rettv); -static void f_getfsize(typval_T *argvars, typval_T *rettv); -static void f_getftime(typval_T *argvars, typval_T *rettv); -static void f_getftype(typval_T *argvars, typval_T *rettv); -static void f_getline(typval_T *argvars, typval_T *rettv); -static void f_getmatches(typval_T *argvars, typval_T *rettv); -static void f_getpid(typval_T *argvars, typval_T *rettv); -static void f_getcurpos(typval_T *argvars, typval_T *rettv); -static void f_getpos(typval_T *argvars, typval_T *rettv); -static void f_getqflist(typval_T *argvars, typval_T *rettv); -static void f_getreg(typval_T *argvars, typval_T *rettv); -static void f_getregtype(typval_T *argvars, typval_T *rettv); -static void f_gettabvar(typval_T *argvars, typval_T *rettv); -static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); -static void f_getwinposx(typval_T *argvars, typval_T *rettv); -static void f_getwinposy(typval_T *argvars, typval_T *rettv); -static void f_getwinvar(typval_T *argvars, typval_T *rettv); -static void f_glob(typval_T *argvars, typval_T *rettv); -static void f_globpath(typval_T *argvars, typval_T *rettv); -static void f_glob2regpat(typval_T *argvars, typval_T *rettv); -static void f_has(typval_T *argvars, typval_T *rettv); -static void f_has_key(typval_T *argvars, typval_T *rettv); -static void f_haslocaldir(typval_T *argvars, typval_T *rettv); -static void f_hasmapto(typval_T *argvars, typval_T *rettv); -static void f_histadd(typval_T *argvars, typval_T *rettv); -static void f_histdel(typval_T *argvars, typval_T *rettv); -static void f_histget(typval_T *argvars, typval_T *rettv); -static void f_histnr(typval_T *argvars, typval_T *rettv); -static void f_hlID(typval_T *argvars, typval_T *rettv); -static void f_hlexists(typval_T *argvars, typval_T *rettv); -static void f_hostname(typval_T *argvars, typval_T *rettv); -static void f_iconv(typval_T *argvars, typval_T *rettv); -static void f_indent(typval_T *argvars, typval_T *rettv); -static void f_index(typval_T *argvars, typval_T *rettv); -static void f_input(typval_T *argvars, typval_T *rettv); -static void f_inputdialog(typval_T *argvars, typval_T *rettv); -static void f_inputlist(typval_T *argvars, typval_T *rettv); -static void f_inputrestore(typval_T *argvars, typval_T *rettv); -static void f_inputsave(typval_T *argvars, typval_T *rettv); -static void f_inputsecret(typval_T *argvars, typval_T *rettv); -static void f_insert(typval_T *argvars, typval_T *rettv); -static void f_invert(typval_T *argvars, typval_T *rettv); -static void f_isdirectory(typval_T *argvars, typval_T *rettv); -static void f_islocked(typval_T *argvars, typval_T *rettv); -#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) -static void f_isnan(typval_T *argvars, typval_T *rettv); -#endif -static void f_items(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_JOB_CHANNEL -static void f_job_getchannel(typval_T *argvars, typval_T *rettv); -static void f_job_info(typval_T *argvars, typval_T *rettv); -static void f_job_setoptions(typval_T *argvars, typval_T *rettv); -static void f_job_start(typval_T *argvars, typval_T *rettv); -static void f_job_stop(typval_T *argvars, typval_T *rettv); -static void f_job_status(typval_T *argvars, typval_T *rettv); -#endif -static void f_join(typval_T *argvars, typval_T *rettv); -static void f_js_decode(typval_T *argvars, typval_T *rettv); -static void f_js_encode(typval_T *argvars, typval_T *rettv); -static void f_json_decode(typval_T *argvars, typval_T *rettv); -static void f_json_encode(typval_T *argvars, typval_T *rettv); -static void f_keys(typval_T *argvars, typval_T *rettv); -static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); -static void f_len(typval_T *argvars, typval_T *rettv); -static void f_libcall(typval_T *argvars, typval_T *rettv); -static void f_libcallnr(typval_T *argvars, typval_T *rettv); -static void f_line(typval_T *argvars, typval_T *rettv); -static void f_line2byte(typval_T *argvars, typval_T *rettv); -static void f_lispindent(typval_T *argvars, typval_T *rettv); -static void f_localtime(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_log(typval_T *argvars, typval_T *rettv); -static void f_log10(typval_T *argvars, typval_T *rettv); -#endif -#ifdef FEAT_LUA -static void f_luaeval(typval_T *argvars, typval_T *rettv); -#endif -static void f_map(typval_T *argvars, typval_T *rettv); -static void f_maparg(typval_T *argvars, typval_T *rettv); -static void f_mapcheck(typval_T *argvars, typval_T *rettv); -static void f_match(typval_T *argvars, typval_T *rettv); -static void f_matchadd(typval_T *argvars, typval_T *rettv); -static void f_matchaddpos(typval_T *argvars, typval_T *rettv); -static void f_matcharg(typval_T *argvars, typval_T *rettv); -static void f_matchdelete(typval_T *argvars, typval_T *rettv); -static void f_matchend(typval_T *argvars, typval_T *rettv); -static void f_matchlist(typval_T *argvars, typval_T *rettv); -static void f_matchstr(typval_T *argvars, typval_T *rettv); -static void f_matchstrpos(typval_T *argvars, typval_T *rettv); -static void f_max(typval_T *argvars, typval_T *rettv); -static void f_min(typval_T *argvars, typval_T *rettv); -#ifdef vim_mkdir -static void f_mkdir(typval_T *argvars, typval_T *rettv); -#endif -static void f_mode(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_MZSCHEME -static void f_mzeval(typval_T *argvars, typval_T *rettv); -#endif -static void f_nextnonblank(typval_T *argvars, typval_T *rettv); -static void f_nr2char(typval_T *argvars, typval_T *rettv); -static void f_or(typval_T *argvars, typval_T *rettv); -static void f_pathshorten(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_PERL -static void f_perleval(typval_T *argvars, typval_T *rettv); -#endif -#ifdef FEAT_FLOAT -static void f_pow(typval_T *argvars, typval_T *rettv); -#endif -static void f_prevnonblank(typval_T *argvars, typval_T *rettv); -static void f_printf(typval_T *argvars, typval_T *rettv); -static void f_pumvisible(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_PYTHON3 -static void f_py3eval(typval_T *argvars, typval_T *rettv); -#endif -#ifdef FEAT_PYTHON -static void f_pyeval(typval_T *argvars, typval_T *rettv); -#endif -static void f_range(typval_T *argvars, typval_T *rettv); -static void f_readfile(typval_T *argvars, typval_T *rettv); -static void f_reltime(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_reltimefloat(typval_T *argvars, typval_T *rettv); -#endif -static void f_reltimestr(typval_T *argvars, typval_T *rettv); -static void f_remote_expr(typval_T *argvars, typval_T *rettv); -static void f_remote_foreground(typval_T *argvars, typval_T *rettv); -static void f_remote_peek(typval_T *argvars, typval_T *rettv); -static void f_remote_read(typval_T *argvars, typval_T *rettv); -static void f_remote_send(typval_T *argvars, typval_T *rettv); -static void f_remove(typval_T *argvars, typval_T *rettv); -static void f_rename(typval_T *argvars, typval_T *rettv); -static void f_repeat(typval_T *argvars, typval_T *rettv); -static void f_resolve(typval_T *argvars, typval_T *rettv); -static void f_reverse(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_round(typval_T *argvars, typval_T *rettv); -#endif -static void f_screenattr(typval_T *argvars, typval_T *rettv); -static void f_screenchar(typval_T *argvars, typval_T *rettv); -static void f_screencol(typval_T *argvars, typval_T *rettv); -static void f_screenrow(typval_T *argvars, typval_T *rettv); -static void f_search(typval_T *argvars, typval_T *rettv); -static void f_searchdecl(typval_T *argvars, typval_T *rettv); -static void f_searchpair(typval_T *argvars, typval_T *rettv); -static void f_searchpairpos(typval_T *argvars, typval_T *rettv); -static void f_searchpos(typval_T *argvars, typval_T *rettv); -static void f_server2client(typval_T *argvars, typval_T *rettv); -static void f_serverlist(typval_T *argvars, typval_T *rettv); -static void f_setbufvar(typval_T *argvars, typval_T *rettv); -static void f_setcharsearch(typval_T *argvars, typval_T *rettv); -static void f_setcmdpos(typval_T *argvars, typval_T *rettv); -static void f_setfperm(typval_T *argvars, typval_T *rettv); -static void f_setline(typval_T *argvars, typval_T *rettv); -static void f_setloclist(typval_T *argvars, typval_T *rettv); -static void f_setmatches(typval_T *argvars, typval_T *rettv); -static void f_setpos(typval_T *argvars, typval_T *rettv); -static void f_setqflist(typval_T *argvars, typval_T *rettv); -static void f_setreg(typval_T *argvars, typval_T *rettv); -static void f_settabvar(typval_T *argvars, typval_T *rettv); -static void f_settabwinvar(typval_T *argvars, typval_T *rettv); -static void f_setwinvar(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_CRYPT -static void f_sha256(typval_T *argvars, typval_T *rettv); -#endif /* FEAT_CRYPT */ -static void f_shellescape(typval_T *argvars, typval_T *rettv); -static void f_shiftwidth(typval_T *argvars, typval_T *rettv); -static void f_simplify(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_sin(typval_T *argvars, typval_T *rettv); -static void f_sinh(typval_T *argvars, typval_T *rettv); -#endif -static void f_sort(typval_T *argvars, typval_T *rettv); -static void f_soundfold(typval_T *argvars, typval_T *rettv); -static void f_spellbadword(typval_T *argvars, typval_T *rettv); -static void f_spellsuggest(typval_T *argvars, typval_T *rettv); -static void f_split(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_sqrt(typval_T *argvars, typval_T *rettv); -static void f_str2float(typval_T *argvars, typval_T *rettv); -#endif -static void f_str2nr(typval_T *argvars, typval_T *rettv); -static void f_strchars(typval_T *argvars, typval_T *rettv); -#ifdef HAVE_STRFTIME -static void f_strftime(typval_T *argvars, typval_T *rettv); -#endif -static void f_strgetchar(typval_T *argvars, typval_T *rettv); -static void f_stridx(typval_T *argvars, typval_T *rettv); -static void f_string(typval_T *argvars, typval_T *rettv); -static void f_strlen(typval_T *argvars, typval_T *rettv); -static void f_strcharpart(typval_T *argvars, typval_T *rettv); -static void f_strpart(typval_T *argvars, typval_T *rettv); -static void f_strridx(typval_T *argvars, typval_T *rettv); -static void f_strtrans(typval_T *argvars, typval_T *rettv); -static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); -static void f_strwidth(typval_T *argvars, typval_T *rettv); -static void f_submatch(typval_T *argvars, typval_T *rettv); -static void f_substitute(typval_T *argvars, typval_T *rettv); -static void f_synID(typval_T *argvars, typval_T *rettv); -static void f_synIDattr(typval_T *argvars, typval_T *rettv); -static void f_synIDtrans(typval_T *argvars, typval_T *rettv); -static void f_synstack(typval_T *argvars, typval_T *rettv); -static void f_synconcealed(typval_T *argvars, typval_T *rettv); -static void f_system(typval_T *argvars, typval_T *rettv); -static void f_systemlist(typval_T *argvars, typval_T *rettv); -static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); -static void f_tabpagenr(typval_T *argvars, typval_T *rettv); -static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv); -static void f_taglist(typval_T *argvars, typval_T *rettv); -static void f_tagfiles(typval_T *argvars, typval_T *rettv); -static void f_tempname(typval_T *argvars, typval_T *rettv); -static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); -static void f_test_autochdir(typval_T *argvars, typval_T *rettv); -static void f_test_disable_char_avail(typval_T *argvars, typval_T *rettv); -static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_JOB_CHANNEL -static void f_test_null_channel(typval_T *argvars, typval_T *rettv); -#endif -static void f_test_null_dict(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_JOB_CHANNEL -static void f_test_null_job(typval_T *argvars, typval_T *rettv); -#endif -static void f_test_null_list(typval_T *argvars, typval_T *rettv); -static void f_test_null_partial(typval_T *argvars, typval_T *rettv); -static void f_test_null_string(typval_T *argvars, typval_T *rettv); -static void f_test_settime(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_tan(typval_T *argvars, typval_T *rettv); -static void f_tanh(typval_T *argvars, typval_T *rettv); -#endif -#ifdef FEAT_TIMERS -static void f_timer_start(typval_T *argvars, typval_T *rettv); -static void f_timer_stop(typval_T *argvars, typval_T *rettv); -#endif -static void f_tolower(typval_T *argvars, typval_T *rettv); -static void f_toupper(typval_T *argvars, typval_T *rettv); -static void f_tr(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_trunc(typval_T *argvars, typval_T *rettv); -#endif -static void f_type(typval_T *argvars, typval_T *rettv); -static void f_undofile(typval_T *argvars, typval_T *rettv); -static void f_undotree(typval_T *argvars, typval_T *rettv); -static void f_uniq(typval_T *argvars, typval_T *rettv); -static void f_values(typval_T *argvars, typval_T *rettv); -static void f_virtcol(typval_T *argvars, typval_T *rettv); -static void f_visualmode(typval_T *argvars, typval_T *rettv); -static void f_wildmenumode(typval_T *argvars, typval_T *rettv); -static void f_win_findbuf(typval_T *argvars, typval_T *rettv); -static void f_win_getid(typval_T *argvars, typval_T *rettv); -static void f_win_gotoid(typval_T *argvars, typval_T *rettv); -static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); -static void f_win_id2win(typval_T *argvars, typval_T *rettv); -static void f_winbufnr(typval_T *argvars, typval_T *rettv); -static void f_wincol(typval_T *argvars, typval_T *rettv); -static void f_winheight(typval_T *argvars, typval_T *rettv); -static void f_winline(typval_T *argvars, typval_T *rettv); -static void f_winnr(typval_T *argvars, typval_T *rettv); -static void f_winrestcmd(typval_T *argvars, typval_T *rettv); -static void f_winrestview(typval_T *argvars, typval_T *rettv); -static void f_winsaveview(typval_T *argvars, typval_T *rettv); -static void f_winwidth(typval_T *argvars, typval_T *rettv); -static void f_writefile(typval_T *argvars, typval_T *rettv); -static void f_wordcount(typval_T *argvars, typval_T *rettv); -static void f_xor(typval_T *argvars, typval_T *rettv); - -static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp); -static pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum); + + static int get_env_len(char_u **arg); -static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose); static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); -static int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload); static typval_T *alloc_string_tv(char_u *string); -static void init_tv(typval_T *varp); -#ifdef FEAT_FLOAT -static float_T get_tv_float(typval_T *varp); -#endif -static linenr_T get_tv_lnum(typval_T *argvars); -static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf); -static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); static hashtab_T *find_var_ht(char_u *name, char_u **varname); static void delete_var(hashtab_T *ht, hashitem_T *hi); static void list_one_var(dictitem_T *v, char_u *prefix, int *first); static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first); -static void set_var(char_u *name, typval_T *varp, int copy); -static int var_check_fixed(int flags, char_u *name, int use_gettext); static char_u *find_option_end(char_u **arg, int *opt_flags); -static win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp); -static win_T *find_tabwin(typval_T *wvp, typval_T *tvp); -static void getwinvar(typval_T *argvars, typval_T *rettv, int off); -static int searchpair_cmn(typval_T *argvars, pos_T *match_pos); -static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp); -static void setwinvar(typval_T *argvars, typval_T *rettv, int off); -static int write_list(FILE *fd, list_T *list, int binary); -static void get_cmd_output_as_rettv(typval_T *argvars, typval_T *rettv, int retlist); - #ifdef EBCDIC static int compare_func_name(const void *s1, const void *s2); static void sortFunctions(); #endif +/* for VIM_VERSION_ defines */ +#include "version.h" + /* * Initialize the global and v: variables. */ @@ -2200,7 +1765,7 @@ ex_let_one( /* * If "arg" is equal to "b:changedtick" give an error and return TRUE. */ - static int + int check_changedtick(char_u *arg) { if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) @@ -3413,22 +2978,6 @@ item_lock(typval_T *tv, int deep, int lo --recurse; } -/* - * Return TRUE if typeval "tv" is locked: Either that value is locked itself - * or it refers to a List or Dictionary that is locked. - */ - static int -tv_islocked(typval_T *tv) -{ - return (tv->v_lock & VAR_LOCKED) - || (tv->v_type == VAR_LIST - && tv->vval.v_list != NULL - && (tv->vval.v_list->lv_lock & VAR_LOCKED)) - || (tv->v_type == VAR_DICT - && tv->vval.v_dict != NULL - && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); -} - #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO) /* * Delete all "menutrans_" variables. @@ -5159,7 +4708,7 @@ eval_index( * "arg" is advanced to character after the option name. * Return OK or FAIL. */ - static int + int get_option_tv( char_u **arg, typval_T *rettv, /* when NULL, only check if option exists */ @@ -6421,12882 +5970,13 @@ get_env_tv(char_u **arg, typval_T *rettv return OK; } -/* - * Array with names and number of arguments of all internal functions - * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! - */ -static struct fst -{ - char *f_name; /* function name */ - char f_min_argc; /* minimal number of arguments */ - char f_max_argc; /* maximal number of arguments */ - void (*f_func)(typval_T *args, typval_T *rvar); - /* implementation of function */ -} functions[] = -{ -#ifdef FEAT_FLOAT - {"abs", 1, 1, f_abs}, - {"acos", 1, 1, f_acos}, /* WJMc */ -#endif - {"add", 2, 2, f_add}, - {"and", 2, 2, f_and}, - {"append", 2, 2, f_append}, - {"argc", 0, 0, f_argc}, - {"argidx", 0, 0, f_argidx}, - {"arglistid", 0, 2, f_arglistid}, - {"argv", 0, 1, f_argv}, -#ifdef FEAT_FLOAT - {"asin", 1, 1, f_asin}, /* WJMc */ -#endif - {"assert_equal", 2, 3, f_assert_equal}, - {"assert_exception", 1, 2, f_assert_exception}, - {"assert_fails", 1, 2, f_assert_fails}, - {"assert_false", 1, 2, f_assert_false}, - {"assert_match", 2, 3, f_assert_match}, - {"assert_notequal", 2, 3, f_assert_notequal}, - {"assert_notmatch", 2, 3, f_assert_notmatch}, - {"assert_true", 1, 2, f_assert_true}, -#ifdef FEAT_FLOAT - {"atan", 1, 1, f_atan}, - {"atan2", 2, 2, f_atan2}, -#endif - {"browse", 4, 4, f_browse}, - {"browsedir", 2, 2, f_browsedir}, - {"bufexists", 1, 1, f_bufexists}, - {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */ - {"buffer_name", 1, 1, f_bufname}, /* obsolete */ - {"buffer_number", 1, 1, f_bufnr}, /* obsolete */ - {"buflisted", 1, 1, f_buflisted}, - {"bufloaded", 1, 1, f_bufloaded}, - {"bufname", 1, 1, f_bufname}, - {"bufnr", 1, 2, f_bufnr}, - {"bufwinid", 1, 1, f_bufwinid}, - {"bufwinnr", 1, 1, f_bufwinnr}, - {"byte2line", 1, 1, f_byte2line}, - {"byteidx", 2, 2, f_byteidx}, - {"byteidxcomp", 2, 2, f_byteidxcomp}, - {"call", 2, 3, f_call}, -#ifdef FEAT_FLOAT - {"ceil", 1, 1, f_ceil}, -#endif -#ifdef FEAT_JOB_CHANNEL - {"ch_close", 1, 1, f_ch_close}, - {"ch_evalexpr", 2, 3, f_ch_evalexpr}, - {"ch_evalraw", 2, 3, f_ch_evalraw}, - {"ch_getbufnr", 2, 2, f_ch_getbufnr}, - {"ch_getjob", 1, 1, f_ch_getjob}, - {"ch_info", 1, 1, f_ch_info}, - {"ch_log", 1, 2, f_ch_log}, - {"ch_logfile", 1, 2, f_ch_logfile}, - {"ch_open", 1, 2, f_ch_open}, - {"ch_read", 1, 2, f_ch_read}, - {"ch_readraw", 1, 2, f_ch_readraw}, - {"ch_sendexpr", 2, 3, f_ch_sendexpr}, - {"ch_sendraw", 2, 3, f_ch_sendraw}, - {"ch_setoptions", 2, 2, f_ch_setoptions}, - {"ch_status", 1, 1, f_ch_status}, -#endif - {"changenr", 0, 0, f_changenr}, - {"char2nr", 1, 2, f_char2nr}, - {"cindent", 1, 1, f_cindent}, - {"clearmatches", 0, 0, f_clearmatches}, - {"col", 1, 1, f_col}, -#if defined(FEAT_INS_EXPAND) - {"complete", 2, 2, f_complete}, - {"complete_add", 1, 1, f_complete_add}, - {"complete_check", 0, 0, f_complete_check}, -#endif - {"confirm", 1, 4, f_confirm}, - {"copy", 1, 1, f_copy}, -#ifdef FEAT_FLOAT - {"cos", 1, 1, f_cos}, - {"cosh", 1, 1, f_cosh}, -#endif - {"count", 2, 4, f_count}, - {"cscope_connection",0,3, f_cscope_connection}, - {"cursor", 1, 3, f_cursor}, - {"deepcopy", 1, 2, f_deepcopy}, - {"delete", 1, 2, f_delete}, - {"did_filetype", 0, 0, f_did_filetype}, - {"diff_filler", 1, 1, f_diff_filler}, - {"diff_hlID", 2, 2, f_diff_hlID}, - {"empty", 1, 1, f_empty}, - {"escape", 2, 2, f_escape}, - {"eval", 1, 1, f_eval}, - {"eventhandler", 0, 0, f_eventhandler}, - {"executable", 1, 1, f_executable}, - {"execute", 1, 2, f_execute}, - {"exepath", 1, 1, f_exepath}, - {"exists", 1, 1, f_exists}, -#ifdef FEAT_FLOAT - {"exp", 1, 1, f_exp}, -#endif - {"expand", 1, 3, f_expand}, - {"extend", 2, 3, f_extend}, - {"feedkeys", 1, 2, f_feedkeys}, - {"file_readable", 1, 1, f_filereadable}, /* obsolete */ - {"filereadable", 1, 1, f_filereadable}, - {"filewritable", 1, 1, f_filewritable}, - {"filter", 2, 2, f_filter}, - {"finddir", 1, 3, f_finddir}, - {"findfile", 1, 3, f_findfile}, -#ifdef FEAT_FLOAT - {"float2nr", 1, 1, f_float2nr}, - {"floor", 1, 1, f_floor}, - {"fmod", 2, 2, f_fmod}, -#endif - {"fnameescape", 1, 1, f_fnameescape}, - {"fnamemodify", 2, 2, f_fnamemodify}, - {"foldclosed", 1, 1, f_foldclosed}, - {"foldclosedend", 1, 1, f_foldclosedend}, - {"foldlevel", 1, 1, f_foldlevel}, - {"foldtext", 0, 0, f_foldtext}, - {"foldtextresult", 1, 1, f_foldtextresult}, - {"foreground", 0, 0, f_foreground}, - {"function", 1, 3, f_function}, - {"garbagecollect", 0, 1, f_garbagecollect}, - {"get", 2, 3, f_get}, - {"getbufline", 2, 3, f_getbufline}, - {"getbufvar", 2, 3, f_getbufvar}, - {"getchar", 0, 1, f_getchar}, - {"getcharmod", 0, 0, f_getcharmod}, - {"getcharsearch", 0, 0, f_getcharsearch}, - {"getcmdline", 0, 0, f_getcmdline}, - {"getcmdpos", 0, 0, f_getcmdpos}, - {"getcmdtype", 0, 0, f_getcmdtype}, - {"getcmdwintype", 0, 0, f_getcmdwintype}, -#if defined(FEAT_CMDL_COMPL) - {"getcompletion", 2, 2, f_getcompletion}, -#endif - {"getcurpos", 0, 0, f_getcurpos}, - {"getcwd", 0, 2, f_getcwd}, - {"getfontname", 0, 1, f_getfontname}, - {"getfperm", 1, 1, f_getfperm}, - {"getfsize", 1, 1, f_getfsize}, - {"getftime", 1, 1, f_getftime}, - {"getftype", 1, 1, f_getftype}, - {"getline", 1, 2, f_getline}, - {"getloclist", 1, 1, f_getqflist}, - {"getmatches", 0, 0, f_getmatches}, - {"getpid", 0, 0, f_getpid}, - {"getpos", 1, 1, f_getpos}, - {"getqflist", 0, 0, f_getqflist}, - {"getreg", 0, 3, f_getreg}, - {"getregtype", 0, 1, f_getregtype}, - {"gettabvar", 2, 3, f_gettabvar}, - {"gettabwinvar", 3, 4, f_gettabwinvar}, - {"getwinposx", 0, 0, f_getwinposx}, - {"getwinposy", 0, 0, f_getwinposy}, - {"getwinvar", 2, 3, f_getwinvar}, - {"glob", 1, 4, f_glob}, - {"glob2regpat", 1, 1, f_glob2regpat}, - {"globpath", 2, 5, f_globpath}, - {"has", 1, 1, f_has}, - {"has_key", 2, 2, f_has_key}, - {"haslocaldir", 0, 2, f_haslocaldir}, - {"hasmapto", 1, 3, f_hasmapto}, - {"highlightID", 1, 1, f_hlID}, /* obsolete */ - {"highlight_exists",1, 1, f_hlexists}, /* obsolete */ - {"histadd", 2, 2, f_histadd}, - {"histdel", 1, 2, f_histdel}, - {"histget", 1, 2, f_histget}, - {"histnr", 1, 1, f_histnr}, - {"hlID", 1, 1, f_hlID}, - {"hlexists", 1, 1, f_hlexists}, - {"hostname", 0, 0, f_hostname}, - {"iconv", 3, 3, f_iconv}, - {"indent", 1, 1, f_indent}, - {"index", 2, 4, f_index}, - {"input", 1, 3, f_input}, - {"inputdialog", 1, 3, f_inputdialog}, - {"inputlist", 1, 1, f_inputlist}, - {"inputrestore", 0, 0, f_inputrestore}, - {"inputsave", 0, 0, f_inputsave}, - {"inputsecret", 1, 2, f_inputsecret}, - {"insert", 2, 3, f_insert}, - {"invert", 1, 1, f_invert}, - {"isdirectory", 1, 1, f_isdirectory}, - {"islocked", 1, 1, f_islocked}, -#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) - {"isnan", 1, 1, f_isnan}, -#endif - {"items", 1, 1, f_items}, -#ifdef FEAT_JOB_CHANNEL - {"job_getchannel", 1, 1, f_job_getchannel}, - {"job_info", 1, 1, f_job_info}, - {"job_setoptions", 2, 2, f_job_setoptions}, - {"job_start", 1, 2, f_job_start}, - {"job_status", 1, 1, f_job_status}, - {"job_stop", 1, 2, f_job_stop}, -#endif - {"join", 1, 2, f_join}, - {"js_decode", 1, 1, f_js_decode}, - {"js_encode", 1, 1, f_js_encode}, - {"json_decode", 1, 1, f_json_decode}, - {"json_encode", 1, 1, f_json_encode}, - {"keys", 1, 1, f_keys}, - {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ - {"len", 1, 1, f_len}, - {"libcall", 3, 3, f_libcall}, - {"libcallnr", 3, 3, f_libcallnr}, - {"line", 1, 1, f_line}, - {"line2byte", 1, 1, f_line2byte}, - {"lispindent", 1, 1, f_lispindent}, - {"localtime", 0, 0, f_localtime}, -#ifdef FEAT_FLOAT - {"log", 1, 1, f_log}, - {"log10", 1, 1, f_log10}, -#endif -#ifdef FEAT_LUA - {"luaeval", 1, 2, f_luaeval}, -#endif - {"map", 2, 2, f_map}, - {"maparg", 1, 4, f_maparg}, - {"mapcheck", 1, 3, f_mapcheck}, - {"match", 2, 4, f_match}, - {"matchadd", 2, 5, f_matchadd}, - {"matchaddpos", 2, 5, f_matchaddpos}, - {"matcharg", 1, 1, f_matcharg}, - {"matchdelete", 1, 1, f_matchdelete}, - {"matchend", 2, 4, f_matchend}, - {"matchlist", 2, 4, f_matchlist}, - {"matchstr", 2, 4, f_matchstr}, - {"matchstrpos", 2, 4, f_matchstrpos}, - {"max", 1, 1, f_max}, - {"min", 1, 1, f_min}, -#ifdef vim_mkdir - {"mkdir", 1, 3, f_mkdir}, -#endif - {"mode", 0, 1, f_mode}, -#ifdef FEAT_MZSCHEME - {"mzeval", 1, 1, f_mzeval}, -#endif - {"nextnonblank", 1, 1, f_nextnonblank}, - {"nr2char", 1, 2, f_nr2char}, - {"or", 2, 2, f_or}, - {"pathshorten", 1, 1, f_pathshorten}, -#ifdef FEAT_PERL - {"perleval", 1, 1, f_perleval}, -#endif -#ifdef FEAT_FLOAT - {"pow", 2, 2, f_pow}, -#endif - {"prevnonblank", 1, 1, f_prevnonblank}, - {"printf", 2, 19, f_printf}, - {"pumvisible", 0, 0, f_pumvisible}, -#ifdef FEAT_PYTHON3 - {"py3eval", 1, 1, f_py3eval}, -#endif -#ifdef FEAT_PYTHON - {"pyeval", 1, 1, f_pyeval}, -#endif - {"range", 1, 3, f_range}, - {"readfile", 1, 3, f_readfile}, - {"reltime", 0, 2, f_reltime}, -#ifdef FEAT_FLOAT - {"reltimefloat", 1, 1, f_reltimefloat}, -#endif - {"reltimestr", 1, 1, f_reltimestr}, - {"remote_expr", 2, 3, f_remote_expr}, - {"remote_foreground", 1, 1, f_remote_foreground}, - {"remote_peek", 1, 2, f_remote_peek}, - {"remote_read", 1, 1, f_remote_read}, - {"remote_send", 2, 3, f_remote_send}, - {"remove", 2, 3, f_remove}, - {"rename", 2, 2, f_rename}, - {"repeat", 2, 2, f_repeat}, - {"resolve", 1, 1, f_resolve}, - {"reverse", 1, 1, f_reverse}, -#ifdef FEAT_FLOAT - {"round", 1, 1, f_round}, -#endif - {"screenattr", 2, 2, f_screenattr}, - {"screenchar", 2, 2, f_screenchar}, - {"screencol", 0, 0, f_screencol}, - {"screenrow", 0, 0, f_screenrow}, - {"search", 1, 4, f_search}, - {"searchdecl", 1, 3, f_searchdecl}, - {"searchpair", 3, 7, f_searchpair}, - {"searchpairpos", 3, 7, f_searchpairpos}, - {"searchpos", 1, 4, f_searchpos}, - {"server2client", 2, 2, f_server2client}, - {"serverlist", 0, 0, f_serverlist}, - {"setbufvar", 3, 3, f_setbufvar}, - {"setcharsearch", 1, 1, f_setcharsearch}, - {"setcmdpos", 1, 1, f_setcmdpos}, - {"setfperm", 2, 2, f_setfperm}, - {"setline", 2, 2, f_setline}, - {"setloclist", 2, 3, f_setloclist}, - {"setmatches", 1, 1, f_setmatches}, - {"setpos", 2, 2, f_setpos}, - {"setqflist", 1, 2, f_setqflist}, - {"setreg", 2, 3, f_setreg}, - {"settabvar", 3, 3, f_settabvar}, - {"settabwinvar", 4, 4, f_settabwinvar}, - {"setwinvar", 3, 3, f_setwinvar}, -#ifdef FEAT_CRYPT - {"sha256", 1, 1, f_sha256}, -#endif - {"shellescape", 1, 2, f_shellescape}, - {"shiftwidth", 0, 0, f_shiftwidth}, - {"simplify", 1, 1, f_simplify}, -#ifdef FEAT_FLOAT - {"sin", 1, 1, f_sin}, - {"sinh", 1, 1, f_sinh}, -#endif - {"sort", 1, 3, f_sort}, - {"soundfold", 1, 1, f_soundfold}, - {"spellbadword", 0, 1, f_spellbadword}, - {"spellsuggest", 1, 3, f_spellsuggest}, - {"split", 1, 3, f_split}, -#ifdef FEAT_FLOAT - {"sqrt", 1, 1, f_sqrt}, - {"str2float", 1, 1, f_str2float}, -#endif - {"str2nr", 1, 2, f_str2nr}, - {"strcharpart", 2, 3, f_strcharpart}, - {"strchars", 1, 2, f_strchars}, - {"strdisplaywidth", 1, 2, f_strdisplaywidth}, -#ifdef HAVE_STRFTIME - {"strftime", 1, 2, f_strftime}, -#endif - {"strgetchar", 2, 2, f_strgetchar}, - {"stridx", 2, 3, f_stridx}, - {"string", 1, 1, f_string}, - {"strlen", 1, 1, f_strlen}, - {"strpart", 2, 3, f_strpart}, - {"strridx", 2, 3, f_strridx}, - {"strtrans", 1, 1, f_strtrans}, - {"strwidth", 1, 1, f_strwidth}, - {"submatch", 1, 2, f_submatch}, - {"substitute", 4, 4, f_substitute}, - {"synID", 3, 3, f_synID}, - {"synIDattr", 2, 3, f_synIDattr}, - {"synIDtrans", 1, 1, f_synIDtrans}, - {"synconcealed", 2, 2, f_synconcealed}, - {"synstack", 2, 2, f_synstack}, - {"system", 1, 2, f_system}, - {"systemlist", 1, 2, f_systemlist}, - {"tabpagebuflist", 0, 1, f_tabpagebuflist}, - {"tabpagenr", 0, 1, f_tabpagenr}, - {"tabpagewinnr", 1, 2, f_tabpagewinnr}, - {"tagfiles", 0, 0, f_tagfiles}, - {"taglist", 1, 1, f_taglist}, -#ifdef FEAT_FLOAT - {"tan", 1, 1, f_tan}, - {"tanh", 1, 1, f_tanh}, -#endif - {"tempname", 0, 0, f_tempname}, - {"test_alloc_fail", 3, 3, f_test_alloc_fail}, - {"test_autochdir", 0, 0, f_test_autochdir}, - {"test_disable_char_avail", 1, 1, f_test_disable_char_avail}, - {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, -#ifdef FEAT_JOB_CHANNEL - {"test_null_channel", 0, 0, f_test_null_channel}, -#endif - {"test_null_dict", 0, 0, f_test_null_dict}, -#ifdef FEAT_JOB_CHANNEL - {"test_null_job", 0, 0, f_test_null_job}, -#endif - {"test_null_list", 0, 0, f_test_null_list}, - {"test_null_partial", 0, 0, f_test_null_partial}, - {"test_null_string", 0, 0, f_test_null_string}, - {"test_settime", 1, 1, f_test_settime}, -#ifdef FEAT_TIMERS - {"timer_start", 2, 3, f_timer_start}, - {"timer_stop", 1, 1, f_timer_stop}, -#endif - {"tolower", 1, 1, f_tolower}, - {"toupper", 1, 1, f_toupper}, - {"tr", 3, 3, f_tr}, -#ifdef FEAT_FLOAT - {"trunc", 1, 1, f_trunc}, -#endif - {"type", 1, 1, f_type}, - {"undofile", 1, 1, f_undofile}, - {"undotree", 0, 0, f_undotree}, - {"uniq", 1, 3, f_uniq}, - {"values", 1, 1, f_values}, - {"virtcol", 1, 1, f_virtcol}, - {"visualmode", 0, 1, f_visualmode}, - {"wildmenumode", 0, 0, f_wildmenumode}, - {"win_findbuf", 1, 1, f_win_findbuf}, - {"win_getid", 0, 2, f_win_getid}, - {"win_gotoid", 1, 1, f_win_gotoid}, - {"win_id2tabwin", 1, 1, f_win_id2tabwin}, - {"win_id2win", 1, 1, f_win_id2win}, - {"winbufnr", 1, 1, f_winbufnr}, - {"wincol", 0, 0, f_wincol}, - {"winheight", 1, 1, f_winheight}, - {"winline", 0, 0, f_winline}, - {"winnr", 0, 1, f_winnr}, - {"winrestcmd", 0, 0, f_winrestcmd}, - {"winrestview", 1, 1, f_winrestview}, - {"winsaveview", 0, 0, f_winsaveview}, - {"winwidth", 1, 1, f_winwidth}, - {"wordcount", 0, 0, f_wordcount}, - {"writefile", 2, 3, f_writefile}, - {"xor", 2, 2, f_xor}, -}; - -#if defined(FEAT_CMDL_COMPL) || defined(PROTO) - -/* - * Function given to ExpandGeneric() to obtain the list of internal - * or user defined function names. - */ - char_u * -get_function_name(expand_T *xp, int idx) -{ - static int intidx = -1; - char_u *name; - - if (idx == 0) - intidx = -1; - if (intidx < 0) - { - name = get_user_func_name(xp, idx); - if (name != NULL) - return name; - } - if (++intidx < (int)(sizeof(functions) / sizeof(struct fst))) - { - STRCPY(IObuff, functions[intidx].f_name); - STRCAT(IObuff, "("); - if (functions[intidx].f_max_argc == 0) - STRCAT(IObuff, ")"); - return IObuff; - } - - return NULL; -} - -/* - * Function given to ExpandGeneric() to obtain the list of internal or - * user defined variable or function names. - */ - char_u * -get_expr_name(expand_T *xp, int idx) -{ - static int intidx = -1; - char_u *name; - - if (idx == 0) - intidx = -1; - if (intidx < 0) - { - name = get_function_name(xp, idx); - if (name != NULL) - return name; - } - return get_user_var_name(xp, ++intidx); -} - -#endif /* FEAT_CMDL_COMPL */ - -#if defined(EBCDIC) || defined(PROTO) -/* - * Compare struct fst by function name. - */ - static int -compare_func_name(const void *s1, const void *s2) -{ - struct fst *p1 = (struct fst *)s1; - struct fst *p2 = (struct fst *)s2; - - return STRCMP(p1->f_name, p2->f_name); -} - -/* - * Sort the function table by function name. - * The sorting of the table above is ASCII dependant. - * On machines using EBCDIC we have to sort it. - */ - static void -sortFunctions(void) -{ - int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1; - - qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name); -} -#endif - - -/* - * Find internal function in table above. - * Return index, or -1 if not found - */ - int -find_internal_func( - char_u *name) /* name of the function */ -{ - int first = 0; - int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; - int cmp; - int x; - - /* - * Find the function name in the table. Binary search. - */ - while (first <= last) - { - x = first + ((unsigned)(last - first) >> 1); - cmp = STRCMP(name, functions[x].f_name); - if (cmp < 0) - last = x - 1; - else if (cmp > 0) - first = x + 1; - else - return x; - } - return -1; -} - - int -call_internal_func( - char_u *name, - int argcount, - typval_T *argvars, - typval_T *rettv) -{ - int i; - - i = find_internal_func(name); - if (i < 0) - return ERROR_UNKNOWN; - if (argcount < functions[i].f_min_argc) - return ERROR_TOOFEW; - if (argcount > functions[i].f_max_argc) - return ERROR_TOOMANY; - argvars[argcount].v_type = VAR_UNKNOWN; - functions[i].f_func(argvars, rettv); - return ERROR_NONE; -} - -/* - * Return TRUE for a non-zero Number and a non-empty String. - */ - static int -non_zero_arg(typval_T *argvars) -{ - return ((argvars[0].v_type == VAR_NUMBER - && argvars[0].vval.v_number != 0) - || (argvars[0].v_type == VAR_SPECIAL - && argvars[0].vval.v_number == VVAL_TRUE) - || (argvars[0].v_type == VAR_STRING - && argvars[0].vval.v_string != NULL - && *argvars[0].vval.v_string != NUL)); -} - -/********************************************* - * Implementation of the built-in functions - */ - -#ifdef FEAT_FLOAT -static int get_float_arg(typval_T *argvars, float_T *f); - -/* - * Get the float value of "argvars[0]" into "f". - * Returns FAIL when the argument is not a Number or Float. - */ - static int -get_float_arg(typval_T *argvars, float_T *f) -{ - if (argvars[0].v_type == VAR_FLOAT) - { - *f = argvars[0].vval.v_float; - return OK; - } - if (argvars[0].v_type == VAR_NUMBER) - { - *f = (float_T)argvars[0].vval.v_number; - return OK; - } - EMSG(_("E808: Number or Float required")); - return FAIL; -} - -/* - * "abs(expr)" function - */ - static void -f_abs(typval_T *argvars, typval_T *rettv) -{ - if (argvars[0].v_type == VAR_FLOAT) - { - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = fabs(argvars[0].vval.v_float); - } - else - { - varnumber_T n; - int error = FALSE; - - n = get_tv_number_chk(&argvars[0], &error); - if (error) - rettv->vval.v_number = -1; - else if (n > 0) - rettv->vval.v_number = n; - else - rettv->vval.v_number = -n; - } -} - -/* - * "acos()" function - */ - static void -f_acos(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = acos(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "add(list, item)" function - */ - static void -f_add(typval_T *argvars, typval_T *rettv) -{ - list_T *l; - - rettv->vval.v_number = 1; /* Default: Failed */ - if (argvars[0].v_type == VAR_LIST) - { - if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, - (char_u *)N_("add() argument"), TRUE) - && list_append_tv(l, &argvars[1]) == OK) - copy_tv(&argvars[0], rettv); - } - else - EMSG(_(e_listreq)); -} - -/* - * "and(expr, expr)" function - */ - static void -f_and(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) - & get_tv_number_chk(&argvars[1], NULL); -} - -/* - * "append(lnum, string/list)" function - */ - static void -f_append(typval_T *argvars, typval_T *rettv) -{ - long lnum; - char_u *line; - list_T *l = NULL; - listitem_T *li = NULL; - typval_T *tv; - long added = 0; - - /* When coming here from Insert mode, sync undo, so that this can be - * undone separately from what was previously inserted. */ - if (u_sync_once == 2) - { - u_sync_once = 1; /* notify that u_sync() was called */ - u_sync(TRUE); - } - - lnum = get_tv_lnum(argvars); - if (lnum >= 0 - && lnum <= curbuf->b_ml.ml_line_count - && u_save(lnum, lnum + 1) == OK) - { - if (argvars[1].v_type == VAR_LIST) - { - l = argvars[1].vval.v_list; - if (l == NULL) - return; - li = l->lv_first; - } - for (;;) - { - if (l == NULL) - tv = &argvars[1]; /* append a string */ - else if (li == NULL) - break; /* end of list */ - else - tv = &li->li_tv; /* append item from list */ - line = get_tv_string_chk(tv); - if (line == NULL) /* type error */ - { - rettv->vval.v_number = 1; /* Failed */ - break; - } - ml_append(lnum + added, line, (colnr_T)0, FALSE); - ++added; - if (l == NULL) - break; - li = li->li_next; - } - - appended_lines_mark(lnum, added); - if (curwin->w_cursor.lnum > lnum) - curwin->w_cursor.lnum += added; - } - else - rettv->vval.v_number = 1; /* Failed */ -} - -/* - * "argc()" function - */ - static void -f_argc(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = ARGCOUNT; -} - -/* - * "argidx()" function - */ - static void -f_argidx(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = curwin->w_arg_idx; -} - -/* - * "arglistid()" function - */ - static void -f_arglistid(typval_T *argvars, typval_T *rettv) -{ - win_T *wp; - - rettv->vval.v_number = -1; - wp = find_tabwin(&argvars[0], &argvars[1]); - if (wp != NULL) - rettv->vval.v_number = wp->w_alist->id; -} - -/* - * "argv(nr)" function - */ - static void -f_argv(typval_T *argvars, typval_T *rettv) -{ - int idx; - - if (argvars[0].v_type != VAR_UNKNOWN) - { - idx = (int)get_tv_number_chk(&argvars[0], NULL); - if (idx >= 0 && idx < ARGCOUNT) - rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx])); - else - rettv->vval.v_string = NULL; - rettv->v_type = VAR_STRING; - } - else if (rettv_list_alloc(rettv) == OK) - for (idx = 0; idx < ARGCOUNT; ++idx) - list_append_string(rettv->vval.v_list, - alist_name(&ARGLIST[idx]), -1); -} - -typedef enum -{ - ASSERT_EQUAL, - ASSERT_NOTEQUAL, - ASSERT_MATCH, - ASSERT_NOTMATCH, - ASSERT_OTHER -} assert_type_T; - -static void prepare_assert_error(garray_T*gap); -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); -static void assert_error(garray_T *gap); -static void assert_bool(typval_T *argvars, int isTrue); - -/* - * Prepare "gap" for an assert error and add the sourcing position. - */ - static void -prepare_assert_error(garray_T *gap) -{ - char buf[NUMBUFLEN]; - - ga_init2(gap, 1, 100); - if (sourcing_name != NULL) - { - ga_concat(gap, sourcing_name); - if (sourcing_lnum > 0) - ga_concat(gap, (char_u *)" "); - } - if (sourcing_lnum > 0) - { - sprintf(buf, "line %ld", (long)sourcing_lnum); - ga_concat(gap, (char_u *)buf); - } - if (sourcing_name != NULL || sourcing_lnum > 0) - ga_concat(gap, (char_u *)": "); -} - -/* - * Append "str" to "gap", escaping unprintable characters. - * Changes NL to \n, CR to \r, etc. - */ - static void -ga_concat_esc(garray_T *gap, char_u *str) -{ - char_u *p; - char_u buf[NUMBUFLEN]; - - if (str == NULL) - { - ga_concat(gap, (char_u *)"NULL"); - return; - } - - for (p = str; *p != NUL; ++p) - switch (*p) - { - case BS: ga_concat(gap, (char_u *)"\\b"); break; - case ESC: ga_concat(gap, (char_u *)"\\e"); break; - case FF: ga_concat(gap, (char_u *)"\\f"); break; - case NL: ga_concat(gap, (char_u *)"\\n"); break; - case TAB: ga_concat(gap, (char_u *)"\\t"); break; - case CAR: ga_concat(gap, (char_u *)"\\r"); break; - case '\\': ga_concat(gap, (char_u *)"\\\\"); break; - default: - if (*p < ' ') - { - vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); - ga_concat(gap, buf); - } - else - ga_append(gap, *p); - break; - } -} - -/* - * Fill "gap" with information about an assert error. - */ - 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 atype) -{ - char_u numbuf[NUMBUFLEN]; - char_u *tofree; - - if (opt_msg_tv->v_type != VAR_UNKNOWN) - { - ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0)); - vim_free(tofree); - } - else - { - if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) - ga_concat(gap, (char_u *)"Pattern "); - else - ga_concat(gap, (char_u *)"Expected "); - if (exp_str == NULL) - { - ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0)); - vim_free(tofree); - } - else - ga_concat_esc(gap, exp_str); - if (atype == ASSERT_MATCH) - ga_concat(gap, (char_u *)" does not match "); - else if (atype == ASSERT_NOTMATCH) - ga_concat(gap, (char_u *)" does match "); - else if (atype == ASSERT_NOTEQUAL) - ga_concat(gap, (char_u *)" differs from "); - else - ga_concat(gap, (char_u *)" but got "); - ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0)); - vim_free(tofree); - } -} - -/* - * Add an assert error to v:errors. - */ - static void -assert_error(garray_T *gap) -{ - struct vimvar *vp = &vimvars[VV_ERRORS]; - - if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) - /* Make sure v:errors is a list. */ - set_vim_var_list(VV_ERRORS, list_alloc()); - list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len); -} - - static void -assert_equal_common(typval_T *argvars, assert_type_T atype) -{ - garray_T ga; - - if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE) - != (atype == ASSERT_EQUAL)) - { - prepare_assert_error(&ga); - fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], - atype); - assert_error(&ga); - ga_clear(&ga); - } -} - -/* - * "assert_equal(expected, actual[, msg])" function - */ - static void -f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_equal_common(argvars, ASSERT_EQUAL); -} - -/* - * "assert_notequal(expected, actual[, msg])" function - */ - static void -f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_equal_common(argvars, ASSERT_NOTEQUAL); -} - -/* - * "assert_exception(string[, msg])" function - */ - static void -f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED) -{ - garray_T ga; - char *error; - - error = (char *)get_tv_string_chk(&argvars[0]); - if (vimvars[VV_EXCEPTION].vv_str == NULL) - { - prepare_assert_error(&ga); - ga_concat(&ga, (char_u *)"v:exception is not set"); - assert_error(&ga); - ga_clear(&ga); - } - else if (error != NULL - && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) - { - prepare_assert_error(&ga); - fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], - &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER); - assert_error(&ga); - ga_clear(&ga); - } -} - -/* - * "assert_fails(cmd [, error])" function - */ - static void -f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED) -{ - char_u *cmd = get_tv_string_chk(&argvars[0]); - garray_T ga; - - called_emsg = FALSE; - suppress_errthrow = TRUE; - emsg_silent = TRUE; - do_cmdline_cmd(cmd); - if (!called_emsg) - { - prepare_assert_error(&ga); - ga_concat(&ga, (char_u *)"command did not fail: "); - ga_concat(&ga, cmd); - assert_error(&ga); - ga_clear(&ga); - } - else if (argvars[1].v_type != VAR_UNKNOWN) - { - char_u buf[NUMBUFLEN]; - char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf); - - if (error == NULL - || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) - { - prepare_assert_error(&ga); - fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], - &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); - assert_error(&ga); - ga_clear(&ga); - } - } - - called_emsg = FALSE; - suppress_errthrow = FALSE; - emsg_silent = FALSE; - emsg_on_display = FALSE; - set_vim_var_string(VV_ERRMSG, NULL, 0); -} - -/* - * Common for assert_true() and assert_false(). - */ - static void -assert_bool(typval_T *argvars, int isTrue) -{ - int error = FALSE; - garray_T ga; - - if (argvars[0].v_type == VAR_SPECIAL - && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE)) - return; - if (argvars[0].v_type != VAR_NUMBER - || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue - || error) - { - prepare_assert_error(&ga); - fill_assert_error(&ga, &argvars[1], - (char_u *)(isTrue ? "True" : "False"), - NULL, &argvars[0], ASSERT_OTHER); - assert_error(&ga); - ga_clear(&ga); - } -} - -/* - * "assert_false(actual[, msg])" function - */ - static void -f_assert_false(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_bool(argvars, FALSE); -} - - static void -assert_match_common(typval_T *argvars, assert_type_T atype) -{ - garray_T ga; - char_u buf1[NUMBUFLEN]; - char_u buf2[NUMBUFLEN]; - char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1); - char_u *text = get_tv_string_buf_chk(&argvars[1], buf2); - - if (pat == NULL || text == NULL) - EMSG(_(e_invarg)); - else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH)) - { - prepare_assert_error(&ga); - fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], - atype); - assert_error(&ga); - ga_clear(&ga); - } -} - -/* - * "assert_match(pattern, actual[, msg])" function - */ - static void -f_assert_match(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_match_common(argvars, ASSERT_MATCH); -} - -/* - * "assert_notmatch(pattern, actual[, msg])" function - */ - static void -f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_match_common(argvars, ASSERT_NOTMATCH); -} - -/* - * "assert_true(actual[, msg])" function - */ - static void -f_assert_true(typval_T *argvars, typval_T *rettv UNUSED) -{ - assert_bool(argvars, TRUE); -} - -#ifdef FEAT_FLOAT -/* - * "asin()" function - */ - static void -f_asin(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = asin(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "atan()" function - */ - static void -f_atan(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = atan(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "atan2()" function - */ - static void -f_atan2(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = atan2(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "browse(save, title, initdir, default)" function - */ - static void -f_browse(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_BROWSE - int save; - char_u *title; - char_u *initdir; - char_u *defname; - char_u buf[NUMBUFLEN]; - char_u buf2[NUMBUFLEN]; - int error = FALSE; - - save = (int)get_tv_number_chk(&argvars[0], &error); - title = get_tv_string_chk(&argvars[1]); - initdir = get_tv_string_buf_chk(&argvars[2], buf); - defname = get_tv_string_buf_chk(&argvars[3], buf2); - - if (error || title == NULL || initdir == NULL || defname == NULL) - rettv->vval.v_string = NULL; - else - rettv->vval.v_string = - do_browse(save ? BROWSE_SAVE : 0, - title, defname, NULL, initdir, NULL, curbuf); -#else - rettv->vval.v_string = NULL; -#endif - rettv->v_type = VAR_STRING; -} - -/* - * "browsedir(title, initdir)" function - */ - static void -f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_BROWSE - char_u *title; - char_u *initdir; - char_u buf[NUMBUFLEN]; - - title = get_tv_string_chk(&argvars[0]); - initdir = get_tv_string_buf_chk(&argvars[1], buf); - - if (title == NULL || initdir == NULL) - rettv->vval.v_string = NULL; - else - rettv->vval.v_string = do_browse(BROWSE_DIR, - title, NULL, NULL, initdir, NULL, curbuf); -#else - rettv->vval.v_string = NULL; -#endif - rettv->v_type = VAR_STRING; -} - -static buf_T *find_buffer(typval_T *avar); - -/* - * Find a buffer by number or exact name. - */ - static buf_T * -find_buffer(typval_T *avar) -{ - buf_T *buf = NULL; - - if (avar->v_type == VAR_NUMBER) - buf = buflist_findnr((int)avar->vval.v_number); - else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) - { - buf = buflist_findname_exp(avar->vval.v_string); - if (buf == NULL) - { - /* No full path name match, try a match with a URL or a "nofile" - * buffer, these don't use the full path. */ - for (buf = firstbuf; buf != NULL; buf = buf->b_next) - if (buf->b_fname != NULL - && (path_with_url(buf->b_fname) -#ifdef FEAT_QUICKFIX - || bt_nofile(buf) -#endif - ) - && STRCMP(buf->b_fname, avar->vval.v_string) == 0) - break; - } - } - return buf; -} - -/* - * "bufexists(expr)" function - */ - static void -f_bufexists(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); -} - -/* - * "buflisted(expr)" function - */ - static void -f_buflisted(typval_T *argvars, typval_T *rettv) -{ - buf_T *buf; - - buf = find_buffer(&argvars[0]); - rettv->vval.v_number = (buf != NULL && buf->b_p_bl); -} - -/* - * "bufloaded(expr)" function - */ - static void -f_bufloaded(typval_T *argvars, typval_T *rettv) -{ - buf_T *buf; - - buf = find_buffer(&argvars[0]); - rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); -} - - buf_T * -buflist_find_by_name(char_u *name, int curtab_only) -{ - int save_magic; - char_u *save_cpo; - buf_T *buf; - - /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ - save_magic = p_magic; - p_magic = TRUE; - save_cpo = p_cpo; - p_cpo = (char_u *)""; - - buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), - TRUE, FALSE, curtab_only)); - - p_magic = save_magic; - p_cpo = save_cpo; - return buf; -} - -/* - * Get buffer by number or pattern. - */ - static buf_T * -get_buf_tv(typval_T *tv, int curtab_only) -{ - char_u *name = tv->vval.v_string; - buf_T *buf; - - if (tv->v_type == VAR_NUMBER) - return buflist_findnr((int)tv->vval.v_number); - if (tv->v_type != VAR_STRING) - return NULL; - if (name == NULL || *name == NUL) - return curbuf; - if (name[0] == '$' && name[1] == NUL) - return lastbuf; - - buf = buflist_find_by_name(name, curtab_only); - - /* If not found, try expanding the name, like done for bufexists(). */ - if (buf == NULL) - buf = find_buffer(tv); - - return buf; -} - -/* - * "bufname(expr)" function - */ - static void -f_bufname(typval_T *argvars, typval_T *rettv) -{ - buf_T *buf; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - rettv->v_type = VAR_STRING; - if (buf != NULL && buf->b_fname != NULL) - rettv->vval.v_string = vim_strsave(buf->b_fname); - else - rettv->vval.v_string = NULL; - --emsg_off; -} - -/* - * "bufnr(expr)" function - */ - static void -f_bufnr(typval_T *argvars, typval_T *rettv) -{ - buf_T *buf; - int error = FALSE; - char_u *name; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - --emsg_off; - - /* If the buffer isn't found and the second argument is not zero create a - * new buffer. */ - if (buf == NULL - && argvars[1].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[1], &error) != 0 - && !error - && (name = get_tv_string_chk(&argvars[0])) != NULL - && !error) - buf = buflist_new(name, NULL, (linenr_T)1, 0); - - if (buf != NULL) - rettv->vval.v_number = buf->b_fnum; - else - rettv->vval.v_number = -1; -} - - static void -buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) -{ -#ifdef FEAT_WINDOWS - win_T *wp; - int winnr = 0; -#endif - buf_T *buf; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], TRUE); -#ifdef FEAT_WINDOWS - for (wp = firstwin; wp; wp = wp->w_next) - { - ++winnr; - if (wp->w_buffer == buf) - break; - } - rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); -#else - rettv->vval.v_number = (curwin->w_buffer == buf - ? (get_nr ? 1 : curwin->w_id) : -1); -#endif - --emsg_off; -} - -/* - * "bufwinid(nr)" function - */ - static void -f_bufwinid(typval_T *argvars, typval_T *rettv) -{ - buf_win_common(argvars, rettv, FALSE); -} - -/* - * "bufwinnr(nr)" function - */ - static void -f_bufwinnr(typval_T *argvars, typval_T *rettv) -{ - buf_win_common(argvars, rettv, TRUE); -} - -/* - * "byte2line(byte)" function - */ - static void -f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifndef FEAT_BYTEOFF - rettv->vval.v_number = -1; -#else - long boff = 0; - - boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ - if (boff < 0) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = ml_find_line_or_offset(curbuf, - (linenr_T)0, &boff); -#endif -} - - static void -byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) -{ -#ifdef FEAT_MBYTE - char_u *t; -#endif - char_u *str; - varnumber_T idx; - - str = get_tv_string_chk(&argvars[0]); - idx = get_tv_number_chk(&argvars[1], NULL); - rettv->vval.v_number = -1; - if (str == NULL || idx < 0) - return; - -#ifdef FEAT_MBYTE - t = str; - for ( ; idx > 0; idx--) - { - if (*t == NUL) /* EOL reached */ - return; - if (enc_utf8 && comp) - t += utf_ptr2len(t); - else - t += (*mb_ptr2len)(t); - } - rettv->vval.v_number = (varnumber_T)(t - str); -#else - if ((size_t)idx <= STRLEN(str)) - rettv->vval.v_number = idx; -#endif -} - -/* - * "byteidx()" function - */ - static void -f_byteidx(typval_T *argvars, typval_T *rettv) -{ - byteidx(argvars, rettv, FALSE); -} - -/* - * "byteidxcomp()" function - */ - static void -f_byteidxcomp(typval_T *argvars, typval_T *rettv) -{ - byteidx(argvars, rettv, TRUE); -} - -/* - * "call(func, arglist [, dict])" function - */ - static void -f_call(typval_T *argvars, typval_T *rettv) -{ - char_u *func; - partial_T *partial = NULL; - dict_T *selfdict = NULL; - - if (argvars[1].v_type != VAR_LIST) - { - EMSG(_(e_listreq)); - return; - } - if (argvars[1].vval.v_list == NULL) - return; - - if (argvars[0].v_type == VAR_FUNC) - func = argvars[0].vval.v_string; - else if (argvars[0].v_type == VAR_PARTIAL) - { - partial = argvars[0].vval.v_partial; - func = partial->pt_name; - } - else - func = get_tv_string(&argvars[0]); - if (*func == NUL) - return; /* type error or empty name */ - - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (argvars[2].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - selfdict = argvars[2].vval.v_dict; - } - - (void)func_call(func, &argvars[1], partial, selfdict, rettv); -} - -#ifdef FEAT_FLOAT -/* - * "ceil({float})" function - */ - static void -f_ceil(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = ceil(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -#ifdef FEAT_JOB_CHANNEL -/* - * "ch_close()" function - */ - static void -f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) -{ - channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); - - if (channel != NULL) - { - channel_close(channel, FALSE); - channel_clear(channel); - } -} - -/* - * "ch_getbufnr()" function - */ - static void -f_ch_getbufnr(typval_T *argvars, typval_T *rettv) -{ - channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - - rettv->vval.v_number = -1; - if (channel != NULL) - { - char_u *what = get_tv_string(&argvars[1]); - int part; - - if (STRCMP(what, "err") == 0) - part = PART_ERR; - else if (STRCMP(what, "out") == 0) - part = PART_OUT; - else if (STRCMP(what, "in") == 0) - part = PART_IN; - else - part = PART_SOCK; - if (channel->ch_part[part].ch_bufref.br_buf != NULL) - rettv->vval.v_number = - channel->ch_part[part].ch_bufref.br_buf->b_fnum; - } -} - -/* - * "ch_getjob()" function - */ - static void -f_ch_getjob(typval_T *argvars, typval_T *rettv) -{ - channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - - if (channel != NULL) - { - rettv->v_type = VAR_JOB; - rettv->vval.v_job = channel->ch_job; - if (channel->ch_job != NULL) - ++channel->ch_job->jv_refcount; - } -} - -/* - * "ch_info()" function - */ - static void -f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) -{ - channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - - if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) - channel_info(channel, rettv->vval.v_dict); -} - -/* - * "ch_log()" function - */ - static void -f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) -{ - char_u *msg = get_tv_string(&argvars[0]); - channel_T *channel = NULL; - - if (argvars[1].v_type != VAR_UNKNOWN) - channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); - - ch_log(channel, (char *)msg); -} - -/* - * "ch_logfile()" function - */ - static void -f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) -{ - char_u *fname; - char_u *opt = (char_u *)""; - char_u buf[NUMBUFLEN]; - - fname = get_tv_string(&argvars[0]); - if (argvars[1].v_type == VAR_STRING) - opt = get_tv_string_buf(&argvars[1], buf); - ch_logfile(fname, opt); -} - -/* - * "ch_open()" function - */ - static void -f_ch_open(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_CHANNEL; - if (check_restricted() || check_secure()) - return; - rettv->vval.v_channel = channel_open_func(argvars); -} - -/* - * "ch_read()" function - */ - static void -f_ch_read(typval_T *argvars, typval_T *rettv) -{ - common_channel_read(argvars, rettv, FALSE); -} - -/* - * "ch_readraw()" function - */ - static void -f_ch_readraw(typval_T *argvars, typval_T *rettv) -{ - common_channel_read(argvars, rettv, TRUE); -} - -/* - * "ch_evalexpr()" function - */ - static void -f_ch_evalexpr(typval_T *argvars, typval_T *rettv) -{ - ch_expr_common(argvars, rettv, TRUE); -} - -/* - * "ch_sendexpr()" function - */ - static void -f_ch_sendexpr(typval_T *argvars, typval_T *rettv) -{ - ch_expr_common(argvars, rettv, FALSE); -} - -/* - * "ch_evalraw()" function - */ - static void -f_ch_evalraw(typval_T *argvars, typval_T *rettv) -{ - ch_raw_common(argvars, rettv, TRUE); -} - -/* - * "ch_sendraw()" function - */ - static void -f_ch_sendraw(typval_T *argvars, typval_T *rettv) -{ - ch_raw_common(argvars, rettv, FALSE); -} - -/* - * "ch_setoptions()" function - */ - static void -f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) -{ - channel_T *channel; - jobopt_T opt; - - channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - if (channel == NULL) - return; - clear_job_options(&opt); - if (get_job_options(&argvars[1], &opt, - JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK) - channel_set_options(channel, &opt); - free_job_options(&opt); -} - -/* - * "ch_status()" function - */ - static void -f_ch_status(typval_T *argvars, typval_T *rettv) -{ - channel_T *channel; - - /* return an empty string by default */ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); - rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel)); -} -#endif - -/* - * "changenr()" function - */ - static void -f_changenr(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = curbuf->b_u_seq_cur; -} - -/* - * "char2nr(string)" function - */ - static void -f_char2nr(typval_T *argvars, typval_T *rettv) -{ -#ifdef FEAT_MBYTE - if (has_mbyte) - { - int utf8 = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) - utf8 = (int)get_tv_number_chk(&argvars[1], NULL); - - if (utf8) - rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0])); - else - rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0])); - } - else -#endif - rettv->vval.v_number = get_tv_string(&argvars[0])[0]; -} - -/* - * "cindent(lnum)" function - */ - static void -f_cindent(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_CINDENT - pos_T pos; - linenr_T lnum; - - pos = curwin->w_cursor; - lnum = get_tv_lnum(argvars); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) - { - curwin->w_cursor.lnum = lnum; - rettv->vval.v_number = get_c_indent(); - curwin->w_cursor = pos; - } - else -#endif - rettv->vval.v_number = -1; -} - -/* - * "clearmatches()" function - */ - static void -f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - clear_matches(curwin); -#endif -} - -/* - * "col(string)" function - */ - static void -f_col(typval_T *argvars, typval_T *rettv) -{ - colnr_T col = 0; - pos_T *fp; - int fnum = curbuf->b_fnum; - - fp = var2fpos(&argvars[0], FALSE, &fnum); - if (fp != NULL && fnum == curbuf->b_fnum) - { - if (fp->col == MAXCOL) - { - /* '> can be MAXCOL, get the length of the line then */ - if (fp->lnum <= curbuf->b_ml.ml_line_count) - col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; - else - col = MAXCOL; - } - else - { - col = fp->col + 1; -#ifdef FEAT_VIRTUALEDIT - /* col(".") when the cursor is on the NUL at the end of the line - * because of "coladd" can be seen as an extra column. */ - if (virtual_active() && fp == &curwin->w_cursor) - { - char_u *p = ml_get_cursor(); - - if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, - curwin->w_virtcol - curwin->w_cursor.coladd)) - { -# ifdef FEAT_MBYTE - int l; - - if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) - col += l; -# else - if (*p != NUL && p[1] == NUL) - ++col; -# endif - } - } -#endif - } - } - rettv->vval.v_number = col; -} - -#if defined(FEAT_INS_EXPAND) -/* - * "complete()" function - */ - static void -f_complete(typval_T *argvars, typval_T *rettv UNUSED) -{ - int startcol; - - if ((State & INSERT) == 0) - { - EMSG(_("E785: complete() can only be used in Insert mode")); - return; - } - - /* Check for undo allowed here, because if something was already inserted - * the line was already saved for undo and this check isn't done. */ - if (!undo_allowed()) - return; - - if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) - { - EMSG(_(e_invarg)); - return; - } - - startcol = (int)get_tv_number_chk(&argvars[0], NULL); - if (startcol <= 0) - return; - - set_completion(startcol - 1, argvars[1].vval.v_list); -} - -/* - * "complete_add()" function - */ - static void -f_complete_add(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); -} - -/* - * "complete_check()" function - */ - static void -f_complete_check(typval_T *argvars UNUSED, typval_T *rettv) -{ - int saved = RedrawingDisabled; - - RedrawingDisabled = 0; - ins_compl_check_keys(0); - rettv->vval.v_number = compl_interrupted; - RedrawingDisabled = saved; -} -#endif - -/* - * "confirm(message, buttons[, default [, type]])" function - */ - static void -f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) - char_u *message; - char_u *buttons = NULL; - char_u buf[NUMBUFLEN]; - char_u buf2[NUMBUFLEN]; - int def = 1; - int type = VIM_GENERIC; - char_u *typestr; - int error = FALSE; - - message = get_tv_string_chk(&argvars[0]); - if (message == NULL) - error = TRUE; - if (argvars[1].v_type != VAR_UNKNOWN) - { - buttons = get_tv_string_buf_chk(&argvars[1], buf); - if (buttons == NULL) - error = TRUE; - if (argvars[2].v_type != VAR_UNKNOWN) - { - def = (int)get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - typestr = get_tv_string_buf_chk(&argvars[3], buf2); - if (typestr == NULL) - error = TRUE; - else - { - switch (TOUPPER_ASC(*typestr)) - { - case 'E': type = VIM_ERROR; break; - case 'Q': type = VIM_QUESTION; break; - case 'I': type = VIM_INFO; break; - case 'W': type = VIM_WARNING; break; - case 'G': type = VIM_GENERIC; break; - } - } - } - } - } - - if (buttons == NULL || *buttons == NUL) - buttons = (char_u *)_("&Ok"); - - if (!error) - rettv->vval.v_number = do_dialog(type, NULL, message, buttons, - def, NULL, FALSE); -#endif -} - -/* - * "copy()" function - */ - static void -f_copy(typval_T *argvars, typval_T *rettv) -{ - item_copy(&argvars[0], rettv, FALSE, 0); -} - -#ifdef FEAT_FLOAT -/* - * "cos()" function - */ - static void -f_cos(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = cos(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "cosh()" function - */ - static void -f_cosh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = cosh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "count()" function - */ - static void -f_count(typval_T *argvars, typval_T *rettv) -{ - long n = 0; - int ic = FALSE; - - if (argvars[0].v_type == VAR_LIST) - { - listitem_T *li; - list_T *l; - long idx; - - if ((l = argvars[0].vval.v_list) != NULL) - { - li = l->lv_first; - if (argvars[2].v_type != VAR_UNKNOWN) - { - int error = FALSE; - - ic = (int)get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - idx = (long)get_tv_number_chk(&argvars[3], &error); - if (!error) - { - li = list_find(l, idx); - if (li == NULL) - EMSGN(_(e_listidx), idx); - } - } - if (error) - li = NULL; - } - - for ( ; li != NULL; li = li->li_next) - if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) - ++n; - } - } - else if (argvars[0].v_type == VAR_DICT) - { - int todo; - dict_T *d; - hashitem_T *hi; - - if ((d = argvars[0].vval.v_dict) != NULL) - { - int error = FALSE; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - ic = (int)get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - EMSG(_(e_invarg)); - } - - todo = error ? 0 : (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) - ++n; - } - } - } - } - else - EMSG2(_(e_listdictarg), "count()"); - rettv->vval.v_number = n; -} - -/* - * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function - * - * Checks the existence of a cscope connection. - */ - static void -f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_CSCOPE - int num = 0; - char_u *dbpath = NULL; - char_u *prepend = NULL; - char_u buf[NUMBUFLEN]; - - if (argvars[0].v_type != VAR_UNKNOWN - && argvars[1].v_type != VAR_UNKNOWN) - { - num = (int)get_tv_number(&argvars[0]); - dbpath = get_tv_string(&argvars[1]); - if (argvars[2].v_type != VAR_UNKNOWN) - prepend = get_tv_string_buf(&argvars[2], buf); - } - - rettv->vval.v_number = cs_connection(num, dbpath, prepend); -#endif -} - -/* - * "cursor(lnum, col)" function, or - * "cursor(list)" - * - * Moves the cursor to the specified line and column. - * Returns 0 when the position could be set, -1 otherwise. - */ - static void -f_cursor(typval_T *argvars, typval_T *rettv) -{ - long line, col; -#ifdef FEAT_VIRTUALEDIT - long coladd = 0; -#endif - int set_curswant = TRUE; - - rettv->vval.v_number = -1; - if (argvars[1].v_type == VAR_UNKNOWN) - { - pos_T pos; - colnr_T curswant = -1; - - if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) - { - EMSG(_(e_invarg)); - return; - } - line = pos.lnum; - col = pos.col; -#ifdef FEAT_VIRTUALEDIT - coladd = pos.coladd; -#endif - if (curswant >= 0) - { - curwin->w_curswant = curswant - 1; - set_curswant = FALSE; - } - } - else - { - line = get_tv_lnum(argvars); - col = (long)get_tv_number_chk(&argvars[1], NULL); -#ifdef FEAT_VIRTUALEDIT - if (argvars[2].v_type != VAR_UNKNOWN) - coladd = (long)get_tv_number_chk(&argvars[2], NULL); -#endif - } - if (line < 0 || col < 0 -#ifdef FEAT_VIRTUALEDIT - || coladd < 0 -#endif - ) - return; /* type error; errmsg already given */ - if (line > 0) - curwin->w_cursor.lnum = line; - if (col > 0) - curwin->w_cursor.col = col - 1; -#ifdef FEAT_VIRTUALEDIT - curwin->w_cursor.coladd = coladd; -#endif - - /* Make sure the cursor is in a valid position. */ - check_cursor(); -#ifdef FEAT_MBYTE - /* Correct cursor for multi-byte character. */ - if (has_mbyte) - mb_adjust_cursor(); -#endif - - curwin->w_set_curswant = set_curswant; - rettv->vval.v_number = 0; -} - -/* - * "deepcopy()" function - */ - static void -f_deepcopy(typval_T *argvars, typval_T *rettv) -{ - int noref = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) - noref = (int)get_tv_number_chk(&argvars[1], NULL); - if (noref < 0 || noref > 1) - EMSG(_(e_invarg)); - else - { - current_copyID += COPYID_INC; - item_copy(&argvars[0], rettv, TRUE, noref == 0 ? current_copyID : 0); - } -} - -/* - * "delete()" function - */ - static void -f_delete(typval_T *argvars, typval_T *rettv) -{ - char_u nbuf[NUMBUFLEN]; - char_u *name; - char_u *flags; - - rettv->vval.v_number = -1; - if (check_restricted() || check_secure()) - return; - - name = get_tv_string(&argvars[0]); - if (name == NULL || *name == NUL) - { - EMSG(_(e_invarg)); - return; - } - - if (argvars[1].v_type != VAR_UNKNOWN) - flags = get_tv_string_buf(&argvars[1], nbuf); - else - flags = (char_u *)""; - - if (*flags == NUL) - /* delete a file */ - rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; - else if (STRCMP(flags, "d") == 0) - /* delete an empty directory */ - rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; - else if (STRCMP(flags, "rf") == 0) - /* delete a directory recursively */ - rettv->vval.v_number = delete_recursive(name); - else - EMSG2(_(e_invexpr2), flags); -} - -/* - * "did_filetype()" function - */ - static void -f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_AUTOCMD - rettv->vval.v_number = did_filetype; -#endif -} - -/* - * "diff_filler()" function - */ - static void -f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_DIFF - rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars)); -#endif -} - -/* - * "diff_hlID()" function - */ - static void -f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_DIFF - linenr_T lnum = get_tv_lnum(argvars); - static linenr_T prev_lnum = 0; - static int changedtick = 0; - static int fnum = 0; - static int change_start = 0; - static int change_end = 0; - static hlf_T hlID = (hlf_T)0; - int filler_lines; - int col; - - if (lnum < 0) /* ignore type error in {lnum} arg */ - lnum = 0; - if (lnum != prev_lnum - || changedtick != curbuf->b_changedtick - || fnum != curbuf->b_fnum) - { - /* New line, buffer, change: need to get the values. */ - filler_lines = diff_check(curwin, lnum); - if (filler_lines < 0) - { - if (filler_lines == -1) - { - change_start = MAXCOL; - change_end = -1; - if (diff_find_change(curwin, lnum, &change_start, &change_end)) - hlID = HLF_ADD; /* added line */ - else - hlID = HLF_CHD; /* changed line */ - } - else - hlID = HLF_ADD; /* added line */ - } - else - hlID = (hlf_T)0; - prev_lnum = lnum; - changedtick = curbuf->b_changedtick; - fnum = curbuf->b_fnum; - } - - if (hlID == HLF_CHD || hlID == HLF_TXD) - { - col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */ - if (col >= change_start && col <= change_end) - hlID = HLF_TXD; /* changed text */ - else - hlID = HLF_CHD; /* changed line */ - } - rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; -#endif -} - -/* - * "empty({expr})" function - */ - static void -f_empty(typval_T *argvars, typval_T *rettv) -{ - int n = FALSE; - - switch (argvars[0].v_type) - { - case VAR_STRING: - case VAR_FUNC: - n = argvars[0].vval.v_string == NULL - || *argvars[0].vval.v_string == NUL; - break; - case VAR_PARTIAL: - n = FALSE; - break; - case VAR_NUMBER: - n = argvars[0].vval.v_number == 0; - break; - case VAR_FLOAT: -#ifdef FEAT_FLOAT - n = argvars[0].vval.v_float == 0.0; - break; -#endif - case VAR_LIST: - n = argvars[0].vval.v_list == NULL - || argvars[0].vval.v_list->lv_first == NULL; - break; - case VAR_DICT: - n = argvars[0].vval.v_dict == NULL - || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; - break; - case VAR_SPECIAL: - n = argvars[0].vval.v_number != VVAL_TRUE; - break; - - case VAR_JOB: -#ifdef FEAT_JOB_CHANNEL - n = argvars[0].vval.v_job == NULL - || argvars[0].vval.v_job->jv_status != JOB_STARTED; - break; -#endif - case VAR_CHANNEL: -#ifdef FEAT_JOB_CHANNEL - n = argvars[0].vval.v_channel == NULL - || !channel_is_open(argvars[0].vval.v_channel); - break; -#endif - case VAR_UNKNOWN: - EMSG2(_(e_intern2), "f_empty(UNKNOWN)"); - n = TRUE; - break; - } - - rettv->vval.v_number = n; -} - -/* - * "escape({string}, {chars})" function - */ - static void -f_escape(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - - rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]), - get_tv_string_buf(&argvars[1], buf)); - rettv->v_type = VAR_STRING; -} - -/* - * "eval()" function - */ - static void -f_eval(typval_T *argvars, typval_T *rettv) -{ - char_u *s, *p; - - s = get_tv_string_chk(&argvars[0]); - if (s != NULL) - s = skipwhite(s); - - p = s; - if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) - { - if (p != NULL && !aborting()) - EMSG2(_(e_invexpr2), p); - need_clr_eos = FALSE; - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = 0; - } - else if (*s != NUL) - EMSG(_(e_trailing)); -} - -/* - * "eventhandler()" function - */ - static void -f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = vgetc_busy; -} - -/* - * "executable()" function - */ - static void -f_executable(typval_T *argvars, typval_T *rettv) -{ - char_u *name = get_tv_string(&argvars[0]); - - /* Check in $PATH and also check directly if there is a directory name. */ - rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) - || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); -} - -static garray_T redir_execute_ga; - -/* - * Append "value[value_len]" to the execute() output. - */ - void -execute_redir_str(char_u *value, int value_len) -{ - int len; - - if (value_len == -1) - len = (int)STRLEN(value); /* Append the entire string */ - else - len = value_len; /* Append only "value_len" characters */ - if (ga_grow(&redir_execute_ga, len) == OK) - { - mch_memmove((char *)redir_execute_ga.ga_data - + redir_execute_ga.ga_len, value, len); - redir_execute_ga.ga_len += len; - } -} - -/* - * Get next line from a list. - * Called by do_cmdline() to get the next line. - * Returns allocated string, or NULL for end of function. - */ - - static char_u * -get_list_line( - int c UNUSED, - void *cookie, - int indent UNUSED) -{ - listitem_T **p = (listitem_T **)cookie; - listitem_T *item = *p; - char_u buf[NUMBUFLEN]; - char_u *s; - - if (item == NULL) - return NULL; - s = get_tv_string_buf_chk(&item->li_tv, buf); - *p = item->li_next; - return s == NULL ? NULL : vim_strsave(s); -} - -/* - * "execute()" function - */ - static void -f_execute(typval_T *argvars, typval_T *rettv) -{ - char_u *cmd = NULL; - list_T *list = NULL; - int save_msg_silent = msg_silent; - int save_emsg_silent = emsg_silent; - int save_emsg_noredir = emsg_noredir; - int save_redir_execute = redir_execute; - garray_T save_ga; - - rettv->vval.v_string = NULL; - rettv->v_type = VAR_STRING; - - if (argvars[0].v_type == VAR_LIST) - { - list = argvars[0].vval.v_list; - if (list == NULL || list->lv_first == NULL) - /* empty list, no commands, empty output */ - return; - ++list->lv_refcount; - } - else - { - cmd = get_tv_string_chk(&argvars[0]); - if (cmd == NULL) - return; - } - - if (argvars[1].v_type != VAR_UNKNOWN) - { - char_u buf[NUMBUFLEN]; - char_u *s = get_tv_string_buf_chk(&argvars[1], buf); - - if (s == NULL) - return; - if (STRNCMP(s, "silent", 6) == 0) - ++msg_silent; - if (STRCMP(s, "silent!") == 0) - { - emsg_silent = TRUE; - emsg_noredir = TRUE; - } - } - else - ++msg_silent; - - if (redir_execute) - save_ga = redir_execute_ga; - ga_init2(&redir_execute_ga, (int)sizeof(char), 500); - redir_execute = TRUE; - - if (cmd != NULL) - do_cmdline_cmd(cmd); - else - { - listitem_T *item = list->lv_first; - - do_cmdline(NULL, get_list_line, (void *)&item, - DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); - --list->lv_refcount; - } - - rettv->vval.v_string = redir_execute_ga.ga_data; - msg_silent = save_msg_silent; - emsg_silent = save_emsg_silent; - emsg_noredir = save_emsg_noredir; - - redir_execute = save_redir_execute; - if (redir_execute) - redir_execute_ga = save_ga; - - /* "silent reg" or "silent echo x" leaves msg_col somewhere in the - * line. Put it back in the first column. */ - msg_col = 0; -} - -/* - * "exepath()" function - */ - static void -f_exepath(typval_T *argvars, typval_T *rettv) -{ - char_u *p = NULL; - - (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = p; -} - -/* - * "exists()" function - */ - static void -f_exists(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - char_u *name; - int n = FALSE; - int len = 0; - - p = get_tv_string(&argvars[0]); - if (*p == '$') /* environment variable */ - { - /* first try "normal" environment variables (fast) */ - if (mch_getenv(p + 1) != NULL) - n = TRUE; - else - { - /* try expanding things like $VIM and ${HOME} */ - p = expand_env_save(p); - if (p != NULL && *p != '$') - n = TRUE; - vim_free(p); - } - } - else if (*p == '&' || *p == '+') /* option */ - { - n = (get_option_tv(&p, NULL, TRUE) == OK); - if (*skipwhite(p) != NUL) - n = FALSE; /* trailing garbage */ - } - else if (*p == '*') /* internal or user defined function */ - { - n = function_exists(p + 1); - } - else if (*p == ':') - { - n = cmd_exists(p + 1); - } - else if (*p == '#') - { -#ifdef FEAT_AUTOCMD - if (p[1] == '#') - n = autocmd_supported(p + 2); - else - n = au_exists(p + 1); -#endif - } - else /* internal variable */ - { - char_u *tofree; - typval_T tv; - - /* get_name_len() takes care of expanding curly braces */ - name = p; - len = get_name_len(&p, &tofree, TRUE, FALSE); - if (len > 0) - { - if (tofree != NULL) - name = tofree; - n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); - if (n) - { - /* handle d.key, l[idx], f(expr) */ - n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); - if (n) - clear_tv(&tv); - } - } - if (*p != NUL) - n = FALSE; - - vim_free(tofree); - } - - rettv->vval.v_number = n; -} - -#ifdef FEAT_FLOAT -/* - * "exp()" function - */ - static void -f_exp(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = exp(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "expand()" function - */ - static void -f_expand(typval_T *argvars, typval_T *rettv) -{ - char_u *s; - int len; - char_u *errormsg; - int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; - expand_T xpc; - int error = FALSE; - char_u *result; - - rettv->v_type = VAR_STRING; - if (argvars[1].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[2], &error) - && !error) - { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; - } - - s = get_tv_string(&argvars[0]); - if (*s == '%' || *s == '#' || *s == '<') - { - ++emsg_off; - result = eval_vars(s, s, &len, NULL, &errormsg, NULL); - --emsg_off; - if (rettv->v_type == VAR_LIST) - { - if (rettv_list_alloc(rettv) != FAIL && result != NULL) - list_append_string(rettv->vval.v_list, result, -1); - else - vim_free(result); - } - else - rettv->vval.v_string = result; - } - else - { - /* When the optional second argument is non-zero, don't remove matches - * for 'wildignore' and don't put matches for 'suffixes' at the end. */ - if (argvars[1].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[1], &error)) - options |= WILD_KEEP_ALL; - if (!error) - { - ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; - if (p_wic) - options += WILD_ICASE; - if (rettv->v_type == VAR_STRING) - rettv->vval.v_string = ExpandOne(&xpc, s, NULL, - options, WILD_ALL); - else if (rettv_list_alloc(rettv) != FAIL) - { - int i; - - ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); - for (i = 0; i < xpc.xp_numfiles; i++) - list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); - ExpandCleanup(&xpc); - } - } - else - rettv->vval.v_string = NULL; - } -} - -/* - * "extend(list, list [, idx])" function - * "extend(dict, dict [, action])" function - */ - static void -f_extend(typval_T *argvars, typval_T *rettv) -{ - char_u *arg_errmsg = (char_u *)N_("extend() argument"); - - if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) - { - list_T *l1, *l2; - listitem_T *item; - long before; - int error = FALSE; - - l1 = argvars[0].vval.v_list; - l2 = argvars[1].vval.v_list; - if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE) - && l2 != NULL) - { - if (argvars[2].v_type != VAR_UNKNOWN) - { - before = (long)get_tv_number_chk(&argvars[2], &error); - if (error) - return; /* type error; errmsg already given */ - - if (before == l1->lv_len) - item = NULL; - else - { - item = list_find(l1, before); - if (item == NULL) - { - EMSGN(_(e_listidx), before); - return; - } - } - } - else - item = NULL; - list_extend(l1, l2, item); - - copy_tv(&argvars[0], rettv); - } - } - else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) - { - dict_T *d1, *d2; - char_u *action; - int i; - - d1 = argvars[0].vval.v_dict; - d2 = argvars[1].vval.v_dict; - if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE) - && d2 != NULL) - { - /* Check the third argument. */ - if (argvars[2].v_type != VAR_UNKNOWN) - { - static char *(av[]) = {"keep", "force", "error"}; - - action = get_tv_string_chk(&argvars[2]); - if (action == NULL) - return; /* type error; errmsg already given */ - for (i = 0; i < 3; ++i) - if (STRCMP(action, av[i]) == 0) - break; - if (i == 3) - { - EMSG2(_(e_invarg2), action); - return; - } - } - else - action = (char_u *)"force"; - - dict_extend(d1, d2, action); - - copy_tv(&argvars[0], rettv); - } - } - else - EMSG2(_(e_listdictarg), "extend()"); -} - -/* - * "feedkeys()" function - */ - static void -f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) -{ - int remap = TRUE; - int insert = FALSE; - char_u *keys, *flags; - char_u nbuf[NUMBUFLEN]; - int typed = FALSE; - int execute = FALSE; - int dangerous = FALSE; - char_u *keys_esc; - - /* This is not allowed in the sandbox. If the commands would still be - * executed in the sandbox it would be OK, but it probably happens later, - * when "sandbox" is no longer set. */ - if (check_secure()) - return; - - keys = get_tv_string(&argvars[0]); - - if (argvars[1].v_type != VAR_UNKNOWN) - { - flags = get_tv_string_buf(&argvars[1], nbuf); - for ( ; *flags != NUL; ++flags) - { - switch (*flags) - { - case 'n': remap = FALSE; break; - case 'm': remap = TRUE; break; - case 't': typed = TRUE; break; - case 'i': insert = TRUE; break; - case 'x': execute = TRUE; break; - case '!': dangerous = TRUE; break; - } - } - } - - if (*keys != NUL || execute) - { - /* Need to escape K_SPECIAL and CSI before putting the string in the - * typeahead buffer. */ - keys_esc = vim_strsave_escape_csi(keys); - if (keys_esc != NULL) - { - ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), - insert ? 0 : typebuf.tb_len, !typed, FALSE); - vim_free(keys_esc); - if (vgetc_busy) - typebuf_was_filled = TRUE; - if (execute) - { - int save_msg_scroll = msg_scroll; - - /* Avoid a 1 second delay when the keys start Insert mode. */ - msg_scroll = FALSE; - - if (!dangerous) - ++ex_normal_busy; - exec_normal(TRUE); - if (!dangerous) - --ex_normal_busy; - msg_scroll |= save_msg_scroll; - } - } - } -} - -/* - * "filereadable()" function - */ - static void -f_filereadable(typval_T *argvars, typval_T *rettv) -{ - int fd; - char_u *p; - int n; - -#ifndef O_NONBLOCK -# define O_NONBLOCK 0 -#endif - p = get_tv_string(&argvars[0]); - if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, - O_RDONLY | O_NONBLOCK, 0)) >= 0) - { - n = TRUE; - close(fd); - } - else - n = FALSE; - - rettv->vval.v_number = n; -} - -/* - * Return 0 for not writable, 1 for writable file, 2 for a dir which we have - * rights to write into. - */ - static void -f_filewritable(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = filewritable(get_tv_string(&argvars[0])); -} - - static void -findfilendir( - typval_T *argvars UNUSED, - typval_T *rettv, - int find_what UNUSED) -{ -#ifdef FEAT_SEARCHPATH - char_u *fname; - char_u *fresult = NULL; - char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; - char_u *p; - char_u pathbuf[NUMBUFLEN]; - int count = 1; - int first = TRUE; - int error = FALSE; -#endif - - rettv->vval.v_string = NULL; - rettv->v_type = VAR_STRING; - -#ifdef FEAT_SEARCHPATH - fname = get_tv_string(&argvars[0]); - - if (argvars[1].v_type != VAR_UNKNOWN) - { - p = get_tv_string_buf_chk(&argvars[1], pathbuf); - if (p == NULL) - error = TRUE; - else - { - if (*p != NUL) - path = p; - - if (argvars[2].v_type != VAR_UNKNOWN) - count = (int)get_tv_number_chk(&argvars[2], &error); - } - } - - if (count < 0 && rettv_list_alloc(rettv) == FAIL) - error = TRUE; - - if (*fname != NUL && !error) - { - do - { - if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) - vim_free(fresult); - fresult = find_file_in_path_option(first ? fname : NULL, - first ? (int)STRLEN(fname) : 0, - 0, first, path, - find_what, - curbuf->b_ffname, - find_what == FINDFILE_DIR - ? (char_u *)"" : curbuf->b_p_sua); - first = FALSE; - - if (fresult != NULL && rettv->v_type == VAR_LIST) - list_append_string(rettv->vval.v_list, fresult, -1); - - } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); - } - - if (rettv->v_type == VAR_STRING) - rettv->vval.v_string = fresult; -#endif -} - -static void filter_map(typval_T *argvars, typval_T *rettv, int map); -static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp); - -/* - * Implementation of map() and filter(). - */ - static void -filter_map(typval_T *argvars, typval_T *rettv, int map) -{ - typval_T *expr; - listitem_T *li, *nli; - list_T *l = NULL; - dictitem_T *di; - hashtab_T *ht; - hashitem_T *hi; - dict_T *d = NULL; - typval_T save_val; - typval_T save_key; - int rem; - int todo; - char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); - char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") - : N_("filter() argument")); - int save_did_emsg; - int idx = 0; - - if (argvars[0].v_type == VAR_LIST) - { - if ((l = argvars[0].vval.v_list) == NULL - || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE))) - return; - } - else if (argvars[0].v_type == VAR_DICT) - { - if ((d = argvars[0].vval.v_dict) == NULL - || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE))) - return; - } - else - { - EMSG2(_(e_listdictarg), ermsg); - return; - } - - expr = &argvars[1]; - /* On type errors, the preceding call has already displayed an error - * message. Avoid a misleading error message for an empty string that - * was not passed as argument. */ - if (expr->v_type != VAR_UNKNOWN) - { - prepare_vimvar(VV_VAL, &save_val); - - /* We reset "did_emsg" to be able to detect whether an error - * occurred during evaluation of the expression. */ - save_did_emsg = did_emsg; - did_emsg = FALSE; - - prepare_vimvar(VV_KEY, &save_key); - if (argvars[0].v_type == VAR_DICT) - { - vimvars[VV_KEY].vv_type = VAR_STRING; - - ht = &d->dv_hashtab; - hash_lock(ht); - todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - int r; - - --todo; - di = HI2DI(hi); - if (map && - (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) - || var_check_ro(di->di_flags, arg_errmsg, TRUE))) - break; - vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); - r = filter_map_one(&di->di_tv, expr, map, &rem); - clear_tv(&vimvars[VV_KEY].vv_tv); - if (r == FAIL || did_emsg) - break; - if (!map && rem) - { - if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) - || var_check_ro(di->di_flags, arg_errmsg, TRUE)) - break; - dictitem_remove(d, di); - } - } - } - hash_unlock(ht); - } - else - { - vimvars[VV_KEY].vv_type = VAR_NUMBER; - - for (li = l->lv_first; li != NULL; li = nli) - { - if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) - break; - nli = li->li_next; - vimvars[VV_KEY].vv_nr = idx; - if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL - || did_emsg) - break; - if (!map && rem) - listitem_remove(l, li); - ++idx; - } - } - - restore_vimvar(VV_KEY, &save_key); - restore_vimvar(VV_VAL, &save_val); - - did_emsg |= save_did_emsg; - } - - copy_tv(&argvars[0], rettv); -} - - static int -filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) -{ - typval_T rettv; - typval_T argv[3]; - char_u buf[NUMBUFLEN]; - char_u *s; - int retval = FAIL; - int dummy; - - copy_tv(tv, &vimvars[VV_VAL].vv_tv); - argv[0] = vimvars[VV_KEY].vv_tv; - argv[1] = vimvars[VV_VAL].vv_tv; - if (expr->v_type == VAR_FUNC) - { - s = expr->vval.v_string; - if (call_func(s, (int)STRLEN(s), - &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL) - goto theend; - } - else if (expr->v_type == VAR_PARTIAL) - { - partial_T *partial = expr->vval.v_partial; - - s = partial->pt_name; - if (call_func(s, (int)STRLEN(s), - &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL) - == FAIL) - goto theend; - } - else - { - s = get_tv_string_buf_chk(expr, buf); - if (s == NULL) - goto theend; - s = skipwhite(s); - if (eval1(&s, &rettv, TRUE) == FAIL) - goto theend; - if (*s != NUL) /* check for trailing chars after expr */ - { - EMSG2(_(e_invexpr2), s); - goto theend; - } - } - if (map) - { - /* map(): replace the list item value */ - clear_tv(tv); - rettv.v_lock = 0; - *tv = rettv; - } - else - { - int error = FALSE; - - /* filter(): when expr is zero remove the item */ - *remp = (get_tv_number_chk(&rettv, &error) == 0); - clear_tv(&rettv); - /* On type error, nothing has been removed; return FAIL to stop the - * loop. The error message was given by get_tv_number_chk(). */ - if (error) - goto theend; - } - retval = OK; -theend: - clear_tv(&vimvars[VV_VAL].vv_tv); - return retval; -} - -/* - * "filter()" function - */ - static void -f_filter(typval_T *argvars, typval_T *rettv) -{ - filter_map(argvars, rettv, FALSE); -} - -/* - * "finddir({fname}[, {path}[, {count}]])" function - */ - static void -f_finddir(typval_T *argvars, typval_T *rettv) -{ - findfilendir(argvars, rettv, FINDFILE_DIR); -} - -/* - * "findfile({fname}[, {path}[, {count}]])" function - */ - static void -f_findfile(typval_T *argvars, typval_T *rettv) -{ - findfilendir(argvars, rettv, FINDFILE_FILE); -} - -#ifdef FEAT_FLOAT -/* - * "float2nr({float})" function - */ - static void -f_float2nr(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - if (get_float_arg(argvars, &f) == OK) - { -# ifdef FEAT_NUM64 - if (f < -0x7fffffffffffffff) - rettv->vval.v_number = -0x7fffffffffffffff; - else if (f > 0x7fffffffffffffff) - rettv->vval.v_number = 0x7fffffffffffffff; - else - rettv->vval.v_number = (varnumber_T)f; -# else - if (f < -0x7fffffff) - rettv->vval.v_number = -0x7fffffff; - else if (f > 0x7fffffff) - rettv->vval.v_number = 0x7fffffff; - else - rettv->vval.v_number = (varnumber_T)f; -# endif - } -} - -/* - * "floor({float})" function - */ - static void -f_floor(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = floor(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "fmod()" function - */ - static void -f_fmod(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = fmod(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "fnameescape({string})" function - */ - static void -f_fnameescape(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_string = vim_strsave_fnameescape( - get_tv_string(&argvars[0]), FALSE); - rettv->v_type = VAR_STRING; -} - -/* - * "fnamemodify({fname}, {mods})" function - */ - static void -f_fnamemodify(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - char_u *mods; - int usedlen = 0; - int len; - char_u *fbuf = NULL; - char_u buf[NUMBUFLEN]; - - fname = get_tv_string_chk(&argvars[0]); - mods = get_tv_string_buf_chk(&argvars[1], buf); - if (fname == NULL || mods == NULL) - fname = NULL; - else - { - len = (int)STRLEN(fname); - (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); - } - - rettv->v_type = VAR_STRING; - if (fname == NULL) - rettv->vval.v_string = NULL; - else - rettv->vval.v_string = vim_strnsave(fname, len); - vim_free(fbuf); -} - -static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end); - -/* - * "foldclosed()" function - */ - static void -foldclosed_both( - typval_T *argvars UNUSED, - typval_T *rettv, - int end UNUSED) -{ -#ifdef FEAT_FOLDING - linenr_T lnum; - linenr_T first, last; - - lnum = get_tv_lnum(argvars); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) - { - if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) - { - if (end) - rettv->vval.v_number = (varnumber_T)last; - else - rettv->vval.v_number = (varnumber_T)first; - return; - } - } -#endif - rettv->vval.v_number = -1; -} - -/* - * "foldclosed()" function - */ - static void -f_foldclosed(typval_T *argvars, typval_T *rettv) -{ - foldclosed_both(argvars, rettv, FALSE); -} - -/* - * "foldclosedend()" function - */ - static void -f_foldclosedend(typval_T *argvars, typval_T *rettv) -{ - foldclosed_both(argvars, rettv, TRUE); -} - -/* - * "foldlevel()" function - */ - static void -f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_FOLDING - linenr_T lnum; - - lnum = get_tv_lnum(argvars); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) - rettv->vval.v_number = foldLevel(lnum); -#endif -} - -/* - * "foldtext()" function - */ - static void -f_foldtext(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_FOLDING - linenr_T lnum; - char_u *s; - char_u *r; - int len; - char *txt; -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_FOLDING - if ((linenr_T)vimvars[VV_FOLDSTART].vv_nr > 0 - && (linenr_T)vimvars[VV_FOLDEND].vv_nr - <= curbuf->b_ml.ml_line_count - && vimvars[VV_FOLDDASHES].vv_str != NULL) - { - /* Find first non-empty line in the fold. */ - lnum = (linenr_T)vimvars[VV_FOLDSTART].vv_nr; - while (lnum < (linenr_T)vimvars[VV_FOLDEND].vv_nr) - { - if (!linewhite(lnum)) - break; - ++lnum; - } - - /* Find interesting text in this line. */ - s = skipwhite(ml_get(lnum)); - /* skip C comment-start */ - if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) - { - s = skipwhite(s + 2); - if (*skipwhite(s) == NUL - && lnum + 1 < (linenr_T)vimvars[VV_FOLDEND].vv_nr) - { - s = skipwhite(ml_get(lnum + 1)); - if (*s == '*') - s = skipwhite(s + 1); - } - } - txt = _("+-%s%3ld lines: "); - r = alloc((unsigned)(STRLEN(txt) - + STRLEN(vimvars[VV_FOLDDASHES].vv_str) /* for %s */ - + 20 /* for %3ld */ - + STRLEN(s))); /* concatenated */ - if (r != NULL) - { - sprintf((char *)r, txt, vimvars[VV_FOLDDASHES].vv_str, - (long)((linenr_T)vimvars[VV_FOLDEND].vv_nr - - (linenr_T)vimvars[VV_FOLDSTART].vv_nr + 1)); - len = (int)STRLEN(r); - STRCAT(r, s); - /* remove 'foldmarker' and 'commentstring' */ - foldtext_cleanup(r + len); - rettv->vval.v_string = r; - } - } -#endif -} - -/* - * "foldtextresult(lnum)" function - */ - static void -f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_FOLDING - linenr_T lnum; - char_u *text; - char_u buf[51]; - foldinfo_T foldinfo; - int fold_count; -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_FOLDING - lnum = get_tv_lnum(argvars); - /* treat illegal types and illegal string values for {lnum} the same */ - if (lnum < 0) - lnum = 0; - fold_count = foldedCount(curwin, lnum, &foldinfo); - if (fold_count > 0) - { - text = get_foldtext(curwin, lnum, lnum + fold_count - 1, - &foldinfo, buf); - if (text == buf) - text = vim_strsave(text); - rettv->vval.v_string = text; - } -#endif -} - -/* - * "foreground()" function - */ - static void -f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_GUI - if (gui.in_use) - gui_mch_set_foreground(); -#else -# ifdef WIN32 - win32_set_foreground(); -# endif -#endif -} - -/* - * "function()" function - */ - static void -f_function(typval_T *argvars, typval_T *rettv) -{ - char_u *s; - char_u *name; - int use_string = FALSE; - partial_T *arg_pt = NULL; - - if (argvars[0].v_type == VAR_FUNC) - { - /* function(MyFunc, [arg], dict) */ - s = argvars[0].vval.v_string; - } - else if (argvars[0].v_type == VAR_PARTIAL - && argvars[0].vval.v_partial != NULL) - { - /* function(dict.MyFunc, [arg]) */ - arg_pt = argvars[0].vval.v_partial; - s = arg_pt->pt_name; - } - else - { - /* function('MyFunc', [arg], dict) */ - s = get_tv_string(&argvars[0]); - use_string = TRUE; - } - - if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))) - EMSG2(_(e_invarg2), s); - /* Don't check an autoload name for existence here. */ - else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL - && !function_exists(s)) - EMSG2(_("E700: Unknown function: %s"), s); - else - { - int dict_idx = 0; - int arg_idx = 0; - list_T *list = NULL; - - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) - { - char sid_buf[25]; - int off = *s == 's' ? 2 : 5; - - /* Expand s: and <SID> into <SNR>nr_, so that the function can - * also be called from another script. Using trans_function_name() - * would also work, but some plugins depend on the name being - * printable text. */ - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID); - name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); - if (name != NULL) - { - STRCPY(name, sid_buf); - STRCAT(name, s + off); - } - } - else - name = vim_strsave(s); - - if (argvars[1].v_type != VAR_UNKNOWN) - { - if (argvars[2].v_type != VAR_UNKNOWN) - { - /* function(name, [args], dict) */ - arg_idx = 1; - dict_idx = 2; - } - else if (argvars[1].v_type == VAR_DICT) - /* function(name, dict) */ - dict_idx = 1; - else - /* function(name, [args]) */ - arg_idx = 1; - if (dict_idx > 0) - { - if (argvars[dict_idx].v_type != VAR_DICT) - { - EMSG(_("E922: expected a dict")); - vim_free(name); - return; - } - if (argvars[dict_idx].vval.v_dict == NULL) - dict_idx = 0; - } - if (arg_idx > 0) - { - if (argvars[arg_idx].v_type != VAR_LIST) - { - EMSG(_("E923: Second argument of function() must be a list or a dict")); - vim_free(name); - return; - } - list = argvars[arg_idx].vval.v_list; - if (list == NULL || list->lv_len == 0) - arg_idx = 0; - } - } - if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL) - { - partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); - - /* result is a VAR_PARTIAL */ - if (pt == NULL) - vim_free(name); - else - { - if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) - { - listitem_T *li; - int i = 0; - int arg_len = 0; - int lv_len = 0; - - if (arg_pt != NULL) - arg_len = arg_pt->pt_argc; - if (list != NULL) - lv_len = list->lv_len; - pt->pt_argc = arg_len + lv_len; - pt->pt_argv = (typval_T *)alloc( - sizeof(typval_T) * pt->pt_argc); - if (pt->pt_argv == NULL) - { - vim_free(pt); - vim_free(name); - return; - } - else - { - for (i = 0; i < arg_len; i++) - copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); - if (lv_len > 0) - for (li = list->lv_first; li != NULL; - li = li->li_next) - copy_tv(&li->li_tv, &pt->pt_argv[i++]); - } - } - - /* For "function(dict.func, [], dict)" and "func" is a partial - * use "dict". That is backwards compatible. */ - if (dict_idx > 0) - { - /* The dict is bound explicitly, pt_auto is FALSE. */ - pt->pt_dict = argvars[dict_idx].vval.v_dict; - ++pt->pt_dict->dv_refcount; - } - else if (arg_pt != NULL) - { - /* If the dict was bound automatically the result is also - * bound automatically. */ - pt->pt_dict = arg_pt->pt_dict; - pt->pt_auto = arg_pt->pt_auto; - if (pt->pt_dict != NULL) - ++pt->pt_dict->dv_refcount; - } - - pt->pt_refcount = 1; - pt->pt_name = name; - func_ref(pt->pt_name); - } - rettv->v_type = VAR_PARTIAL; - rettv->vval.v_partial = pt; - } - else - { - /* result is a VAR_FUNC */ - rettv->v_type = VAR_FUNC; - rettv->vval.v_string = name; - func_ref(name); - } - } -} - -/* - * "garbagecollect()" function - */ - static void -f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) -{ - /* This is postponed until we are back at the toplevel, because we may be - * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ - want_garbage_collect = TRUE; - - if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1) - garbage_collect_at_exit = TRUE; -} - -/* - * "get()" function - */ - static void -f_get(typval_T *argvars, typval_T *rettv) -{ - listitem_T *li; - list_T *l; - dictitem_T *di; - dict_T *d; - typval_T *tv = NULL; - - if (argvars[0].v_type == VAR_LIST) - { - if ((l = argvars[0].vval.v_list) != NULL) - { - int error = FALSE; - - li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error)); - if (!error && li != NULL) - tv = &li->li_tv; - } - } - else if (argvars[0].v_type == VAR_DICT) - { - if ((d = argvars[0].vval.v_dict) != NULL) - { - di = dict_find(d, get_tv_string(&argvars[1]), -1); - if (di != NULL) - tv = &di->di_tv; - } - } - else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) - { - partial_T *pt; - partial_T fref_pt; - - if (argvars[0].v_type == VAR_PARTIAL) - pt = argvars[0].vval.v_partial; - else - { - vim_memset(&fref_pt, 0, sizeof(fref_pt)); - fref_pt.pt_name = argvars[0].vval.v_string; - pt = &fref_pt; - } - - if (pt != NULL) - { - char_u *what = get_tv_string(&argvars[1]); - - if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) - { - rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); - if (pt->pt_name == NULL) - rettv->vval.v_string = NULL; - else - rettv->vval.v_string = vim_strsave(pt->pt_name); - } - else if (STRCMP(what, "dict") == 0) - { - rettv->v_type = VAR_DICT; - rettv->vval.v_dict = pt->pt_dict; - if (pt->pt_dict != NULL) - ++pt->pt_dict->dv_refcount; - } - else if (STRCMP(what, "args") == 0) - { - rettv->v_type = VAR_LIST; - if (rettv_list_alloc(rettv) == OK) - { - int i; - - for (i = 0; i < pt->pt_argc; ++i) - list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); - } - } - else - EMSG2(_(e_invarg2), what); - return; - } - } - else - EMSG2(_(e_listdictarg), "get()"); - - if (tv == NULL) - { - if (argvars[2].v_type != VAR_UNKNOWN) - copy_tv(&argvars[2], rettv); - } - else - copy_tv(tv, rettv); -} - -static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv); - -/* - * Get line or list of lines from buffer "buf" into "rettv". - * Return a range (from start to end) of lines in rettv from the specified - * buffer. - * If 'retlist' is TRUE, then the lines are returned as a Vim List. - */ - static void -get_buffer_lines( - buf_T *buf, - linenr_T start, - linenr_T end, - int retlist, - typval_T *rettv) -{ - char_u *p; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - if (retlist && rettv_list_alloc(rettv) == FAIL) - return; - - if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) - return; - - if (!retlist) - { - if (start >= 1 && start <= buf->b_ml.ml_line_count) - p = ml_get_buf(buf, start, FALSE); - else - p = (char_u *)""; - rettv->vval.v_string = vim_strsave(p); - } - else - { - if (end < start) - return; - - if (start < 1) - start = 1; - if (end > buf->b_ml.ml_line_count) - end = buf->b_ml.ml_line_count; - while (start <= end) - if (list_append_string(rettv->vval.v_list, - ml_get_buf(buf, start++, FALSE), -1) == FAIL) - break; - } -} - -/* - * "getbufline()" function - */ - static void -f_getbufline(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - linenr_T end; - buf_T *buf; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - --emsg_off; - - lnum = get_tv_lnum_buf(&argvars[1], buf); - if (argvars[2].v_type == VAR_UNKNOWN) - end = lnum; - else - end = get_tv_lnum_buf(&argvars[2], buf); - - get_buffer_lines(buf, lnum, end, TRUE, rettv); -} - -/* - * "getbufvar()" function - */ - static void -f_getbufvar(typval_T *argvars, typval_T *rettv) -{ - buf_T *buf; - buf_T *save_curbuf; - char_u *varname; - dictitem_T *v; - int done = FALSE; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - varname = get_tv_string_chk(&argvars[1]); - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - if (buf != NULL && varname != NULL) - { - /* set curbuf to be our buf, temporarily */ - save_curbuf = curbuf; - curbuf = buf; - - if (*varname == '&') /* buffer-local-option */ - { - if (get_option_tv(&varname, rettv, TRUE) == OK) - done = TRUE; - } - else if (STRCMP(varname, "changedtick") == 0) - { - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = curbuf->b_changedtick; - done = TRUE; - } - else - { - /* Look up the variable. */ - /* Let getbufvar({nr}, "") return the "b:" dictionary. */ - v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, - 'b', varname, FALSE); - if (v != NULL) - { - copy_tv(&v->di_tv, rettv); - done = TRUE; - } - } - - /* restore previous notion of curbuf */ - curbuf = save_curbuf; - } - - if (!done && argvars[2].v_type != VAR_UNKNOWN) - /* use the default value */ - copy_tv(&argvars[2], rettv); - - --emsg_off; -} - -/* - * "getchar()" function - */ - static void -f_getchar(typval_T *argvars, typval_T *rettv) -{ - varnumber_T n; - int error = FALSE; - - /* Position the cursor. Needed after a message that ends in a space. */ - windgoto(msg_row, msg_col); - - ++no_mapping; - ++allow_keys; - for (;;) - { - if (argvars[0].v_type == VAR_UNKNOWN) - /* getchar(): blocking wait. */ - n = safe_vgetc(); - else if (get_tv_number_chk(&argvars[0], &error) == 1) - /* getchar(1): only check if char avail */ - n = vpeekc_any(); - else if (error || vpeekc_any() == NUL) - /* illegal argument or getchar(0) and no char avail: return zero */ - n = 0; - else - /* getchar(0) and char avail: return char */ - n = safe_vgetc(); - - if (n == K_IGNORE) - continue; - break; - } - --no_mapping; - --allow_keys; - - vimvars[VV_MOUSE_WIN].vv_nr = 0; - vimvars[VV_MOUSE_WINID].vv_nr = 0; - vimvars[VV_MOUSE_LNUM].vv_nr = 0; - vimvars[VV_MOUSE_COL].vv_nr = 0; - - rettv->vval.v_number = n; - if (IS_SPECIAL(n) || mod_mask != 0) - { - char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ - int i = 0; - - /* Turn a special key into three bytes, plus modifier. */ - if (mod_mask != 0) - { - temp[i++] = K_SPECIAL; - temp[i++] = KS_MODIFIER; - temp[i++] = mod_mask; - } - if (IS_SPECIAL(n)) - { - temp[i++] = K_SPECIAL; - temp[i++] = K_SECOND(n); - temp[i++] = K_THIRD(n); - } -#ifdef FEAT_MBYTE - else if (has_mbyte) - i += (*mb_char2bytes)(n, temp + i); -#endif - else - temp[i++] = n; - temp[i++] = NUL; - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave(temp); - -#ifdef FEAT_MOUSE - if (is_mouse_key(n)) - { - int row = mouse_row; - int col = mouse_col; - win_T *win; - linenr_T lnum; -# ifdef FEAT_WINDOWS - win_T *wp; -# endif - int winnr = 1; - - if (row >= 0 && col >= 0) - { - /* Find the window at the mouse coordinates and compute the - * text position. */ - win = mouse_find_win(&row, &col); - (void)mouse_comp_pos(win, &row, &col, &lnum); -# ifdef FEAT_WINDOWS - for (wp = firstwin; wp != win; wp = wp->w_next) - ++winnr; -# endif - vimvars[VV_MOUSE_WIN].vv_nr = winnr; - vimvars[VV_MOUSE_WINID].vv_nr = win->w_id; - vimvars[VV_MOUSE_LNUM].vv_nr = lnum; - vimvars[VV_MOUSE_COL].vv_nr = col + 1; - } - } -#endif - } -} - -/* - * "getcharmod()" function - */ - static void -f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = mod_mask; -} - -/* - * "getcharsearch()" function - */ - static void -f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (rettv_dict_alloc(rettv) != FAIL) - { - dict_T *dict = rettv->vval.v_dict; - - dict_add_nr_str(dict, "char", 0L, last_csearch()); - dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL); - dict_add_nr_str(dict, "until", last_csearch_until(), NULL); - } -} - -/* - * "getcmdline()" function - */ - static void -f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_cmdline_str(); -} - -/* - * "getcmdpos()" function - */ - static void -f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = get_cmdline_pos() + 1; -} - -/* - * "getcmdtype()" function - */ - static void -f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = alloc(2); - if (rettv->vval.v_string != NULL) - { - rettv->vval.v_string[0] = get_cmdline_type(); - rettv->vval.v_string[1] = NUL; - } -} - -/* - * "getcmdwintype()" function - */ - static void -f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_CMDWIN - rettv->vval.v_string = alloc(2); - if (rettv->vval.v_string != NULL) - { - rettv->vval.v_string[0] = cmdwin_type; - rettv->vval.v_string[1] = NUL; - } -#endif -} - -#if defined(FEAT_CMDL_COMPL) -/* - * "getcompletion()" function - */ - static void -f_getcompletion(typval_T *argvars, typval_T *rettv) -{ - char_u *pat; - expand_T xpc; - int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL - | WILD_LIST_NOTFOUND | WILD_NO_BEEP; - - if (p_wic) - options |= WILD_ICASE; - - ExpandInit(&xpc); - xpc.xp_pattern = get_tv_string(&argvars[0]); - xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); - xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1])); - if (xpc.xp_context == EXPAND_NOTHING) - { - if (argvars[1].v_type == VAR_STRING) - EMSG2(_(e_invarg2), argvars[1].vval.v_string); - else - EMSG(_(e_invarg)); - return; - } - -# if defined(FEAT_MENU) - if (xpc.xp_context == EXPAND_MENUS) - { - set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); - xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); - } -# endif - - pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); - if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) - { - int i; - - ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); - - for (i = 0; i < xpc.xp_numfiles; i++) - list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); - } - vim_free(pat); - ExpandCleanup(&xpc); -} -#endif - -/* - * "getcwd()" function - */ - static void -f_getcwd(typval_T *argvars, typval_T *rettv) -{ - win_T *wp = NULL; - char_u *cwd; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - wp = find_tabwin(&argvars[0], &argvars[1]); - if (wp != NULL) - { - if (wp->w_localdir != NULL) - rettv->vval.v_string = vim_strsave(wp->w_localdir); - else if (globaldir != NULL) - rettv->vval.v_string = vim_strsave(globaldir); - else - { - cwd = alloc(MAXPATHL); - if (cwd != NULL) - { - if (mch_dirname(cwd, MAXPATHL) != FAIL) - rettv->vval.v_string = vim_strsave(cwd); - vim_free(cwd); - } - } -#ifdef BACKSLASH_IN_FILENAME - if (rettv->vval.v_string != NULL) - slash_adjust(rettv->vval.v_string); -#endif - } -} - -/* - * "getfontname()" function - */ - static void -f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_GUI - if (gui.in_use) - { - GuiFont font; - char_u *name = NULL; - - if (argvars[0].v_type == VAR_UNKNOWN) - { - /* Get the "Normal" font. Either the name saved by - * hl_set_font_name() or from the font ID. */ - font = gui.norm_font; - name = hl_get_font_name(); - } - else - { - name = get_tv_string(&argvars[0]); - if (STRCMP(name, "*") == 0) /* don't use font dialog */ - return; - font = gui_mch_get_font(name, FALSE); - if (font == NOFONT) - return; /* Invalid font name, return empty string. */ - } - rettv->vval.v_string = gui_mch_get_fontname(font, name); - if (argvars[0].v_type != VAR_UNKNOWN) - gui_mch_free_font(font); - } -#endif -} - -/* - * "getfperm({fname})" function - */ - static void -f_getfperm(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - stat_T st; - char_u *perm = NULL; - char_u flags[] = "rwx"; - int i; - - fname = get_tv_string(&argvars[0]); - - rettv->v_type = VAR_STRING; - if (mch_stat((char *)fname, &st) >= 0) - { - perm = vim_strsave((char_u *)"---------"); - if (perm != NULL) - { - for (i = 0; i < 9; i++) - { - if (st.st_mode & (1 << (8 - i))) - perm[i] = flags[i % 3]; - } - } - } - rettv->vval.v_string = perm; -} - -/* - * "getfsize({fname})" function - */ - static void -f_getfsize(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - stat_T st; - - fname = get_tv_string(&argvars[0]); - - rettv->v_type = VAR_NUMBER; - - if (mch_stat((char *)fname, &st) >= 0) - { - if (mch_isdir(fname)) - rettv->vval.v_number = 0; - else - { - rettv->vval.v_number = (varnumber_T)st.st_size; - - /* non-perfect check for overflow */ - if ((off_T)rettv->vval.v_number != (off_T)st.st_size) - rettv->vval.v_number = -2; - } - } - else - rettv->vval.v_number = -1; -} - -/* - * "getftime({fname})" function - */ - static void -f_getftime(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - stat_T st; - - fname = get_tv_string(&argvars[0]); - - if (mch_stat((char *)fname, &st) >= 0) - rettv->vval.v_number = (varnumber_T)st.st_mtime; - else - rettv->vval.v_number = -1; -} - -/* - * "getftype({fname})" function - */ - static void -f_getftype(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - stat_T st; - char_u *type = NULL; - char *t; - - fname = get_tv_string(&argvars[0]); - - rettv->v_type = VAR_STRING; - if (mch_lstat((char *)fname, &st) >= 0) - { -#ifdef S_ISREG - if (S_ISREG(st.st_mode)) - t = "file"; - else if (S_ISDIR(st.st_mode)) - t = "dir"; -# ifdef S_ISLNK - else if (S_ISLNK(st.st_mode)) - t = "link"; -# endif -# ifdef S_ISBLK - else if (S_ISBLK(st.st_mode)) - t = "bdev"; -# endif -# ifdef S_ISCHR - else if (S_ISCHR(st.st_mode)) - t = "cdev"; -# endif -# ifdef S_ISFIFO - else if (S_ISFIFO(st.st_mode)) - t = "fifo"; -# endif -# ifdef S_ISSOCK - else if (S_ISSOCK(st.st_mode)) - t = "fifo"; -# endif - else - t = "other"; -#else -# ifdef S_IFMT - switch (st.st_mode & S_IFMT) - { - case S_IFREG: t = "file"; break; - case S_IFDIR: t = "dir"; break; -# ifdef S_IFLNK - case S_IFLNK: t = "link"; break; -# endif -# ifdef S_IFBLK - case S_IFBLK: t = "bdev"; break; -# endif -# ifdef S_IFCHR - case S_IFCHR: t = "cdev"; break; -# endif -# ifdef S_IFIFO - case S_IFIFO: t = "fifo"; break; -# endif -# ifdef S_IFSOCK - case S_IFSOCK: t = "socket"; break; -# endif - default: t = "other"; - } -# else - if (mch_isdir(fname)) - t = "dir"; - else - t = "file"; -# endif -#endif - type = vim_strsave((char_u *)t); - } - rettv->vval.v_string = type; -} - -/* - * "getline(lnum, [end])" function - */ - static void -f_getline(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - linenr_T end; - int retlist; - - lnum = get_tv_lnum(argvars); - if (argvars[1].v_type == VAR_UNKNOWN) - { - end = 0; - retlist = FALSE; - } - else - { - end = get_tv_lnum(&argvars[1]); - retlist = TRUE; - } - - get_buffer_lines(curbuf, lnum, end, retlist, rettv); -} - -/* - * "getmatches()" function - */ - static void -f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - dict_T *dict; - matchitem_T *cur = curwin->w_match_head; - int i; - - if (rettv_list_alloc(rettv) == OK) - { - while (cur != NULL) - { - dict = dict_alloc(); - if (dict == NULL) - return; - if (cur->match.regprog == NULL) - { - /* match added with matchaddpos() */ - for (i = 0; i < MAXPOSMATCH; ++i) - { - llpos_T *llpos; - char buf[6]; - list_T *l; - - llpos = &cur->pos.pos[i]; - if (llpos->lnum == 0) - break; - l = list_alloc(); - if (l == NULL) - break; - list_append_number(l, (varnumber_T)llpos->lnum); - if (llpos->col > 0) - { - list_append_number(l, (varnumber_T)llpos->col); - list_append_number(l, (varnumber_T)llpos->len); - } - sprintf(buf, "pos%d", i + 1); - dict_add_list(dict, buf, l); - } - } - else - { - dict_add_nr_str(dict, "pattern", 0L, cur->pattern); - } - dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); - dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); - dict_add_nr_str(dict, "id", (long)cur->id, NULL); -# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE) - if (cur->conceal_char) - { - char_u buf[MB_MAXBYTES + 1]; - - buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; - dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); - } -# endif - list_append_dict(rettv->vval.v_list, dict); - cur = cur->next; - } - } -#endif -} - -/* - * "getpid()" function - */ - static void -f_getpid(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = mch_get_pid(); -} - - static void -getpos_both( - typval_T *argvars, - typval_T *rettv, - int getcurpos) -{ - pos_T *fp; - list_T *l; - int fnum = -1; - - if (rettv_list_alloc(rettv) == OK) - { - l = rettv->vval.v_list; - if (getcurpos) - fp = &curwin->w_cursor; - else - fp = var2fpos(&argvars[0], TRUE, &fnum); - if (fnum != -1) - list_append_number(l, (varnumber_T)fnum); - else - list_append_number(l, (varnumber_T)0); - list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum - : (varnumber_T)0); - list_append_number(l, (fp != NULL) - ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) - : (varnumber_T)0); - list_append_number(l, -#ifdef FEAT_VIRTUALEDIT - (fp != NULL) ? (varnumber_T)fp->coladd : -#endif - (varnumber_T)0); - if (getcurpos) - { - update_curswant(); - list_append_number(l, curwin->w_curswant == MAXCOL ? - (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); - } - } - else - rettv->vval.v_number = FALSE; -} - - -/* - * "getcurpos()" function - */ - static void -f_getcurpos(typval_T *argvars, typval_T *rettv) -{ - getpos_both(argvars, rettv, TRUE); -} - -/* - * "getpos(string)" function - */ - static void -f_getpos(typval_T *argvars, typval_T *rettv) -{ - getpos_both(argvars, rettv, FALSE); -} - -/* - * "getqflist()" and "getloclist()" functions - */ - static void -f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_QUICKFIX - win_T *wp; -#endif - -#ifdef FEAT_QUICKFIX - if (rettv_list_alloc(rettv) == OK) - { - wp = NULL; - if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */ - { - wp = find_win_by_nr(&argvars[0], NULL); - if (wp == NULL) - return; - } - - (void)get_errorlist(wp, rettv->vval.v_list); - } -#endif -} - -/* - * "getreg()" function - */ - static void -f_getreg(typval_T *argvars, typval_T *rettv) -{ - char_u *strregname; - int regname; - int arg2 = FALSE; - int return_list = FALSE; - int error = FALSE; - - if (argvars[0].v_type != VAR_UNKNOWN) - { - strregname = get_tv_string_chk(&argvars[0]); - error = strregname == NULL; - if (argvars[1].v_type != VAR_UNKNOWN) - { - arg2 = (int)get_tv_number_chk(&argvars[1], &error); - if (!error && argvars[2].v_type != VAR_UNKNOWN) - return_list = (int)get_tv_number_chk(&argvars[2], &error); - } - } - else - strregname = vimvars[VV_REG].vv_str; - - if (error) - return; - - regname = (strregname == NULL ? '"' : *strregname); - if (regname == 0) - regname = '"'; - - if (return_list) - { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = (list_T *)get_reg_contents(regname, - (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); - if (rettv->vval.v_list == NULL) - (void)rettv_list_alloc(rettv); - else - ++rettv->vval.v_list->lv_refcount; - } - else - { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_reg_contents(regname, - arg2 ? GREG_EXPR_SRC : 0); - } -} - -/* - * "getregtype()" function - */ - static void -f_getregtype(typval_T *argvars, typval_T *rettv) -{ - char_u *strregname; - int regname; - char_u buf[NUMBUFLEN + 2]; - long reglen = 0; - - if (argvars[0].v_type != VAR_UNKNOWN) - { - strregname = get_tv_string_chk(&argvars[0]); - if (strregname == NULL) /* type error; errmsg already given */ - { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - return; - } - } - else - /* Default to v:register */ - strregname = vimvars[VV_REG].vv_str; - - regname = (strregname == NULL ? '"' : *strregname); - if (regname == 0) - regname = '"'; - - buf[0] = NUL; - buf[1] = NUL; - switch (get_reg_type(regname, ®len)) - { - case MLINE: buf[0] = 'V'; break; - case MCHAR: buf[0] = 'v'; break; - case MBLOCK: - buf[0] = Ctrl_V; - sprintf((char *)buf + 1, "%ld", reglen + 1); - break; - } - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave(buf); -} - -/* - * "gettabvar()" function - */ - static void -f_gettabvar(typval_T *argvars, typval_T *rettv) -{ - win_T *oldcurwin; - tabpage_T *tp, *oldtabpage; - dictitem_T *v; - char_u *varname; - int done = FALSE; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - varname = get_tv_string_chk(&argvars[1]); - tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); - if (tp != NULL && varname != NULL) - { - /* Set tp to be our tabpage, temporarily. Also set the window to the - * first window in the tabpage, otherwise the window is not valid. */ - if (switch_win(&oldcurwin, &oldtabpage, - tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) - == OK) - { - /* look up the variable */ - /* Let gettabvar({nr}, "") return the "t:" dictionary. */ - v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); - if (v != NULL) - { - copy_tv(&v->di_tv, rettv); - done = TRUE; - } - } - - /* restore previous notion of curwin */ - restore_win(oldcurwin, oldtabpage, TRUE); - } - - if (!done && argvars[2].v_type != VAR_UNKNOWN) - copy_tv(&argvars[2], rettv); -} - -/* - * "gettabwinvar()" function - */ - static void -f_gettabwinvar(typval_T *argvars, typval_T *rettv) -{ - getwinvar(argvars, rettv, 1); -} - -/* - * "getwinposx()" function - */ - static void -f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = -1; -#ifdef FEAT_GUI - if (gui.in_use) - { - int x, y; - - if (gui_mch_get_winpos(&x, &y) == OK) - rettv->vval.v_number = x; - } -#endif -} - -/* - * "win_findbuf()" function - */ - static void -f_win_findbuf(typval_T *argvars, typval_T *rettv) -{ - if (rettv_list_alloc(rettv) != FAIL) - win_findbuf(argvars, rettv->vval.v_list); -} - -/* - * "win_getid()" function - */ - static void -f_win_getid(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = win_getid(argvars); -} - -/* - * "win_gotoid()" function - */ - static void -f_win_gotoid(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = win_gotoid(argvars); -} - -/* - * "win_id2tabwin()" function - */ - static void -f_win_id2tabwin(typval_T *argvars, typval_T *rettv) -{ - if (rettv_list_alloc(rettv) != FAIL) - win_id2tabwin(argvars, rettv->vval.v_list); -} - -/* - * "win_id2win()" function - */ - static void -f_win_id2win(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = win_id2win(argvars); -} - -/* - * "getwinposy()" function - */ - static void -f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = -1; -#ifdef FEAT_GUI - if (gui.in_use) - { - int x, y; - - if (gui_mch_get_winpos(&x, &y) == OK) - rettv->vval.v_number = y; - } -#endif -} - -/* - * Find window specified by "vp" in tabpage "tp". - */ - static win_T * -find_win_by_nr( - typval_T *vp, - tabpage_T *tp UNUSED) /* NULL for current tab page */ -{ -#ifdef FEAT_WINDOWS - win_T *wp; -#endif - int nr; - - nr = (int)get_tv_number_chk(vp, NULL); - -#ifdef FEAT_WINDOWS - if (nr < 0) - return NULL; - if (nr == 0) - return curwin; - - for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin; - wp != NULL; wp = wp->w_next) - if (nr >= LOWEST_WIN_ID) - { - if (wp->w_id == nr) - return wp; - } - else if (--nr <= 0) - break; - if (nr >= LOWEST_WIN_ID) - return NULL; - return wp; -#else - if (nr == 0 || nr == 1 || nr == curwin->w_id) - return curwin; - return NULL; -#endif -} - -/* - * Find window specified by "wvp" in tabpage "tvp". - */ - static win_T * -find_tabwin( - typval_T *wvp, /* VAR_UNKNOWN for current window */ - typval_T *tvp) /* VAR_UNKNOWN for current tab page */ -{ - win_T *wp = NULL; - tabpage_T *tp = NULL; - long n; - - if (wvp->v_type != VAR_UNKNOWN) - { - if (tvp->v_type != VAR_UNKNOWN) - { - n = (long)get_tv_number(tvp); - if (n >= 0) - tp = find_tabpage(n); - } - else - tp = curtab; - - if (tp != NULL) - wp = find_win_by_nr(wvp, tp); - } - else - wp = curwin; - - return wp; -} - -/* - * "getwinvar()" function - */ - static void -f_getwinvar(typval_T *argvars, typval_T *rettv) -{ - getwinvar(argvars, rettv, 0); -} - -/* - * getwinvar() and gettabwinvar() - */ - static void -getwinvar( - typval_T *argvars, - typval_T *rettv, - int off) /* 1 for gettabwinvar() */ -{ - win_T *win; - char_u *varname; - dictitem_T *v; - tabpage_T *tp = NULL; - int done = FALSE; -#ifdef FEAT_WINDOWS - win_T *oldcurwin; - tabpage_T *oldtabpage; - int need_switch_win; -#endif - -#ifdef FEAT_WINDOWS - if (off == 1) - tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); - else - tp = curtab; -#endif - win = find_win_by_nr(&argvars[off], tp); - varname = get_tv_string_chk(&argvars[off + 1]); - ++emsg_off; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - if (win != NULL && varname != NULL) - { -#ifdef FEAT_WINDOWS - /* Set curwin to be our win, temporarily. Also set the tabpage, - * otherwise the window is not valid. Only do this when needed, - * autocommands get blocked. */ - need_switch_win = !(tp == curtab && win == curwin); - if (!need_switch_win - || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) -#endif - { - if (*varname == '&') /* window-local-option */ - { - if (get_option_tv(&varname, rettv, 1) == OK) - done = TRUE; - } - else - { - /* Look up the variable. */ - /* Let getwinvar({nr}, "") return the "w:" dictionary. */ - v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', - varname, FALSE); - if (v != NULL) - { - copy_tv(&v->di_tv, rettv); - done = TRUE; - } - } - } - -#ifdef FEAT_WINDOWS - if (need_switch_win) - /* restore previous notion of curwin */ - restore_win(oldcurwin, oldtabpage, TRUE); -#endif - } - - if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) - /* use the default return value */ - copy_tv(&argvars[off + 2], rettv); - - --emsg_off; -} - -/* - * "glob()" function - */ - static void -f_glob(typval_T *argvars, typval_T *rettv) -{ - int options = WILD_SILENT|WILD_USE_NL; - expand_T xpc; - int error = FALSE; - - /* When the optional second argument is non-zero, don't remove matches - * for 'wildignore' and don't put matches for 'suffixes' at the end. */ - rettv->v_type = VAR_STRING; - if (argvars[1].v_type != VAR_UNKNOWN) - { - if (get_tv_number_chk(&argvars[1], &error)) - options |= WILD_KEEP_ALL; - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (get_tv_number_chk(&argvars[2], &error)) - { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; - } - if (argvars[3].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[3], &error)) - options |= WILD_ALLLINKS; - } - } - if (!error) - { - ExpandInit(&xpc); - xpc.xp_context = EXPAND_FILES; - if (p_wic) - options += WILD_ICASE; - if (rettv->v_type == VAR_STRING) - rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]), - NULL, options, WILD_ALL); - else if (rettv_list_alloc(rettv) != FAIL) - { - int i; - - ExpandOne(&xpc, get_tv_string(&argvars[0]), - NULL, options, WILD_ALL_KEEP); - for (i = 0; i < xpc.xp_numfiles; i++) - list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); - - ExpandCleanup(&xpc); - } - } - else - rettv->vval.v_string = NULL; -} - -/* - * "globpath()" function - */ - static void -f_globpath(typval_T *argvars, typval_T *rettv) -{ - int flags = 0; - char_u buf1[NUMBUFLEN]; - char_u *file = get_tv_string_buf_chk(&argvars[1], buf1); - int error = FALSE; - garray_T ga; - int i; - - /* When the optional second argument is non-zero, don't remove matches - * for 'wildignore' and don't put matches for 'suffixes' at the end. */ - rettv->v_type = VAR_STRING; - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (get_tv_number_chk(&argvars[2], &error)) - flags |= WILD_KEEP_ALL; - if (argvars[3].v_type != VAR_UNKNOWN) - { - if (get_tv_number_chk(&argvars[3], &error)) - { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; - } - if (argvars[4].v_type != VAR_UNKNOWN - && get_tv_number_chk(&argvars[4], &error)) - flags |= WILD_ALLLINKS; - } - } - if (file != NULL && !error) - { - ga_init2(&ga, (int)sizeof(char_u *), 10); - globpath(get_tv_string(&argvars[0]), file, &ga, flags); - if (rettv->v_type == VAR_STRING) - rettv->vval.v_string = ga_concat_strings(&ga, "\n"); - else if (rettv_list_alloc(rettv) != FAIL) - for (i = 0; i < ga.ga_len; ++i) - list_append_string(rettv->vval.v_list, - ((char_u **)(ga.ga_data))[i], -1); - ga_clear_strings(&ga); - } - else - rettv->vval.v_string = NULL; -} - -/* - * "glob2regpat()" function - */ - static void -f_glob2regpat(typval_T *argvars, typval_T *rettv) -{ - char_u *pat = get_tv_string_chk(&argvars[0]); - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = (pat == NULL) - ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); -} - -/* - * "has()" function - */ - static void -f_has(typval_T *argvars, typval_T *rettv) -{ - int i; - char_u *name; - int n = FALSE; - static char *(has_list[]) = - { -#ifdef AMIGA - "amiga", -# ifdef FEAT_ARP - "arp", -# endif -#endif -#ifdef __BEOS__ - "beos", -#endif -#ifdef MACOS - "mac", -#endif -#if defined(MACOS_X_UNIX) - "macunix", /* built with 'darwin' enabled */ -#endif -#if defined(__APPLE__) && __APPLE__ == 1 - "osx", /* built with or without 'darwin' enabled */ -#endif -#ifdef __QNX__ - "qnx", -#endif -#ifdef UNIX - "unix", -#endif -#ifdef VMS - "vms", -#endif -#ifdef WIN32 - "win32", -#endif -#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) - "win32unix", -#endif -#if defined(WIN64) || defined(_WIN64) - "win64", -#endif -#ifdef EBCDIC - "ebcdic", -#endif -#ifndef CASE_INSENSITIVE_FILENAME - "fname_case", -#endif -#ifdef HAVE_ACL - "acl", -#endif -#ifdef FEAT_ARABIC - "arabic", -#endif -#ifdef FEAT_AUTOCMD - "autocmd", -#endif -#ifdef FEAT_BEVAL - "balloon_eval", -# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */ - "balloon_multiline", -# endif -#endif -#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) - "builtin_terms", -# ifdef ALL_BUILTIN_TCAPS - "all_builtin_terms", -# endif -#endif -#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ - || defined(FEAT_GUI_W32) \ - || defined(FEAT_GUI_MOTIF)) - "browsefilter", -#endif -#ifdef FEAT_BYTEOFF - "byte_offset", -#endif -#ifdef FEAT_JOB_CHANNEL - "channel", -#endif -#ifdef FEAT_CINDENT - "cindent", -#endif -#ifdef FEAT_CLIENTSERVER - "clientserver", -#endif -#ifdef FEAT_CLIPBOARD - "clipboard", -#endif -#ifdef FEAT_CMDL_COMPL - "cmdline_compl", -#endif -#ifdef FEAT_CMDHIST - "cmdline_hist", -#endif -#ifdef FEAT_COMMENTS - "comments", -#endif -#ifdef FEAT_CONCEAL - "conceal", -#endif -#ifdef FEAT_CRYPT - "cryptv", - "crypt-blowfish", - "crypt-blowfish2", -#endif -#ifdef FEAT_CSCOPE - "cscope", -#endif -#ifdef FEAT_CURSORBIND - "cursorbind", -#endif -#ifdef CURSOR_SHAPE - "cursorshape", -#endif -#ifdef DEBUG - "debug", -#endif -#ifdef FEAT_CON_DIALOG - "dialog_con", -#endif -#ifdef FEAT_GUI_DIALOG - "dialog_gui", -#endif -#ifdef FEAT_DIFF - "diff", -#endif -#ifdef FEAT_DIGRAPHS - "digraphs", -#endif -#ifdef FEAT_DIRECTX - "directx", -#endif -#ifdef FEAT_DND - "dnd", -#endif -#ifdef FEAT_EMACS_TAGS - "emacs_tags", -#endif - "eval", /* always present, of course! */ - "ex_extra", /* graduated feature */ -#ifdef FEAT_SEARCH_EXTRA - "extra_search", -#endif -#ifdef FEAT_FKMAP - "farsi", -#endif -#ifdef FEAT_SEARCHPATH - "file_in_path", -#endif -#ifdef FEAT_FILTERPIPE - "filterpipe", -#endif -#ifdef FEAT_FIND_ID - "find_in_path", -#endif -#ifdef FEAT_FLOAT - "float", -#endif -#ifdef FEAT_FOLDING - "folding", -#endif -#ifdef FEAT_FOOTER - "footer", -#endif -#if !defined(USE_SYSTEM) && defined(UNIX) - "fork", -#endif -#ifdef FEAT_GETTEXT - "gettext", -#endif -#ifdef FEAT_GUI - "gui", -#endif -#ifdef FEAT_GUI_ATHENA -# ifdef FEAT_GUI_NEXTAW - "gui_neXtaw", -# else - "gui_athena", -# endif -#endif -#ifdef FEAT_GUI_GTK - "gui_gtk", -# ifdef USE_GTK3 - "gui_gtk3", -# else - "gui_gtk2", -# endif -#endif -#ifdef FEAT_GUI_GNOME - "gui_gnome", -#endif -#ifdef FEAT_GUI_MAC - "gui_mac", -#endif -#ifdef FEAT_GUI_MOTIF - "gui_motif", -#endif -#ifdef FEAT_GUI_PHOTON - "gui_photon", -#endif -#ifdef FEAT_GUI_W32 - "gui_win32", -#endif -#ifdef FEAT_HANGULIN - "hangul_input", -#endif -#if defined(HAVE_ICONV_H) && defined(USE_ICONV) - "iconv", -#endif -#ifdef FEAT_INS_EXPAND - "insert_expand", -#endif -#ifdef FEAT_JOB_CHANNEL - "job", -#endif -#ifdef FEAT_JUMPLIST - "jumplist", -#endif -#ifdef FEAT_KEYMAP - "keymap", -#endif -#ifdef FEAT_LANGMAP - "langmap", -#endif -#ifdef FEAT_LIBCALL - "libcall", -#endif -#ifdef FEAT_LINEBREAK - "linebreak", -#endif -#ifdef FEAT_LISP - "lispindent", -#endif -#ifdef FEAT_LISTCMDS - "listcmds", -#endif -#ifdef FEAT_LOCALMAP - "localmap", -#endif -#ifdef FEAT_LUA -# ifndef DYNAMIC_LUA - "lua", -# endif -#endif -#ifdef FEAT_MENU - "menu", -#endif -#ifdef FEAT_SESSION - "mksession", -#endif -#ifdef FEAT_MODIFY_FNAME - "modify_fname", -#endif -#ifdef FEAT_MOUSE - "mouse", -#endif -#ifdef FEAT_MOUSESHAPE - "mouseshape", -#endif -#if defined(UNIX) || defined(VMS) -# ifdef FEAT_MOUSE_DEC - "mouse_dec", -# endif -# ifdef FEAT_MOUSE_GPM - "mouse_gpm", -# endif -# ifdef FEAT_MOUSE_JSB - "mouse_jsbterm", -# endif -# ifdef FEAT_MOUSE_NET - "mouse_netterm", -# endif -# ifdef FEAT_MOUSE_PTERM - "mouse_pterm", -# endif -# ifdef FEAT_MOUSE_SGR - "mouse_sgr", -# endif -# ifdef FEAT_SYSMOUSE - "mouse_sysmouse", -# endif -# ifdef FEAT_MOUSE_URXVT - "mouse_urxvt", -# endif -# ifdef FEAT_MOUSE_XTERM - "mouse_xterm", -# endif -#endif -#ifdef FEAT_MBYTE - "multi_byte", -#endif -#ifdef FEAT_MBYTE_IME - "multi_byte_ime", -#endif -#ifdef FEAT_MULTI_LANG - "multi_lang", -#endif -#ifdef FEAT_MZSCHEME -#ifndef DYNAMIC_MZSCHEME - "mzscheme", -#endif -#endif -#ifdef FEAT_NUM64 - "num64", -#endif -#ifdef FEAT_OLE - "ole", -#endif - "packages", -#ifdef FEAT_PATH_EXTRA - "path_extra", -#endif -#ifdef FEAT_PERL -#ifndef DYNAMIC_PERL - "perl", -#endif -#endif -#ifdef FEAT_PERSISTENT_UNDO - "persistent_undo", -#endif -#ifdef FEAT_PYTHON -#ifndef DYNAMIC_PYTHON - "python", -#endif -#endif -#ifdef FEAT_PYTHON3 -#ifndef DYNAMIC_PYTHON3 - "python3", -#endif -#endif -#ifdef FEAT_POSTSCRIPT - "postscript", -#endif -#ifdef FEAT_PRINTER - "printer", -#endif -#ifdef FEAT_PROFILE - "profile", -#endif -#ifdef FEAT_RELTIME - "reltime", -#endif -#ifdef FEAT_QUICKFIX - "quickfix", -#endif -#ifdef FEAT_RIGHTLEFT - "rightleft", -#endif -#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) - "ruby", -#endif -#ifdef FEAT_SCROLLBIND - "scrollbind", -#endif -#ifdef FEAT_CMDL_INFO - "showcmd", - "cmdline_info", -#endif -#ifdef FEAT_SIGNS - "signs", -#endif -#ifdef FEAT_SMARTINDENT - "smartindent", -#endif -#ifdef STARTUPTIME - "startuptime", -#endif -#ifdef FEAT_STL_OPT - "statusline", -#endif -#ifdef FEAT_SUN_WORKSHOP - "sun_workshop", -#endif -#ifdef FEAT_NETBEANS_INTG - "netbeans_intg", -#endif -#ifdef FEAT_SPELL - "spell", -#endif -#ifdef FEAT_SYN_HL - "syntax", -#endif -#if defined(USE_SYSTEM) || !defined(UNIX) - "system", -#endif -#ifdef FEAT_TAG_BINS - "tag_binary", -#endif -#ifdef FEAT_TAG_OLDSTATIC - "tag_old_static", -#endif -#ifdef FEAT_TAG_ANYWHITE - "tag_any_white", -#endif -#ifdef FEAT_TCL -# ifndef DYNAMIC_TCL - "tcl", -# endif -#endif -#ifdef FEAT_TERMGUICOLORS - "termguicolors", -#endif -#ifdef TERMINFO - "terminfo", -#endif -#ifdef FEAT_TERMRESPONSE - "termresponse", -#endif -#ifdef FEAT_TEXTOBJ - "textobjects", -#endif -#ifdef HAVE_TGETENT - "tgetent", -#endif -#ifdef FEAT_TIMERS - "timers", -#endif -#ifdef FEAT_TITLE - "title", -#endif -#ifdef FEAT_TOOLBAR - "toolbar", -#endif -#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) - "unnamedplus", -#endif -#ifdef FEAT_USR_CMDS - "user-commands", /* was accidentally included in 5.4 */ - "user_commands", -#endif -#ifdef FEAT_VIMINFO - "viminfo", -#endif -#ifdef FEAT_WINDOWS - "vertsplit", -#endif -#ifdef FEAT_VIRTUALEDIT - "virtualedit", -#endif - "visual", -#ifdef FEAT_VISUALEXTRA - "visualextra", -#endif -#ifdef FEAT_VREPLACE - "vreplace", -#endif -#ifdef FEAT_WILDIGN - "wildignore", -#endif -#ifdef FEAT_WILDMENU - "wildmenu", -#endif -#ifdef FEAT_WINDOWS - "windows", -#endif -#ifdef FEAT_WAK - "winaltkeys", -#endif -#ifdef FEAT_WRITEBACKUP - "writebackup", -#endif -#ifdef FEAT_XIM - "xim", -#endif -#ifdef FEAT_XFONTSET - "xfontset", -#endif -#ifdef FEAT_XPM_W32 - "xpm", - "xpm_w32", /* for backward compatibility */ -#else -# if defined(HAVE_XPM) - "xpm", -# endif -#endif -#ifdef USE_XSMP - "xsmp", -#endif -#ifdef USE_XSMP_INTERACT - "xsmp_interact", -#endif -#ifdef FEAT_XCLIPBOARD - "xterm_clipboard", -#endif -#ifdef FEAT_XTERM_SAVE - "xterm_save", -#endif -#if defined(UNIX) && defined(FEAT_X11) - "X11", -#endif - NULL - }; - - name = get_tv_string(&argvars[0]); - for (i = 0; has_list[i] != NULL; ++i) - if (STRICMP(name, has_list[i]) == 0) - { - n = TRUE; - break; - } - - if (n == FALSE) - { - if (STRNICMP(name, "patch", 5) == 0) - { - if (name[5] == '-' - && STRLEN(name) >= 11 - && vim_isdigit(name[6]) - && vim_isdigit(name[8]) - && vim_isdigit(name[10])) - { - int major = atoi((char *)name + 6); - int minor = atoi((char *)name + 8); - - /* Expect "patch-9.9.01234". */ - n = (major < VIM_VERSION_MAJOR - || (major == VIM_VERSION_MAJOR - && (minor < VIM_VERSION_MINOR - || (minor == VIM_VERSION_MINOR - && has_patch(atoi((char *)name + 10)))))); - } - else - n = has_patch(atoi((char *)name + 5)); - } - else if (STRICMP(name, "vim_starting") == 0) - n = (starting != 0); -#ifdef FEAT_MBYTE - else if (STRICMP(name, "multi_byte_encoding") == 0) - n = has_mbyte; -#endif -#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32) - else if (STRICMP(name, "balloon_multiline") == 0) - n = multiline_balloon_available(); -#endif -#ifdef DYNAMIC_TCL - else if (STRICMP(name, "tcl") == 0) - n = tcl_enabled(FALSE); -#endif -#if defined(USE_ICONV) && defined(DYNAMIC_ICONV) - else if (STRICMP(name, "iconv") == 0) - n = iconv_enabled(FALSE); -#endif -#ifdef DYNAMIC_LUA - else if (STRICMP(name, "lua") == 0) - n = lua_enabled(FALSE); -#endif -#ifdef DYNAMIC_MZSCHEME - else if (STRICMP(name, "mzscheme") == 0) - n = mzscheme_enabled(FALSE); -#endif -#ifdef DYNAMIC_RUBY - else if (STRICMP(name, "ruby") == 0) - n = ruby_enabled(FALSE); -#endif -#ifdef FEAT_PYTHON -#ifdef DYNAMIC_PYTHON - else if (STRICMP(name, "python") == 0) - n = python_enabled(FALSE); -#endif -#endif -#ifdef FEAT_PYTHON3 -#ifdef DYNAMIC_PYTHON3 - else if (STRICMP(name, "python3") == 0) - n = python3_enabled(FALSE); -#endif -#endif -#ifdef DYNAMIC_PERL - else if (STRICMP(name, "perl") == 0) - n = perl_enabled(FALSE); -#endif -#ifdef FEAT_GUI - else if (STRICMP(name, "gui_running") == 0) - n = (gui.in_use || gui.starting); -# ifdef FEAT_GUI_W32 - else if (STRICMP(name, "gui_win32s") == 0) - n = gui_is_win32s(); -# endif -# ifdef FEAT_BROWSE - else if (STRICMP(name, "browse") == 0) - n = gui.in_use; /* gui_mch_browse() works when GUI is running */ -# endif -#endif -#ifdef FEAT_SYN_HL - else if (STRICMP(name, "syntax_items") == 0) - n = syntax_present(curwin); -#endif -#if defined(WIN3264) - else if (STRICMP(name, "win95") == 0) - n = mch_windows95(); -#endif -#ifdef FEAT_NETBEANS_INTG - else if (STRICMP(name, "netbeans_enabled") == 0) - n = netbeans_active(); -#endif - } - - rettv->vval.v_number = n; -} - -/* - * "has_key()" function - */ - static void -f_has_key(typval_T *argvars, typval_T *rettv) -{ - if (argvars[0].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - if (argvars[0].vval.v_dict == NULL) - return; - - rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, - get_tv_string(&argvars[1]), -1) != NULL; -} - -/* - * "haslocaldir()" function - */ - static void -f_haslocaldir(typval_T *argvars, typval_T *rettv) -{ - win_T *wp = NULL; - - wp = find_tabwin(&argvars[0], &argvars[1]); - rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL); -} - -/* - * "hasmapto()" function - */ - static void -f_hasmapto(typval_T *argvars, typval_T *rettv) -{ - char_u *name; - char_u *mode; - char_u buf[NUMBUFLEN]; - int abbr = FALSE; - - name = get_tv_string(&argvars[0]); - if (argvars[1].v_type == VAR_UNKNOWN) - mode = (char_u *)"nvo"; - else - { - mode = get_tv_string_buf(&argvars[1], buf); - if (argvars[2].v_type != VAR_UNKNOWN) - abbr = (int)get_tv_number(&argvars[2]); - } - - if (map_to_exists(name, mode, abbr)) - rettv->vval.v_number = TRUE; - else - rettv->vval.v_number = FALSE; -} - -/* - * "histadd()" function - */ - static void -f_histadd(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_CMDHIST - int histype; - char_u *str; - char_u buf[NUMBUFLEN]; -#endif - - rettv->vval.v_number = FALSE; - if (check_restricted() || check_secure()) - return; -#ifdef FEAT_CMDHIST - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - histype = str != NULL ? get_histtype(str) : -1; - if (histype >= 0) - { - str = get_tv_string_buf(&argvars[1], buf); - if (*str != NUL) - { - init_history(); - add_to_history(histype, str, FALSE, NUL); - rettv->vval.v_number = TRUE; - return; - } - } -#endif -} - -/* - * "histdel()" function - */ - static void -f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_CMDHIST - int n; - char_u buf[NUMBUFLEN]; - char_u *str; - - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - if (str == NULL) - n = 0; - else if (argvars[1].v_type == VAR_UNKNOWN) - /* only one argument: clear entire history */ - n = clr_history(get_histtype(str)); - else if (argvars[1].v_type == VAR_NUMBER) - /* index given: remove that entry */ - n = del_history_idx(get_histtype(str), - (int)get_tv_number(&argvars[1])); - else - /* string given: remove all matching entries */ - n = del_history_entry(get_histtype(str), - get_tv_string_buf(&argvars[1], buf)); - rettv->vval.v_number = n; -#endif -} - -/* - * "histget()" function - */ - static void -f_histget(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_CMDHIST - int type; - int idx; - char_u *str; - - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - if (str == NULL) - rettv->vval.v_string = NULL; - else - { - type = get_histtype(str); - if (argvars[1].v_type == VAR_UNKNOWN) - idx = get_history_idx(type); - else - idx = (int)get_tv_number_chk(&argvars[1], NULL); - /* -1 on type error */ - rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); - } -#else - rettv->vval.v_string = NULL; -#endif - rettv->v_type = VAR_STRING; -} - -/* - * "histnr()" function - */ - static void -f_histnr(typval_T *argvars UNUSED, typval_T *rettv) -{ - int i; - -#ifdef FEAT_CMDHIST - char_u *history = get_tv_string_chk(&argvars[0]); - - i = history == NULL ? HIST_CMD - 1 : get_histtype(history); - if (i >= HIST_CMD && i < HIST_COUNT) - i = get_history_idx(i); - else -#endif - i = -1; - rettv->vval.v_number = i; -} - -/* - * "highlightID(name)" function - */ - static void -f_hlID(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0])); -} - -/* - * "highlight_exists()" function - */ - static void -f_hlexists(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0])); -} - -/* - * "hostname()" function - */ - static void -f_hostname(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u hostname[256]; - - mch_get_host_name(hostname, 256); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave(hostname); -} - -/* - * iconv() function - */ - static void -f_iconv(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_MBYTE - char_u buf1[NUMBUFLEN]; - char_u buf2[NUMBUFLEN]; - char_u *from, *to, *str; - vimconv_T vimconv; -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - -#ifdef FEAT_MBYTE - str = get_tv_string(&argvars[0]); - from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1))); - to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2))); - vimconv.vc_type = CONV_NONE; - convert_setup(&vimconv, from, to); - - /* If the encodings are equal, no conversion needed. */ - if (vimconv.vc_type == CONV_NONE) - rettv->vval.v_string = vim_strsave(str); - else - rettv->vval.v_string = string_convert(&vimconv, str, NULL); - - convert_setup(&vimconv, NULL, NULL); - vim_free(from); - vim_free(to); -#endif -} - -/* - * "indent()" function - */ - static void -f_indent(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - - lnum = get_tv_lnum(argvars); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) - rettv->vval.v_number = get_indent_lnum(lnum); - else - rettv->vval.v_number = -1; -} - -/* - * "index()" function - */ - static void -f_index(typval_T *argvars, typval_T *rettv) -{ - list_T *l; - listitem_T *item; - long idx = 0; - int ic = FALSE; - - rettv->vval.v_number = -1; - if (argvars[0].v_type != VAR_LIST) - { - EMSG(_(e_listreq)); - return; - } - l = argvars[0].vval.v_list; - if (l != NULL) - { - item = l->lv_first; - if (argvars[2].v_type != VAR_UNKNOWN) - { - int error = FALSE; - - /* Start at specified item. Use the cached index that list_find() - * sets, so that a negative number also works. */ - item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error)); - idx = l->lv_idx; - if (argvars[3].v_type != VAR_UNKNOWN) - ic = (int)get_tv_number_chk(&argvars[3], &error); - if (error) - item = NULL; - } - - for ( ; item != NULL; item = item->li_next, ++idx) - if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) - { - rettv->vval.v_number = idx; - break; - } - } -} - -static int inputsecret_flag = 0; - -static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog); - -/* - * This function is used by f_input() and f_inputdialog() functions. The third - * argument to f_input() specifies the type of completion to use at the - * prompt. The third argument to f_inputdialog() specifies the value to return - * when the user cancels the prompt. - */ - static void -get_user_input( - typval_T *argvars, - typval_T *rettv, - int inputdialog) -{ - char_u *prompt = get_tv_string_chk(&argvars[0]); - char_u *p = NULL; - int c; - char_u buf[NUMBUFLEN]; - int cmd_silent_save = cmd_silent; - char_u *defstr = (char_u *)""; - int xp_type = EXPAND_NOTHING; - char_u *xp_arg = NULL; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - -#ifdef NO_CONSOLE_INPUT - /* While starting up, there is no place to enter text. */ - if (no_console_input()) - return; -#endif - - cmd_silent = FALSE; /* Want to see the prompt. */ - if (prompt != NULL) - { - /* Only the part of the message after the last NL is considered as - * prompt for the command line */ - p = vim_strrchr(prompt, '\n'); - if (p == NULL) - p = prompt; - else - { - ++p; - c = *p; - *p = NUL; - msg_start(); - msg_clr_eos(); - msg_puts_attr(prompt, echo_attr); - msg_didout = FALSE; - msg_starthere(); - *p = c; - } - cmdline_row = msg_row; - - if (argvars[1].v_type != VAR_UNKNOWN) - { - defstr = get_tv_string_buf_chk(&argvars[1], buf); - if (defstr != NULL) - stuffReadbuffSpec(defstr); - - if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) - { - char_u *xp_name; - int xp_namelen; - long argt; - - /* input() with a third argument: completion */ - rettv->vval.v_string = NULL; - - xp_name = get_tv_string_buf_chk(&argvars[2], buf); - if (xp_name == NULL) - return; - - xp_namelen = (int)STRLEN(xp_name); - - if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt, - &xp_arg) == FAIL) - return; - } - } - - if (defstr != NULL) - { - int save_ex_normal_busy = ex_normal_busy; - ex_normal_busy = 0; - rettv->vval.v_string = - getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr, - xp_type, xp_arg); - ex_normal_busy = save_ex_normal_busy; - } - if (inputdialog && rettv->vval.v_string == NULL - && argvars[1].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_UNKNOWN) - rettv->vval.v_string = vim_strsave(get_tv_string_buf( - &argvars[2], buf)); - - vim_free(xp_arg); - - /* since the user typed this, no need to wait for return */ - need_wait_return = FALSE; - msg_didout = FALSE; - } - cmd_silent = cmd_silent_save; -} - -/* - * "input()" function - * Also handles inputsecret() when inputsecret is set. - */ - static void -f_input(typval_T *argvars, typval_T *rettv) -{ - get_user_input(argvars, rettv, FALSE); -} - -/* - * "inputdialog()" function - */ - static void -f_inputdialog(typval_T *argvars, typval_T *rettv) -{ -#if defined(FEAT_GUI_TEXTDIALOG) - /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */ - if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) - { - char_u *message; - char_u buf[NUMBUFLEN]; - char_u *defstr = (char_u *)""; - - message = get_tv_string_chk(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN - && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL) - vim_strncpy(IObuff, defstr, IOSIZE - 1); - else - IObuff[0] = NUL; - if (message != NULL && defstr != NULL - && do_dialog(VIM_QUESTION, NULL, message, - (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) - rettv->vval.v_string = vim_strsave(IObuff); - else - { - if (message != NULL && defstr != NULL - && argvars[1].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_UNKNOWN) - rettv->vval.v_string = vim_strsave( - get_tv_string_buf(&argvars[2], buf)); - else - rettv->vval.v_string = NULL; - } - rettv->v_type = VAR_STRING; - } - else -#endif - get_user_input(argvars, rettv, TRUE); -} - -/* - * "inputlist()" function - */ - static void -f_inputlist(typval_T *argvars, typval_T *rettv) -{ - listitem_T *li; - int selected; - int mouse_used; - -#ifdef NO_CONSOLE_INPUT - /* While starting up, there is no place to enter text. */ - if (no_console_input()) - return; -#endif - if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) - { - EMSG2(_(e_listarg), "inputlist()"); - return; - } - - msg_start(); - msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ - lines_left = Rows; /* avoid more prompt */ - msg_scroll = TRUE; - msg_clr_eos(); - - for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) - { - msg_puts(get_tv_string(&li->li_tv)); - msg_putchar('\n'); - } - - /* Ask for choice. */ - selected = prompt_for_number(&mouse_used); - if (mouse_used) - selected -= lines_left; - - rettv->vval.v_number = selected; -} - - -static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; - -/* - * "inputrestore()" function - */ - static void -f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (ga_userinput.ga_len > 0) - { - --ga_userinput.ga_len; - restore_typeahead((tasave_T *)(ga_userinput.ga_data) - + ga_userinput.ga_len); - /* default return is zero == OK */ - } - else if (p_verbose > 1) - { - verb_msg((char_u *)_("called inputrestore() more often than inputsave()")); - rettv->vval.v_number = 1; /* Failed */ - } -} - -/* - * "inputsave()" function - */ - static void -f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) -{ - /* Add an entry to the stack of typeahead storage. */ - if (ga_grow(&ga_userinput, 1) == OK) - { - save_typeahead((tasave_T *)(ga_userinput.ga_data) - + ga_userinput.ga_len); - ++ga_userinput.ga_len; - /* default return is zero == OK */ - } - else - rettv->vval.v_number = 1; /* Failed */ -} - -/* - * "inputsecret()" function - */ - static void -f_inputsecret(typval_T *argvars, typval_T *rettv) -{ - ++cmdline_star; - ++inputsecret_flag; - f_input(argvars, rettv); - --cmdline_star; - --inputsecret_flag; -} - -/* - * "insert()" function - */ - static void -f_insert(typval_T *argvars, typval_T *rettv) -{ - long before = 0; - listitem_T *item; - list_T *l; - int error = FALSE; - - if (argvars[0].v_type != VAR_LIST) - EMSG2(_(e_listarg), "insert()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) - { - if (argvars[2].v_type != VAR_UNKNOWN) - before = (long)get_tv_number_chk(&argvars[2], &error); - if (error) - return; /* type error; errmsg already given */ - - if (before == l->lv_len) - item = NULL; - else - { - item = list_find(l, before); - if (item == NULL) - { - EMSGN(_(e_listidx), before); - l = NULL; - } - } - if (l != NULL) - { - list_insert_tv(l, &argvars[1], item); - copy_tv(&argvars[0], rettv); - } - } -} - -/* - * "invert(expr)" function - */ - static void -f_invert(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL); -} - -/* - * "isdirectory()" function - */ - static void -f_isdirectory(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); -} - -/* - * "islocked()" function - */ - static void -f_islocked(typval_T *argvars, typval_T *rettv) -{ - lval_T lv; - char_u *end; - dictitem_T *di; - - rettv->vval.v_number = -1; - end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE, - GLV_NO_AUTOLOAD, FNE_CHECK_START); - if (end != NULL && lv.ll_name != NULL) - { - if (*end != NUL) - EMSG(_(e_trailing)); - else - { - if (lv.ll_tv == NULL) - { - if (check_changedtick(lv.ll_name)) - rettv->vval.v_number = 1; /* always locked */ - else - { - di = find_var(lv.ll_name, NULL, TRUE); - if (di != NULL) - { - /* Consider a variable locked when: - * 1. the variable itself is locked - * 2. the value of the variable is locked. - * 3. the List or Dict value is locked. - */ - rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) - || tv_islocked(&di->di_tv)); - } - } - } - else if (lv.ll_range) - EMSG(_("E786: Range not allowed")); - else if (lv.ll_newkey != NULL) - EMSG2(_(e_dictkey), lv.ll_newkey); - else if (lv.ll_list != NULL) - /* List item. */ - rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); - else - /* Dictionary item. */ - rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); - } - } - - clear_lval(&lv); -} - -#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) -/* - * "isnan()" function - */ - static void -f_isnan(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT - && isnan(argvars[0].vval.v_float); -} -#endif - -/* - * "items(dict)" function - */ - static void -f_items(typval_T *argvars, typval_T *rettv) -{ - dict_list(argvars, rettv, 2); -} - -#if defined(FEAT_JOB_CHANNEL) || defined(PROTO) -/* - * Get the job from the argument. - * Returns NULL if the job is invalid. - */ - static job_T * -get_job_arg(typval_T *tv) -{ - job_T *job; - - if (tv->v_type != VAR_JOB) - { - EMSG2(_(e_invarg2), get_tv_string(tv)); - return NULL; - } - job = tv->vval.v_job; - - if (job == NULL) - EMSG(_("E916: not a valid job")); - return job; -} - -/* - * "job_getchannel()" function - */ - static void -f_job_getchannel(typval_T *argvars, typval_T *rettv) -{ - job_T *job = get_job_arg(&argvars[0]); - - if (job != NULL) - { - rettv->v_type = VAR_CHANNEL; - rettv->vval.v_channel = job->jv_channel; - if (job->jv_channel != NULL) - ++job->jv_channel->ch_refcount; - } -} - -/* - * "job_info()" function - */ - static void -f_job_info(typval_T *argvars, typval_T *rettv) -{ - job_T *job = get_job_arg(&argvars[0]); - - if (job != NULL && rettv_dict_alloc(rettv) != FAIL) - job_info(job, rettv->vval.v_dict); -} - -/* - * "job_setoptions()" function - */ - static void -f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) -{ - job_T *job = get_job_arg(&argvars[0]); - jobopt_T opt; - - if (job == NULL) - return; - clear_job_options(&opt); - if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK) - job_set_options(job, &opt); - free_job_options(&opt); -} - -/* - * "job_start()" function - */ - static void -f_job_start(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_JOB; - if (check_restricted() || check_secure()) - return; - rettv->vval.v_job = job_start(argvars); -} - -/* - * "job_status()" function - */ - static void -f_job_status(typval_T *argvars, typval_T *rettv) -{ - job_T *job = get_job_arg(&argvars[0]); - - if (job != NULL) - { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); - } -} - -/* - * "job_stop()" function - */ - static void -f_job_stop(typval_T *argvars, typval_T *rettv) -{ - job_T *job = get_job_arg(&argvars[0]); - - if (job != NULL) - rettv->vval.v_number = job_stop(job, argvars); -} -#endif - -/* - * "join()" function - */ - static void -f_join(typval_T *argvars, typval_T *rettv) -{ - garray_T ga; - char_u *sep; - - if (argvars[0].v_type != VAR_LIST) - { - EMSG(_(e_listreq)); - return; - } - if (argvars[0].vval.v_list == NULL) - return; - if (argvars[1].v_type == VAR_UNKNOWN) - sep = (char_u *)" "; - else - sep = get_tv_string_chk(&argvars[1]); - - rettv->v_type = VAR_STRING; - - if (sep != NULL) - { - ga_init2(&ga, (int)sizeof(char), 80); - list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); - ga_append(&ga, NUL); - rettv->vval.v_string = (char_u *)ga.ga_data; - } - else - rettv->vval.v_string = NULL; -} - -/* - * "js_decode()" function - */ - static void -f_js_decode(typval_T *argvars, typval_T *rettv) -{ - js_read_T reader; - - reader.js_buf = get_tv_string(&argvars[0]); - reader.js_fill = NULL; - reader.js_used = 0; - if (json_decode_all(&reader, rettv, JSON_JS) != OK) - EMSG(_(e_invarg)); -} - -/* - * "js_encode()" function - */ - static void -f_js_encode(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); -} - -/* - * "json_decode()" function - */ - static void -f_json_decode(typval_T *argvars, typval_T *rettv) -{ - js_read_T reader; - - reader.js_buf = get_tv_string(&argvars[0]); - reader.js_fill = NULL; - reader.js_used = 0; - if (json_decode_all(&reader, rettv, 0) != OK) - EMSG(_(e_invarg)); -} - -/* - * "json_encode()" function - */ - static void -f_json_encode(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = json_encode(&argvars[0], 0); -} - -/* - * "keys()" function - */ - static void -f_keys(typval_T *argvars, typval_T *rettv) -{ - dict_list(argvars, rettv, 0); -} - -/* - * "last_buffer_nr()" function. - */ - static void -f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) -{ - int n = 0; - buf_T *buf; - - for (buf = firstbuf; buf != NULL; buf = buf->b_next) - if (n < buf->b_fnum) - n = buf->b_fnum; - - rettv->vval.v_number = n; -} - -/* - * "len()" function - */ - static void -f_len(typval_T *argvars, typval_T *rettv) -{ - switch (argvars[0].v_type) - { - case VAR_STRING: - case VAR_NUMBER: - rettv->vval.v_number = (varnumber_T)STRLEN( - get_tv_string(&argvars[0])); - break; - case VAR_LIST: - rettv->vval.v_number = list_len(argvars[0].vval.v_list); - break; - case VAR_DICT: - rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); - break; - case VAR_UNKNOWN: - case VAR_SPECIAL: - case VAR_FLOAT: - case VAR_FUNC: - case VAR_PARTIAL: - case VAR_JOB: - case VAR_CHANNEL: - EMSG(_("E701: Invalid type for len()")); - break; - } -} - -static void libcall_common(typval_T *argvars, typval_T *rettv, int type); - - static void -libcall_common(typval_T *argvars, typval_T *rettv, int type) -{ -#ifdef FEAT_LIBCALL - char_u *string_in; - char_u **string_result; - int nr_result; -#endif - - rettv->v_type = type; - if (type != VAR_NUMBER) - rettv->vval.v_string = NULL; - - if (check_restricted() || check_secure()) - return; - -#ifdef FEAT_LIBCALL - /* The first two args must be strings, otherwise its meaningless */ - if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) - { - string_in = NULL; - if (argvars[2].v_type == VAR_STRING) - string_in = argvars[2].vval.v_string; - if (type == VAR_NUMBER) - string_result = NULL; - else - string_result = &rettv->vval.v_string; - if (mch_libcall(argvars[0].vval.v_string, - argvars[1].vval.v_string, - string_in, - argvars[2].vval.v_number, - string_result, - &nr_result) == OK - && type == VAR_NUMBER) - rettv->vval.v_number = nr_result; - } -#endif -} - -/* - * "libcall()" function - */ - static void -f_libcall(typval_T *argvars, typval_T *rettv) -{ - libcall_common(argvars, rettv, VAR_STRING); -} - -/* - * "libcallnr()" function - */ - static void -f_libcallnr(typval_T *argvars, typval_T *rettv) -{ - libcall_common(argvars, rettv, VAR_NUMBER); -} - -/* - * "line(string)" function - */ - static void -f_line(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum = 0; - pos_T *fp; - int fnum; - - fp = var2fpos(&argvars[0], TRUE, &fnum); - if (fp != NULL) - lnum = fp->lnum; - rettv->vval.v_number = lnum; -} - -/* - * "line2byte(lnum)" function - */ - static void -f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifndef FEAT_BYTEOFF - rettv->vval.v_number = -1; -#else - linenr_T lnum; - - lnum = get_tv_lnum(argvars); - if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); - if (rettv->vval.v_number >= 0) - ++rettv->vval.v_number; -#endif -} - -/* - * "lispindent(lnum)" function - */ - static void -f_lispindent(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_LISP - pos_T pos; - linenr_T lnum; - - pos = curwin->w_cursor; - lnum = get_tv_lnum(argvars); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) - { - curwin->w_cursor.lnum = lnum; - rettv->vval.v_number = get_lisp_indent(); - curwin->w_cursor = pos; - } - else -#endif - rettv->vval.v_number = -1; -} - -/* - * "localtime()" function - */ - static void -f_localtime(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = (varnumber_T)time(NULL); -} - -static void get_maparg(typval_T *argvars, typval_T *rettv, int exact); - - static void -get_maparg(typval_T *argvars, typval_T *rettv, int exact) -{ - char_u *keys; - char_u *which; - char_u buf[NUMBUFLEN]; - char_u *keys_buf = NULL; - char_u *rhs; - int mode; - int abbr = FALSE; - int get_dict = FALSE; - mapblock_T *mp; - int buffer_local; - - /* return empty string for failure */ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - keys = get_tv_string(&argvars[0]); - if (*keys == NUL) - return; - - if (argvars[1].v_type != VAR_UNKNOWN) - { - which = get_tv_string_buf_chk(&argvars[1], buf); - if (argvars[2].v_type != VAR_UNKNOWN) - { - abbr = (int)get_tv_number(&argvars[2]); - if (argvars[3].v_type != VAR_UNKNOWN) - get_dict = (int)get_tv_number(&argvars[3]); - } - } - else - which = (char_u *)""; - if (which == NULL) - return; - - mode = get_map_mode(&which, 0); - - keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); - rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); - vim_free(keys_buf); - - if (!get_dict) - { - /* Return a string. */ - if (rhs != NULL) - rettv->vval.v_string = str2special_save(rhs, FALSE); - - } - else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) - { - /* Return a dictionary. */ - char_u *lhs = str2special_save(mp->m_keys, TRUE); - char_u *mapmode = map_mode_to_chars(mp->m_mode); - dict_T *dict = rettv->vval.v_dict; - - dict_add_nr_str(dict, "lhs", 0L, lhs); - dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); - dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL); - dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); - dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL); - dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); - dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); - dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); - dict_add_nr_str(dict, "mode", 0L, mapmode); - - vim_free(lhs); - vim_free(mapmode); - } -} - -#ifdef FEAT_FLOAT -/* - * "log()" function - */ - static void -f_log(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = log(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "log10()" function - */ - static void -f_log10(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = log10(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -#ifdef FEAT_LUA -/* - * "luaeval()" function - */ - static void -f_luaeval(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u buf[NUMBUFLEN]; - - str = get_tv_string_buf(&argvars[0], buf); - do_luaeval(str, argvars + 1, rettv); -} -#endif - -/* - * "map()" function - */ - static void -f_map(typval_T *argvars, typval_T *rettv) -{ - filter_map(argvars, rettv, TRUE); -} - -/* - * "maparg()" function - */ - static void -f_maparg(typval_T *argvars, typval_T *rettv) -{ - get_maparg(argvars, rettv, TRUE); -} - -/* - * "mapcheck()" function - */ - static void -f_mapcheck(typval_T *argvars, typval_T *rettv) -{ - get_maparg(argvars, rettv, FALSE); -} - -static void find_some_match(typval_T *argvars, typval_T *rettv, int start); - - static void -find_some_match(typval_T *argvars, typval_T *rettv, int type) -{ - char_u *str = NULL; - long len = 0; - char_u *expr = NULL; - char_u *pat; - regmatch_T regmatch; - char_u patbuf[NUMBUFLEN]; - char_u strbuf[NUMBUFLEN]; - char_u *save_cpo; - long start = 0; - long nth = 1; - colnr_T startcol = 0; - int match = 0; - list_T *l = NULL; - listitem_T *li = NULL; - long idx = 0; - char_u *tofree = NULL; - - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ - save_cpo = p_cpo; - p_cpo = (char_u *)""; - - rettv->vval.v_number = -1; - if (type == 3 || type == 4) - { - /* type 3: return empty list when there are no matches. - * type 4: return ["", -1, -1, -1] */ - if (rettv_list_alloc(rettv) == FAIL) - goto theend; - if (type == 4 - && (list_append_string(rettv->vval.v_list, - (char_u *)"", 0) == FAIL - || list_append_number(rettv->vval.v_list, - (varnumber_T)-1) == FAIL - || list_append_number(rettv->vval.v_list, - (varnumber_T)-1) == FAIL - || list_append_number(rettv->vval.v_list, - (varnumber_T)-1) == FAIL)) - { - list_free(rettv->vval.v_list); - rettv->vval.v_list = NULL; - goto theend; - } - } - else if (type == 2) - { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - } - - if (argvars[0].v_type == VAR_LIST) - { - if ((l = argvars[0].vval.v_list) == NULL) - goto theend; - li = l->lv_first; - } - else - { - expr = str = get_tv_string(&argvars[0]); - len = (long)STRLEN(str); - } - - pat = get_tv_string_buf_chk(&argvars[1], patbuf); - if (pat == NULL) - goto theend; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - int error = FALSE; - - start = (long)get_tv_number_chk(&argvars[2], &error); - if (error) - goto theend; - if (l != NULL) - { - li = list_find(l, start); - if (li == NULL) - goto theend; - idx = l->lv_idx; /* use the cached index */ - } - else - { - if (start < 0) - start = 0; - if (start > len) - goto theend; - /* When "count" argument is there ignore matches before "start", - * otherwise skip part of the string. Differs when pattern is "^" - * or "\<". */ - if (argvars[3].v_type != VAR_UNKNOWN) - startcol = start; - else - { - str += start; - len -= start; - } - } - - if (argvars[3].v_type != VAR_UNKNOWN) - nth = (long)get_tv_number_chk(&argvars[3], &error); - if (error) - goto theend; - } - - regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); - if (regmatch.regprog != NULL) - { - regmatch.rm_ic = p_ic; - - for (;;) - { - if (l != NULL) - { - if (li == NULL) - { - match = FALSE; - break; - } - vim_free(tofree); - expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); - if (str == NULL) - break; - } - - match = vim_regexec_nl(®match, str, (colnr_T)startcol); - - if (match && --nth <= 0) - break; - if (l == NULL && !match) - break; - - /* Advance to just after the match. */ - if (l != NULL) - { - li = li->li_next; - ++idx; - } - else - { -#ifdef FEAT_MBYTE - startcol = (colnr_T)(regmatch.startp[0] - + (*mb_ptr2len)(regmatch.startp[0]) - str); -#else - startcol = (colnr_T)(regmatch.startp[0] + 1 - str); -#endif - if (startcol > (colnr_T)len - || str + startcol <= regmatch.startp[0]) - { - match = FALSE; - break; - } - } - } - - if (match) - { - if (type == 4) - { - listitem_T *li1 = rettv->vval.v_list->lv_first; - listitem_T *li2 = li1->li_next; - listitem_T *li3 = li2->li_next; - listitem_T *li4 = li3->li_next; - - vim_free(li1->li_tv.vval.v_string); - li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], - (int)(regmatch.endp[0] - regmatch.startp[0])); - li3->li_tv.vval.v_number = - (varnumber_T)(regmatch.startp[0] - expr); - li4->li_tv.vval.v_number = - (varnumber_T)(regmatch.endp[0] - expr); - if (l != NULL) - li2->li_tv.vval.v_number = (varnumber_T)idx; - } - else if (type == 3) - { - int i; - - /* return list with matched string and submatches */ - for (i = 0; i < NSUBEXP; ++i) - { - if (regmatch.endp[i] == NULL) - { - if (list_append_string(rettv->vval.v_list, - (char_u *)"", 0) == FAIL) - break; - } - else if (list_append_string(rettv->vval.v_list, - regmatch.startp[i], - (int)(regmatch.endp[i] - regmatch.startp[i])) - == FAIL) - break; - } - } - else if (type == 2) - { - /* return matched string */ - if (l != NULL) - copy_tv(&li->li_tv, rettv); - else - rettv->vval.v_string = vim_strnsave(regmatch.startp[0], - (int)(regmatch.endp[0] - regmatch.startp[0])); - } - else if (l != NULL) - rettv->vval.v_number = idx; - else - { - if (type != 0) - rettv->vval.v_number = - (varnumber_T)(regmatch.startp[0] - str); - else - rettv->vval.v_number = - (varnumber_T)(regmatch.endp[0] - str); - rettv->vval.v_number += (varnumber_T)(str - expr); - } - } - vim_regfree(regmatch.regprog); - } - - if (type == 4 && l == NULL) - /* matchstrpos() without a list: drop the second item. */ - listitem_remove(rettv->vval.v_list, - rettv->vval.v_list->lv_first->li_next); - -theend: - vim_free(tofree); - p_cpo = save_cpo; -} - -/* - * "match()" function - */ - static void -f_match(typval_T *argvars, typval_T *rettv) -{ - find_some_match(argvars, rettv, 1); -} - -/* - * "matchadd()" function - */ - static void -f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - char_u buf[NUMBUFLEN]; - char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ - char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ - int prio = 10; /* default priority */ - int id = -1; - int error = FALSE; - char_u *conceal_char = NULL; - - rettv->vval.v_number = -1; - - if (grp == NULL || pat == NULL) - return; - if (argvars[2].v_type != VAR_UNKNOWN) - { - prio = (int)get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - id = (int)get_tv_number_chk(&argvars[3], &error); - if (argvars[4].v_type != VAR_UNKNOWN) - { - if (argvars[4].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - if (dict_find(argvars[4].vval.v_dict, - (char_u *)"conceal", -1) != NULL) - conceal_char = get_dict_string(argvars[4].vval.v_dict, - (char_u *)"conceal", FALSE); - } - } - } - if (error == TRUE) - return; - if (id >= 1 && id <= 3) - { - EMSGN("E798: ID is reserved for \":match\": %ld", id); - return; - } - - rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, - conceal_char); -#endif -} - -/* - * "matchaddpos()" function - */ - static void -f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - char_u buf[NUMBUFLEN]; - char_u *group; - int prio = 10; - int id = -1; - int error = FALSE; - list_T *l; - char_u *conceal_char = NULL; - - rettv->vval.v_number = -1; - - group = get_tv_string_buf_chk(&argvars[0], buf); - if (group == NULL) - return; - - if (argvars[1].v_type != VAR_LIST) - { - EMSG2(_(e_listarg), "matchaddpos()"); - return; - } - l = argvars[1].vval.v_list; - if (l == NULL) - return; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - prio = (int)get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - id = (int)get_tv_number_chk(&argvars[3], &error); - if (argvars[4].v_type != VAR_UNKNOWN) - { - if (argvars[4].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - if (dict_find(argvars[4].vval.v_dict, - (char_u *)"conceal", -1) != NULL) - conceal_char = get_dict_string(argvars[4].vval.v_dict, - (char_u *)"conceal", FALSE); - } - } - } - if (error == TRUE) - return; - - /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ - if (id == 1 || id == 2) - { - EMSGN("E798: ID is reserved for \":match\": %ld", id); - return; - } - - rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, - conceal_char); -#endif -} - -/* - * "matcharg()" function - */ - static void -f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (rettv_list_alloc(rettv) == OK) - { -#ifdef FEAT_SEARCH_EXTRA - int id = (int)get_tv_number(&argvars[0]); - matchitem_T *m; - - if (id >= 1 && id <= 3) - { - if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) - { - list_append_string(rettv->vval.v_list, - syn_id2name(m->hlg_id), -1); - list_append_string(rettv->vval.v_list, m->pattern, -1); - } - else - { - list_append_string(rettv->vval.v_list, NULL, -1); - list_append_string(rettv->vval.v_list, NULL, -1); - } - } -#endif - } -} - -/* - * "matchdelete()" function - */ - static void -f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - rettv->vval.v_number = match_delete(curwin, - (int)get_tv_number(&argvars[0]), TRUE); -#endif -} - -/* - * "matchend()" function - */ - static void -f_matchend(typval_T *argvars, typval_T *rettv) -{ - find_some_match(argvars, rettv, 0); -} - -/* - * "matchlist()" function - */ - static void -f_matchlist(typval_T *argvars, typval_T *rettv) -{ - find_some_match(argvars, rettv, 3); -} - -/* - * "matchstr()" function - */ - static void -f_matchstr(typval_T *argvars, typval_T *rettv) -{ - find_some_match(argvars, rettv, 2); -} - -/* - * "matchstrpos()" function - */ - static void -f_matchstrpos(typval_T *argvars, typval_T *rettv) -{ - find_some_match(argvars, rettv, 4); -} - -static void max_min(typval_T *argvars, typval_T *rettv, int domax); - - static void -max_min(typval_T *argvars, typval_T *rettv, int domax) -{ - varnumber_T n = 0; - varnumber_T i; - int error = FALSE; - - if (argvars[0].v_type == VAR_LIST) - { - list_T *l; - listitem_T *li; - - l = argvars[0].vval.v_list; - if (l != NULL) - { - li = l->lv_first; - if (li != NULL) - { - n = get_tv_number_chk(&li->li_tv, &error); - for (;;) - { - li = li->li_next; - if (li == NULL) - break; - i = get_tv_number_chk(&li->li_tv, &error); - if (domax ? i > n : i < n) - n = i; - } - } - } - } - else if (argvars[0].v_type == VAR_DICT) - { - dict_T *d; - int first = TRUE; - hashitem_T *hi; - int todo; - - d = argvars[0].vval.v_dict; - if (d != NULL) - { - todo = (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error); - if (first) - { - n = i; - first = FALSE; - } - else if (domax ? i > n : i < n) - n = i; - } - } - } - } - else - EMSG(_(e_listdictarg)); - rettv->vval.v_number = error ? 0 : n; -} - -/* - * "max()" function - */ - static void -f_max(typval_T *argvars, typval_T *rettv) -{ - max_min(argvars, rettv, TRUE); -} - -/* - * "min()" function - */ - static void -f_min(typval_T *argvars, typval_T *rettv) -{ - max_min(argvars, rettv, FALSE); -} - -static int mkdir_recurse(char_u *dir, int prot); - -/* - * Create the directory in which "dir" is located, and higher levels when - * needed. - */ - static int -mkdir_recurse(char_u *dir, int prot) -{ - char_u *p; - char_u *updir; - int r = FAIL; - - /* Get end of directory name in "dir". - * We're done when it's "/" or "c:/". */ - p = gettail_sep(dir); - if (p <= get_past_head(dir)) - return OK; - - /* If the directory exists we're done. Otherwise: create it.*/ - updir = vim_strnsave(dir, (int)(p - dir)); - if (updir == NULL) - return FAIL; - if (mch_isdir(updir)) - r = OK; - else if (mkdir_recurse(updir, prot) == OK) - r = vim_mkdir_emsg(updir, prot); - vim_free(updir); - return r; -} - -#ifdef vim_mkdir -/* - * "mkdir()" function - */ - static void -f_mkdir(typval_T *argvars, typval_T *rettv) -{ - char_u *dir; - char_u buf[NUMBUFLEN]; - int prot = 0755; - - rettv->vval.v_number = FAIL; - if (check_restricted() || check_secure()) - return; - - dir = get_tv_string_buf(&argvars[0], buf); - if (*dir == NUL) - rettv->vval.v_number = FAIL; - else - { - if (*gettail(dir) == NUL) - /* remove trailing slashes */ - *gettail_sep(dir) = NUL; - - if (argvars[1].v_type != VAR_UNKNOWN) - { - if (argvars[2].v_type != VAR_UNKNOWN) - prot = (int)get_tv_number_chk(&argvars[2], NULL); - if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) - mkdir_recurse(dir, prot); - } - rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot); - } -} -#endif - -/* - * "mode()" function - */ - static void -f_mode(typval_T *argvars, typval_T *rettv) -{ - char_u buf[3]; - - buf[1] = NUL; - buf[2] = NUL; - - if (time_for_testing == 93784) - { - /* Testing the two-character code. */ - buf[0] = 'x'; - buf[1] = '!'; - } - else if (VIsual_active) - { - if (VIsual_select) - buf[0] = VIsual_mode + 's' - 'v'; - else - buf[0] = VIsual_mode; - } - else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE - || State == CONFIRM) - { - buf[0] = 'r'; - if (State == ASKMORE) - buf[1] = 'm'; - else if (State == CONFIRM) - buf[1] = '?'; - } - else if (State == EXTERNCMD) - buf[0] = '!'; - else if (State & INSERT) - { -#ifdef FEAT_VREPLACE - if (State & VREPLACE_FLAG) - { - buf[0] = 'R'; - buf[1] = 'v'; - } - else -#endif - if (State & REPLACE_FLAG) - buf[0] = 'R'; - else - buf[0] = 'i'; - } - else if (State & CMDLINE) - { - buf[0] = 'c'; - if (exmode_active) - buf[1] = 'v'; - } - else if (exmode_active) - { - buf[0] = 'c'; - buf[1] = 'e'; - } - else - { - buf[0] = 'n'; - if (finish_op) - buf[1] = 'o'; - } - - /* Clear out the minor mode when the argument is not a non-zero number or - * non-empty string. */ - if (!non_zero_arg(&argvars[0])) - buf[1] = NUL; - - rettv->vval.v_string = vim_strsave(buf); - rettv->v_type = VAR_STRING; -} - -#if defined(FEAT_MZSCHEME) || defined(PROTO) -/* - * "mzeval()" function - */ - static void -f_mzeval(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u buf[NUMBUFLEN]; - - str = get_tv_string_buf(&argvars[0], buf); - do_mzeval(str, rettv); -} - - void -mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) -{ - typval_T argvars[3]; - - argvars[0].v_type = VAR_STRING; - argvars[0].vval.v_string = name; - copy_tv(args, &argvars[1]); - argvars[2].v_type = VAR_UNKNOWN; - f_call(argvars, rettv); - clear_tv(&argvars[1]); -} -#endif - -/* - * "nextnonblank()" function - */ - static void -f_nextnonblank(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - - for (lnum = get_tv_lnum(argvars); ; ++lnum) - { - if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) - { - lnum = 0; - break; - } - if (*skipwhite(ml_get(lnum)) != NUL) - break; - } - rettv->vval.v_number = lnum; -} - -/* - * "nr2char()" function - */ - static void -f_nr2char(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - -#ifdef FEAT_MBYTE - if (has_mbyte) - { - int utf8 = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) - utf8 = (int)get_tv_number_chk(&argvars[1], NULL); - if (utf8) - buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; - else - buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; - } - else -#endif - { - buf[0] = (char_u)get_tv_number(&argvars[0]); - buf[1] = NUL; - } - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strsave(buf); -} - -/* - * "or(expr, expr)" function - */ - static void -f_or(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) - | get_tv_number_chk(&argvars[1], NULL); -} - -/* - * "pathshorten()" function - */ - static void -f_pathshorten(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - - rettv->v_type = VAR_STRING; - p = get_tv_string_chk(&argvars[0]); - if (p == NULL) - rettv->vval.v_string = NULL; - else - { - p = vim_strsave(p); - rettv->vval.v_string = p; - if (p != NULL) - shorten_dir(p); - } -} - -#ifdef FEAT_PERL -/* - * "perleval()" function - */ - static void -f_perleval(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u buf[NUMBUFLEN]; - - str = get_tv_string_buf(&argvars[0], buf); - do_perleval(str, rettv); -} -#endif - -#ifdef FEAT_FLOAT -/* - * "pow()" function - */ - static void -f_pow(typval_T *argvars, typval_T *rettv) -{ - float_T fx = 0.0, fy = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &fx) == OK - && get_float_arg(&argvars[1], &fy) == OK) - rettv->vval.v_float = pow(fx, fy); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "prevnonblank()" function - */ - static void -f_prevnonblank(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - - lnum = get_tv_lnum(argvars); - if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) - lnum = 0; - else - while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) - --lnum; - rettv->vval.v_number = lnum; -} - -/* This dummy va_list is here because: - * - passing a NULL pointer doesn't work when va_list isn't a pointer - * - locally in the function results in a "used before set" warning - * - using va_start() to initialize it gives "function with fixed args" error */ -static va_list ap; - -/* - * "printf()" function - */ - static void -f_printf(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - int len; - char_u *s; - int saved_did_emsg = did_emsg; - char *fmt; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - /* Get the required length, allocate the buffer and do it for real. */ - did_emsg = FALSE; - fmt = (char *)get_tv_string_buf(&argvars[0], buf); - len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1); - if (!did_emsg) - { - s = alloc(len + 1); - if (s != NULL) - { - rettv->vval.v_string = s; - (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1); - } - } - did_emsg |= saved_did_emsg; -} - -/* - * "pumvisible()" function - */ - static void -f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_INS_EXPAND - if (pum_visible()) - rettv->vval.v_number = 1; -#endif -} - -#ifdef FEAT_PYTHON3 -/* - * "py3eval()" function - */ - static void -f_py3eval(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u buf[NUMBUFLEN]; - - str = get_tv_string_buf(&argvars[0], buf); - do_py3eval(str, rettv); -} -#endif - -#ifdef FEAT_PYTHON -/* - * "pyeval()" function - */ - static void -f_pyeval(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u buf[NUMBUFLEN]; - - str = get_tv_string_buf(&argvars[0], buf); - do_pyeval(str, rettv); -} -#endif - -/* - * "range()" function - */ - static void -f_range(typval_T *argvars, typval_T *rettv) -{ - varnumber_T start; - varnumber_T end; - varnumber_T stride = 1; - varnumber_T i; - int error = FALSE; - - start = get_tv_number_chk(&argvars[0], &error); - if (argvars[1].v_type == VAR_UNKNOWN) - { - end = start - 1; - start = 0; - } - else - { - end = get_tv_number_chk(&argvars[1], &error); - if (argvars[2].v_type != VAR_UNKNOWN) - stride = get_tv_number_chk(&argvars[2], &error); - } - - if (error) - return; /* type error; errmsg already given */ - if (stride == 0) - EMSG(_("E726: Stride is zero")); - else if (stride > 0 ? end + 1 < start : end - 1 > start) - EMSG(_("E727: Start past end")); - else - { - if (rettv_list_alloc(rettv) == OK) - for (i = start; stride > 0 ? i <= end : i >= end; i += stride) - if (list_append_number(rettv->vval.v_list, - (varnumber_T)i) == FAIL) - break; - } -} - -/* - * "readfile()" function - */ - static void -f_readfile(typval_T *argvars, typval_T *rettv) -{ - int binary = FALSE; - int failed = FALSE; - char_u *fname; - FILE *fd; - char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ - int io_size = sizeof(buf); - int readlen; /* size of last fread() */ - char_u *prev = NULL; /* previously read bytes, if any */ - long prevlen = 0; /* length of data in prev */ - long prevsize = 0; /* size of prev buffer */ - long maxline = MAXLNUM; - long cnt = 0; - char_u *p; /* position in buf */ - char_u *start; /* start of current line */ - - if (argvars[1].v_type != VAR_UNKNOWN) - { - if (STRCMP(get_tv_string(&argvars[1]), "b") == 0) - binary = TRUE; - if (argvars[2].v_type != VAR_UNKNOWN) - maxline = (long)get_tv_number(&argvars[2]); - } - - if (rettv_list_alloc(rettv) == FAIL) - return; - - /* Always open the file in binary mode, library functions have a mind of - * their own about CR-LF conversion. */ - fname = get_tv_string(&argvars[0]); - if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) - { - EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); - return; - } - - while (cnt < maxline || maxline < 0) - { - readlen = (int)fread(buf, 1, io_size, fd); - - /* This for loop processes what was read, but is also entered at end - * of file so that either: - * - an incomplete line gets written - * - a "binary" file gets an empty line at the end if it ends in a - * newline. */ - for (p = buf, start = buf; - p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); - ++p) - { - if (*p == '\n' || readlen <= 0) - { - listitem_T *li; - char_u *s = NULL; - long_u len = p - start; - - /* Finished a line. Remove CRs before NL. */ - if (readlen > 0 && !binary) - { - while (len > 0 && start[len - 1] == '\r') - --len; - /* removal may cross back to the "prev" string */ - if (len == 0) - while (prevlen > 0 && prev[prevlen - 1] == '\r') - --prevlen; - } - if (prevlen == 0) - s = vim_strnsave(start, (int)len); - else - { - /* Change "prev" buffer to be the right size. This way - * the bytes are only copied once, and very long lines are - * allocated only once. */ - if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) - { - mch_memmove(s + prevlen, start, len); - s[prevlen + len] = NUL; - prev = NULL; /* the list will own the string */ - prevlen = prevsize = 0; - } - } - if (s == NULL) - { - do_outofmem_msg((long_u) prevlen + len + 1); - failed = TRUE; - break; - } - - if ((li = listitem_alloc()) == NULL) - { - vim_free(s); - failed = TRUE; - break; - } - li->li_tv.v_type = VAR_STRING; - li->li_tv.v_lock = 0; - li->li_tv.vval.v_string = s; - list_append(rettv->vval.v_list, li); - - start = p + 1; /* step over newline */ - if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) - break; - } - else if (*p == NUL) - *p = '\n'; -#ifdef FEAT_MBYTE - /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this - * when finding the BF and check the previous two bytes. */ - else if (*p == 0xbf && enc_utf8 && !binary) - { - /* Find the two bytes before the 0xbf. If p is at buf, or buf - * + 1, these may be in the "prev" string. */ - char_u back1 = p >= buf + 1 ? p[-1] - : prevlen >= 1 ? prev[prevlen - 1] : NUL; - char_u back2 = p >= buf + 2 ? p[-2] - : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] - : prevlen >= 2 ? prev[prevlen - 2] : NUL; - - if (back2 == 0xef && back1 == 0xbb) - { - char_u *dest = p - 2; - - /* Usually a BOM is at the beginning of a file, and so at - * the beginning of a line; then we can just step over it. - */ - if (start == dest) - start = p + 1; - else - { - /* have to shuffle buf to close gap */ - int adjust_prevlen = 0; - - if (dest < buf) - { - adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ - dest = buf; - } - if (readlen > p - buf + 1) - mch_memmove(dest, p + 1, readlen - (p - buf) - 1); - readlen -= 3 - adjust_prevlen; - prevlen -= adjust_prevlen; - p = dest - 1; - } - } - } -#endif - } /* for */ - - if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) - break; - if (start < p) - { - /* There's part of a line in buf, store it in "prev". */ - if (p - start + prevlen >= prevsize) - { - /* need bigger "prev" buffer */ - char_u *newprev; - - /* A common use case is ordinary text files and "prev" gets a - * fragment of a line, so the first allocation is made - * small, to avoid repeatedly 'allocing' large and - * 'reallocing' small. */ - if (prevsize == 0) - prevsize = (long)(p - start); - else - { - long grow50pc = (prevsize * 3) / 2; - long growmin = (long)((p - start) * 2 + prevlen); - prevsize = grow50pc > growmin ? grow50pc : growmin; - } - newprev = prev == NULL ? alloc(prevsize) - : vim_realloc(prev, prevsize); - if (newprev == NULL) - { - do_outofmem_msg((long_u)prevsize); - failed = TRUE; - break; - } - prev = newprev; - } - /* Add the line part to end of "prev". */ - mch_memmove(prev + prevlen, start, p - start); - prevlen += (long)(p - start); - } - } /* while */ - - /* - * For a negative line count use only the lines at the end of the file, - * free the rest. - */ - if (!failed && maxline < 0) - while (cnt > -maxline) - { - listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); - --cnt; - } - - if (failed) - { - list_free(rettv->vval.v_list); - /* readfile doc says an empty list is returned on error */ - rettv->vval.v_list = list_alloc(); - } - - vim_free(prev); - fclose(fd); -} - -#if defined(FEAT_RELTIME) -static int list2proftime(typval_T *arg, proftime_T *tm); - -/* - * Convert a List to proftime_T. - * Return FAIL when there is something wrong. - */ - static int -list2proftime(typval_T *arg, proftime_T *tm) -{ - long n1, n2; - int error = FALSE; - - if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL - || arg->vval.v_list->lv_len != 2) - return FAIL; - n1 = list_find_nr(arg->vval.v_list, 0L, &error); - n2 = list_find_nr(arg->vval.v_list, 1L, &error); -# ifdef WIN3264 - tm->HighPart = n1; - tm->LowPart = n2; -# else - tm->tv_sec = n1; - tm->tv_usec = n2; -# endif - return error ? FAIL : OK; -} -#endif /* FEAT_RELTIME */ - -/* - * "reltime()" function - */ - static void -f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_RELTIME - proftime_T res; - proftime_T start; - - if (argvars[0].v_type == VAR_UNKNOWN) - { - /* No arguments: get current time. */ - profile_start(&res); - } - else if (argvars[1].v_type == VAR_UNKNOWN) - { - if (list2proftime(&argvars[0], &res) == FAIL) - return; - profile_end(&res); - } - else - { - /* Two arguments: compute the difference. */ - if (list2proftime(&argvars[0], &start) == FAIL - || list2proftime(&argvars[1], &res) == FAIL) - return; - profile_sub(&res, &start); - } - - if (rettv_list_alloc(rettv) == OK) - { - long n1, n2; - -# ifdef WIN3264 - n1 = res.HighPart; - n2 = res.LowPart; -# else - n1 = res.tv_sec; - n2 = res.tv_usec; -# endif - list_append_number(rettv->vval.v_list, (varnumber_T)n1); - list_append_number(rettv->vval.v_list, (varnumber_T)n2); - } -#endif -} - -#ifdef FEAT_FLOAT -/* - * "reltimefloat()" function - */ - static void -f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) -{ -# ifdef FEAT_RELTIME - proftime_T tm; -# endif - - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = 0; -# ifdef FEAT_RELTIME - if (list2proftime(&argvars[0], &tm) == OK) - rettv->vval.v_float = profile_float(&tm); -# endif -} -#endif - -/* - * "reltimestr()" function - */ - static void -f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_RELTIME - proftime_T tm; -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_RELTIME - if (list2proftime(&argvars[0], &tm) == OK) - rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); -#endif -} - -#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) -static void make_connection(void); -static int check_connection(void); - - static void -make_connection(void) -{ - if (X_DISPLAY == NULL -# ifdef FEAT_GUI - && !gui.in_use -# endif - ) - { - x_force_connect = TRUE; - setup_term_clip(); - x_force_connect = FALSE; - } -} - - static int -check_connection(void) -{ - make_connection(); - if (X_DISPLAY == NULL) - { - EMSG(_("E240: No connection to Vim server")); - return FAIL; - } - return OK; -} -#endif - -#ifdef FEAT_CLIENTSERVER - static void -remote_common(typval_T *argvars, typval_T *rettv, int expr) -{ - char_u *server_name; - char_u *keys; - char_u *r = NULL; - char_u buf[NUMBUFLEN]; -# ifdef WIN32 - HWND w; -# else - Window w; -# endif - - if (check_restricted() || check_secure()) - return; - -# ifdef FEAT_X11 - if (check_connection() == FAIL) - return; -# endif - - server_name = get_tv_string_chk(&argvars[0]); - if (server_name == NULL) - return; /* type error; errmsg already given */ - keys = get_tv_string_buf(&argvars[1], buf); -# ifdef WIN32 - if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0) -# else - if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE) - < 0) -# endif - { - if (r != NULL) - EMSG(r); /* sending worked but evaluation failed */ - else - EMSG2(_("E241: Unable to send to %s"), server_name); - return; - } - - rettv->vval.v_string = r; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - dictitem_T v; - char_u str[30]; - char_u *idvar; - - sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); - v.di_tv.v_type = VAR_STRING; - v.di_tv.vval.v_string = vim_strsave(str); - idvar = get_tv_string_chk(&argvars[2]); - if (idvar != NULL) - set_var(idvar, &v.di_tv, FALSE); - vim_free(v.di_tv.vval.v_string); - } -} -#endif - -/* - * "remote_expr()" function - */ - static void -f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_CLIENTSERVER - remote_common(argvars, rettv, TRUE); -#endif -} - -/* - * "remote_foreground()" function - */ - static void -f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_CLIENTSERVER -# ifdef WIN32 - /* On Win32 it's done in this application. */ - { - char_u *server_name = get_tv_string_chk(&argvars[0]); - - if (server_name != NULL) - serverForeground(server_name); - } -# else - /* Send a foreground() expression to the server. */ - argvars[1].v_type = VAR_STRING; - argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); - argvars[2].v_type = VAR_UNKNOWN; - remote_common(argvars, rettv, TRUE); - vim_free(argvars[1].vval.v_string); -# endif -#endif -} - - static void -f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_CLIENTSERVER - dictitem_T v; - char_u *s = NULL; -# ifdef WIN32 - long_u n = 0; -# endif - char_u *serverid; - - if (check_restricted() || check_secure()) - { - rettv->vval.v_number = -1; - return; - } - serverid = get_tv_string_chk(&argvars[0]); - if (serverid == NULL) - { - rettv->vval.v_number = -1; - return; /* type error; errmsg already given */ - } -# ifdef WIN32 - sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); - if (n == 0) - rettv->vval.v_number = -1; - else - { - s = serverGetReply((HWND)n, FALSE, FALSE, FALSE); - rettv->vval.v_number = (s != NULL); - } -# else - if (check_connection() == FAIL) - return; - - rettv->vval.v_number = serverPeekReply(X_DISPLAY, - serverStrToWin(serverid), &s); -# endif - - if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) - { - char_u *retvar; - - v.di_tv.v_type = VAR_STRING; - v.di_tv.vval.v_string = vim_strsave(s); - retvar = get_tv_string_chk(&argvars[1]); - if (retvar != NULL) - set_var(retvar, &v.di_tv, FALSE); - vim_free(v.di_tv.vval.v_string); - } -#else - rettv->vval.v_number = -1; -#endif -} - - static void -f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u *r = NULL; - -#ifdef FEAT_CLIENTSERVER - char_u *serverid = get_tv_string_chk(&argvars[0]); - - if (serverid != NULL && !check_restricted() && !check_secure()) - { -# ifdef WIN32 - /* The server's HWND is encoded in the 'id' parameter */ - long_u n = 0; - - sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); - if (n != 0) - r = serverGetReply((HWND)n, FALSE, TRUE, TRUE); - if (r == NULL) -# else - if (check_connection() == FAIL || serverReadReply(X_DISPLAY, - serverStrToWin(serverid), &r, FALSE) < 0) -# endif - EMSG(_("E277: Unable to read a server reply")); - } -#endif - rettv->v_type = VAR_STRING; - rettv->vval.v_string = r; -} - -/* - * "remote_send()" function - */ - static void -f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_CLIENTSERVER - remote_common(argvars, rettv, FALSE); -#endif -} - -/* - * "remove()" function - */ - static void -f_remove(typval_T *argvars, typval_T *rettv) -{ - list_T *l; - listitem_T *item, *item2; - listitem_T *li; - long idx; - long end; - char_u *key; - dict_T *d; - dictitem_T *di; - char_u *arg_errmsg = (char_u *)N_("remove() argument"); - - if (argvars[0].v_type == VAR_DICT) - { - if (argvars[2].v_type != VAR_UNKNOWN) - EMSG2(_(e_toomanyarg), "remove()"); - else if ((d = argvars[0].vval.v_dict) != NULL - && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE)) - { - key = get_tv_string_chk(&argvars[1]); - if (key != NULL) - { - di = dict_find(d, key, -1); - if (di == NULL) - EMSG2(_(e_dictkey), key); - else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) - && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) - { - *rettv = di->di_tv; - init_tv(&di->di_tv); - dictitem_remove(d, di); - } - } - } - } - else if (argvars[0].v_type != VAR_LIST) - EMSG2(_(e_listdictarg), "remove()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE)) - { - int error = FALSE; - - idx = (long)get_tv_number_chk(&argvars[1], &error); - if (error) - ; /* type error: do nothing, errmsg already given */ - else if ((item = list_find(l, idx)) == NULL) - EMSGN(_(e_listidx), idx); - else - { - if (argvars[2].v_type == VAR_UNKNOWN) - { - /* Remove one item, return its value. */ - vimlist_remove(l, item, item); - *rettv = item->li_tv; - vim_free(item); - } - else - { - /* Remove range of items, return list with values. */ - end = (long)get_tv_number_chk(&argvars[2], &error); - if (error) - ; /* type error: do nothing */ - else if ((item2 = list_find(l, end)) == NULL) - EMSGN(_(e_listidx), end); - else - { - int cnt = 0; - - for (li = item; li != NULL; li = li->li_next) - { - ++cnt; - if (li == item2) - break; - } - if (li == NULL) /* didn't find "item2" after "item" */ - EMSG(_(e_invrange)); - else - { - vimlist_remove(l, item, item2); - if (rettv_list_alloc(rettv) == OK) - { - l = rettv->vval.v_list; - l->lv_first = item; - l->lv_last = item2; - item->li_prev = NULL; - item2->li_next = NULL; - l->lv_len = cnt; - } - } - } - } - } - } -} - -/* - * "rename({from}, {to})" function - */ - static void -f_rename(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - - if (check_restricted() || check_secure()) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]), - get_tv_string_buf(&argvars[1], buf)); -} - -/* - * "repeat()" function - */ - static void -f_repeat(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - int n; - int slen; - int len; - char_u *r; - int i; - - n = (int)get_tv_number(&argvars[1]); - if (argvars[0].v_type == VAR_LIST) - { - if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) - while (n-- > 0) - if (list_extend(rettv->vval.v_list, - argvars[0].vval.v_list, NULL) == FAIL) - break; - } - else - { - p = get_tv_string(&argvars[0]); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - slen = (int)STRLEN(p); - len = slen * n; - if (len <= 0) - return; - - r = alloc(len + 1); - if (r != NULL) - { - for (i = 0; i < n; i++) - mch_memmove(r + i * slen, p, (size_t)slen); - r[len] = NUL; - } - - rettv->vval.v_string = r; - } -} - -/* - * "resolve()" function - */ - static void -f_resolve(typval_T *argvars, typval_T *rettv) -{ - char_u *p; -#ifdef HAVE_READLINK - char_u *buf = NULL; -#endif - - p = get_tv_string(&argvars[0]); -#ifdef FEAT_SHORTCUT - { - char_u *v = NULL; - - v = mch_resolve_shortcut(p); - if (v != NULL) - rettv->vval.v_string = v; - else - rettv->vval.v_string = vim_strsave(p); - } -#else -# ifdef HAVE_READLINK - { - char_u *cpy; - int len; - char_u *remain = NULL; - char_u *q; - int is_relative_to_current = FALSE; - int has_trailing_pathsep = FALSE; - int limit = 100; - - p = vim_strsave(p); - - if (p[0] == '.' && (vim_ispathsep(p[1]) - || (p[1] == '.' && (vim_ispathsep(p[2]))))) - is_relative_to_current = TRUE; - - len = STRLEN(p); - if (len > 0 && after_pathsep(p, p + len)) - { - has_trailing_pathsep = TRUE; - p[len - 1] = NUL; /* the trailing slash breaks readlink() */ - } - - q = getnextcomp(p); - if (*q != NUL) - { - /* Separate the first path component in "p", and keep the - * remainder (beginning with the path separator). */ - remain = vim_strsave(q - 1); - q[-1] = NUL; - } - - buf = alloc(MAXPATHL + 1); - if (buf == NULL) - goto fail; - - for (;;) - { - for (;;) - { - len = readlink((char *)p, (char *)buf, MAXPATHL); - if (len <= 0) - break; - buf[len] = NUL; - - if (limit-- == 0) - { - vim_free(p); - vim_free(remain); - EMSG(_("E655: Too many symbolic links (cycle?)")); - rettv->vval.v_string = NULL; - goto fail; - } - - /* Ensure that the result will have a trailing path separator - * if the argument has one. */ - if (remain == NULL && has_trailing_pathsep) - add_pathsep(buf); - - /* Separate the first path component in the link value and - * concatenate the remainders. */ - q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); - if (*q != NUL) - { - if (remain == NULL) - remain = vim_strsave(q - 1); - else - { - cpy = concat_str(q - 1, remain); - if (cpy != NULL) - { - vim_free(remain); - remain = cpy; - } - } - q[-1] = NUL; - } - - q = gettail(p); - if (q > p && *q == NUL) - { - /* Ignore trailing path separator. */ - q[-1] = NUL; - q = gettail(p); - } - if (q > p && !mch_isFullName(buf)) - { - /* symlink is relative to directory of argument */ - cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); - if (cpy != NULL) - { - STRCPY(cpy, p); - STRCPY(gettail(cpy), buf); - vim_free(p); - p = cpy; - } - } - else - { - vim_free(p); - p = vim_strsave(buf); - } - } - - if (remain == NULL) - break; - - /* Append the first path component of "remain" to "p". */ - q = getnextcomp(remain + 1); - len = q - remain - (*q != NUL); - cpy = vim_strnsave(p, STRLEN(p) + len); - if (cpy != NULL) - { - STRNCAT(cpy, remain, len); - vim_free(p); - p = cpy; - } - /* Shorten "remain". */ - if (*q != NUL) - STRMOVE(remain, q - 1); - else - { - vim_free(remain); - remain = NULL; - } - } - - /* If the result is a relative path name, make it explicitly relative to - * the current directory if and only if the argument had this form. */ - if (!vim_ispathsep(*p)) - { - if (is_relative_to_current - && *p != NUL - && !(p[0] == '.' - && (p[1] == NUL - || vim_ispathsep(p[1]) - || (p[1] == '.' - && (p[2] == NUL - || vim_ispathsep(p[2])))))) - { - /* Prepend "./". */ - cpy = concat_str((char_u *)"./", p); - if (cpy != NULL) - { - vim_free(p); - p = cpy; - } - } - else if (!is_relative_to_current) - { - /* Strip leading "./". */ - q = p; - while (q[0] == '.' && vim_ispathsep(q[1])) - q += 2; - if (q > p) - STRMOVE(p, p + 2); - } - } - - /* Ensure that the result will have no trailing path separator - * if the argument had none. But keep "/" or "//". */ - if (!has_trailing_pathsep) - { - q = p + STRLEN(p); - if (after_pathsep(p, q)) - *gettail_sep(p) = NUL; - } - - rettv->vval.v_string = p; - } -# else - rettv->vval.v_string = vim_strsave(p); -# endif -#endif - - simplify_filename(rettv->vval.v_string); - -#ifdef HAVE_READLINK -fail: - vim_free(buf); -#endif - rettv->v_type = VAR_STRING; -} - -/* - * "reverse({list})" function - */ - static void -f_reverse(typval_T *argvars, typval_T *rettv) -{ - list_T *l; - listitem_T *li, *ni; - - if (argvars[0].v_type != VAR_LIST) - EMSG2(_(e_listarg), "reverse()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, - (char_u *)N_("reverse() argument"), TRUE)) - { - li = l->lv_last; - l->lv_first = l->lv_last = NULL; - l->lv_len = 0; - while (li != NULL) - { - ni = li->li_prev; - list_append(l, li); - li = ni; - } - rettv->vval.v_list = l; - rettv->v_type = VAR_LIST; - ++l->lv_refcount; - l->lv_idx = l->lv_len - l->lv_idx - 1; - } -} - -#define SP_NOMOVE 0x01 /* don't move cursor */ -#define SP_REPEAT 0x02 /* repeat to find outer pair */ -#define SP_RETCOUNT 0x04 /* return matchcount */ -#define SP_SETPCMARK 0x08 /* set previous context mark */ -#define SP_START 0x10 /* accept match at start position */ -#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ -#define SP_END 0x40 /* leave cursor at end of match */ -#define SP_COLUMN 0x80 /* start at cursor column */ - -static int get_search_arg(typval_T *varp, int *flagsp); - -/* - * Get flags for a search function. - * Possibly sets "p_ws". - * Returns BACKWARD, FORWARD or zero (for an error). - */ - static int -get_search_arg(typval_T *varp, int *flagsp) -{ - int dir = FORWARD; - char_u *flags; - char_u nbuf[NUMBUFLEN]; - int mask; - - if (varp->v_type != VAR_UNKNOWN) - { - flags = get_tv_string_buf_chk(varp, nbuf); - if (flags == NULL) - return 0; /* type error; errmsg already given */ - while (*flags != NUL) - { - switch (*flags) - { - case 'b': dir = BACKWARD; break; - case 'w': p_ws = TRUE; break; - case 'W': p_ws = FALSE; break; - default: mask = 0; - if (flagsp != NULL) - switch (*flags) - { - case 'c': mask = SP_START; break; - case 'e': mask = SP_END; break; - case 'm': mask = SP_RETCOUNT; break; - case 'n': mask = SP_NOMOVE; break; - case 'p': mask = SP_SUBPAT; break; - case 'r': mask = SP_REPEAT; break; - case 's': mask = SP_SETPCMARK; break; - case 'z': mask = SP_COLUMN; break; - } - if (mask == 0) - { - EMSG2(_(e_invarg2), flags); - dir = 0; - } - else - *flagsp |= mask; - } - if (dir == 0) - break; - ++flags; - } - } - return dir; -} - -/* - * Shared by search() and searchpos() functions. - */ - static int -search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) -{ - int flags; - char_u *pat; - pos_T pos; - pos_T save_cursor; - int save_p_ws = p_ws; - int dir; - int retval = 0; /* default: FAIL */ - long lnum_stop = 0; - proftime_T tm; -#ifdef FEAT_RELTIME - long time_limit = 0; -#endif - int options = SEARCH_KEEP; - int subpatnum; - - pat = get_tv_string(&argvars[0]); - dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */ - if (dir == 0) - goto theend; - flags = *flagsp; - if (flags & SP_START) - options |= SEARCH_START; - if (flags & SP_END) - options |= SEARCH_END; - if (flags & SP_COLUMN) - options |= SEARCH_COL; - - /* Optional arguments: line number to stop searching and timeout. */ - if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) - { - lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL); - if (lnum_stop < 0) - goto theend; -#ifdef FEAT_RELTIME - if (argvars[3].v_type != VAR_UNKNOWN) - { - time_limit = (long)get_tv_number_chk(&argvars[3], NULL); - if (time_limit < 0) - goto theend; - } -#endif - } - -#ifdef FEAT_RELTIME - /* Set the time limit, if there is one. */ - profile_setlimit(time_limit, &tm); -#endif - - /* - * This function does not accept SP_REPEAT and SP_RETCOUNT flags. - * Check to make sure only those flags are set. - * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both - * flags cannot be set. Check for that condition also. - */ - if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) - || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) - { - EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); - goto theend; - } - - pos = save_cursor = curwin->w_cursor; - subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L, - options, RE_SEARCH, (linenr_T)lnum_stop, &tm); - if (subpatnum != FAIL) - { - if (flags & SP_SUBPAT) - retval = subpatnum; - else - retval = pos.lnum; - if (flags & SP_SETPCMARK) - setpcmark(); - curwin->w_cursor = pos; - if (match_pos != NULL) - { - /* Store the match cursor position */ - match_pos->lnum = pos.lnum; - match_pos->col = pos.col + 1; - } - /* "/$" will put the cursor after the end of the line, may need to - * correct that here */ - check_cursor(); - } - - /* If 'n' flag is used: restore cursor position. */ - if (flags & SP_NOMOVE) - curwin->w_cursor = save_cursor; - else - curwin->w_set_curswant = TRUE; -theend: - p_ws = save_p_ws; - - return retval; -} - -#ifdef FEAT_FLOAT - -/* - * round() is not in C90, use ceil() or floor() instead. - */ - float_T -vim_round(float_T f) -{ - return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); -} - -/* - * "round({float})" function - */ - static void -f_round(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = vim_round(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "screenattr()" function - */ - static void -f_screenattr(typval_T *argvars, typval_T *rettv) -{ - int row; - int col; - int c; - - row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; - col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; - if (row < 0 || row >= screen_Rows - || col < 0 || col >= screen_Columns) - c = -1; - else - c = ScreenAttrs[LineOffset[row] + col]; - rettv->vval.v_number = c; -} - -/* - * "screenchar()" function - */ - static void -f_screenchar(typval_T *argvars, typval_T *rettv) -{ - int row; - int col; - int off; - int c; - - row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; - col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; - if (row < 0 || row >= screen_Rows - || col < 0 || col >= screen_Columns) - c = -1; - else - { - off = LineOffset[row] + col; -#ifdef FEAT_MBYTE - if (enc_utf8 && ScreenLinesUC[off] != 0) - c = ScreenLinesUC[off]; - else -#endif - c = ScreenLines[off]; - } - rettv->vval.v_number = c; -} - -/* - * "screencol()" function - * - * First column is 1 to be consistent with virtcol(). - */ - static void -f_screencol(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = screen_screencol() + 1; -} - -/* - * "screenrow()" function - */ - static void -f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = screen_screenrow() + 1; -} - -/* - * "search()" function - */ - static void -f_search(typval_T *argvars, typval_T *rettv) -{ - int flags = 0; - - rettv->vval.v_number = search_cmn(argvars, NULL, &flags); -} - -/* - * "searchdecl()" function - */ - static void -f_searchdecl(typval_T *argvars, typval_T *rettv) -{ - int locally = 1; - int thisblock = 0; - int error = FALSE; - char_u *name; - - rettv->vval.v_number = 1; /* default: FAIL */ - - name = get_tv_string_chk(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN) - { - locally = (int)get_tv_number_chk(&argvars[1], &error) == 0; - if (!error && argvars[2].v_type != VAR_UNKNOWN) - thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0; - } - if (!error && name != NULL) - rettv->vval.v_number = find_decl(name, (int)STRLEN(name), - locally, thisblock, SEARCH_KEEP) == FAIL; -} - -/* - * Used by searchpair() and searchpairpos() - */ - static int -searchpair_cmn(typval_T *argvars, pos_T *match_pos) -{ - char_u *spat, *mpat, *epat; - char_u *skip; - int save_p_ws = p_ws; - int dir; - int flags = 0; - char_u nbuf1[NUMBUFLEN]; - char_u nbuf2[NUMBUFLEN]; - char_u nbuf3[NUMBUFLEN]; - int retval = 0; /* default: FAIL */ - long lnum_stop = 0; - long time_limit = 0; - - /* Get the three pattern arguments: start, middle, end. */ - spat = get_tv_string_chk(&argvars[0]); - mpat = get_tv_string_buf_chk(&argvars[1], nbuf1); - epat = get_tv_string_buf_chk(&argvars[2], nbuf2); - if (spat == NULL || mpat == NULL || epat == NULL) - goto theend; /* type error */ - - /* Handle the optional fourth argument: flags */ - dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */ - if (dir == 0) - goto theend; - - /* Don't accept SP_END or SP_SUBPAT. - * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. - */ - if ((flags & (SP_END | SP_SUBPAT)) != 0 - || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) - { - EMSG2(_(e_invarg2), get_tv_string(&argvars[3])); - goto theend; - } - - /* Using 'r' implies 'W', otherwise it doesn't work. */ - if (flags & SP_REPEAT) - p_ws = FALSE; - - /* Optional fifth argument: skip expression */ - if (argvars[3].v_type == VAR_UNKNOWN - || argvars[4].v_type == VAR_UNKNOWN) - skip = (char_u *)""; - else - { - skip = get_tv_string_buf_chk(&argvars[4], nbuf3); - if (argvars[5].v_type != VAR_UNKNOWN) - { - lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL); - if (lnum_stop < 0) - goto theend; -#ifdef FEAT_RELTIME - if (argvars[6].v_type != VAR_UNKNOWN) - { - time_limit = (long)get_tv_number_chk(&argvars[6], NULL); - if (time_limit < 0) - goto theend; - } -#endif - } - } - if (skip == NULL) - goto theend; /* type error */ - - retval = do_searchpair(spat, mpat, epat, dir, skip, flags, - match_pos, lnum_stop, time_limit); - -theend: - p_ws = save_p_ws; - - return retval; -} - -/* - * "searchpair()" function - */ - static void -f_searchpair(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = searchpair_cmn(argvars, NULL); -} - -/* - * "searchpairpos()" function - */ - static void -f_searchpairpos(typval_T *argvars, typval_T *rettv) -{ - pos_T match_pos; - int lnum = 0; - int col = 0; - - if (rettv_list_alloc(rettv) == FAIL) - return; - - if (searchpair_cmn(argvars, &match_pos) > 0) - { - lnum = match_pos.lnum; - col = match_pos.col; - } - - list_append_number(rettv->vval.v_list, (varnumber_T)lnum); - list_append_number(rettv->vval.v_list, (varnumber_T)col); -} - -/* - * Search for a start/middle/end thing. - * Used by searchpair(), see its documentation for the details. - * Returns 0 or -1 for no match, - */ - long -do_searchpair( - char_u *spat, /* start pattern */ - char_u *mpat, /* middle pattern */ - char_u *epat, /* end pattern */ - int dir, /* BACKWARD or FORWARD */ - char_u *skip, /* skip expression */ - int flags, /* SP_SETPCMARK and other SP_ values */ - pos_T *match_pos, - linenr_T lnum_stop, /* stop at this line if not zero */ - long time_limit UNUSED) /* stop after this many msec */ -{ - char_u *save_cpo; - char_u *pat, *pat2 = NULL, *pat3 = NULL; - long retval = 0; - pos_T pos; - pos_T firstpos; - pos_T foundpos; - pos_T save_cursor; - pos_T save_pos; - int n; - int r; - int nest = 1; - int err; - int options = SEARCH_KEEP; - proftime_T tm; - - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ - save_cpo = p_cpo; - p_cpo = empty_option; - -#ifdef FEAT_RELTIME - /* Set the time limit, if there is one. */ - profile_setlimit(time_limit, &tm); -#endif - - /* Make two search patterns: start/end (pat2, for in nested pairs) and - * start/middle/end (pat3, for the top pair). */ - pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15)); - pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23)); - if (pat2 == NULL || pat3 == NULL) - goto theend; - sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); - if (*mpat == NUL) - STRCPY(pat3, pat2); - else - sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", - spat, epat, mpat); - if (flags & SP_START) - options |= SEARCH_START; - - save_cursor = curwin->w_cursor; - pos = curwin->w_cursor; - clearpos(&firstpos); - clearpos(&foundpos); - pat = pat3; - for (;;) - { - n = searchit(curwin, curbuf, &pos, dir, pat, 1L, - options, RE_SEARCH, lnum_stop, &tm); - if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) - /* didn't find it or found the first match again: FAIL */ - break; - - if (firstpos.lnum == 0) - firstpos = pos; - if (equalpos(pos, foundpos)) - { - /* Found the same position again. Can happen with a pattern that - * has "\zs" at the end and searching backwards. Advance one - * character and try again. */ - if (dir == BACKWARD) - decl(&pos); - else - incl(&pos); - } - foundpos = pos; - - /* clear the start flag to avoid getting stuck here */ - options &= ~SEARCH_START; - - /* If the skip pattern matches, ignore this match. */ - if (*skip != NUL) - { - save_pos = curwin->w_cursor; - curwin->w_cursor = pos; - r = eval_to_bool(skip, &err, NULL, FALSE); - curwin->w_cursor = save_pos; - if (err) - { - /* Evaluating {skip} caused an error, break here. */ - curwin->w_cursor = save_cursor; - retval = -1; - break; - } - if (r) - continue; - } - - if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) - { - /* Found end when searching backwards or start when searching - * forward: nested pair. */ - ++nest; - pat = pat2; /* nested, don't search for middle */ - } - else - { - /* Found end when searching forward or start when searching - * backward: end of (nested) pair; or found middle in outer pair. */ - if (--nest == 1) - pat = pat3; /* outer level, search for middle */ - } - - if (nest == 0) - { - /* Found the match: return matchcount or line number. */ - if (flags & SP_RETCOUNT) - ++retval; - else - retval = pos.lnum; - if (flags & SP_SETPCMARK) - setpcmark(); - curwin->w_cursor = pos; - if (!(flags & SP_REPEAT)) - break; - nest = 1; /* search for next unmatched */ - } - } - - if (match_pos != NULL) - { - /* Store the match cursor position */ - match_pos->lnum = curwin->w_cursor.lnum; - match_pos->col = curwin->w_cursor.col + 1; - } - - /* If 'n' flag is used or search failed: restore cursor position. */ - if ((flags & SP_NOMOVE) || retval == 0) - curwin->w_cursor = save_cursor; - -theend: - vim_free(pat2); - vim_free(pat3); - if (p_cpo == empty_option) - p_cpo = save_cpo; - else - /* Darn, evaluating the {skip} expression changed the value. */ - free_string_option(save_cpo); - - return retval; -} - -/* - * "searchpos()" function - */ - static void -f_searchpos(typval_T *argvars, typval_T *rettv) -{ - pos_T match_pos; - int lnum = 0; - int col = 0; - int n; - int flags = 0; - - if (rettv_list_alloc(rettv) == FAIL) - return; - - n = search_cmn(argvars, &match_pos, &flags); - if (n > 0) - { - lnum = match_pos.lnum; - col = match_pos.col; - } - - list_append_number(rettv->vval.v_list, (varnumber_T)lnum); - list_append_number(rettv->vval.v_list, (varnumber_T)col); - if (flags & SP_SUBPAT) - list_append_number(rettv->vval.v_list, (varnumber_T)n); -} - - static void -f_server2client(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_CLIENTSERVER - char_u buf[NUMBUFLEN]; - char_u *server = get_tv_string_chk(&argvars[0]); - char_u *reply = get_tv_string_buf_chk(&argvars[1], buf); - - rettv->vval.v_number = -1; - if (server == NULL || reply == NULL) - return; - if (check_restricted() || check_secure()) - return; -# ifdef FEAT_X11 - if (check_connection() == FAIL) - return; -# endif - - if (serverSendReply(server, reply) < 0) - { - EMSG(_("E258: Unable to send to client")); - return; - } - rettv->vval.v_number = 0; -#else - rettv->vval.v_number = -1; -#endif -} - - static void -f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u *r = NULL; - -#ifdef FEAT_CLIENTSERVER -# ifdef WIN32 - r = serverGetVimNames(); -# else - make_connection(); - if (X_DISPLAY != NULL) - r = serverGetVimNames(X_DISPLAY); -# endif -#endif - rettv->v_type = VAR_STRING; - rettv->vval.v_string = r; -} - -/* - * "setbufvar()" function - */ - static void -f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED) -{ - buf_T *buf; - char_u *varname, *bufvarname; - typval_T *varp; - char_u nbuf[NUMBUFLEN]; - - if (check_restricted() || check_secure()) - return; - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - varname = get_tv_string_chk(&argvars[1]); - buf = get_buf_tv(&argvars[0], FALSE); - varp = &argvars[2]; - - if (buf != NULL && varname != NULL && varp != NULL) - { - if (*varname == '&') - { - long numval; - char_u *strval; - int error = FALSE; - aco_save_T aco; - - /* set curbuf to be our buf, temporarily */ - aucmd_prepbuf(&aco, buf); - - ++varname; - numval = (long)get_tv_number_chk(varp, &error); - strval = get_tv_string_buf_chk(varp, nbuf); - if (!error && strval != NULL) - set_option_value(varname, numval, strval, OPT_LOCAL); - - /* reset notion of buffer */ - aucmd_restbuf(&aco); - } - else - { - buf_T *save_curbuf = curbuf; - - bufvarname = alloc((unsigned)STRLEN(varname) + 3); - if (bufvarname != NULL) - { - curbuf = buf; - STRCPY(bufvarname, "b:"); - STRCPY(bufvarname + 2, varname); - set_var(bufvarname, varp, TRUE); - vim_free(bufvarname); - curbuf = save_curbuf; - } - } - } -} - - static void -f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) -{ - dict_T *d; - dictitem_T *di; - char_u *csearch; - - if (argvars[0].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - - if ((d = argvars[0].vval.v_dict) != NULL) - { - csearch = get_dict_string(d, (char_u *)"char", FALSE); - if (csearch != NULL) - { -#ifdef FEAT_MBYTE - if (enc_utf8) - { - int pcc[MAX_MCO]; - int c = utfc_ptr2char(csearch, pcc); - - set_last_csearch(c, csearch, utfc_ptr2len(csearch)); - } - else -#endif - set_last_csearch(PTR2CHAR(csearch), - csearch, MB_PTR2LEN(csearch)); - } - - di = dict_find(d, (char_u *)"forward", -1); - if (di != NULL) - set_csearch_direction((int)get_tv_number(&di->di_tv) - ? FORWARD : BACKWARD); - - di = dict_find(d, (char_u *)"until", -1); - if (di != NULL) - set_csearch_until(!!get_tv_number(&di->di_tv)); - } -} - -/* - * "setcmdpos()" function - */ - static void -f_setcmdpos(typval_T *argvars, typval_T *rettv) -{ - int pos = (int)get_tv_number(&argvars[0]) - 1; - - if (pos >= 0) - rettv->vval.v_number = set_cmdline_pos(pos); -} - -/* - * "setfperm({fname}, {mode})" function - */ - static void -f_setfperm(typval_T *argvars, typval_T *rettv) -{ - char_u *fname; - char_u modebuf[NUMBUFLEN]; - char_u *mode_str; - int i; - int mask; - int mode = 0; - - rettv->vval.v_number = 0; - fname = get_tv_string_chk(&argvars[0]); - if (fname == NULL) - return; - mode_str = get_tv_string_buf_chk(&argvars[1], modebuf); - if (mode_str == NULL) - return; - if (STRLEN(mode_str) != 9) - { - EMSG2(_(e_invarg2), mode_str); - return; - } - - mask = 1; - for (i = 8; i >= 0; --i) - { - if (mode_str[i] != '-') - mode |= mask; - mask = mask << 1; - } - rettv->vval.v_number = mch_setperm(fname, mode) == OK; -} - -/* - * "setline()" function - */ - static void -f_setline(typval_T *argvars, typval_T *rettv) -{ - linenr_T lnum; - char_u *line = NULL; - list_T *l = NULL; - listitem_T *li = NULL; - long added = 0; - linenr_T lcount = curbuf->b_ml.ml_line_count; - - lnum = get_tv_lnum(&argvars[0]); - if (argvars[1].v_type == VAR_LIST) - { - l = argvars[1].vval.v_list; - li = l->lv_first; - } - else - line = get_tv_string_chk(&argvars[1]); - - /* default result is zero == OK */ - for (;;) - { - if (l != NULL) - { - /* list argument, get next string */ - if (li == NULL) - break; - line = get_tv_string_chk(&li->li_tv); - li = li->li_next; - } - - rettv->vval.v_number = 1; /* FAIL */ - if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) - break; - - /* When coming here from Insert mode, sync undo, so that this can be - * undone separately from what was previously inserted. */ - if (u_sync_once == 2) - { - u_sync_once = 1; /* notify that u_sync() was called */ - u_sync(TRUE); - } - - if (lnum <= curbuf->b_ml.ml_line_count) - { - /* existing line, replace it */ - if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) - { - changed_bytes(lnum, 0); - if (lnum == curwin->w_cursor.lnum) - check_cursor_col(); - rettv->vval.v_number = 0; /* OK */ - } - } - else if (added > 0 || u_save(lnum - 1, lnum) == OK) - { - /* lnum is one past the last line, append the line */ - ++added; - if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) - rettv->vval.v_number = 0; /* OK */ - } - - if (l == NULL) /* only one string argument */ - break; - ++lnum; - } - - if (added > 0) - appended_lines_mark(lcount, added); -} - -static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv); - -/* - * Used by "setqflist()" and "setloclist()" functions - */ - static void -set_qf_ll_list( - win_T *wp UNUSED, - typval_T *list_arg UNUSED, - typval_T *action_arg UNUSED, - typval_T *rettv) -{ -#ifdef FEAT_QUICKFIX - static char *e_invact = N_("E927: Invalid action: '%s'"); - char_u *act; - int action = 0; -#endif - - rettv->vval.v_number = -1; - -#ifdef FEAT_QUICKFIX - if (list_arg->v_type != VAR_LIST) - EMSG(_(e_listreq)); - else - { - list_T *l = list_arg->vval.v_list; - - if (action_arg->v_type == VAR_STRING) - { - act = get_tv_string_chk(action_arg); - if (act == NULL) - return; /* type error; errmsg already given */ - if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) - action = *act; - else - EMSG2(_(e_invact), act); - } - else if (action_arg->v_type == VAR_UNKNOWN) - action = ' '; - else - EMSG(_(e_stringreq)); - - if (l != NULL && action && set_errorlist(wp, l, action, - (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK) - rettv->vval.v_number = 0; - } -#endif -} - -/* - * "setloclist()" function - */ - static void -f_setloclist(typval_T *argvars, typval_T *rettv) -{ - win_T *win; - - rettv->vval.v_number = -1; - - win = find_win_by_nr(&argvars[0], NULL); - if (win != NULL) - set_qf_ll_list(win, &argvars[1], &argvars[2], rettv); -} - -/* - * "setmatches()" function - */ - static void -f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - list_T *l; - listitem_T *li; - dict_T *d; - list_T *s = NULL; - - rettv->vval.v_number = -1; - if (argvars[0].v_type != VAR_LIST) - { - EMSG(_(e_listreq)); - return; - } - if ((l = argvars[0].vval.v_list) != NULL) - { - - /* To some extent make sure that we are dealing with a list from - * "getmatches()". */ - li = l->lv_first; - while (li != NULL) - { - if (li->li_tv.v_type != VAR_DICT - || (d = li->li_tv.vval.v_dict) == NULL) - { - EMSG(_(e_invarg)); - return; - } - if (!(dict_find(d, (char_u *)"group", -1) != NULL - && (dict_find(d, (char_u *)"pattern", -1) != NULL - || dict_find(d, (char_u *)"pos1", -1) != NULL) - && dict_find(d, (char_u *)"priority", -1) != NULL - && dict_find(d, (char_u *)"id", -1) != NULL)) - { - EMSG(_(e_invarg)); - return; - } - li = li->li_next; - } - - clear_matches(curwin); - li = l->lv_first; - while (li != NULL) - { - int i = 0; - char_u buf[5]; - dictitem_T *di; - char_u *group; - int priority; - int id; - char_u *conceal; - - d = li->li_tv.vval.v_dict; - if (dict_find(d, (char_u *)"pattern", -1) == NULL) - { - if (s == NULL) - { - s = list_alloc(); - if (s == NULL) - return; - } - - /* match from matchaddpos() */ - for (i = 1; i < 9; i++) - { - sprintf((char *)buf, (char *)"pos%d", i); - if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) - { - if (di->di_tv.v_type != VAR_LIST) - return; - - list_append_tv(s, &di->di_tv); - s->lv_refcount++; - } - else - break; - } - } - - group = get_dict_string(d, (char_u *)"group", FALSE); - priority = (int)get_dict_number(d, (char_u *)"priority"); - id = (int)get_dict_number(d, (char_u *)"id"); - conceal = dict_find(d, (char_u *)"conceal", -1) != NULL - ? get_dict_string(d, (char_u *)"conceal", FALSE) - : NULL; - if (i == 0) - { - match_add(curwin, group, - get_dict_string(d, (char_u *)"pattern", FALSE), - priority, id, NULL, conceal); - } - else - { - match_add(curwin, group, NULL, priority, id, s, conceal); - list_unref(s); - s = NULL; - } - - li = li->li_next; - } - rettv->vval.v_number = 0; - } -#endif -} - -/* - * "setpos()" function - */ - static void -f_setpos(typval_T *argvars, typval_T *rettv) -{ - pos_T pos; - int fnum; - char_u *name; - colnr_T curswant = -1; - - rettv->vval.v_number = -1; - name = get_tv_string_chk(argvars); - if (name != NULL) - { - if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) - { - if (--pos.col < 0) - pos.col = 0; - if (name[0] == '.' && name[1] == NUL) - { - /* set cursor */ - if (fnum == curbuf->b_fnum) - { - curwin->w_cursor = pos; - if (curswant >= 0) - { - curwin->w_curswant = curswant - 1; - curwin->w_set_curswant = FALSE; - } - check_cursor(); - rettv->vval.v_number = 0; - } - else - EMSG(_(e_invarg)); - } - else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) - { - /* set mark */ - if (setmark_pos(name[1], &pos, fnum) == OK) - rettv->vval.v_number = 0; - } - else - EMSG(_(e_invarg)); - } - } -} - -/* - * "setqflist()" function - */ - static void -f_setqflist(typval_T *argvars, typval_T *rettv) -{ - set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv); -} - -/* - * "setreg()" function - */ - static void -f_setreg(typval_T *argvars, typval_T *rettv) -{ - int regname; - char_u *strregname; - char_u *stropt; - char_u *strval; - int append; - char_u yank_type; - long block_len; - - block_len = -1; - yank_type = MAUTO; - append = FALSE; - - strregname = get_tv_string_chk(argvars); - rettv->vval.v_number = 1; /* FAIL is default */ - - if (strregname == NULL) - return; /* type error; errmsg already given */ - regname = *strregname; - if (regname == 0 || regname == '@') - regname = '"'; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - stropt = get_tv_string_chk(&argvars[2]); - if (stropt == NULL) - return; /* type error */ - for (; *stropt != NUL; ++stropt) - switch (*stropt) - { - case 'a': case 'A': /* append */ - append = TRUE; - break; - case 'v': case 'c': /* character-wise selection */ - yank_type = MCHAR; - break; - case 'V': case 'l': /* line-wise selection */ - yank_type = MLINE; - break; - case 'b': case Ctrl_V: /* block-wise selection */ - yank_type = MBLOCK; - if (VIM_ISDIGIT(stropt[1])) - { - ++stropt; - block_len = getdigits(&stropt) - 1; - --stropt; - } - break; - } - } - - if (argvars[1].v_type == VAR_LIST) - { - char_u **lstval; - char_u **allocval; - char_u buf[NUMBUFLEN]; - char_u **curval; - char_u **curallocval; - list_T *ll = argvars[1].vval.v_list; - listitem_T *li; - int len; - - /* If the list is NULL handle like an empty list. */ - len = ll == NULL ? 0 : ll->lv_len; - - /* First half: use for pointers to result lines; second half: use for - * pointers to allocated copies. */ - lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2)); - if (lstval == NULL) - return; - curval = lstval; - allocval = lstval + len + 2; - curallocval = allocval; - - for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; - li = li->li_next) - { - strval = get_tv_string_buf_chk(&li->li_tv, buf); - if (strval == NULL) - goto free_lstval; - if (strval == buf) - { - /* Need to make a copy, next get_tv_string_buf_chk() will - * overwrite the string. */ - strval = vim_strsave(buf); - if (strval == NULL) - goto free_lstval; - *curallocval++ = strval; - } - *curval++ = strval; - } - *curval++ = NULL; - - write_reg_contents_lst(regname, lstval, -1, - append, yank_type, block_len); -free_lstval: - while (curallocval > allocval) - vim_free(*--curallocval); - vim_free(lstval); - } - else - { - strval = get_tv_string_chk(&argvars[1]); - if (strval == NULL) - return; - write_reg_contents_ex(regname, strval, -1, - append, yank_type, block_len); - } - rettv->vval.v_number = 0; -} - -/* - * "settabvar()" function - */ - static void -f_settabvar(typval_T *argvars, typval_T *rettv) -{ -#ifdef FEAT_WINDOWS - tabpage_T *save_curtab; - tabpage_T *tp; -#endif - char_u *varname, *tabvarname; - typval_T *varp; - - rettv->vval.v_number = 0; - - if (check_restricted() || check_secure()) - return; - -#ifdef FEAT_WINDOWS - tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); -#endif - varname = get_tv_string_chk(&argvars[1]); - varp = &argvars[2]; - - if (varname != NULL && varp != NULL -#ifdef FEAT_WINDOWS - && tp != NULL -#endif - ) - { -#ifdef FEAT_WINDOWS - save_curtab = curtab; - goto_tabpage_tp(tp, FALSE, FALSE); -#endif - - tabvarname = alloc((unsigned)STRLEN(varname) + 3); - if (tabvarname != NULL) - { - STRCPY(tabvarname, "t:"); - STRCPY(tabvarname + 2, varname); - set_var(tabvarname, varp, TRUE); - vim_free(tabvarname); - } - -#ifdef FEAT_WINDOWS - /* Restore current tabpage */ - if (valid_tabpage(save_curtab)) - goto_tabpage_tp(save_curtab, FALSE, FALSE); -#endif - } -} - -/* - * "settabwinvar()" function - */ - static void -f_settabwinvar(typval_T *argvars, typval_T *rettv) -{ - setwinvar(argvars, rettv, 1); -} - -/* - * "setwinvar()" function - */ - static void -f_setwinvar(typval_T *argvars, typval_T *rettv) -{ - setwinvar(argvars, rettv, 0); -} - -/* - * "setwinvar()" and "settabwinvar()" functions - */ - - static void -setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off) -{ - win_T *win; -#ifdef FEAT_WINDOWS - win_T *save_curwin; - tabpage_T *save_curtab; - int need_switch_win; -#endif - char_u *varname, *winvarname; - typval_T *varp; - char_u nbuf[NUMBUFLEN]; - tabpage_T *tp = NULL; - - if (check_restricted() || check_secure()) - return; - -#ifdef FEAT_WINDOWS - if (off == 1) - tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); - else - tp = curtab; -#endif - win = find_win_by_nr(&argvars[off], tp); - varname = get_tv_string_chk(&argvars[off + 1]); - varp = &argvars[off + 2]; - - if (win != NULL && varname != NULL && varp != NULL) - { -#ifdef FEAT_WINDOWS - need_switch_win = !(tp == curtab && win == curwin); - if (!need_switch_win - || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) -#endif - { - if (*varname == '&') - { - long numval; - char_u *strval; - int error = FALSE; - - ++varname; - numval = (long)get_tv_number_chk(varp, &error); - strval = get_tv_string_buf_chk(varp, nbuf); - if (!error && strval != NULL) - set_option_value(varname, numval, strval, OPT_LOCAL); - } - else - { - winvarname = alloc((unsigned)STRLEN(varname) + 3); - if (winvarname != NULL) - { - STRCPY(winvarname, "w:"); - STRCPY(winvarname + 2, varname); - set_var(winvarname, varp, TRUE); - vim_free(winvarname); - } - } - } -#ifdef FEAT_WINDOWS - if (need_switch_win) - restore_win(save_curwin, save_curtab, TRUE); -#endif - } -} - -#ifdef FEAT_CRYPT -/* - * "sha256({string})" function - */ - static void -f_sha256(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - - p = get_tv_string(&argvars[0]); - rettv->vval.v_string = vim_strsave( - sha256_bytes(p, (int)STRLEN(p), NULL, 0)); - rettv->v_type = VAR_STRING; -} -#endif /* FEAT_CRYPT */ - -/* - * "shellescape({string})" function - */ - static void -f_shellescape(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_string = vim_strsave_shellescape( - get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE); - rettv->v_type = VAR_STRING; -} - -/* - * shiftwidth() function - */ - static void -f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = get_sw_value(curbuf); -} - -/* - * "simplify()" function - */ - static void -f_simplify(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - - p = get_tv_string(&argvars[0]); - rettv->vval.v_string = vim_strsave(p); - simplify_filename(rettv->vval.v_string); /* simplify in place */ - rettv->v_type = VAR_STRING; -} - -#ifdef FEAT_FLOAT -/* - * "sin()" function - */ - static void -f_sin(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sin(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "sinh()" function - */ - static void -f_sinh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sinh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -static int -#ifdef __BORLANDC__ - _RTLENTRYF -#endif - item_compare(const void *s1, const void *s2); -static int -#ifdef __BORLANDC__ - _RTLENTRYF -#endif - item_compare2(const void *s1, const void *s2); - -/* struct used in the array that's given to qsort() */ -typedef struct -{ - listitem_T *item; - int idx; -} sortItem_T; - -/* struct storing information about current sort */ -typedef struct -{ - int item_compare_ic; - int item_compare_numeric; - int item_compare_numbers; -#ifdef FEAT_FLOAT - int item_compare_float; -#endif - char_u *item_compare_func; - partial_T *item_compare_partial; - dict_T *item_compare_selfdict; - int item_compare_func_err; - int item_compare_keep_zero; -} sortinfo_T; -static sortinfo_T *sortinfo = NULL; -static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort); -#define ITEM_COMPARE_FAIL 999 - -/* - * Compare functions for f_sort() and f_uniq() below. - */ - static int -#ifdef __BORLANDC__ -_RTLENTRYF -#endif -item_compare(const void *s1, const void *s2) -{ - sortItem_T *si1, *si2; - typval_T *tv1, *tv2; - char_u *p1, *p2; - char_u *tofree1 = NULL, *tofree2 = NULL; - int res; - char_u numbuf1[NUMBUFLEN]; - char_u numbuf2[NUMBUFLEN]; - - si1 = (sortItem_T *)s1; - si2 = (sortItem_T *)s2; - tv1 = &si1->item->li_tv; - tv2 = &si2->item->li_tv; - - if (sortinfo->item_compare_numbers) - { - varnumber_T v1 = get_tv_number(tv1); - varnumber_T v2 = get_tv_number(tv2); - - return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; - } - -#ifdef FEAT_FLOAT - if (sortinfo->item_compare_float) - { - float_T v1 = get_tv_float(tv1); - float_T v2 = get_tv_float(tv2); - - return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; - } -#endif - - /* tv2string() puts quotes around a string and allocates memory. Don't do - * that for string variables. Use a single quote when comparing with a - * non-string to do what the docs promise. */ - if (tv1->v_type == VAR_STRING) - { - if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) - p1 = (char_u *)"'"; - else - p1 = tv1->vval.v_string; - } - else - p1 = tv2string(tv1, &tofree1, numbuf1, 0); - if (tv2->v_type == VAR_STRING) - { - if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) - p2 = (char_u *)"'"; - else - p2 = tv2->vval.v_string; - } - else - p2 = tv2string(tv2, &tofree2, numbuf2, 0); - if (p1 == NULL) - p1 = (char_u *)""; - if (p2 == NULL) - p2 = (char_u *)""; - if (!sortinfo->item_compare_numeric) - { - if (sortinfo->item_compare_ic) - res = STRICMP(p1, p2); - else - res = STRCMP(p1, p2); - } - else - { - double n1, n2; - n1 = strtod((char *)p1, (char **)&p1); - n2 = strtod((char *)p2, (char **)&p2); - res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; - } - - /* When the result would be zero, compare the item indexes. Makes the - * sort stable. */ - if (res == 0 && !sortinfo->item_compare_keep_zero) - res = si1->idx > si2->idx ? 1 : -1; - - vim_free(tofree1); - vim_free(tofree2); - return res; -} - - static int -#ifdef __BORLANDC__ -_RTLENTRYF -#endif -item_compare2(const void *s1, const void *s2) -{ - sortItem_T *si1, *si2; - int res; - typval_T rettv; - typval_T argv[3]; - int dummy; - char_u *func_name; - partial_T *partial = sortinfo->item_compare_partial; - - /* shortcut after failure in previous call; compare all items equal */ - if (sortinfo->item_compare_func_err) - return 0; - - si1 = (sortItem_T *)s1; - si2 = (sortItem_T *)s2; - - if (partial == NULL) - func_name = sortinfo->item_compare_func; - else - func_name = partial->pt_name; - - /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED - * in the copy without changing the original list items. */ - copy_tv(&si1->item->li_tv, &argv[0]); - copy_tv(&si2->item->li_tv, &argv[1]); - - rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ - res = call_func(func_name, (int)STRLEN(func_name), - &rettv, 2, argv, 0L, 0L, &dummy, TRUE, - partial, sortinfo->item_compare_selfdict); - clear_tv(&argv[0]); - clear_tv(&argv[1]); - - if (res == FAIL) - res = ITEM_COMPARE_FAIL; - else - res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err); - if (sortinfo->item_compare_func_err) - res = ITEM_COMPARE_FAIL; /* return value has wrong type */ - clear_tv(&rettv); - - /* When the result would be zero, compare the pointers themselves. Makes - * the sort stable. */ - if (res == 0 && !sortinfo->item_compare_keep_zero) - res = si1->idx > si2->idx ? 1 : -1; - - return res; -} - -/* - * "sort({list})" function - */ - static void -do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) -{ - list_T *l; - listitem_T *li; - sortItem_T *ptrs; - sortinfo_T *old_sortinfo; - sortinfo_T info; - long len; - long i; - - /* Pointer to current info struct used in compare function. Save and - * restore the current one for nested calls. */ - old_sortinfo = sortinfo; - sortinfo = &info; - - if (argvars[0].v_type != VAR_LIST) - EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); - else - { - l = argvars[0].vval.v_list; - if (l == NULL || tv_check_lock(l->lv_lock, - (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), - TRUE)) - goto theend; - rettv->vval.v_list = l; - rettv->v_type = VAR_LIST; - ++l->lv_refcount; - - len = list_len(l); - if (len <= 1) - goto theend; /* short list sorts pretty quickly */ - - info.item_compare_ic = FALSE; - info.item_compare_numeric = FALSE; - info.item_compare_numbers = FALSE; -#ifdef FEAT_FLOAT - info.item_compare_float = FALSE; -#endif - info.item_compare_func = NULL; - info.item_compare_partial = NULL; - info.item_compare_selfdict = NULL; - if (argvars[1].v_type != VAR_UNKNOWN) - { - /* optional second argument: {func} */ - if (argvars[1].v_type == VAR_FUNC) - info.item_compare_func = argvars[1].vval.v_string; - else if (argvars[1].v_type == VAR_PARTIAL) - info.item_compare_partial = argvars[1].vval.v_partial; - else - { - int error = FALSE; - - i = (long)get_tv_number_chk(&argvars[1], &error); - if (error) - goto theend; /* type error; errmsg already given */ - if (i == 1) - info.item_compare_ic = TRUE; - else if (argvars[1].v_type != VAR_NUMBER) - info.item_compare_func = get_tv_string(&argvars[1]); - else if (i != 0) - { - EMSG(_(e_invarg)); - goto theend; - } - if (info.item_compare_func != NULL) - { - if (*info.item_compare_func == NUL) - { - /* empty string means default sort */ - info.item_compare_func = NULL; - } - else if (STRCMP(info.item_compare_func, "n") == 0) - { - info.item_compare_func = NULL; - info.item_compare_numeric = TRUE; - } - else if (STRCMP(info.item_compare_func, "N") == 0) - { - info.item_compare_func = NULL; - info.item_compare_numbers = TRUE; - } -#ifdef FEAT_FLOAT - else if (STRCMP(info.item_compare_func, "f") == 0) - { - info.item_compare_func = NULL; - info.item_compare_float = TRUE; - } -#endif - else if (STRCMP(info.item_compare_func, "i") == 0) - { - info.item_compare_func = NULL; - info.item_compare_ic = TRUE; - } - } - } - - if (argvars[2].v_type != VAR_UNKNOWN) - { - /* optional third argument: {dict} */ - if (argvars[2].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - goto theend; - } - info.item_compare_selfdict = argvars[2].vval.v_dict; - } - } - - /* Make an array with each entry pointing to an item in the List. */ - ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T))); - if (ptrs == NULL) - goto theend; - - i = 0; - if (sort) - { - /* sort(): ptrs will be the list to sort */ - for (li = l->lv_first; li != NULL; li = li->li_next) - { - ptrs[i].item = li; - ptrs[i].idx = i; - ++i; - } - - info.item_compare_func_err = FALSE; - info.item_compare_keep_zero = FALSE; - /* test the compare function */ - if ((info.item_compare_func != NULL - || info.item_compare_partial != NULL) - && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) - == ITEM_COMPARE_FAIL) - EMSG(_("E702: Sort compare function failed")); - else - { - /* Sort the array with item pointers. */ - qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), - info.item_compare_func == NULL - && info.item_compare_partial == NULL - ? item_compare : item_compare2); - - if (!info.item_compare_func_err) - { - /* Clear the List and append the items in sorted order. */ - l->lv_first = l->lv_last = l->lv_idx_item = NULL; - l->lv_len = 0; - for (i = 0; i < len; ++i) - list_append(l, ptrs[i].item); - } - } - } - else - { - int (*item_compare_func_ptr)(const void *, const void *); - - /* f_uniq(): ptrs will be a stack of items to remove */ - info.item_compare_func_err = FALSE; - info.item_compare_keep_zero = TRUE; - item_compare_func_ptr = info.item_compare_func != NULL - || info.item_compare_partial != NULL - ? item_compare2 : item_compare; - - for (li = l->lv_first; li != NULL && li->li_next != NULL; - li = li->li_next) - { - if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) - == 0) - ptrs[i++].item = li; - if (info.item_compare_func_err) - { - EMSG(_("E882: Uniq compare function failed")); - break; - } - } - - if (!info.item_compare_func_err) - { - while (--i >= 0) - { - li = ptrs[i].item->li_next; - ptrs[i].item->li_next = li->li_next; - if (li->li_next != NULL) - li->li_next->li_prev = ptrs[i].item; - else - l->lv_last = ptrs[i].item; - list_fix_watch(l, li); - listitem_free(li); - l->lv_len--; - } - } - } - - vim_free(ptrs); - } -theend: - sortinfo = old_sortinfo; -} - -/* - * "sort({list})" function - */ - static void -f_sort(typval_T *argvars, typval_T *rettv) -{ - do_sort_uniq(argvars, rettv, TRUE); -} - -/* - * "uniq({list})" function - */ - static void -f_uniq(typval_T *argvars, typval_T *rettv) -{ - do_sort_uniq(argvars, rettv, FALSE); -} - -/* - * "soundfold({word})" function - */ - static void -f_soundfold(typval_T *argvars, typval_T *rettv) -{ - char_u *s; - - rettv->v_type = VAR_STRING; - s = get_tv_string(&argvars[0]); -#ifdef FEAT_SPELL - rettv->vval.v_string = eval_soundfold(s); -#else - rettv->vval.v_string = vim_strsave(s); -#endif -} - -/* - * "spellbadword()" function - */ - static void -f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u *word = (char_u *)""; - hlf_T attr = HLF_COUNT; - int len = 0; - - if (rettv_list_alloc(rettv) == FAIL) - return; - -#ifdef FEAT_SPELL - if (argvars[0].v_type == VAR_UNKNOWN) - { - /* Find the start and length of the badly spelled word. */ - len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); - if (len != 0) - word = ml_get_cursor(); - } - else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) - { - char_u *str = get_tv_string_chk(&argvars[0]); - int capcol = -1; - - if (str != NULL) - { - /* Check the argument for spelling. */ - while (*str != NUL) - { - len = spell_check(curwin, str, &attr, &capcol, FALSE); - if (attr != HLF_COUNT) - { - word = str; - break; - } - str += len; - } - } - } -#endif - - list_append_string(rettv->vval.v_list, word, len); - list_append_string(rettv->vval.v_list, (char_u *)( - attr == HLF_SPB ? "bad" : - attr == HLF_SPR ? "rare" : - attr == HLF_SPL ? "local" : - attr == HLF_SPC ? "caps" : - ""), -1); -} - -/* - * "spellsuggest()" function - */ - static void -f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_SPELL - char_u *str; - int typeerr = FALSE; - int maxcount; - garray_T ga; - int i; - listitem_T *li; - int need_capital = FALSE; -#endif - - if (rettv_list_alloc(rettv) == FAIL) - return; - -#ifdef FEAT_SPELL - if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) - { - str = get_tv_string(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN) - { - maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr); - if (maxcount <= 0) - return; - if (argvars[2].v_type != VAR_UNKNOWN) - { - need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr); - if (typeerr) - return; - } - } - else - maxcount = 25; - - spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); - - for (i = 0; i < ga.ga_len; ++i) - { - str = ((char_u **)ga.ga_data)[i]; - - li = listitem_alloc(); - if (li == NULL) - vim_free(str); - else - { - li->li_tv.v_type = VAR_STRING; - li->li_tv.v_lock = 0; - li->li_tv.vval.v_string = str; - list_append(rettv->vval.v_list, li); - } - } - ga_clear(&ga); - } -#endif -} - - static void -f_split(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - char_u *end; - char_u *pat = NULL; - regmatch_T regmatch; - char_u patbuf[NUMBUFLEN]; - char_u *save_cpo; - int match; - colnr_T col = 0; - int keepempty = FALSE; - int typeerr = FALSE; - - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ - save_cpo = p_cpo; - p_cpo = (char_u *)""; - - str = get_tv_string(&argvars[0]); - if (argvars[1].v_type != VAR_UNKNOWN) - { - pat = get_tv_string_buf_chk(&argvars[1], patbuf); - if (pat == NULL) - typeerr = TRUE; - if (argvars[2].v_type != VAR_UNKNOWN) - keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr); - } - if (pat == NULL || *pat == NUL) - pat = (char_u *)"[\\x01- ]\\+"; - - if (rettv_list_alloc(rettv) == FAIL) - return; - if (typeerr) - return; - - regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); - if (regmatch.regprog != NULL) - { - regmatch.rm_ic = FALSE; - while (*str != NUL || keepempty) - { - if (*str == NUL) - match = FALSE; /* empty item at the end */ - else - match = vim_regexec_nl(®match, str, col); - if (match) - end = regmatch.startp[0]; - else - end = str + STRLEN(str); - if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 - && *str != NUL && match && end < regmatch.endp[0])) - { - if (list_append_string(rettv->vval.v_list, str, - (int)(end - str)) == FAIL) - break; - } - if (!match) - break; - /* Advance to just after the match. */ - if (regmatch.endp[0] > str) - col = 0; - else - { - /* Don't get stuck at the same match. */ -#ifdef FEAT_MBYTE - col = (*mb_ptr2len)(regmatch.endp[0]); -#else - col = 1; -#endif - } - str = regmatch.endp[0]; - } - - vim_regfree(regmatch.regprog); - } - - p_cpo = save_cpo; -} - -#ifdef FEAT_FLOAT -/* - * "sqrt()" function - */ - static void -f_sqrt(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = sqrt(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "str2float()" function - */ - static void -f_str2float(typval_T *argvars, typval_T *rettv) -{ - char_u *p = skipwhite(get_tv_string(&argvars[0])); - - if (*p == '+') - p = skipwhite(p + 1); - (void)string2float(p, &rettv->vval.v_float); - rettv->v_type = VAR_FLOAT; -} -#endif - -/* - * "str2nr()" function - */ - static void -f_str2nr(typval_T *argvars, typval_T *rettv) -{ - int base = 10; - char_u *p; - varnumber_T n; - int what; - - if (argvars[1].v_type != VAR_UNKNOWN) - { - base = (int)get_tv_number(&argvars[1]); - if (base != 2 && base != 8 && base != 10 && base != 16) - { - EMSG(_(e_invarg)); - return; - } - } - - p = skipwhite(get_tv_string(&argvars[0])); - if (*p == '+') - p = skipwhite(p + 1); - switch (base) - { - case 2: what = STR2NR_BIN + STR2NR_FORCE; break; - case 8: what = STR2NR_OCT + STR2NR_FORCE; break; - case 16: what = STR2NR_HEX + STR2NR_FORCE; break; - default: what = 0; - } - vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); - rettv->vval.v_number = n; -} - -#ifdef HAVE_STRFTIME -/* - * "strftime({format}[, {time}])" function - */ - static void -f_strftime(typval_T *argvars, typval_T *rettv) -{ - char_u result_buf[256]; - struct tm *curtime; - time_t seconds; - char_u *p; - - rettv->v_type = VAR_STRING; - - p = get_tv_string(&argvars[0]); - if (argvars[1].v_type == VAR_UNKNOWN) - seconds = time(NULL); - else - seconds = (time_t)get_tv_number(&argvars[1]); - curtime = localtime(&seconds); - /* MSVC returns NULL for an invalid value of seconds. */ - if (curtime == NULL) - rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); - else - { -# ifdef FEAT_MBYTE - vimconv_T conv; - char_u *enc; - - conv.vc_type = CONV_NONE; - enc = enc_locale(); - convert_setup(&conv, p_enc, enc); - if (conv.vc_type != CONV_NONE) - p = string_convert(&conv, p, NULL); -# endif - if (p != NULL) - (void)strftime((char *)result_buf, sizeof(result_buf), - (char *)p, curtime); - else - result_buf[0] = NUL; - -# ifdef FEAT_MBYTE - if (conv.vc_type != CONV_NONE) - vim_free(p); - convert_setup(&conv, enc, p_enc); - if (conv.vc_type != CONV_NONE) - rettv->vval.v_string = string_convert(&conv, result_buf, NULL); - else -# endif - rettv->vval.v_string = vim_strsave(result_buf); - -# ifdef FEAT_MBYTE - /* Release conversion descriptors */ - convert_setup(&conv, NULL, NULL); - vim_free(enc); -# endif - } -} -#endif - -/* - * "strgetchar()" function - */ - static void -f_strgetchar(typval_T *argvars, typval_T *rettv) -{ - char_u *str; - int len; - int error = FALSE; - int charidx; - - rettv->vval.v_number = -1; - str = get_tv_string_chk(&argvars[0]); - if (str == NULL) - return; - len = (int)STRLEN(str); - charidx = (int)get_tv_number_chk(&argvars[1], &error); - if (error) - return; -#ifdef FEAT_MBYTE - { - int byteidx = 0; - - while (charidx >= 0 && byteidx < len) - { - if (charidx == 0) - { - rettv->vval.v_number = mb_ptr2char(str + byteidx); - break; - } - --charidx; - byteidx += mb_cptr2len(str + byteidx); - } - } -#else - if (charidx < len) - rettv->vval.v_number = str[charidx]; -#endif -} - -/* - * "stridx()" function - */ - static void -f_stridx(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - char_u *needle; - char_u *haystack; - char_u *save_haystack; - char_u *pos; - int start_idx; - - needle = get_tv_string_chk(&argvars[1]); - save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf); - rettv->vval.v_number = -1; - if (needle == NULL || haystack == NULL) - return; /* type error; errmsg already given */ - - if (argvars[2].v_type != VAR_UNKNOWN) - { - int error = FALSE; - - start_idx = (int)get_tv_number_chk(&argvars[2], &error); - if (error || start_idx >= (int)STRLEN(haystack)) - return; - if (start_idx >= 0) - haystack += start_idx; - } - - pos = (char_u *)strstr((char *)haystack, (char *)needle); - if (pos != NULL) - rettv->vval.v_number = (varnumber_T)(pos - save_haystack); -} - -/* - * "string()" function - */ - static void -f_string(typval_T *argvars, typval_T *rettv) -{ - char_u *tofree; - char_u numbuf[NUMBUFLEN]; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, - get_copyID()); - /* Make a copy if we have a value but it's not in allocated memory. */ - if (rettv->vval.v_string != NULL && tofree == NULL) - rettv->vval.v_string = vim_strsave(rettv->vval.v_string); -} - -/* - * "strlen()" function - */ - static void -f_strlen(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = (varnumber_T)(STRLEN( - get_tv_string(&argvars[0]))); -} - -/* - * "strchars()" function - */ - static void -f_strchars(typval_T *argvars, typval_T *rettv) -{ - char_u *s = get_tv_string(&argvars[0]); - int skipcc = 0; -#ifdef FEAT_MBYTE - varnumber_T len = 0; - int (*func_mb_ptr2char_adv)(char_u **pp); -#endif - - if (argvars[1].v_type != VAR_UNKNOWN) - skipcc = (int)get_tv_number_chk(&argvars[1], NULL); - if (skipcc < 0 || skipcc > 1) - EMSG(_(e_invarg)); - else - { -#ifdef FEAT_MBYTE - func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; - while (*s != NUL) - { - func_mb_ptr2char_adv(&s); - ++len; - } - rettv->vval.v_number = len; -#else - rettv->vval.v_number = (varnumber_T)(STRLEN(s)); -#endif - } -} - -/* - * "strdisplaywidth()" function - */ - static void -f_strdisplaywidth(typval_T *argvars, typval_T *rettv) -{ - char_u *s = get_tv_string(&argvars[0]); - int col = 0; - - if (argvars[1].v_type != VAR_UNKNOWN) - col = (int)get_tv_number(&argvars[1]); - - rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); -} - -/* - * "strwidth()" function - */ - static void -f_strwidth(typval_T *argvars, typval_T *rettv) -{ - char_u *s = get_tv_string(&argvars[0]); - - rettv->vval.v_number = (varnumber_T)( -#ifdef FEAT_MBYTE - mb_string2cells(s, -1) -#else - STRLEN(s) -#endif - ); -} - -/* - * "strcharpart()" function - */ - static void -f_strcharpart(typval_T *argvars, typval_T *rettv) -{ -#ifdef FEAT_MBYTE - char_u *p; - int nchar; - int nbyte = 0; - int charlen; - int len = 0; - int slen; - int error = FALSE; - - p = get_tv_string(&argvars[0]); - slen = (int)STRLEN(p); - - nchar = (int)get_tv_number_chk(&argvars[1], &error); - if (!error) - { - if (nchar > 0) - while (nchar > 0 && nbyte < slen) - { - nbyte += mb_cptr2len(p + nbyte); - --nchar; - } - else - nbyte = nchar; - if (argvars[2].v_type != VAR_UNKNOWN) - { - charlen = (int)get_tv_number(&argvars[2]); - while (charlen > 0 && nbyte + len < slen) - { - int off = nbyte + len; - - if (off < 0) - len += 1; - else - len += mb_cptr2len(p + off); - --charlen; - } - } - else - len = slen - nbyte; /* default: all bytes that are available. */ - } - - /* - * Only return the overlap between the specified part and the actual - * string. - */ - if (nbyte < 0) - { - len += nbyte; - nbyte = 0; - } - else if (nbyte > slen) - nbyte = slen; - if (len < 0) - len = 0; - else if (nbyte + len > slen) - len = slen - nbyte; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strnsave(p + nbyte, len); -#else - f_strpart(argvars, rettv); -#endif -} - -/* - * "strpart()" function - */ - static void -f_strpart(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - int n; - int len; - int slen; - int error = FALSE; - - p = get_tv_string(&argvars[0]); - slen = (int)STRLEN(p); - - n = (int)get_tv_number_chk(&argvars[1], &error); - if (error) - len = 0; - else if (argvars[2].v_type != VAR_UNKNOWN) - len = (int)get_tv_number(&argvars[2]); - else - len = slen - n; /* default len: all bytes that are available. */ - - /* - * Only return the overlap between the specified part and the actual - * string. - */ - if (n < 0) - { - len += n; - n = 0; - } - else if (n > slen) - n = slen; - if (len < 0) - len = 0; - else if (n + len > slen) - len = slen - n; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_strnsave(p + n, len); -} - -/* - * "strridx()" function - */ - static void -f_strridx(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - char_u *needle; - char_u *haystack; - char_u *rest; - char_u *lastmatch = NULL; - int haystack_len, end_idx; - - needle = get_tv_string_chk(&argvars[1]); - haystack = get_tv_string_buf_chk(&argvars[0], buf); - - rettv->vval.v_number = -1; - if (needle == NULL || haystack == NULL) - return; /* type error; errmsg already given */ - - haystack_len = (int)STRLEN(haystack); - if (argvars[2].v_type != VAR_UNKNOWN) - { - /* Third argument: upper limit for index */ - end_idx = (int)get_tv_number_chk(&argvars[2], NULL); - if (end_idx < 0) - return; /* can never find a match */ - } - else - end_idx = haystack_len; - - if (*needle == NUL) - { - /* Empty string matches past the end. */ - lastmatch = haystack + end_idx; - } - else - { - for (rest = haystack; *rest != '\0'; ++rest) - { - rest = (char_u *)strstr((char *)rest, (char *)needle); - if (rest == NULL || rest > haystack + end_idx) - break; - lastmatch = rest; - } - } - - if (lastmatch == NULL) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); -} - -/* - * "strtrans()" function - */ - static void -f_strtrans(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = transstr(get_tv_string(&argvars[0])); -} - -/* - * "submatch()" function - */ - static void -f_submatch(typval_T *argvars, typval_T *rettv) -{ - int error = FALSE; - int no; - int retList = 0; - - no = (int)get_tv_number_chk(&argvars[0], &error); - if (error) - return; - error = FALSE; - if (argvars[1].v_type != VAR_UNKNOWN) - retList = (int)get_tv_number_chk(&argvars[1], &error); - if (error) - return; - - if (retList == 0) - { - rettv->v_type = VAR_STRING; - rettv->vval.v_string = reg_submatch(no); - } - else - { - rettv->v_type = VAR_LIST; - rettv->vval.v_list = reg_submatch_list(no); - } -} - -/* - * "substitute()" function - */ - static void -f_substitute(typval_T *argvars, typval_T *rettv) -{ - char_u patbuf[NUMBUFLEN]; - char_u subbuf[NUMBUFLEN]; - char_u flagsbuf[NUMBUFLEN]; - - char_u *str = get_tv_string_chk(&argvars[0]); - char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); - char_u *sub = get_tv_string_buf_chk(&argvars[2], subbuf); - char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); - - rettv->v_type = VAR_STRING; - if (str == NULL || pat == NULL || sub == NULL || flg == NULL) - rettv->vval.v_string = NULL; - else - rettv->vval.v_string = do_string_sub(str, pat, sub, flg); -} - -/* - * "synID(lnum, col, trans)" function - */ - static void -f_synID(typval_T *argvars UNUSED, typval_T *rettv) -{ - int id = 0; -#ifdef FEAT_SYN_HL - linenr_T lnum; - colnr_T col; - int trans; - int transerr = FALSE; - - lnum = get_tv_lnum(argvars); /* -1 on type error */ - col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ - trans = (int)get_tv_number_chk(&argvars[2], &transerr); - - if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && col < (long)STRLEN(ml_get(lnum))) - id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); -#endif - - rettv->vval.v_number = id; -} - -/* - * "synIDattr(id, what [, mode])" function - */ - static void -f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u *p = NULL; -#ifdef FEAT_SYN_HL - int id; - char_u *what; - char_u *mode; - char_u modebuf[NUMBUFLEN]; - int modec; - - id = (int)get_tv_number(&argvars[0]); - what = get_tv_string(&argvars[1]); - if (argvars[2].v_type != VAR_UNKNOWN) - { - mode = get_tv_string_buf(&argvars[2], modebuf); - modec = TOLOWER_ASC(mode[0]); - if (modec != 't' && modec != 'c' && modec != 'g') - modec = 0; /* replace invalid with current */ - } - else - { -#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) - if (USE_24BIT) - modec = 'g'; - else -#endif - if (t_colors > 1) - modec = 'c'; - else - modec = 't'; - } - - - switch (TOLOWER_ASC(what[0])) - { - case 'b': - if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */ - p = highlight_color(id, what, modec); - else /* bold */ - p = highlight_has_attr(id, HL_BOLD, modec); - break; - - case 'f': /* fg[#] or font */ - p = highlight_color(id, what, modec); - break; - - case 'i': - if (TOLOWER_ASC(what[1]) == 'n') /* inverse */ - p = highlight_has_attr(id, HL_INVERSE, modec); - else /* italic */ - p = highlight_has_attr(id, HL_ITALIC, modec); - break; - - case 'n': /* name */ - p = get_highlight_name(NULL, id - 1); - break; - - case 'r': /* reverse */ - p = highlight_has_attr(id, HL_INVERSE, modec); - break; - - case 's': - if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ - p = highlight_color(id, what, modec); - else /* standout */ - p = highlight_has_attr(id, HL_STANDOUT, modec); - break; - - case 'u': - if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') - /* underline */ - p = highlight_has_attr(id, HL_UNDERLINE, modec); - else - /* undercurl */ - p = highlight_has_attr(id, HL_UNDERCURL, modec); - break; - } - - if (p != NULL) - p = vim_strsave(p); -#endif - rettv->v_type = VAR_STRING; - rettv->vval.v_string = p; -} - -/* - * "synIDtrans(id)" function - */ - static void -f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) -{ - int id; - -#ifdef FEAT_SYN_HL - id = (int)get_tv_number(&argvars[0]); - - if (id > 0) - id = syn_get_final_id(id); - else -#endif - id = 0; - - rettv->vval.v_number = id; -} - -/* - * "synconcealed(lnum, col)" function - */ - static void -f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) -{ -#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) - linenr_T lnum; - colnr_T col; - int syntax_flags = 0; - int cchar; - int matchid = 0; - char_u str[NUMBUFLEN]; -#endif - - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; - -#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) - lnum = get_tv_lnum(argvars); /* -1 on type error */ - col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ - - vim_memset(str, NUL, sizeof(str)); - - if (rettv_list_alloc(rettv) != FAIL) - { - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) - && curwin->w_p_cole > 0) - { - (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); - syntax_flags = get_syntax_info(&matchid); - - /* get the conceal character */ - if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) - { - cchar = syn_get_sub_char(); - if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL) - cchar = lcs_conceal; - if (cchar != NUL) - { -# ifdef FEAT_MBYTE - if (has_mbyte) - (*mb_char2bytes)(cchar, str); - else -# endif - str[0] = cchar; - } - } - } - - list_append_number(rettv->vval.v_list, - (syntax_flags & HL_CONCEAL) != 0); - /* -1 to auto-determine strlen */ - list_append_string(rettv->vval.v_list, str, -1); - list_append_number(rettv->vval.v_list, matchid); - } -#endif -} - -/* - * "synstack(lnum, col)" function - */ - static void -f_synstack(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_SYN_HL - linenr_T lnum; - colnr_T col; - int i; - int id; -#endif - - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; - -#ifdef FEAT_SYN_HL - lnum = get_tv_lnum(argvars); /* -1 on type error */ - col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ - - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) - && rettv_list_alloc(rettv) != FAIL) - { - (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); - for (i = 0; ; ++i) - { - id = syn_get_stack_item(i); - if (id < 0) - break; - if (list_append_number(rettv->vval.v_list, id) == FAIL) - break; - } - } -#endif -} - - static void -get_cmd_output_as_rettv( - typval_T *argvars, - typval_T *rettv, - int retlist) -{ - char_u *res = NULL; - char_u *p; - char_u *infile = NULL; - char_u buf[NUMBUFLEN]; - int err = FALSE; - FILE *fd; - list_T *list = NULL; - int flags = SHELL_SILENT; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - if (check_restricted() || check_secure()) - goto errret; - - if (argvars[1].v_type != VAR_UNKNOWN) - { - /* - * Write the string to a temp file, to be used for input of the shell - * command. - */ - if ((infile = vim_tempname('i', TRUE)) == NULL) - { - EMSG(_(e_notmp)); - goto errret; - } - - fd = mch_fopen((char *)infile, WRITEBIN); - if (fd == NULL) - { - EMSG2(_(e_notopen), infile); - goto errret; - } - if (argvars[1].v_type == VAR_LIST) - { - if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL) - err = TRUE; - } - else - { - size_t len; - - p = get_tv_string_buf_chk(&argvars[1], buf); - if (p == NULL) - { - fclose(fd); - goto errret; /* type error; errmsg already given */ - } - len = STRLEN(p); - if (len > 0 && fwrite(p, len, 1, fd) != 1) - err = TRUE; - } - if (fclose(fd) != 0) - err = TRUE; - if (err) - { - EMSG(_("E677: Error writing temp file")); - goto errret; - } - } - - /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell - * echoes typeahead, that messes up the display. */ - if (!msg_silent) - flags += SHELL_COOKED; - - if (retlist) - { - int len; - listitem_T *li; - char_u *s = NULL; - char_u *start; - char_u *end; - int i; - - res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len); - if (res == NULL) - goto errret; - - list = list_alloc(); - if (list == NULL) - goto errret; - - for (i = 0; i < len; ++i) - { - start = res + i; - while (i < len && res[i] != NL) - ++i; - end = res + i; - - s = alloc((unsigned)(end - start + 1)); - if (s == NULL) - goto errret; - - for (p = s; start < end; ++p, ++start) - *p = *start == NUL ? NL : *start; - *p = NUL; - - li = listitem_alloc(); - if (li == NULL) - { - vim_free(s); - goto errret; - } - li->li_tv.v_type = VAR_STRING; - li->li_tv.v_lock = 0; - li->li_tv.vval.v_string = s; - list_append(list, li); - } - - ++list->lv_refcount; - rettv->v_type = VAR_LIST; - rettv->vval.v_list = list; - list = NULL; - } - else - { - res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL); -#ifdef USE_CR - /* translate <CR> into <NL> */ - if (res != NULL) - { - char_u *s; - - for (s = res; *s; ++s) - { - if (*s == CAR) - *s = NL; - } - } -#else -# ifdef USE_CRNL - /* translate <CR><NL> into <NL> */ - if (res != NULL) - { - char_u *s, *d; - - d = res; - for (s = res; *s; ++s) - { - if (s[0] == CAR && s[1] == NL) - ++s; - *d++ = *s; - } - *d = NUL; - } -# endif -#endif - rettv->vval.v_string = res; - res = NULL; - } - -errret: - if (infile != NULL) - { - mch_remove(infile); - vim_free(infile); - } - if (res != NULL) - vim_free(res); - if (list != NULL) - list_free(list); -} - -/* - * "system()" function - */ - static void -f_system(typval_T *argvars, typval_T *rettv) -{ - get_cmd_output_as_rettv(argvars, rettv, FALSE); -} - -/* - * "systemlist()" function - */ - static void -f_systemlist(typval_T *argvars, typval_T *rettv) -{ - get_cmd_output_as_rettv(argvars, rettv, TRUE); -} - -/* - * "tabpagebuflist()" function - */ - static void -f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_WINDOWS - tabpage_T *tp; - win_T *wp = NULL; - - if (argvars[0].v_type == VAR_UNKNOWN) - wp = firstwin; - else - { - tp = find_tabpage((int)get_tv_number(&argvars[0])); - if (tp != NULL) - wp = (tp == curtab) ? firstwin : tp->tp_firstwin; - } - if (wp != NULL && rettv_list_alloc(rettv) != FAIL) - { - for (; wp != NULL; wp = wp->w_next) - if (list_append_number(rettv->vval.v_list, - wp->w_buffer->b_fnum) == FAIL) - break; - } -#endif -} - - -/* - * "tabpagenr()" function - */ - static void -f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) -{ - int nr = 1; -#ifdef FEAT_WINDOWS - char_u *arg; - - if (argvars[0].v_type != VAR_UNKNOWN) - { - arg = get_tv_string_chk(&argvars[0]); - nr = 0; - if (arg != NULL) - { - if (STRCMP(arg, "$") == 0) - nr = tabpage_index(NULL) - 1; - else - EMSG2(_(e_invexpr2), arg); - } - } - else - nr = tabpage_index(curtab); -#endif - rettv->vval.v_number = nr; -} - - -#ifdef FEAT_WINDOWS -static int get_winnr(tabpage_T *tp, typval_T *argvar); - -/* - * Common code for tabpagewinnr() and winnr(). - */ - static int -get_winnr(tabpage_T *tp, typval_T *argvar) -{ - win_T *twin; - int nr = 1; - win_T *wp; - char_u *arg; - - twin = (tp == curtab) ? curwin : tp->tp_curwin; - if (argvar->v_type != VAR_UNKNOWN) - { - arg = get_tv_string_chk(argvar); - if (arg == NULL) - nr = 0; /* type error; errmsg already given */ - else if (STRCMP(arg, "$") == 0) - twin = (tp == curtab) ? lastwin : tp->tp_lastwin; - else if (STRCMP(arg, "#") == 0) - { - twin = (tp == curtab) ? prevwin : tp->tp_prevwin; - if (twin == NULL) - nr = 0; - } - else - { - EMSG2(_(e_invexpr2), arg); - nr = 0; - } - } - - if (nr > 0) - for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; - wp != twin; wp = wp->w_next) - { - if (wp == NULL) - { - /* didn't find it in this tabpage */ - nr = 0; - break; - } - ++nr; - } - return nr; -} -#endif - -/* - * "tabpagewinnr()" function - */ - static void -f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) -{ - int nr = 1; -#ifdef FEAT_WINDOWS - tabpage_T *tp; - - tp = find_tabpage((int)get_tv_number(&argvars[0])); - if (tp == NULL) - nr = 0; - else - nr = get_winnr(tp, &argvars[1]); -#endif - rettv->vval.v_number = nr; -} - - -/* - * "tagfiles()" function - */ - static void -f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) -{ - char_u *fname; - tagname_T tn; - int first; - - if (rettv_list_alloc(rettv) == FAIL) - return; - fname = alloc(MAXPATHL); - if (fname == NULL) - return; - - for (first = TRUE; ; first = FALSE) - if (get_tagfname(&tn, first, fname) == FAIL - || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) - break; - tagname_free(&tn); - vim_free(fname); -} - -/* - * "taglist()" function - */ - static void -f_taglist(typval_T *argvars, typval_T *rettv) -{ - char_u *tag_pattern; - - tag_pattern = get_tv_string(&argvars[0]); - - rettv->vval.v_number = FALSE; - if (*tag_pattern == NUL) - return; - - if (rettv_list_alloc(rettv) == OK) - (void)get_tags(rettv->vval.v_list, tag_pattern); -} - -/* - * "tempname()" function - */ - static void -f_tempname(typval_T *argvars UNUSED, typval_T *rettv) -{ - static int x = 'A'; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = vim_tempname(x, FALSE); - - /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different - * names. Skip 'I' and 'O', they are used for shell redirection. */ - do - { - if (x == 'Z') - x = '0'; - else if (x == '9') - x = 'A'; - else - { -#ifdef EBCDIC - if (x == 'I') - x = 'J'; - else if (x == 'R') - x = 'S'; - else -#endif - ++x; - } - } while (x == 'I' || x == 'O'); -} - -#ifdef FEAT_FLOAT -/* - * "tan()" function - */ - static void -f_tan(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = tan(f); - else - rettv->vval.v_float = 0.0; -} - -/* - * "tanh()" function - */ - static void -f_tanh(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - rettv->vval.v_float = tanh(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "test_alloc_fail(id, countdown, repeat)" function - */ - static void -f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) -{ - if (argvars[0].v_type != VAR_NUMBER - || argvars[0].vval.v_number <= 0 - || argvars[1].v_type != VAR_NUMBER - || argvars[1].vval.v_number < 0 - || argvars[2].v_type != VAR_NUMBER) - EMSG(_(e_invarg)); - else - { - alloc_fail_id = argvars[0].vval.v_number; - if (alloc_fail_id >= aid_last) - EMSG(_(e_invarg)); - alloc_fail_countdown = argvars[1].vval.v_number; - alloc_fail_repeat = argvars[2].vval.v_number; - did_outofmem_msg = FALSE; - } -} - -/* - * "test_autochdir()" - */ - static void -f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#if defined(FEAT_AUTOCHDIR) - test_autochdir = TRUE; -#endif -} - -/* - * "test_disable_char_avail({expr})" function - */ - static void -f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED) -{ - disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]); -} - -/* - * "test_garbagecollect_now()" function - */ - static void -f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ - /* This is dangerous, any Lists and Dicts used internally may be freed - * while still in use. */ - garbage_collect(TRUE); -} - -#ifdef FEAT_JOB_CHANNEL - static void -f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_CHANNEL; - rettv->vval.v_channel = NULL; -} -#endif - - static void -f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_DICT; - rettv->vval.v_dict = NULL; -} - -#ifdef FEAT_JOB_CHANNEL - static void -f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_JOB; - rettv->vval.v_job = NULL; -} -#endif - - static void -f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_LIST; - rettv->vval.v_list = NULL; -} - - static void -f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_PARTIAL; - rettv->vval.v_partial = NULL; -} - - static void -f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -} - - static void -f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) -{ - time_for_testing = (time_t)get_tv_number(&argvars[0]); -} - -#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO) -/* - * Get a callback from "arg". It can be a Funcref or a function name. - * When "arg" is zero return an empty string. - * Return NULL for an invalid argument. - */ - char_u * -get_callback(typval_T *arg, partial_T **pp) -{ - if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) - { - *pp = arg->vval.v_partial; - ++(*pp)->pt_refcount; - return (*pp)->pt_name; - } - *pp = NULL; - if (arg->v_type == VAR_FUNC) - { - func_ref(arg->vval.v_string); - return arg->vval.v_string; - } - if (arg->v_type == VAR_STRING) - return arg->vval.v_string; - if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) - return (char_u *)""; - EMSG(_("E921: Invalid callback argument")); - return NULL; -} - -/* - * Unref/free "callback" and "partial" retured by get_callback(). - */ - void -free_callback(char_u *callback, partial_T *partial) -{ - if (partial != NULL) - partial_unref(partial); - else if (callback != NULL) - { - func_unref(callback); - vim_free(callback); - } -} -#endif - -#ifdef FEAT_TIMERS -/* - * "timer_start(time, callback [, options])" function - */ - static void -f_timer_start(typval_T *argvars, typval_T *rettv) -{ - long msec = (long)get_tv_number(&argvars[0]); - timer_T *timer; - int repeat = 0; - char_u *callback; - dict_T *dict; - - if (check_secure()) - return; - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (argvars[2].v_type != VAR_DICT - || (dict = argvars[2].vval.v_dict) == NULL) - { - EMSG2(_(e_invarg2), get_tv_string(&argvars[2])); - return; - } - if (dict_find(dict, (char_u *)"repeat", -1) != NULL) - repeat = get_dict_number(dict, (char_u *)"repeat"); - } - - timer = create_timer(msec, repeat); - callback = get_callback(&argvars[1], &timer->tr_partial); - if (callback == NULL) - { - stop_timer(timer); - rettv->vval.v_number = -1; - } - else - { - timer->tr_callback = vim_strsave(callback); - rettv->vval.v_number = timer->tr_id; - } -} - -/* - * "timer_stop(timer)" function - */ - static void -f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) -{ - timer_T *timer; - - if (argvars[0].v_type != VAR_NUMBER) - { - EMSG(_(e_number_exp)); - return; - } - timer = find_timer((int)get_tv_number(&argvars[0])); - if (timer != NULL) - stop_timer(timer); -} -#endif - -/* - * "tolower(string)" function - */ - static void -f_tolower(typval_T *argvars, typval_T *rettv) -{ - char_u *p; - - p = vim_strsave(get_tv_string(&argvars[0])); - rettv->v_type = VAR_STRING; - rettv->vval.v_string = p; - - if (p != NULL) - while (*p != NUL) - { -#ifdef FEAT_MBYTE - int l; - - if (enc_utf8) - { - int c, lc; - - c = utf_ptr2char(p); - lc = utf_tolower(c); - l = utf_ptr2len(p); - /* TODO: reallocate string when byte count changes. */ - if (utf_char2len(lc) == l) - utf_char2bytes(lc, p); - p += l; - } - else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) - p += l; /* skip multi-byte character */ - else -#endif - { - *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */ - ++p; - } - } -} - -/* - * "toupper(string)" function - */ - static void -f_toupper(typval_T *argvars, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); -} - -/* - * "tr(string, fromstr, tostr)" function - */ - static void -f_tr(typval_T *argvars, typval_T *rettv) -{ - char_u *in_str; - char_u *fromstr; - char_u *tostr; - char_u *p; -#ifdef FEAT_MBYTE - int inlen; - int fromlen; - int tolen; - int idx; - char_u *cpstr; - int cplen; - int first = TRUE; -#endif - char_u buf[NUMBUFLEN]; - char_u buf2[NUMBUFLEN]; - garray_T ga; - - in_str = get_tv_string(&argvars[0]); - fromstr = get_tv_string_buf_chk(&argvars[1], buf); - tostr = get_tv_string_buf_chk(&argvars[2], buf2); - - /* Default return value: empty string. */ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - if (fromstr == NULL || tostr == NULL) - return; /* type error; errmsg already given */ - ga_init2(&ga, (int)sizeof(char), 80); - -#ifdef FEAT_MBYTE - if (!has_mbyte) -#endif - /* not multi-byte: fromstr and tostr must be the same length */ - if (STRLEN(fromstr) != STRLEN(tostr)) - { -#ifdef FEAT_MBYTE -error: -#endif - EMSG2(_(e_invarg2), fromstr); - ga_clear(&ga); - return; - } - - /* fromstr and tostr have to contain the same number of chars */ - while (*in_str != NUL) - { -#ifdef FEAT_MBYTE - if (has_mbyte) - { - inlen = (*mb_ptr2len)(in_str); - cpstr = in_str; - cplen = inlen; - idx = 0; - for (p = fromstr; *p != NUL; p += fromlen) - { - fromlen = (*mb_ptr2len)(p); - if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) - { - for (p = tostr; *p != NUL; p += tolen) - { - tolen = (*mb_ptr2len)(p); - if (idx-- == 0) - { - cplen = tolen; - cpstr = p; - break; - } - } - if (*p == NUL) /* tostr is shorter than fromstr */ - goto error; - break; - } - ++idx; - } - - if (first && cpstr == in_str) - { - /* Check that fromstr and tostr have the same number of - * (multi-byte) characters. Done only once when a character - * of in_str doesn't appear in fromstr. */ - first = FALSE; - for (p = tostr; *p != NUL; p += tolen) - { - tolen = (*mb_ptr2len)(p); - --idx; - } - if (idx != 0) - goto error; - } - - (void)ga_grow(&ga, cplen); - mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); - ga.ga_len += cplen; - - in_str += inlen; - } - else -#endif - { - /* When not using multi-byte chars we can do it faster. */ - p = vim_strchr(fromstr, *in_str); - if (p != NULL) - ga_append(&ga, tostr[p - fromstr]); - else - ga_append(&ga, *in_str); - ++in_str; - } - } - - /* add a terminating NUL */ - (void)ga_grow(&ga, 1); - ga_append(&ga, NUL); - - rettv->vval.v_string = ga.ga_data; -} - -#ifdef FEAT_FLOAT -/* - * "trunc({float})" function - */ - static void -f_trunc(typval_T *argvars, typval_T *rettv) -{ - float_T f = 0.0; - - rettv->v_type = VAR_FLOAT; - if (get_float_arg(argvars, &f) == OK) - /* trunc() is not in C90, use floor() or ceil() instead. */ - rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); - else - rettv->vval.v_float = 0.0; -} -#endif - -/* - * "type(expr)" function - */ - static void -f_type(typval_T *argvars, typval_T *rettv) -{ - int n = -1; - - switch (argvars[0].v_type) - { - case VAR_NUMBER: n = 0; break; - case VAR_STRING: n = 1; break; - case VAR_PARTIAL: - case VAR_FUNC: n = 2; break; - case VAR_LIST: n = 3; break; - case VAR_DICT: n = 4; break; - case VAR_FLOAT: n = 5; break; - case VAR_SPECIAL: - if (argvars[0].vval.v_number == VVAL_FALSE - || argvars[0].vval.v_number == VVAL_TRUE) - n = 6; - else - n = 7; - break; - case VAR_JOB: n = 8; break; - case VAR_CHANNEL: n = 9; break; - case VAR_UNKNOWN: - EMSG2(_(e_intern2), "f_type(UNKNOWN)"); - n = -1; - break; - } - rettv->vval.v_number = n; -} - -/* - * "undofile(name)" function - */ - static void -f_undofile(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; -#ifdef FEAT_PERSISTENT_UNDO - { - char_u *fname = get_tv_string(&argvars[0]); - - if (*fname == NUL) - { - /* If there is no file name there will be no undo file. */ - rettv->vval.v_string = NULL; - } - else - { - char_u *ffname = FullName_save(fname, FALSE); - - if (ffname != NULL) - rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); - vim_free(ffname); - } - } -#else - rettv->vval.v_string = NULL; -#endif -} - -/* - * "undotree()" function - */ - static void -f_undotree(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (rettv_dict_alloc(rettv) == OK) - { - dict_T *dict = rettv->vval.v_dict; - list_T *list; - - dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL); - dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL); - dict_add_nr_str(dict, "save_last", - (long)curbuf->b_u_save_nr_last, NULL); - dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL); - dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL); - dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL); - - list = list_alloc(); - if (list != NULL) - { - u_eval_tree(curbuf->b_u_oldhead, list); - dict_add_list(dict, "entries", list); - } - } -} - -/* - * "values(dict)" function - */ - static void -f_values(typval_T *argvars, typval_T *rettv) -{ - dict_list(argvars, rettv, 1); -} - -/* - * "virtcol(string)" function - */ - static void -f_virtcol(typval_T *argvars, typval_T *rettv) -{ - colnr_T vcol = 0; - pos_T *fp; - int fnum = curbuf->b_fnum; - - fp = var2fpos(&argvars[0], FALSE, &fnum); - if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count - && fnum == curbuf->b_fnum) - { - getvvcol(curwin, fp, NULL, NULL, &vcol); - ++vcol; - } - - rettv->vval.v_number = vcol; -} - -/* - * "visualmode()" function - */ - static void -f_visualmode(typval_T *argvars, typval_T *rettv) -{ - char_u str[2]; - - rettv->v_type = VAR_STRING; - str[0] = curbuf->b_visual_mode_eval; - str[1] = NUL; - rettv->vval.v_string = vim_strsave(str); - - /* A non-zero number or non-empty string argument: reset mode. */ - if (non_zero_arg(&argvars[0])) - curbuf->b_visual_mode_eval = NUL; -} - -/* - * "wildmenumode()" function - */ - static void -f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_WILDMENU - if (wild_menu_showing) - rettv->vval.v_number = 1; -#endif -} - -/* - * "winbufnr(nr)" function - */ - static void -f_winbufnr(typval_T *argvars, typval_T *rettv) -{ - win_T *wp; - - wp = find_win_by_nr(&argvars[0], NULL); - if (wp == NULL) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = wp->w_buffer->b_fnum; -} - -/* - * "wincol()" function - */ - static void -f_wincol(typval_T *argvars UNUSED, typval_T *rettv) -{ - validate_cursor(); - rettv->vval.v_number = curwin->w_wcol + 1; -} - -/* - * "winheight(nr)" function - */ - static void -f_winheight(typval_T *argvars, typval_T *rettv) -{ - win_T *wp; - - wp = find_win_by_nr(&argvars[0], NULL); - if (wp == NULL) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = wp->w_height; -} - -/* - * "winline()" function - */ - static void -f_winline(typval_T *argvars UNUSED, typval_T *rettv) -{ - validate_cursor(); - rettv->vval.v_number = curwin->w_wrow + 1; -} - -/* - * "winnr()" function - */ - static void -f_winnr(typval_T *argvars UNUSED, typval_T *rettv) -{ - int nr = 1; - -#ifdef FEAT_WINDOWS - nr = get_winnr(curtab, &argvars[0]); -#endif - rettv->vval.v_number = nr; -} - -/* - * "winrestcmd()" function - */ - static void -f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_WINDOWS - win_T *wp; - int winnr = 1; - garray_T ga; - char_u buf[50]; - - ga_init2(&ga, (int)sizeof(char), 70); - for (wp = firstwin; wp != NULL; wp = wp->w_next) - { - sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height); - ga_concat(&ga, buf); - sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width); - ga_concat(&ga, buf); - ++winnr; - } - ga_append(&ga, NUL); - - rettv->vval.v_string = ga.ga_data; -#else - rettv->vval.v_string = NULL; -#endif - rettv->v_type = VAR_STRING; -} - -/* - * "winrestview()" function - */ - static void -f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) -{ - dict_T *dict; - - if (argvars[0].v_type != VAR_DICT - || (dict = argvars[0].vval.v_dict) == NULL) - EMSG(_(e_invarg)); - else - { - if (dict_find(dict, (char_u *)"lnum", -1) != NULL) - curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum"); - if (dict_find(dict, (char_u *)"col", -1) != NULL) - curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col"); -#ifdef FEAT_VIRTUALEDIT - if (dict_find(dict, (char_u *)"coladd", -1) != NULL) - curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd"); -#endif - if (dict_find(dict, (char_u *)"curswant", -1) != NULL) - { - curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant"); - curwin->w_set_curswant = FALSE; - } - - if (dict_find(dict, (char_u *)"topline", -1) != NULL) - set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline")); -#ifdef FEAT_DIFF - if (dict_find(dict, (char_u *)"topfill", -1) != NULL) - curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill"); -#endif - if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) - curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol"); - if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) - curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol"); - - check_cursor(); - win_new_height(curwin, curwin->w_height); -# ifdef FEAT_WINDOWS - win_new_width(curwin, W_WIDTH(curwin)); -# endif - changed_window_setting(); - - if (curwin->w_topline <= 0) - curwin->w_topline = 1; - if (curwin->w_topline > curbuf->b_ml.ml_line_count) - curwin->w_topline = curbuf->b_ml.ml_line_count; -#ifdef FEAT_DIFF - check_topfill(curwin, TRUE); -#endif - } -} - -/* - * "winsaveview()" function - */ - static void -f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) -{ - dict_T *dict; - - if (rettv_dict_alloc(rettv) == FAIL) - return; - dict = rettv->vval.v_dict; - - dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL); - dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL); -#ifdef FEAT_VIRTUALEDIT - dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL); -#endif - update_curswant(); - dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL); - - dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL); -#ifdef FEAT_DIFF - dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL); -#endif - dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL); - dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL); -} - -/* - * "winwidth(nr)" function - */ - static void -f_winwidth(typval_T *argvars, typval_T *rettv) -{ - win_T *wp; - - wp = find_win_by_nr(&argvars[0], NULL); - if (wp == NULL) - rettv->vval.v_number = -1; - else -#ifdef FEAT_WINDOWS - rettv->vval.v_number = wp->w_width; -#else - rettv->vval.v_number = Columns; -#endif -} - -/* - * "wordcount()" function - */ - static void -f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (rettv_dict_alloc(rettv) == FAIL) - return; - cursor_pos_info(rettv->vval.v_dict); -} - -/* - * Write list of strings to file - */ - static int -write_list(FILE *fd, list_T *list, int binary) -{ - listitem_T *li; - int c; - int ret = OK; - char_u *s; - - for (li = list->lv_first; li != NULL; li = li->li_next) - { - for (s = get_tv_string(&li->li_tv); *s != NUL; ++s) - { - if (*s == '\n') - c = putc(NUL, fd); - else - c = putc(*s, fd); - if (c == EOF) - { - ret = FAIL; - break; - } - } - if (!binary || li->li_next != NULL) - if (putc('\n', fd) == EOF) - { - ret = FAIL; - break; - } - if (ret == FAIL) - { - EMSG(_(e_write)); - break; - } - } - return ret; -} - -/* - * "writefile()" function - */ - static void -f_writefile(typval_T *argvars, typval_T *rettv) -{ - int binary = FALSE; - int append = FALSE; - char_u *fname; - FILE *fd; - int ret = 0; - - if (check_restricted() || check_secure()) - return; - - if (argvars[0].v_type != VAR_LIST) - { - EMSG2(_(e_listarg), "writefile()"); - return; - } - if (argvars[0].vval.v_list == NULL) - return; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL) - binary = TRUE; - if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL) - append = TRUE; - } - - /* Always open the file in binary mode, library functions have a mind of - * their own about CR-LF conversion. */ - fname = get_tv_string(&argvars[1]); - if (*fname == NUL || (fd = mch_fopen((char *)fname, - append ? APPENDBIN : WRITEBIN)) == NULL) - { - EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); - ret = -1; - } - else - { - if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL) - ret = -1; - fclose(fd); - } - - rettv->vval.v_number = ret; -} - -/* - * "xor(expr, expr)" function - */ - static void -f_xor(typval_T *argvars, typval_T *rettv) -{ - rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) - ^ get_tv_number_chk(&argvars[1], NULL); -} /* * Translate a String variable into a position. * Returns NULL when there is an error. */ - static pos_T * + pos_T * var2fpos( typval_T *varp, int dollar_lnum, /* TRUE when $ is last line */ @@ -19415,7 +6095,7 @@ var2fpos( * Return FAIL when conversion is not possible, doesn't check the position for * validity. */ - static int + int list2fpos( typval_T *arg, pos_T *posp, @@ -19531,7 +6211,7 @@ get_id_len(char_u **arg) * If the name contains 'magic' {}'s, expand them and return the * expanded name in an allocated string via 'alias' - caller must free. */ - static int + int get_name_len( char_u **arg, char_u **alias, @@ -20032,7 +6712,7 @@ set_cmdarg(exarg_T *eap, char_u *oldarg) * Get the value of internal variable "name". * Return OK or FAIL. */ - static int + int get_var_tv( char_u *name, int len, /* length of "name" */ @@ -20324,7 +7004,7 @@ clear_tv(typval_T *varp) /* * Set the value of a variable to NULL without freeing items. */ - static void + void init_tv(typval_T *varp) { if (varp != NULL) @@ -20401,7 +7081,7 @@ get_tv_number_chk(typval_T *varp, int *d } #ifdef FEAT_FLOAT - static float_T + float_T get_tv_float(typval_T *varp) { switch (varp->v_type) @@ -20445,44 +7125,6 @@ get_tv_float(typval_T *varp) #endif /* - * Get the lnum from the first argument. - * Also accepts ".", "$", etc., but that only works for the current buffer. - * Returns -1 on error. - */ - static linenr_T -get_tv_lnum(typval_T *argvars) -{ - typval_T rettv; - linenr_T lnum; - - lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL); - if (lnum == 0) /* no valid number, try using line() */ - { - rettv.v_type = VAR_NUMBER; - f_line(argvars, &rettv); - lnum = (linenr_T)rettv.vval.v_number; - clear_tv(&rettv); - } - return lnum; -} - -/* - * Get the lnum from the first argument. - * Also accepts "$", then "buf" is used. - * Returns 0 on error. - */ - static linenr_T -get_tv_lnum_buf(typval_T *argvars, buf_T *buf) -{ - if (argvars[0].v_type == VAR_STRING - && argvars[0].vval.v_string != NULL - && argvars[0].vval.v_string[0] == '$' - && buf != NULL) - return buf->b_ml.ml_line_count; - return (linenr_T)get_tv_number_chk(&argvars[0], NULL); -} - -/* * Get the string value of a variable. * If it is a Number variable, the number is converted into a string. * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE! @@ -20624,7 +7266,7 @@ find_var(char_u *name, hashtab_T **htp, * Find variable "varname" in hashtab "ht" with name "htname". * Returns NULL if not found. */ - static dictitem_T * + dictitem_T * find_var_in_ht( hashtab_T *ht, int htname, @@ -20936,7 +7578,7 @@ list_one_var_a( * If the variable already exists, the value is updated. * Otherwise the variable is created. */ - static void + void set_var( char_u *name, typval_T *tv, @@ -21064,7 +7706,7 @@ var_check_ro(int flags, char_u *name, in * Return TRUE if di_flags "flags" indicates variable "name" is fixed. * Also give an error message. */ - static int + int var_check_fixed(int flags, char_u *name, int use_gettext) { if (flags & DI_FLAGS_FIX) @@ -21310,6 +7952,110 @@ item_copy( } /* + * This function is used by f_input() and f_inputdialog() functions. The third + * argument to f_input() specifies the type of completion to use at the + * prompt. The third argument to f_inputdialog() specifies the value to return + * when the user cancels the prompt. + */ + void +get_user_input( + typval_T *argvars, + typval_T *rettv, + int inputdialog, + int secret) +{ + char_u *prompt = get_tv_string_chk(&argvars[0]); + char_u *p = NULL; + int c; + char_u buf[NUMBUFLEN]; + int cmd_silent_save = cmd_silent; + char_u *defstr = (char_u *)""; + int xp_type = EXPAND_NOTHING; + char_u *xp_arg = NULL; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + +#ifdef NO_CONSOLE_INPUT + /* While starting up, there is no place to enter text. */ + if (no_console_input()) + return; +#endif + + cmd_silent = FALSE; /* Want to see the prompt. */ + if (prompt != NULL) + { + /* Only the part of the message after the last NL is considered as + * prompt for the command line */ + p = vim_strrchr(prompt, '\n'); + if (p == NULL) + p = prompt; + else + { + ++p; + c = *p; + *p = NUL; + msg_start(); + msg_clr_eos(); + msg_puts_attr(prompt, echo_attr); + msg_didout = FALSE; + msg_starthere(); + *p = c; + } + cmdline_row = msg_row; + + if (argvars[1].v_type != VAR_UNKNOWN) + { + defstr = get_tv_string_buf_chk(&argvars[1], buf); + if (defstr != NULL) + stuffReadbuffSpec(defstr); + + if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) + { + char_u *xp_name; + int xp_namelen; + long argt; + + /* input() with a third argument: completion */ + rettv->vval.v_string = NULL; + + xp_name = get_tv_string_buf_chk(&argvars[2], buf); + if (xp_name == NULL) + return; + + xp_namelen = (int)STRLEN(xp_name); + + if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt, + &xp_arg) == FAIL) + return; + } + } + + if (defstr != NULL) + { + int save_ex_normal_busy = ex_normal_busy; + ex_normal_busy = 0; + rettv->vval.v_string = + getcmdline_prompt(secret ? NUL : '@', p, echo_attr, + xp_type, xp_arg); + ex_normal_busy = save_ex_normal_busy; + } + if (inputdialog && rettv->vval.v_string == NULL + && argvars[1].v_type != VAR_UNKNOWN + && argvars[2].v_type != VAR_UNKNOWN) + rettv->vval.v_string = vim_strsave(get_tv_string_buf( + &argvars[2], buf)); + + vim_free(xp_arg); + + /* since the user typed this, no need to wait for return */ + need_wait_return = FALSE; + msg_didout = FALSE; + } + cmd_silent = cmd_silent_save; +} + +/* * ":echo expr1 ..." print each argument separated with a space, add a * newline at the end. * ":echon expr1 ..." print each argument plain. @@ -21516,6 +8262,224 @@ ex_execute(exarg_T *eap) } /* + * Find window specified by "vp" in tabpage "tp". + */ + win_T * +find_win_by_nr( + typval_T *vp, + tabpage_T *tp UNUSED) /* NULL for current tab page */ +{ +#ifdef FEAT_WINDOWS + win_T *wp; +#endif + int nr; + + nr = (int)get_tv_number_chk(vp, NULL); + +#ifdef FEAT_WINDOWS + if (nr < 0) + return NULL; + if (nr == 0) + return curwin; + + for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin; + wp != NULL; wp = wp->w_next) + if (nr >= LOWEST_WIN_ID) + { + if (wp->w_id == nr) + return wp; + } + else if (--nr <= 0) + break; + if (nr >= LOWEST_WIN_ID) + return NULL; + return wp; +#else + if (nr == 0 || nr == 1 || nr == curwin->w_id) + return curwin; + return NULL; +#endif +} + +/* + * Find window specified by "wvp" in tabpage "tvp". + */ + win_T * +find_tabwin( + typval_T *wvp, /* VAR_UNKNOWN for current window */ + typval_T *tvp) /* VAR_UNKNOWN for current tab page */ +{ + win_T *wp = NULL; + tabpage_T *tp = NULL; + long n; + + if (wvp->v_type != VAR_UNKNOWN) + { + if (tvp->v_type != VAR_UNKNOWN) + { + n = (long)get_tv_number(tvp); + if (n >= 0) + tp = find_tabpage(n); + } + else + tp = curtab; + + if (tp != NULL) + wp = find_win_by_nr(wvp, tp); + } + else + wp = curwin; + + return wp; +} + +/* + * getwinvar() and gettabwinvar() + */ + void +getwinvar( + typval_T *argvars, + typval_T *rettv, + int off) /* 1 for gettabwinvar() */ +{ + win_T *win; + char_u *varname; + dictitem_T *v; + tabpage_T *tp = NULL; + int done = FALSE; +#ifdef FEAT_WINDOWS + win_T *oldcurwin; + tabpage_T *oldtabpage; + int need_switch_win; +#endif + +#ifdef FEAT_WINDOWS + if (off == 1) + tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); + else + tp = curtab; +#endif + win = find_win_by_nr(&argvars[off], tp); + varname = get_tv_string_chk(&argvars[off + 1]); + ++emsg_off; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (win != NULL && varname != NULL) + { +#ifdef FEAT_WINDOWS + /* Set curwin to be our win, temporarily. Also set the tabpage, + * otherwise the window is not valid. Only do this when needed, + * autocommands get blocked. */ + need_switch_win = !(tp == curtab && win == curwin); + if (!need_switch_win + || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) +#endif + { + if (*varname == '&') /* window-local-option */ + { + if (get_option_tv(&varname, rettv, 1) == OK) + done = TRUE; + } + else + { + /* Look up the variable. */ + /* Let getwinvar({nr}, "") return the "w:" dictionary. */ + v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', + varname, FALSE); + if (v != NULL) + { + copy_tv(&v->di_tv, rettv); + done = TRUE; + } + } + } + +#ifdef FEAT_WINDOWS + if (need_switch_win) + /* restore previous notion of curwin */ + restore_win(oldcurwin, oldtabpage, TRUE); +#endif + } + + if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) + /* use the default return value */ + copy_tv(&argvars[off + 2], rettv); + + --emsg_off; +} + +/* + * "setwinvar()" and "settabwinvar()" functions + */ + void +setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off) +{ + win_T *win; +#ifdef FEAT_WINDOWS + win_T *save_curwin; + tabpage_T *save_curtab; + int need_switch_win; +#endif + char_u *varname, *winvarname; + typval_T *varp; + char_u nbuf[NUMBUFLEN]; + tabpage_T *tp = NULL; + + if (check_restricted() || check_secure()) + return; + +#ifdef FEAT_WINDOWS + if (off == 1) + tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); + else + tp = curtab; +#endif + win = find_win_by_nr(&argvars[off], tp); + varname = get_tv_string_chk(&argvars[off + 1]); + varp = &argvars[off + 2]; + + if (win != NULL && varname != NULL && varp != NULL) + { +#ifdef FEAT_WINDOWS + need_switch_win = !(tp == curtab && win == curwin); + if (!need_switch_win + || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) +#endif + { + if (*varname == '&') + { + long numval; + char_u *strval; + int error = FALSE; + + ++varname; + numval = (long)get_tv_number_chk(varp, &error); + strval = get_tv_string_buf_chk(varp, nbuf); + if (!error && strval != NULL) + set_option_value(varname, numval, strval, OPT_LOCAL); + } + else + { + winvarname = alloc((unsigned)STRLEN(varname) + 3); + if (winvarname != NULL) + { + STRCPY(winvarname, "w:"); + STRCPY(winvarname + 2, varname); + set_var(winvarname, varp, TRUE); + vim_free(winvarname); + } + } + } +#ifdef FEAT_WINDOWS + if (need_switch_win) + restore_win(save_curwin, save_curtab, TRUE); +#endif + } +} + +/* * Skip over the name of an option: "&option", "&g:option" or "&l:option". * "arg" points to the "&" or '+' when called, to "option" when returning. * Returns NULL when no option name found. Otherwise pointer to the char @@ -21932,6 +8896,255 @@ reset_v_option_vars(void) set_vim_var_string(VV_OPTION_TYPE, NULL, -1); } +/* + * Prepare "gap" for an assert error and add the sourcing position. + */ + void +prepare_assert_error(garray_T *gap) +{ + char buf[NUMBUFLEN]; + + ga_init2(gap, 1, 100); + if (sourcing_name != NULL) + { + ga_concat(gap, sourcing_name); + if (sourcing_lnum > 0) + ga_concat(gap, (char_u *)" "); + } + if (sourcing_lnum > 0) + { + sprintf(buf, "line %ld", (long)sourcing_lnum); + ga_concat(gap, (char_u *)buf); + } + if (sourcing_name != NULL || sourcing_lnum > 0) + ga_concat(gap, (char_u *)": "); +} + +/* + * Add an assert error to v:errors. + */ + void +assert_error(garray_T *gap) +{ + struct vimvar *vp = &vimvars[VV_ERRORS]; + + if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) + /* Make sure v:errors is a list. */ + set_vim_var_list(VV_ERRORS, list_alloc()); + list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len); +} + + void +assert_equal_common(typval_T *argvars, assert_type_T atype) +{ + garray_T ga; + + if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE) + != (atype == ASSERT_EQUAL)) + { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], + atype); + assert_error(&ga); + ga_clear(&ga); + } +} + + void +assert_match_common(typval_T *argvars, assert_type_T atype) +{ + garray_T ga; + char_u buf1[NUMBUFLEN]; + char_u buf2[NUMBUFLEN]; + char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1); + char_u *text = get_tv_string_buf_chk(&argvars[1], buf2); + + if (pat == NULL || text == NULL) + EMSG(_(e_invarg)); + else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH)) + { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], + atype); + assert_error(&ga); + ga_clear(&ga); + } +} + +/* + * Common for assert_true() and assert_false(). + */ + void +assert_bool(typval_T *argvars, int isTrue) +{ + int error = FALSE; + garray_T ga; + + if (argvars[0].v_type == VAR_SPECIAL + && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE)) + return; + if (argvars[0].v_type != VAR_NUMBER + || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue + || error) + { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[1], + (char_u *)(isTrue ? "True" : "False"), + NULL, &argvars[0], ASSERT_OTHER); + assert_error(&ga); + ga_clear(&ga); + } +} + + void +assert_exception(typval_T *argvars) +{ + garray_T ga; + char_u *error = get_tv_string_chk(&argvars[0]); + + if (vimvars[VV_EXCEPTION].vv_str == NULL) + { + prepare_assert_error(&ga); + ga_concat(&ga, (char_u *)"v:exception is not set"); + assert_error(&ga); + ga_clear(&ga); + } + else if (error != NULL + && strstr((char *)vimvars[VV_EXCEPTION].vv_str, (char *)error) == NULL) + { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], + &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER); + assert_error(&ga); + ga_clear(&ga); + } +} + + void +assert_fails(typval_T *argvars) +{ + char_u *cmd = get_tv_string_chk(&argvars[0]); + garray_T ga; + + called_emsg = FALSE; + suppress_errthrow = TRUE; + emsg_silent = TRUE; + do_cmdline_cmd(cmd); + if (!called_emsg) + { + prepare_assert_error(&ga); + ga_concat(&ga, (char_u *)"command did not fail: "); + ga_concat(&ga, cmd); + assert_error(&ga); + ga_clear(&ga); + } + else if (argvars[1].v_type != VAR_UNKNOWN) + { + char_u buf[NUMBUFLEN]; + char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf); + + if (error == NULL + || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) + { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], + &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); + assert_error(&ga); + ga_clear(&ga); + } + } + + called_emsg = FALSE; + suppress_errthrow = FALSE; + emsg_silent = FALSE; + emsg_on_display = FALSE; + set_vim_var_string(VV_ERRMSG, NULL, 0); +} + +/* + * Append "str" to "gap", escaping unprintable characters. + * Changes NL to \n, CR to \r, etc. + */ + static void +ga_concat_esc(garray_T *gap, char_u *str) +{ + char_u *p; + char_u buf[NUMBUFLEN]; + + if (str == NULL) + { + ga_concat(gap, (char_u *)"NULL"); + return; + } + + for (p = str; *p != NUL; ++p) + switch (*p) + { + case BS: ga_concat(gap, (char_u *)"\\b"); break; + case ESC: ga_concat(gap, (char_u *)"\\e"); break; + case FF: ga_concat(gap, (char_u *)"\\f"); break; + case NL: ga_concat(gap, (char_u *)"\\n"); break; + case TAB: ga_concat(gap, (char_u *)"\\t"); break; + case CAR: ga_concat(gap, (char_u *)"\\r"); break; + case '\\': ga_concat(gap, (char_u *)"\\\\"); break; + default: + if (*p < ' ') + { + vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); + ga_concat(gap, buf); + } + else + ga_append(gap, *p); + break; + } +} + +/* + * Fill "gap" with information about an assert error. + */ + 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 atype) +{ + char_u numbuf[NUMBUFLEN]; + char_u *tofree; + + if (opt_msg_tv->v_type != VAR_UNKNOWN) + { + ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0)); + vim_free(tofree); + } + else + { + if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) + ga_concat(gap, (char_u *)"Pattern "); + else + ga_concat(gap, (char_u *)"Expected "); + if (exp_str == NULL) + { + ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0)); + vim_free(tofree); + } + else + ga_concat_esc(gap, exp_str); + if (atype == ASSERT_MATCH) + ga_concat(gap, (char_u *)" does not match "); + else if (atype == ASSERT_NOTMATCH) + ga_concat(gap, (char_u *)" does match "); + else if (atype == ASSERT_NOTEQUAL) + ga_concat(gap, (char_u *)" differs from "); + else + ga_concat(gap, (char_u *)" but got "); + ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0)); + vim_free(tofree); + } +} + #endif /* FEAT_EVAL */ @@ -22678,4 +9891,192 @@ do_string_sub( return ret; } + static int +filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) +{ + typval_T rettv; + typval_T argv[3]; + char_u buf[NUMBUFLEN]; + char_u *s; + int retval = FAIL; + int dummy; + + copy_tv(tv, &vimvars[VV_VAL].vv_tv); + argv[0] = vimvars[VV_KEY].vv_tv; + argv[1] = vimvars[VV_VAL].vv_tv; + if (expr->v_type == VAR_FUNC) + { + s = expr->vval.v_string; + if (call_func(s, (int)STRLEN(s), + &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL) + goto theend; + } + else if (expr->v_type == VAR_PARTIAL) + { + partial_T *partial = expr->vval.v_partial; + + s = partial->pt_name; + if (call_func(s, (int)STRLEN(s), + &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL) + == FAIL) + goto theend; + } + else + { + s = get_tv_string_buf_chk(expr, buf); + if (s == NULL) + goto theend; + s = skipwhite(s); + if (eval1(&s, &rettv, TRUE) == FAIL) + goto theend; + if (*s != NUL) /* check for trailing chars after expr */ + { + EMSG2(_(e_invexpr2), s); + goto theend; + } + } + if (map) + { + /* map(): replace the list item value */ + clear_tv(tv); + rettv.v_lock = 0; + *tv = rettv; + } + else + { + int error = FALSE; + + /* filter(): when expr is zero remove the item */ + *remp = (get_tv_number_chk(&rettv, &error) == 0); + clear_tv(&rettv); + /* On type error, nothing has been removed; return FAIL to stop the + * loop. The error message was given by get_tv_number_chk(). */ + if (error) + goto theend; + } + retval = OK; +theend: + clear_tv(&vimvars[VV_VAL].vv_tv); + return retval; +} + + +/* + * Implementation of map() and filter(). + */ + void +filter_map(typval_T *argvars, typval_T *rettv, int map) +{ + typval_T *expr; + listitem_T *li, *nli; + list_T *l = NULL; + dictitem_T *di; + hashtab_T *ht; + hashitem_T *hi; + dict_T *d = NULL; + typval_T save_val; + typval_T save_key; + int rem; + int todo; + char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); + char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") + : N_("filter() argument")); + int save_did_emsg; + int idx = 0; + + if (argvars[0].v_type == VAR_LIST) + { + if ((l = argvars[0].vval.v_list) == NULL + || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE))) + return; + } + else if (argvars[0].v_type == VAR_DICT) + { + if ((d = argvars[0].vval.v_dict) == NULL + || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE))) + return; + } + else + { + EMSG2(_(e_listdictarg), ermsg); + return; + } + + expr = &argvars[1]; + /* On type errors, the preceding call has already displayed an error + * message. Avoid a misleading error message for an empty string that + * was not passed as argument. */ + if (expr->v_type != VAR_UNKNOWN) + { + prepare_vimvar(VV_VAL, &save_val); + + /* We reset "did_emsg" to be able to detect whether an error + * occurred during evaluation of the expression. */ + save_did_emsg = did_emsg; + did_emsg = FALSE; + + prepare_vimvar(VV_KEY, &save_key); + if (argvars[0].v_type == VAR_DICT) + { + vimvars[VV_KEY].vv_type = VAR_STRING; + + ht = &d->dv_hashtab; + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + int r; + + --todo; + di = HI2DI(hi); + if (map && + (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) + || var_check_ro(di->di_flags, arg_errmsg, TRUE))) + break; + vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); + r = filter_map_one(&di->di_tv, expr, map, &rem); + clear_tv(&vimvars[VV_KEY].vv_tv); + if (r == FAIL || did_emsg) + break; + if (!map && rem) + { + if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) + || var_check_ro(di->di_flags, arg_errmsg, TRUE)) + break; + dictitem_remove(d, di); + } + } + } + hash_unlock(ht); + } + else + { + vimvars[VV_KEY].vv_type = VAR_NUMBER; + + for (li = l->lv_first; li != NULL; li = nli) + { + if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) + break; + nli = li->li_next; + vimvars[VV_KEY].vv_nr = idx; + if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL + || did_emsg) + break; + if (!map && rem) + listitem_remove(l, li); + ++idx; + } + } + + restore_vimvar(VV_KEY, &save_key); + restore_vimvar(VV_VAL, &save_val); + + did_emsg |= save_did_emsg; + } + + copy_tv(&argvars[0], rettv); +} + #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */