aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c19819
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