diff options
Diffstat (limited to 'src/nvim/eval.c')
| -rw-r--r-- | src/nvim/eval.c | 19819 |
1 files changed, 19819 insertions, 0 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c new file mode 100644 index 0000000000..98ab1ea2fe --- /dev/null +++ b/src/nvim/eval.c @@ -0,0 +1,19819 @@ +/* + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * eval.c: Expression evaluation. + */ + +#include <string.h> +#include <stdlib.h> + +#include "vim.h" +#include "eval.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "if_cscope.h" +#include "indent_c.h" +#include "indent.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "memory.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "keymap.h" +#include "file_search.h" +#include "garray.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "path.h" +#include "popupmnu.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "sha256.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "version.h" +#include "window.h" +#include "os/os.h" +#include "os/job.h" +#include "os/rstream.h" +#include "os/rstream_defs.h" +#include "os/time.h" + +#if defined(FEAT_FLOAT) +# include <math.h> +#endif + +#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ + +#define DO_NOT_FREE_CNT 99999 /* refcount for dict or list that should not + be freed. */ + +/* + * In a hashtab item "hi_key" points to "di_key" in a dictitem. + * This avoids adding a pointer to the hashtab item. + * DI2HIKEY() converts a dictitem pointer to a hashitem key pointer. + * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer. + * HI2DI() converts a hashitem pointer to a dictitem pointer. + */ +static dictitem_T dumdi; +#define DI2HIKEY(di) ((di)->di_key) +#define HIKEY2DI(p) ((dictitem_T *)(p - (dumdi.di_key - (char_u *)&dumdi))) +#define HI2DI(hi) HIKEY2DI((hi)->hi_key) + +/* + * Structure returned by get_lval() and used by set_var_lval(). + * For a plain name: + * "name" points to the variable name. + * "exp_name" is NULL. + * "tv" is NULL + * For a magic braces name: + * "name" points to the expanded variable name. + * "exp_name" is non-NULL, to be freed later. + * "tv" is NULL + * For an index in a list: + * "name" points to the (expanded) variable name. + * "exp_name" NULL or non-NULL, to be freed later. + * "tv" points to the (first) list item value + * "li" points to the (first) list item + * "range", "n1", "n2" and "empty2" indicate what items are used. + * For an existing Dict item: + * "name" points to the (expanded) variable name. + * "exp_name" NULL or non-NULL, to be freed later. + * "tv" points to the dict item value + * "newkey" is NULL + * For a non-existing Dict item: + * "name" points to the (expanded) variable name. + * "exp_name" NULL or non-NULL, to be freed later. + * "tv" points to the Dictionary typval_T + * "newkey" is the key for the new item. + */ +typedef struct lval_S { + char_u *ll_name; /* start of variable name (can be NULL) */ + char_u *ll_exp_name; /* NULL or expanded name in allocated memory. */ + typval_T *ll_tv; /* Typeval of item being used. If "newkey" + isn't NULL it's the Dict to which to add + the item. */ + listitem_T *ll_li; /* The list item or NULL. */ + list_T *ll_list; /* The list or NULL. */ + int ll_range; /* TRUE when a [i:j] range was used */ + long ll_n1; /* First index for list */ + long ll_n2; /* Second index for list range */ + int ll_empty2; /* Second index is empty: [i:] */ + dict_T *ll_dict; /* The Dictionary or NULL */ + dictitem_T *ll_di; /* The dictitem or NULL */ + char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */ +} lval_T; + + +static char *e_letunexp = N_("E18: Unexpected characters in :let"); +static char *e_listidx = N_("E684: list index out of range: %" PRId64); +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_emptykey = N_("E713: Cannot use empty key for Dictionary"); +static char *e_listreq = N_("E714: List required"); +static char *e_dictreq = N_("E715: Dictionary required"); +static char *e_toomanyarg = N_("E118: Too many arguments for function: %s"); +static char *e_dictkey = N_("E716: Key not present in Dictionary: %s"); +static char *e_funcexts = N_( + "E122: Function %s already exists, add ! to replace it"); +static char *e_funcdict = N_("E717: Dictionary entry already exists"); +static char *e_funcref = N_("E718: Funcref required"); +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_nofunc = N_("E130: Unknown function: %s"); +static char *e_illvar = N_("E461: Illegal variable name: %s"); +static char *e_float_as_string = N_("E806: using Float as a String"); + +static dictitem_T globvars_var; /* variable used for g: */ +#define globvarht globvardict.dv_hashtab + +/* + * Old Vim variables such as "v:version" are also available without the "v:". + * Also in functions. We need a special hashtable for them. + */ +static hashtab_T compat_hashtab; + +/* + * When recursively copying lists and dicts we need to remember which ones we + * have done to avoid endless recursiveness. This unique ID is used for that. + * The last bit is used for previous_funccal, ignored when comparing. + */ +static int current_copyID = 0; +#define COPYID_INC 2 +#define COPYID_MASK (~0x1) + +/* + * Array to hold the hashtab with variables local to each sourced script. + * Each item holds a variable (nameless) that points to the dict_T. + */ +typedef struct { + dictitem_T sv_var; + dict_T sv_dict; +} scriptvar_T; + +static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL}; +#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1]) +#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) + +static int echo_attr = 0; /* attributes used for ":echo" */ + +/* Values for trans_function_name() argument: */ +#define TFN_INT 1 /* internal function name OK */ +#define TFN_QUIET 2 /* no error messages */ +#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */ + +/* Values for get_lval() flags argument: */ +#define GLV_QUIET TFN_QUIET /* no error messages */ +#define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD /* do not use script autoloading */ + +/* + * Structure to hold info for a user function. + */ +typedef struct ufunc ufunc_T; + +struct ufunc { + int uf_varargs; /* variable nr of arguments */ + int uf_flags; + int uf_calls; /* nr of active calls */ + garray_T uf_args; /* arguments */ + garray_T uf_lines; /* function lines */ + int uf_profiling; /* TRUE when func is being profiled */ + /* profiling the function as a whole */ + int uf_tm_count; /* nr of calls */ + proftime_T uf_tm_total; /* time spent in function + children */ + proftime_T uf_tm_self; /* time spent in function itself */ + proftime_T uf_tm_children; /* time spent in children this call */ + /* profiling the function per line */ + int *uf_tml_count; /* nr of times line was executed */ + proftime_T *uf_tml_total; /* time spent in a line + children */ + proftime_T *uf_tml_self; /* time spent in a line itself */ + proftime_T uf_tml_start; /* start time for current line */ + proftime_T uf_tml_children; /* time spent in children for this line */ + proftime_T uf_tml_wait; /* start wait time for current line */ + int uf_tml_idx; /* index of line being timed; -1 if none */ + int uf_tml_execed; /* line being timed was executed */ + scid_T uf_script_ID; /* ID of script where function was defined, + used for s: variables */ + int uf_refcount; /* for numbered function: reference count */ + char_u uf_name[1]; /* name of function (actually longer); can + start with <SNR>123_ (<SNR> is K_SPECIAL + KS_EXTRA KE_SNR) */ +}; + +/* function flags */ +#define FC_ABORT 1 /* abort function on error */ +#define FC_RANGE 2 /* function accepts range */ +#define FC_DICT 4 /* Dict function, uses "self" */ + +/* + * All user-defined functions are found in this hashtable. + */ +static hashtab_T func_hashtab; + +/* The names of packages that once were loaded are remembered. */ +static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL}; + +/* list heads for garbage collection */ +static dict_T *first_dict = NULL; /* list of all dicts */ +static list_T *first_list = NULL; /* list of all lists */ + +/* From user function to hashitem and back. */ +static ufunc_T dumuf; +#define UF2HIKEY(fp) ((fp)->uf_name) +#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf))) +#define HI2UF(hi) HIKEY2UF((hi)->hi_key) + +#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] +#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j] + +#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */ +#define VAR_SHORT_LEN 20 /* short variable name length */ +#define FIXVAR_CNT 12 /* number of fixed variables */ + +/* structure to hold info for a function that is currently being executed. */ +typedef struct funccall_S funccall_T; + +struct funccall_S { + ufunc_T *func; /* function being called */ + int linenr; /* next line to be executed */ + int returned; /* ":return" used */ + struct /* fixed variables for arguments */ + { + dictitem_T var; /* variable (without room for name) */ + char_u room[VAR_SHORT_LEN]; /* room for the name */ + } fixvar[FIXVAR_CNT]; + dict_T l_vars; /* l: local function variables */ + dictitem_T l_vars_var; /* variable for l: scope */ + dict_T l_avars; /* a: argument variables */ + dictitem_T l_avars_var; /* variable for a: scope */ + list_T l_varlist; /* list for a:000 */ + listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */ + typval_T *rettv; /* return value */ + linenr_T breakpoint; /* next line with breakpoint or zero */ + int dbg_tick; /* debug_tick when breakpoint was set */ + int level; /* top nesting level of executed function */ + proftime_T prof_child; /* time spent in a child */ + funccall_T *caller; /* calling function or NULL */ +}; + +/* + * Info used by a ":for" loop. + */ +typedef struct { + int fi_semicolon; /* TRUE if ending in '; var]' */ + int fi_varcount; /* nr of variables in the list */ + listwatch_T fi_lw; /* keep an eye on the item used. */ + list_T *fi_list; /* list being used */ +} forinfo_T; + +/* + * Struct used by trans_function_name() + */ +typedef struct { + dict_T *fd_dict; /* Dictionary used */ + char_u *fd_newkey; /* new key in "dict" in allocated memory */ + dictitem_T *fd_di; /* Dictionary item used */ +} funcdict_T; + + +/* + * Array to hold the value of v: variables. + * The value is in a dictitem, so that it can also be used in the v: scope. + * The reason to use this table anyway is for very quick access to the + * variables with the VV_ defines. + */ +#include "version_defs.h" + +/* values for vv_flags: */ +#define VV_COMPAT 1 /* compatible, also used without "v:" */ +#define VV_RO 2 /* read-only */ +#define VV_RO_SBX 4 /* read-only in the sandbox */ + +#define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}, {0} + +static struct vimvar { + char *vv_name; /* name of variable, without v: */ + dictitem_T vv_di; /* value and name for key */ + char vv_filler[16]; /* space for LONGEST name below!!! */ + char vv_flags; /* VV_COMPAT, VV_RO, VV_RO_SBX */ +} vimvars[VV_LEN] = +{ + /* + * The order here must match the VV_ defines in vim.h! + * Initializing a union does not work, leave tv.vval empty to get zero's. + */ + {VV_NAME("count", VAR_NUMBER), VV_COMPAT+VV_RO}, + {VV_NAME("count1", VAR_NUMBER), VV_RO}, + {VV_NAME("prevcount", VAR_NUMBER), VV_RO}, + {VV_NAME("errmsg", VAR_STRING), VV_COMPAT}, + {VV_NAME("warningmsg", VAR_STRING), 0}, + {VV_NAME("statusmsg", VAR_STRING), 0}, + {VV_NAME("shell_error", VAR_NUMBER), VV_COMPAT+VV_RO}, + {VV_NAME("this_session", VAR_STRING), VV_COMPAT}, + {VV_NAME("version", VAR_NUMBER), VV_COMPAT+VV_RO}, + {VV_NAME("lnum", VAR_NUMBER), VV_RO_SBX}, + {VV_NAME("termresponse", VAR_STRING), VV_RO}, + {VV_NAME("fname", VAR_STRING), VV_RO}, + {VV_NAME("lang", VAR_STRING), VV_RO}, + {VV_NAME("lc_time", VAR_STRING), VV_RO}, + {VV_NAME("ctype", VAR_STRING), VV_RO}, + {VV_NAME("charconvert_from", VAR_STRING), VV_RO}, + {VV_NAME("charconvert_to", VAR_STRING), VV_RO}, + {VV_NAME("fname_in", VAR_STRING), VV_RO}, + {VV_NAME("fname_out", VAR_STRING), VV_RO}, + {VV_NAME("fname_new", VAR_STRING), VV_RO}, + {VV_NAME("fname_diff", VAR_STRING), VV_RO}, + {VV_NAME("cmdarg", VAR_STRING), VV_RO}, + {VV_NAME("foldstart", VAR_NUMBER), VV_RO_SBX}, + {VV_NAME("foldend", VAR_NUMBER), VV_RO_SBX}, + {VV_NAME("folddashes", VAR_STRING), VV_RO_SBX}, + {VV_NAME("foldlevel", VAR_NUMBER), VV_RO_SBX}, + {VV_NAME("progname", VAR_STRING), VV_RO}, + {VV_NAME("servername", VAR_STRING), VV_RO}, + {VV_NAME("dying", VAR_NUMBER), VV_RO}, + {VV_NAME("exception", VAR_STRING), VV_RO}, + {VV_NAME("throwpoint", VAR_STRING), VV_RO}, + {VV_NAME("register", VAR_STRING), VV_RO}, + {VV_NAME("cmdbang", VAR_NUMBER), VV_RO}, + {VV_NAME("insertmode", VAR_STRING), VV_RO}, + {VV_NAME("val", VAR_UNKNOWN), VV_RO}, + {VV_NAME("key", VAR_UNKNOWN), VV_RO}, + {VV_NAME("profiling", VAR_NUMBER), VV_RO}, + {VV_NAME("fcs_reason", VAR_STRING), VV_RO}, + {VV_NAME("fcs_choice", VAR_STRING), 0}, + {VV_NAME("beval_bufnr", VAR_NUMBER), VV_RO}, + {VV_NAME("beval_winnr", VAR_NUMBER), VV_RO}, + {VV_NAME("beval_lnum", VAR_NUMBER), VV_RO}, + {VV_NAME("beval_col", VAR_NUMBER), VV_RO}, + {VV_NAME("beval_text", VAR_STRING), VV_RO}, + {VV_NAME("scrollstart", VAR_STRING), 0}, + {VV_NAME("swapname", VAR_STRING), VV_RO}, + {VV_NAME("swapchoice", VAR_STRING), 0}, + {VV_NAME("swapcommand", VAR_STRING), VV_RO}, + {VV_NAME("char", VAR_STRING), 0}, + {VV_NAME("mouse_win", VAR_NUMBER), 0}, + {VV_NAME("mouse_lnum", VAR_NUMBER), 0}, + {VV_NAME("mouse_col", VAR_NUMBER), 0}, + {VV_NAME("operator", VAR_STRING), VV_RO}, + {VV_NAME("searchforward", VAR_NUMBER), 0}, + {VV_NAME("hlsearch", VAR_NUMBER), 0}, + {VV_NAME("oldfiles", VAR_LIST), 0}, + {VV_NAME("windowid", VAR_NUMBER), VV_RO}, + {VV_NAME("progpath", VAR_STRING), VV_RO}, + {VV_NAME("job_data", VAR_LIST), 0} +}; + +/* shorthand */ +#define vv_type vv_di.di_tv.v_type +#define vv_nr vv_di.di_tv.vval.v_number +#define vv_float vv_di.di_tv.vval.v_float +#define vv_str vv_di.di_tv.vval.v_string +#define vv_list vv_di.di_tv.vval.v_list +#define vv_tv vv_di.di_tv + +static dictitem_T vimvars_var; /* variable used for v: */ +#define vimvarht vimvardict.dv_hashtab + +static void on_job_stdout(RStream *rstream, void *data, bool eof); +static void on_job_stderr(RStream *rstream, void *data, bool eof); +static void on_job_exit(Job *job, void *data); +static void on_job_data(RStream *rstream, void *data, bool eof, char *type); +static void apply_job_autocmds(Job *job, char *name, char *type, char *str); +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); +static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, + int empty, + int *first); +static void list_glob_vars(int *first); +static void list_buf_vars(int *first); +static void list_win_vars(int *first); +static void list_tab_vars(int *first); +static void list_vim_vars(int *first); +static void list_script_vars(int *first); +static void list_func_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 char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, + int unlet, int skip, int flags, + int fne_flags); +static void clear_lval(lval_T *lp); +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 list_fix_watch(list_T *l, listitem_T *item); +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 eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, + int evaluate); +static int eval1(char_u **arg, typval_T *rettv, int evaluate); +static int eval2(char_u **arg, typval_T *rettv, int evaluate); +static int eval3(char_u **arg, typval_T *rettv, int evaluate); +static int eval4(char_u **arg, typval_T *rettv, int evaluate); +static int eval5(char_u **arg, typval_T *rettv, int evaluate); +static int eval6(char_u **arg, typval_T *rettv, int evaluate, + int want_string); +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 get_list_tv(char_u **arg, typval_T *rettv, int evaluate); +static void rettv_list_alloc(typval_T *rettv); +static long list_len(list_T *l); +static int list_equal(list_T *l1, list_T *l2, int ic, int recursive); +static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); +static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); +static long list_find_nr(list_T *l, long idx, int *errorp); +static long list_idx_of_item(list_T *l, listitem_T *item); +static void list_append_number(list_T *l, varnumber_T n); +static int list_extend(list_T *l1, list_T *l2, listitem_T *bef); +static int list_concat(list_T *l1, list_T *l2, typval_T *tv); +static list_T *list_copy(list_T *orig, int deep, int copyID); +static char_u *list2string(typval_T *tv, int copyID); +static int list_join_inner(garray_T *gap, list_T *l, char_u *sep, + int echo_style, int copyID, + garray_T *join_gap); +static int list_join(garray_T *gap, list_T *l, char_u *sep, int echo, + int copyID); +static int free_unref_items(int copyID); +static int rettv_dict_alloc(typval_T *rettv); +static dictitem_T *dictitem_copy(dictitem_T *org); +static void dictitem_remove(dict_T *dict, dictitem_T *item); +static dict_T *dict_copy(dict_T *orig, int deep, int copyID); +static long dict_len(dict_T *d); +static char_u *dict2string(typval_T *tv, int copyID); +static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate); +static char_u *echo_string(typval_T *tv, char_u **tofree, + char_u *numbuf, + int copyID); +static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, + int copyID); +static char_u *string_quote(char_u *str, int function); +static int string2float(char_u *text, float_T *value); +static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); +static int find_internal_func(char_u *name); +static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload); +static int get_func_tv(char_u *name, int len, typval_T *rettv, + char_u **arg, linenr_T firstline, linenr_T lastline, + int *doesrange, int evaluate, + dict_T *selfdict); +static int call_func(char_u *funcname, int len, typval_T *rettv, + int argcount, typval_T *argvars, + linenr_T firstline, linenr_T lastline, + int *doesrange, int evaluate, + dict_T *selfdict); +static void emsg_funcname(char *ermsg, char_u *name); +static int non_zero_arg(typval_T *argvars); + +static void f_abs(typval_T *argvars, typval_T *rettv); +static void f_acos(typval_T *argvars, typval_T *rettv); +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_argv(typval_T *argvars, typval_T *rettv); +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); +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_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); +static void f_ceil(typval_T *argvars, typval_T *rettv); +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); +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); +static void f_confirm(typval_T *argvars, typval_T *rettv); +static void f_copy(typval_T *argvars, typval_T *rettv); +static void f_cos(typval_T *argvars, typval_T *rettv); +static void f_cosh(typval_T *argvars, typval_T *rettv); +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_exists(typval_T *argvars, typval_T *rettv); +static void f_exp(typval_T *argvars, typval_T *rettv); +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); +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); +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_getcmdline(typval_T *argvars, typval_T *rettv); +static void f_getcmdpos(typval_T *argvars, typval_T *rettv); +static void f_getcmdtype(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_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_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); +static void f_items(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_write(typval_T *argvars, typval_T *rettv); +static void f_join(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); +static void f_log(typval_T *argvars, typval_T *rettv); +static void f_log10(typval_T *argvars, typval_T *rettv); +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_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_max(typval_T *argvars, typval_T *rettv); +static void f_min(typval_T *argvars, typval_T *rettv); +static void f_mkdir(typval_T *argvars, typval_T *rettv); +static void f_mode(typval_T *argvars, typval_T *rettv); +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); +static void f_pow(typval_T *argvars, typval_T *rettv); +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); +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); +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); +static void f_round(typval_T *argvars, typval_T *rettv); +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_setcmdpos(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); +static void f_sha256(typval_T *argvars, typval_T *rettv); +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); +static void f_sin(typval_T *argvars, typval_T *rettv); +static void f_sinh(typval_T *argvars, typval_T *rettv); +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); +static void f_sqrt(typval_T *argvars, typval_T *rettv); +static void f_str2float(typval_T *argvars, typval_T *rettv); +static void f_str2nr(typval_T *argvars, typval_T *rettv); +static void f_strchars(typval_T *argvars, typval_T *rettv); +static void f_strftime(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_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_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(typval_T *argvars, typval_T *rettv); +static void f_tan(typval_T *argvars, typval_T *rettv); +static void f_tanh(typval_T *argvars, typval_T *rettv); +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); +static void f_trunc(typval_T *argvars, typval_T *rettv); +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_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_xor(typval_T *argvars, typval_T *rettv); + +static int list2fpos(typval_T *arg, pos_T *posp, int *fnump); +static pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum); +static int get_env_len(char_u **arg); +static int get_id_len(char_u **arg); +static int get_name_len(char_u **arg, char_u **alias, int evaluate, + int verbose); +static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u * + *expr_end, + int flags); +#define FNE_INCL_BR 1 /* find_name_end(): include [] in name */ +#define FNE_CHECK_START 2 /* find_name_end(): check name starts with + valid character */ +static char_u * +make_expanded_name(char_u *in_start, char_u *expr_start, char_u * + expr_end, + char_u *in_end); +static int eval_isnamec(int c); +static int eval_isnamec1(int c); +static int get_var_tv(char_u *name, int len, typval_T *rettv, + int verbose, + int no_autoload); +static int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, + int verbose); +static void init_tv(typval_T *varp); +static long get_tv_number(typval_T *varp); +static linenr_T get_tv_lnum(typval_T *argvars); +static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf); +static char_u *get_tv_string(typval_T *varp); +static char_u *get_tv_string_buf(typval_T *varp, char_u *buf); +static char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf); +static dictitem_T *find_var(char_u *name, hashtab_T **htp, + int no_autoload); +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 vars_clear_ext(hashtab_T *ht, int free_val); +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_ro(int flags, char_u *name); +static int var_check_fixed(int flags, char_u *name); +static int var_check_func_name(char_u *name, int new_var); +static int va |