From da51dc9cf202772f60bd2da975dbef257bd9237c Mon Sep 17 00:00:00 2001 From: Eliseo Martínez Date: Mon, 12 May 2014 02:25:17 +0200 Subject: Introduce nvim namespace: Move files. Move files from src/ to src/nvim/. - src/nvim/ becomes the new root dir for nvim executable sources. - src/libnvim/ is planned to become root dir of the neovim library. --- src/nvim/eval.c | 19819 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 19819 insertions(+) create mode 100644 src/nvim/eval.c (limited to 'src/nvim/eval.c') 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 +#include + +#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 +#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 123_ ( 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 valid_varname(char_u *varname); +static int tv_check_lock(int lock, char_u *name); +static int item_copy(typval_T *from, typval_T *to, int deep, int copyID); +static char_u *find_option_end(char_u **arg, int *opt_flags); +static char_u *trans_function_name(char_u **pp, int skip, int flags, + funcdict_T *fd); +static int eval_fname_script(char_u *p); +static int eval_fname_sid(char_u *p); +static void list_func_head(ufunc_T *fp, int indent); +static ufunc_T *find_func(char_u *name); +static int function_exists(char_u *name); +static bool builtin_function(char_u *name, int len); +static void func_do_profile(ufunc_T *fp); +static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, + char *title, + int prefer_self); +static void prof_func_line(FILE *fd, int count, proftime_T *total, + proftime_T *self, + int prefer_self); +static int +prof_total_cmp(const void *s1, const void *s2); +static int +prof_self_cmp(const void *s1, const void *s2); +static int script_autoload(char_u *name, int reload); +static char_u *autoload_name(char_u *name); +static void cat_func_name(char_u *buf, ufunc_T *fp); +static void func_free(ufunc_T *fp); +static void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, + typval_T *rettv, linenr_T firstline, + linenr_T lastline, + dict_T *selfdict); +static int can_free_funccal(funccall_T *fc, int copyID); +static void free_funccal(funccall_T *fc, int free_val); +static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, + varnumber_T nr); +static win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp); +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); + + + +/* + * Initialize the global and v: variables. + */ +void eval_init(void) +{ + int i; + struct vimvar *p; + + init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE); + init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE); + vimvardict.dv_lock = VAR_FIXED; + hash_init(&compat_hashtab); + hash_init(&func_hashtab); + + for (i = 0; i < VV_LEN; ++i) { + p = &vimvars[i]; + STRCPY(p->vv_di.di_key, p->vv_name); + if (p->vv_flags & VV_RO) + p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; + else if (p->vv_flags & VV_RO_SBX) + p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX; + else + p->vv_di.di_flags = DI_FLAGS_FIX; + + /* add to v: scope dict, unless the value is not always available */ + if (p->vv_type != VAR_UNKNOWN) + hash_add(&vimvarht, p->vv_di.di_key); + if (p->vv_flags & VV_COMPAT) + /* add to compat scope dict */ + hash_add(&compat_hashtab, p->vv_di.di_key); + } + set_vim_var_nr(VV_SEARCHFORWARD, 1L); + set_vim_var_nr(VV_HLSEARCH, 1L); + set_reg_var(0); /* default for v:register is not 0 but '"' */ + +} + +#if defined(EXITFREE) || defined(PROTO) +void eval_clear(void) +{ + int i; + struct vimvar *p; + + for (i = 0; i < VV_LEN; ++i) { + p = &vimvars[i]; + if (p->vv_di.di_tv.v_type == VAR_STRING) { + free(p->vv_str); + p->vv_str = NULL; + } else if (p->vv_di.di_tv.v_type == VAR_LIST) { + list_unref(p->vv_list); + p->vv_list = NULL; + } + } + hash_clear(&vimvarht); + hash_init(&vimvarht); /* garbage_collect() will access it */ + hash_clear(&compat_hashtab); + + free_scriptnames(); + free_locales(); + + /* global variables */ + vars_clear(&globvarht); + + /* autoloaded script names */ + ga_clear_strings(&ga_loaded); + + /* Script-local variables. First clear all the variables and in a second + * loop free the scriptvar_T, because a variable in one script might hold + * a reference to the whole scope of another script. */ + for (i = 1; i <= ga_scripts.ga_len; ++i) + vars_clear(&SCRIPT_VARS(i)); + for (i = 1; i <= ga_scripts.ga_len; ++i) + free(SCRIPT_SV(i)); + ga_clear(&ga_scripts); + + /* unreferenced lists and dicts */ + (void)garbage_collect(); + + /* functions */ + free_all_functions(); + hash_clear(&func_hashtab); +} + +#endif + +/* + * Return the name of the executed function. + */ +char_u *func_name(void *cookie) +{ + return ((funccall_T *)cookie)->func->uf_name; +} + +/* + * Return the address holding the next breakpoint line for a funccall cookie. + */ +linenr_T *func_breakpoint(void *cookie) +{ + return &((funccall_T *)cookie)->breakpoint; +} + +/* + * Return the address holding the debug tick for a funccall cookie. + */ +int *func_dbg_tick(void *cookie) +{ + return &((funccall_T *)cookie)->dbg_tick; +} + +/* + * Return the nesting level for a funccall cookie. + */ +int func_level(void *cookie) +{ + return ((funccall_T *)cookie)->level; +} + +/* pointer to funccal for currently active function */ +funccall_T *current_funccal = NULL; + +/* pointer to list of previously used funccal, still around because some + * item in it is still being used. */ +funccall_T *previous_funccal = NULL; + +/* + * Return TRUE when a function was ended by a ":return" command. + */ +int current_func_returned(void) +{ + return current_funccal->returned; +} + +/* + * Set an internal variable to a string value. Creates the variable if it does + * not already exist. + */ +void set_internal_string_var(char_u *name, char_u *value) +{ + char_u *val = vim_strsave(value); + typval_T *tvp = xcalloc(1, sizeof(typval_T)); + + tvp->v_type = VAR_STRING; + tvp->vval.v_string = val; + set_var(name, tvp, FALSE); + free_tv(tvp); +} + +static lval_T *redir_lval = NULL; +static garray_T redir_ga; /* only valid when redir_lval is not NULL */ +static char_u *redir_endp = NULL; +static char_u *redir_varname = NULL; + +/* + * Start recording command output to a variable + * Returns OK if successfully completed the setup. FAIL otherwise. + */ +int +var_redir_start ( + char_u *name, + int append /* append to an existing variable */ +) +{ + int save_emsg; + int err; + typval_T tv; + + /* Catch a bad name early. */ + if (!eval_isnamec1(*name)) { + EMSG(_(e_invarg)); + return FAIL; + } + + /* Make a copy of the name, it is used in redir_lval until redir ends. */ + redir_varname = vim_strsave(name); + if (redir_varname == NULL) + return FAIL; + + redir_lval = xcalloc(1, sizeof(lval_T)); + + /* The output is stored in growarray "redir_ga" until redirection ends. */ + ga_init(&redir_ga, (int)sizeof(char), 500); + + /* Parse the variable name (can be a dict or list entry). */ + redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0, + FNE_CHECK_START); + if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != + NUL) { + clear_lval(redir_lval); + if (redir_endp != NULL && *redir_endp != NUL) + /* Trailing characters are present after the variable name */ + EMSG(_(e_trailing)); + else + EMSG(_(e_invarg)); + redir_endp = NULL; /* don't store a value, only cleanup */ + var_redir_stop(); + return FAIL; + } + + /* check if we can write to the variable: set it to or append an empty + * string */ + save_emsg = did_emsg; + did_emsg = FALSE; + tv.v_type = VAR_STRING; + tv.vval.v_string = (char_u *)""; + if (append) + set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"."); + else + set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"="); + clear_lval(redir_lval); + err = did_emsg; + did_emsg |= save_emsg; + if (err) { + redir_endp = NULL; /* don't store a value, only cleanup */ + var_redir_stop(); + return FAIL; + } + + return OK; +} + +/* + * Append "value[value_len]" to the variable set by var_redir_start(). + * The actual appending is postponed until redirection ends, because the value + * appended may in fact be the string we write to, changing it may cause freed + * memory to be used: + * :redir => foo + * :let foo + * :redir END + */ +void var_redir_str(char_u *value, int value_len) +{ + int len; + + if (redir_lval == NULL) + return; + + if (value_len == -1) + len = (int)STRLEN(value); /* Append the entire string */ + else + len = value_len; /* Append only "value_len" characters */ + + ga_grow(&redir_ga, len); + memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len); + redir_ga.ga_len += len; +} + +/* + * Stop redirecting command output to a variable. + * Frees the allocated memory. + */ +void var_redir_stop(void) +{ + typval_T tv; + + if (redir_lval != NULL) { + /* If there was no error: assign the text to the variable. */ + if (redir_endp != NULL) { + ga_append(&redir_ga, NUL); /* Append the trailing NUL. */ + tv.v_type = VAR_STRING; + tv.vval.v_string = redir_ga.ga_data; + /* Call get_lval() again, if it's inside a Dict or List it may + * have changed. */ + redir_endp = get_lval(redir_varname, NULL, redir_lval, + FALSE, FALSE, 0, FNE_CHECK_START); + if (redir_endp != NULL && redir_lval->ll_name != NULL) + set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)"."); + clear_lval(redir_lval); + } + + /* free the collected output */ + free(redir_ga.ga_data); + redir_ga.ga_data = NULL; + + free(redir_lval); + redir_lval = NULL; + } + free(redir_varname); + redir_varname = NULL; +} + +int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, char_u *fname_to) +{ + int err = FALSE; + + set_vim_var_string(VV_CC_FROM, enc_from, -1); + set_vim_var_string(VV_CC_TO, enc_to, -1); + set_vim_var_string(VV_FNAME_IN, fname_from, -1); + set_vim_var_string(VV_FNAME_OUT, fname_to, -1); + if (eval_to_bool(p_ccv, &err, NULL, FALSE)) + err = TRUE; + set_vim_var_string(VV_CC_FROM, NULL, -1); + set_vim_var_string(VV_CC_TO, NULL, -1); + set_vim_var_string(VV_FNAME_IN, NULL, -1); + set_vim_var_string(VV_FNAME_OUT, NULL, -1); + + if (err) + return FAIL; + return OK; +} + +int eval_printexpr(char_u *fname, char_u *args) +{ + int err = FALSE; + + set_vim_var_string(VV_FNAME_IN, fname, -1); + set_vim_var_string(VV_CMDARG, args, -1); + if (eval_to_bool(p_pexpr, &err, NULL, FALSE)) + err = TRUE; + set_vim_var_string(VV_FNAME_IN, NULL, -1); + set_vim_var_string(VV_CMDARG, NULL, -1); + + if (err) { + os_remove((char *)fname); + return FAIL; + } + return OK; +} + +void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile) +{ + int err = FALSE; + + set_vim_var_string(VV_FNAME_IN, origfile, -1); + set_vim_var_string(VV_FNAME_NEW, newfile, -1); + set_vim_var_string(VV_FNAME_OUT, outfile, -1); + (void)eval_to_bool(p_dex, &err, NULL, FALSE); + set_vim_var_string(VV_FNAME_IN, NULL, -1); + set_vim_var_string(VV_FNAME_NEW, NULL, -1); + set_vim_var_string(VV_FNAME_OUT, NULL, -1); +} + +void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile) +{ + int err; + + set_vim_var_string(VV_FNAME_IN, origfile, -1); + set_vim_var_string(VV_FNAME_DIFF, difffile, -1); + set_vim_var_string(VV_FNAME_OUT, outfile, -1); + (void)eval_to_bool(p_pex, &err, NULL, FALSE); + set_vim_var_string(VV_FNAME_IN, NULL, -1); + set_vim_var_string(VV_FNAME_DIFF, NULL, -1); + set_vim_var_string(VV_FNAME_OUT, NULL, -1); +} + +/* + * Top level evaluation function, returning a boolean. + * Sets "error" to TRUE if there was an error. + * Return TRUE or FALSE. + */ +int +eval_to_bool ( + char_u *arg, + int *error, + char_u **nextcmd, + int skip /* only parse, don't execute */ +) +{ + typval_T tv; + int retval = FALSE; + + if (skip) + ++emsg_skip; + if (eval0(arg, &tv, nextcmd, !skip) == FAIL) + *error = TRUE; + else { + *error = FALSE; + if (!skip) { + retval = (get_tv_number_chk(&tv, error) != 0); + clear_tv(&tv); + } + } + if (skip) + --emsg_skip; + + return retval; +} + +/* + * Top level evaluation function, returning a string. If "skip" is TRUE, + * only parsing to "nextcmd" is done, without reporting errors. Return + * pointer to allocated memory, or NULL for failure or when "skip" is TRUE. + */ +char_u * +eval_to_string_skip ( + char_u *arg, + char_u **nextcmd, + int skip /* only parse, don't execute */ +) +{ + typval_T tv; + char_u *retval; + + if (skip) + ++emsg_skip; + if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip) + retval = NULL; + else { + retval = vim_strsave(get_tv_string(&tv)); + clear_tv(&tv); + } + if (skip) + --emsg_skip; + + return retval; +} + +/* + * Skip over an expression at "*pp". + * Return FAIL for an error, OK otherwise. + */ +int skip_expr(char_u **pp) +{ + typval_T rettv; + + *pp = skipwhite(*pp); + return eval1(pp, &rettv, FALSE); +} + +/* + * Top level evaluation function, returning a string. + * When "convert" is TRUE convert a List into a sequence of lines and convert + * a Float to a String. + * Return pointer to allocated memory, or NULL for failure. + */ +char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert) +{ + typval_T tv; + char_u *retval; + garray_T ga; + char_u numbuf[NUMBUFLEN]; + + if (eval0(arg, &tv, nextcmd, TRUE) == FAIL) + retval = NULL; + else { + if (convert && tv.v_type == VAR_LIST) { + ga_init(&ga, (int)sizeof(char), 80); + if (tv.vval.v_list != NULL) { + list_join(&ga, tv.vval.v_list, (char_u *)"\n", TRUE, 0); + if (tv.vval.v_list->lv_len > 0) + ga_append(&ga, NL); + } + ga_append(&ga, NUL); + retval = (char_u *)ga.ga_data; + } else if (convert && tv.v_type == VAR_FLOAT) { + vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv.vval.v_float); + retval = vim_strsave(numbuf); + } else + retval = vim_strsave(get_tv_string(&tv)); + clear_tv(&tv); + } + + return retval; +} + +/* + * Call eval_to_string() without using current local variables and using + * textlock. When "use_sandbox" is TRUE use the sandbox. + */ +char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox) +{ + char_u *retval; + void *save_funccalp; + + save_funccalp = save_funccal(); + if (use_sandbox) + ++sandbox; + ++textlock; + retval = eval_to_string(arg, nextcmd, FALSE); + if (use_sandbox) + --sandbox; + --textlock; + restore_funccal(save_funccalp); + return retval; +} + +/* + * Top level evaluation function, returning a number. + * Evaluates "expr" silently. + * Returns -1 for an error. + */ +int eval_to_number(char_u *expr) +{ + typval_T rettv; + int retval; + char_u *p = skipwhite(expr); + + ++emsg_off; + + if (eval1(&p, &rettv, TRUE) == FAIL) + retval = -1; + else { + retval = get_tv_number_chk(&rettv, NULL); + clear_tv(&rettv); + } + --emsg_off; + + return retval; +} + + +/* + * Prepare v: variable "idx" to be used. + * Save the current typeval in "save_tv". + * When not used yet add the variable to the v: hashtable. + */ +static void prepare_vimvar(int idx, typval_T *save_tv) +{ + *save_tv = vimvars[idx].vv_tv; + if (vimvars[idx].vv_type == VAR_UNKNOWN) + hash_add(&vimvarht, vimvars[idx].vv_di.di_key); +} + +/* + * Restore v: variable "idx" to typeval "save_tv". + * When no longer defined, remove the variable from the v: hashtable. + */ +static void restore_vimvar(int idx, typval_T *save_tv) +{ + hashitem_T *hi; + + vimvars[idx].vv_tv = *save_tv; + if (vimvars[idx].vv_type == VAR_UNKNOWN) { + hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key); + if (HASHITEM_EMPTY(hi)) + EMSG2(_(e_intern2), "restore_vimvar()"); + else + hash_remove(&vimvarht, hi); + } +} + +/* + * Evaluate an expression to a list with suggestions. + * For the "expr:" part of 'spellsuggest'. + * Returns NULL when there is an error. + */ +list_T *eval_spell_expr(char_u *badword, char_u *expr) +{ + typval_T save_val; + typval_T rettv; + list_T *list = NULL; + char_u *p = skipwhite(expr); + + /* Set "v:val" to the bad word. */ + prepare_vimvar(VV_VAL, &save_val); + vimvars[VV_VAL].vv_type = VAR_STRING; + vimvars[VV_VAL].vv_str = badword; + if (p_verbose == 0) + ++emsg_off; + + if (eval1(&p, &rettv, TRUE) == OK) { + if (rettv.v_type != VAR_LIST) + clear_tv(&rettv); + else + list = rettv.vval.v_list; + } + + if (p_verbose == 0) + --emsg_off; + restore_vimvar(VV_VAL, &save_val); + + return list; +} + +/* + * "list" is supposed to contain two items: a word and a number. Return the + * word in "pp" and the number as the return value. + * Return -1 if anything isn't right. + * Used to get the good word and score from the eval_spell_expr() result. + */ +int get_spellword(list_T *list, char_u **pp) +{ + listitem_T *li; + + li = list->lv_first; + if (li == NULL) + return -1; + *pp = get_tv_string(&li->li_tv); + + li = li->li_next; + if (li == NULL) + return -1; + return get_tv_number(&li->li_tv); +} + +/* + * Top level evaluation function. + * Returns an allocated typval_T with the result. + * Returns NULL when there is an error. + */ +typval_T *eval_expr(char_u *arg, char_u **nextcmd) +{ + typval_T *tv; + + tv = (typval_T *)alloc(sizeof(typval_T)); + if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL) { + free(tv); + tv = NULL; + } + + return tv; +} + + +/* + * Call some vimL function and return the result in "*rettv". + * Uses argv[argc] for the function arguments. Only Number and String + * arguments are currently supported. + * Returns OK or FAIL. + */ +int +call_vim_function ( + char_u *func, + int argc, + char_u **argv, + int safe, /* use the sandbox */ + int str_arg_only, /* all arguments are strings */ + typval_T *rettv +) +{ + typval_T *argvars; + long n; + int len; + int i; + int doesrange; + void *save_funccalp = NULL; + int ret; + + argvars = (typval_T *)alloc((unsigned)((argc + 1) * sizeof(typval_T))); + if (argvars == NULL) + return FAIL; + + for (i = 0; i < argc; i++) { + /* Pass a NULL or empty argument as an empty string */ + if (argv[i] == NULL || *argv[i] == NUL) { + argvars[i].v_type = VAR_STRING; + argvars[i].vval.v_string = (char_u *)""; + continue; + } + + if (str_arg_only) + len = 0; + else + /* Recognize a number argument, the others must be strings. */ + vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL); + if (len != 0 && len == (int)STRLEN(argv[i])) { + argvars[i].v_type = VAR_NUMBER; + argvars[i].vval.v_number = n; + } else { + argvars[i].v_type = VAR_STRING; + argvars[i].vval.v_string = argv[i]; + } + } + + if (safe) { + save_funccalp = save_funccal(); + ++sandbox; + } + + rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ + ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &doesrange, TRUE, NULL); + if (safe) { + --sandbox; + restore_funccal(save_funccalp); + } + free(argvars); + + if (ret == FAIL) + clear_tv(rettv); + + return ret; +} + +/* + * Call vimL function "func" and return the result as a number. + * Returns -1 when calling the function fails. + * Uses argv[argc] for the function arguments. + */ +long +call_func_retnr ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) +{ + typval_T rettv; + long retval; + + /* All arguments are passed as strings, no conversion to number. */ + if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + return -1; + + retval = get_tv_number_chk(&rettv, NULL); + clear_tv(&rettv); + return retval; +} + +#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \ + || defined(FEAT_COMPL_FUNC) || defined(PROTO) + +/* + * Call vimL function "func" and return the result as a string. + * Returns NULL when calling the function fails. + * Uses argv[argc] for the function arguments. + */ +void * +call_func_retstr ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) +{ + typval_T rettv; + char_u *retval; + + /* All arguments are passed as strings, no conversion to number. */ + if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + return NULL; + + retval = vim_strsave(get_tv_string(&rettv)); + clear_tv(&rettv); + return retval; +} + +/* + * Call vimL function "func" and return the result as a List. + * Uses argv[argc] for the function arguments. + * Returns NULL when there is something wrong. + */ +void * +call_func_retlist ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) +{ + typval_T rettv; + + /* All arguments are passed as strings, no conversion to number. */ + if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + return NULL; + + if (rettv.v_type != VAR_LIST) { + clear_tv(&rettv); + return NULL; + } + + return rettv.vval.v_list; +} +#endif + +/* + * Save the current function call pointer, and set it to NULL. + * Used when executing autocommands and for ":source". + */ +void *save_funccal(void) +{ + funccall_T *fc = current_funccal; + + current_funccal = NULL; + return (void *)fc; +} + +void restore_funccal(void *vfc) +{ + funccall_T *fc = (funccall_T *)vfc; + + current_funccal = fc; +} + +/* + * Prepare profiling for entering a child or something else that is not + * counted for the script/function itself. + * Should always be called in pair with prof_child_exit(). + */ +void prof_child_enter(tm) +proftime_T *tm; /* place to store waittime */ +{ + funccall_T *fc = current_funccal; + + if (fc != NULL && fc->func->uf_profiling) + profile_start(&fc->prof_child); + script_prof_save(tm); +} + +/* + * Take care of time spent in a child. + * Should always be called after prof_child_enter(). + */ +void prof_child_exit(tm) +proftime_T *tm; /* where waittime was stored */ +{ + funccall_T *fc = current_funccal; + + if (fc != NULL && fc->func->uf_profiling) { + profile_end(&fc->prof_child); + profile_sub_wait(tm, &fc->prof_child); /* don't count waiting time */ + profile_add(&fc->func->uf_tm_children, &fc->prof_child); + profile_add(&fc->func->uf_tml_children, &fc->prof_child); + } + script_prof_restore(tm); +} + + +/* + * Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding + * it in "*cp". Doesn't give error messages. + */ +int eval_foldexpr(char_u *arg, int *cp) +{ + typval_T tv; + int retval; + char_u *s; + int use_sandbox = was_set_insecurely((char_u *)"foldexpr", + OPT_LOCAL); + + ++emsg_off; + if (use_sandbox) + ++sandbox; + ++textlock; + *cp = NUL; + if (eval0(arg, &tv, NULL, TRUE) == FAIL) + retval = 0; + else { + /* If the result is a number, just return the number. */ + if (tv.v_type == VAR_NUMBER) + retval = tv.vval.v_number; + else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) + retval = 0; + else { + /* If the result is a string, check if there is a non-digit before +