diff options
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 10682 |
1 files changed, 10682 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c new file mode 100644 index 0000000000..2e339e6d04 --- /dev/null +++ b/src/eval.c @@ -0,0 +1,10682 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * 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. + */ +#if defined(MSDOS) || defined(MSWIN) +# include <io.h> /* for mch_open(), must be before vim.h */ +#endif + +#include "vim.h" + +#ifdef AMIGA +# include <time.h> /* for strftime() */ +#endif + +#ifdef MACOS +# include <time.h> /* for time_t */ +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#if defined(FEAT_EVAL) || defined(PROTO) + +#if SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */ +typedef long varnumber_T; +#else +typedef int varnumber_T; +#endif + +/* + * Structure to hold an internal variable. + */ +typedef struct +{ + char_u *var_name; /* name of variable */ + char var_type; /* VAR_NUMBER or VAR_STRING */ + union + { + varnumber_T var_number; /* number value */ + char_u *var_string; /* string value (Careful: can be NULL!) */ + } var_val; +} var; + +#define VAR_UNKNOWN 0 +#define VAR_NUMBER 1 +#define VAR_STRING 2 + +typedef var * VAR; + +/* + * All user-defined global variables are stored in "variables". + */ +garray_T variables = {0, 0, sizeof(var), 4, NULL}; + +/* + * Array to hold an array with variables local to each sourced script. + */ +static garray_T ga_scripts = {0, 0, sizeof(garray_T), 4, NULL}; +#define SCRIPT_VARS(id) (((garray_T *)ga_scripts.ga_data)[(id) - 1]) + + +#define VAR_ENTRY(idx) (((VAR)(variables.ga_data))[idx]) +#define VAR_GAP_ENTRY(idx, gap) (((VAR)(gap->ga_data))[idx]) +#define BVAR_ENTRY(idx) (((VAR)(curbuf->b_vars.ga_data))[idx]) +#define WVAR_ENTRY(idx) (((VAR)(curwin->w_vars.ga_data))[idx]) + +static int echo_attr = 0; /* attributes used for ":echo" */ + +/* + * Structure to hold info for a user function. + */ +typedef struct ufunc ufunc_T; + +struct ufunc +{ + ufunc_T *next; /* next function in list */ + char_u *name; /* name of function; can start with <SNR>123_ + (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) */ + int varargs; /* variable nr of arguments */ + int flags; + int calls; /* nr of active calls */ + garray_T args; /* arguments */ + garray_T lines; /* function lines */ + scid_T script_ID; /* ID of script where function was defined, + used for s: variables */ +}; + +/* function flags */ +#define FC_ABORT 1 /* abort function on error */ +#define FC_RANGE 2 /* function accepts range */ + +/* + * All user-defined functions are found in the forward-linked function list. + * The first function is pointed at by firstfunc. + */ +ufunc_T *firstfunc = NULL; + +#define FUNCARG(fp, j) ((char_u **)(fp->args.ga_data))[j] +#define FUNCLINE(fp, j) ((char_u **)(fp->lines.ga_data))[j] + +/* structure to hold info for a function that is currently being executed. */ +struct funccall +{ + ufunc_T *func; /* function being called */ + int linenr; /* next line to be executed */ + int returned; /* ":return" used */ + int argcount; /* nr of arguments */ + VAR argvars; /* arguments */ + var a0_var; /* "a:0" variable */ + var firstline; /* "a:firstline" variable */ + var lastline; /* "a:lastline" variable */ + garray_T l_vars; /* local function variables */ + VAR retvar; /* return value variable */ + 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 */ +}; + +/* + * Return the name of the executed function. + */ + char_u * +func_name(cookie) + void *cookie; +{ + return ((struct funccall *)cookie)->func->name; +} + +/* + * Return the address holding the next breakpoint line for a funccall cookie. + */ + linenr_T * +func_breakpoint(cookie) + void *cookie; +{ + return &((struct funccall *)cookie)->breakpoint; +} + +/* + * Return the address holding the debug tick for a funccall cookie. + */ + int * +func_dbg_tick(cookie) + void *cookie; +{ + return &((struct funccall *)cookie)->dbg_tick; +} + +/* + * Return the nesting level for a funccall cookie. + */ + int +func_level(cookie) + void *cookie; +{ + return ((struct funccall *)cookie)->level; +} + +/* pointer to funccal for currently active function */ +struct funccall *current_funccal = NULL; + +/* + * Return TRUE when a function was ended by a ":return" command. + */ + int +current_func_returned() +{ + return current_funccal->returned; +} + + +/* + * Array to hold the value of v: variables. + */ +#include "version.h" + +/* values for flags: */ +#define VV_COMPAT 1 /* compatible, also used without "v:" */ +#define VV_RO 2 /* read-only */ + +struct vimvar +{ + char *name; /* name of variable, without v: */ + int len; /* length of name */ + char_u *val; /* current value (can also be a number!) */ + char type; /* VAR_NUMBER or VAR_STRING */ + char flags; /* VV_COMPAT and VV_RO */ +} vimvars[VV_LEN] = +{ /* The order here must match the VV_ defines in vim.h! */ + {"count", sizeof("count") - 1, NULL, VAR_NUMBER, VV_COMPAT+VV_RO}, + {"count1", sizeof("count1") - 1, NULL, VAR_NUMBER, VV_RO}, + {"prevcount", sizeof("prevcount") - 1, NULL, VAR_NUMBER, VV_RO}, + {"errmsg", sizeof("errmsg") - 1, NULL, VAR_STRING, VV_COMPAT}, + {"warningmsg", sizeof("warningmsg") - 1, NULL, VAR_STRING, 0}, + {"statusmsg", sizeof("statusmsg") - 1, NULL, VAR_STRING, 0}, + {"shell_error", sizeof("shell_error") - 1, NULL, VAR_NUMBER, + VV_COMPAT+VV_RO}, + {"this_session", sizeof("this_session") - 1, NULL, VAR_STRING, VV_COMPAT}, + {"version", sizeof("version") - 1, (char_u *)VIM_VERSION_100, + VAR_NUMBER, VV_COMPAT+VV_RO}, + {"lnum", sizeof("lnum") - 1, NULL, VAR_NUMBER, VV_RO}, + {"termresponse", sizeof("termresponse") - 1, NULL, VAR_STRING, VV_RO}, + {"fname", sizeof("fname") - 1, NULL, VAR_STRING, VV_RO}, + {"lang", sizeof("lang") - 1, NULL, VAR_STRING, VV_RO}, + {"lc_time", sizeof("lc_time") - 1, NULL, VAR_STRING, VV_RO}, + {"ctype", sizeof("ctype") - 1, NULL, VAR_STRING, VV_RO}, + {"charconvert_from", sizeof("charconvert_from") - 1, NULL, VAR_STRING, VV_RO}, + {"charconvert_to", sizeof("charconvert_to") - 1, NULL, VAR_STRING, VV_RO}, + {"fname_in", sizeof("fname_in") - 1, NULL, VAR_STRING, VV_RO}, + {"fname_out", sizeof("fname_out") - 1, NULL, VAR_STRING, VV_RO}, + {"fname_new", sizeof("fname_new") - 1, NULL, VAR_STRING, VV_RO}, + {"fname_diff", sizeof("fname_diff") - 1, NULL, VAR_STRING, VV_RO}, + {"cmdarg", sizeof("cmdarg") - 1, NULL, VAR_STRING, VV_RO}, + {"foldstart", sizeof("foldstart") - 1, NULL, VAR_NUMBER, VV_RO}, + {"foldend", sizeof("foldend") - 1, NULL, VAR_NUMBER, VV_RO}, + {"folddashes", sizeof("folddashes") - 1, NULL, VAR_STRING, VV_RO}, + {"foldlevel", sizeof("foldlevel") - 1, NULL, VAR_NUMBER, VV_RO}, + {"progname", sizeof("progname") - 1, NULL, VAR_STRING, VV_RO}, + {"servername", sizeof("servername") - 1, NULL, VAR_STRING, VV_RO}, + {"dying", sizeof("dying") - 1, NULL, VAR_NUMBER, VV_RO}, + {"exception", sizeof("exception") - 1, NULL, VAR_STRING, VV_RO}, + {"throwpoint", sizeof("throwpoint") - 1, NULL, VAR_STRING, VV_RO}, + {"register", sizeof("register") - 1, NULL, VAR_STRING, VV_RO}, + {"cmdbang", sizeof("cmdbang") - 1, NULL, VAR_NUMBER, VV_RO}, +}; + +static int eval0 __ARGS((char_u *arg, VAR retvar, char_u **nextcmd, int evaluate)); +static int eval1 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval2 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval3 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval4 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval5 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval6 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int eval7 __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int get_option_var __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int get_string_var __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int get_lit_string_var __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int get_env_var __ARGS((char_u **arg, VAR retvar, int evaluate)); +static int find_internal_func __ARGS((char_u *name)); +static int get_func_var __ARGS((char_u *name, int len, VAR retvar, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate)); +static int call_func __ARGS((char_u *name, int len, VAR retvar, int argcount, VAR argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate)); +static void f_append __ARGS((VAR argvars, VAR retvar)); +static void f_argc __ARGS((VAR argvars, VAR retvar)); +static void f_argidx __ARGS((VAR argvars, VAR retvar)); +static void f_argv __ARGS((VAR argvars, VAR retvar)); +static void f_browse __ARGS((VAR argvars, VAR retvar)); +static buf_T *find_buffer __ARGS((VAR avar)); +static void f_bufexists __ARGS((VAR argvars, VAR retvar)); +static void f_buflisted __ARGS((VAR argvars, VAR retvar)); +static void f_bufloaded __ARGS((VAR argvars, VAR retvar)); +static buf_T *get_buf_var __ARGS((VAR avar)); +static void f_bufname __ARGS((VAR argvars, VAR retvar)); +static void f_bufnr __ARGS((VAR argvars, VAR retvar)); +static void f_bufwinnr __ARGS((VAR argvars, VAR retvar)); +static void f_byte2line __ARGS((VAR argvars, VAR retvar)); +static void f_char2nr __ARGS((VAR argvars, VAR retvar)); +static void f_cindent __ARGS((VAR argvars, VAR retvar)); +static void f_col __ARGS((VAR argvars, VAR retvar)); +static void f_confirm __ARGS((VAR argvars, VAR retvar)); +static void f_cscope_connection __ARGS((VAR argvars, VAR retvar)); +static void f_cursor __ARGS((VAR argsvars, VAR retvar)); +static void f_delete __ARGS((VAR argvars, VAR retvar)); +static void f_did_filetype __ARGS((VAR argvars, VAR retvar)); +static void f_escape __ARGS((VAR argvars, VAR retvar)); +static void f_eventhandler __ARGS((VAR argvars, VAR retvar)); +static void f_executable __ARGS((VAR argvars, VAR retvar)); +static void f_exists __ARGS((VAR argvars, VAR retvar)); +static void f_expand __ARGS((VAR argvars, VAR retvar)); +static void f_filereadable __ARGS((VAR argvars, VAR retvar)); +static void f_filewritable __ARGS((VAR argvars, VAR retvar)); +static void f_fnamemodify __ARGS((VAR argvars, VAR retvar)); +static void f_foldclosed __ARGS((VAR argvars, VAR retvar)); +static void f_foldclosedend __ARGS((VAR argvars, VAR retvar)); +static void foldclosed_both __ARGS((VAR argvars, VAR retvar, int end)); +static void f_foldlevel __ARGS((VAR argvars, VAR retvar)); +static void f_foldtext __ARGS((VAR argvars, VAR retvar)); +static void f_foreground __ARGS((VAR argvars, VAR retvar)); +static void f_getbufvar __ARGS((VAR argvars, VAR retvar)); +static void f_getchar __ARGS((VAR argvars, VAR retvar)); +static void f_getcharmod __ARGS((VAR argvars, VAR retvar)); +static void f_getcmdline __ARGS((VAR argvars, VAR retvar)); +static void f_getcmdpos __ARGS((VAR argvars, VAR retvar)); +static void f_getcwd __ARGS((VAR argvars, VAR retvar)); +static void f_getfsize __ARGS((VAR argvars, VAR retvar)); +static void f_getftime __ARGS((VAR argvars, VAR retvar)); +static void f_getline __ARGS((VAR argvars, VAR retvar)); +static void f_getreg __ARGS((VAR argvars, VAR retvar)); +static void f_getregtype __ARGS((VAR argvars, VAR retvar)); +static void f_getwinposx __ARGS((VAR argvars, VAR retvar)); +static void f_getwinposy __ARGS((VAR argvars, VAR retvar)); +static void f_getwinvar __ARGS((VAR argvars, VAR retvar)); +static void f_glob __ARGS((VAR argvars, VAR retvar)); +static void f_globpath __ARGS((VAR argvars, VAR retvar)); +static void f_has __ARGS((VAR argvars, VAR retvar)); +static void f_hasmapto __ARGS((VAR argvars, VAR retvar)); +static void f_histadd __ARGS((VAR argvars, VAR retvar)); +static void f_histdel __ARGS((VAR argvars, VAR retvar)); +static void f_histget __ARGS((VAR argvars, VAR retvar)); +static void f_histnr __ARGS((VAR argvars, VAR retvar)); +static void f_hlexists __ARGS((VAR argvars, VAR retvar)); +static void f_hlID __ARGS((VAR argvars, VAR retvar)); +static void f_hostname __ARGS((VAR argvars, VAR retvar)); +static void f_iconv __ARGS((VAR argvars, VAR retvar)); +static void f_indent __ARGS((VAR argvars, VAR retvar)); +static void f_isdirectory __ARGS((VAR argvars, VAR retvar)); +static void f_input __ARGS((VAR argvars, VAR retvar)); +static void f_inputdialog __ARGS((VAR argvars, VAR retvar)); +static void f_inputrestore __ARGS((VAR argvars, VAR retvar)); +static void f_inputsave __ARGS((VAR argvars, VAR retvar)); +static void f_inputsecret __ARGS((VAR argvars, VAR retvar)); +static void f_last_buffer_nr __ARGS((VAR argvars, VAR retvar)); +static void f_libcall __ARGS((VAR argvars, VAR retvar)); +static void f_libcallnr __ARGS((VAR argvars, VAR retvar)); +static void libcall_common __ARGS((VAR argvars, VAR retvar, int type)); +static void f_line __ARGS((VAR argvars, VAR retvar)); +static void f_line2byte __ARGS((VAR argvars, VAR retvar)); +static void f_lispindent __ARGS((VAR argvars, VAR retvar)); +static void f_localtime __ARGS((VAR argvars, VAR retvar)); +static void f_maparg __ARGS((VAR argvars, VAR retvar)); +static void f_mapcheck __ARGS((VAR argvars, VAR retvar)); +static void get_maparg __ARGS((VAR argvars, VAR retvar, int exact)); +static void f_match __ARGS((VAR argvars, VAR retvar)); +static void f_matchend __ARGS((VAR argvars, VAR retvar)); +static void f_matchstr __ARGS((VAR argvars, VAR retvar)); +static void f_mode __ARGS((VAR argvars, VAR retvar)); +static void f_nextnonblank __ARGS((VAR argvars, VAR retvar)); +static void f_nr2char __ARGS((VAR argvars, VAR retvar)); +static void f_prevnonblank __ARGS((VAR argvars, VAR retvar)); +static void f_setbufvar __ARGS((VAR argvars, VAR retvar)); +static void f_setcmdpos __ARGS((VAR argvars, VAR retvar)); +static void f_setwinvar __ARGS((VAR argvars, VAR retvar)); +static void f_rename __ARGS((VAR argvars, VAR retvar)); +static void f_resolve __ARGS((VAR argvars, VAR retvar)); +static void f_search __ARGS((VAR argvars, VAR retvar)); +static void f_searchpair __ARGS((VAR argvars, VAR retvar)); +static int get_search_arg __ARGS((VAR varp, int *flagsp)); +static void f_remote_expr __ARGS((VAR argvars, VAR retvar)); +static void f_remote_foreground __ARGS((VAR argvars, VAR retvar)); +static void f_remote_peek __ARGS((VAR argvars, VAR retvar)); +static void f_remote_read __ARGS((VAR argvars, VAR retvar)); +static void f_remote_send __ARGS((VAR argvars, VAR retvar)); +static void f_server2client __ARGS((VAR argvars, VAR retvar)); +static void f_serverlist __ARGS((VAR argvars, VAR retvar)); +static void f_setline __ARGS((VAR argvars, VAR retvar)); +static void f_setreg __ARGS((VAR argvars, VAR retvar)); +static void f_simplify __ARGS((VAR argvars, VAR retvar)); +static void find_some_match __ARGS((VAR argvars, VAR retvar, int start)); +static void f_strftime __ARGS((VAR argvars, VAR retvar)); +static void f_stridx __ARGS((VAR argvars, VAR retvar)); +static void f_strlen __ARGS((VAR argvars, VAR retvar)); +static void f_strpart __ARGS((VAR argvars, VAR retvar)); +static void f_strridx __ARGS((VAR argvars, VAR retvar)); +static void f_strtrans __ARGS((VAR argvars, VAR retvar)); +static void f_synID __ARGS((VAR argvars, VAR retvar)); +static void f_synIDattr __ARGS((VAR argvars, VAR retvar)); +static void f_synIDtrans __ARGS((VAR argvars, VAR retvar)); +static void f_system __ARGS((VAR argvars, VAR retvar)); +static void f_submatch __ARGS((VAR argvars, VAR retvar)); +static void f_substitute __ARGS((VAR argvars, VAR retvar)); +static void f_tempname __ARGS((VAR argvars, VAR retvar)); +static void f_tolower __ARGS((VAR argvars, VAR retvar)); +static void f_toupper __ARGS((VAR argvars, VAR retvar)); +static void f_type __ARGS((VAR argvars, VAR retvar)); +static void f_virtcol __ARGS((VAR argvars, VAR retvar)); +static void f_visualmode __ARGS((VAR argvars, VAR retvar)); +static void f_winbufnr __ARGS((VAR argvars, VAR retvar)); +static void f_wincol __ARGS((VAR argvars, VAR retvar)); +static void f_winheight __ARGS((VAR argvars, VAR retvar)); +static void f_winline __ARGS((VAR argvars, VAR retvar)); +static void f_winnr __ARGS((VAR argvars, VAR retvar)); +static void f_winrestcmd __ARGS((VAR argvars, VAR retvar)); +static void f_winwidth __ARGS((VAR argvars, VAR retvar)); +static win_T *find_win_by_nr __ARGS((VAR vp)); +static pos_T *var2fpos __ARGS((VAR varp, int lnum)); +static int get_env_len __ARGS((char_u **arg)); +static int get_id_len __ARGS((char_u **arg)); +static int get_func_len __ARGS((char_u **arg, char_u **alias, int evaluate)); +static char_u *find_name_end __ARGS((char_u *arg, char_u **expr_start, char_u **expr_end)); +static int eval_isnamec __ARGS((int c)); +static int find_vim_var __ARGS((char_u *name, int len)); +static int get_var_var __ARGS((char_u *name, int len, VAR retvar)); +static VAR alloc_var __ARGS((void)); +static VAR alloc_string_var __ARGS((char_u *string)); +static void free_var __ARGS((VAR varp)); +static void clear_var __ARGS((VAR varp)); +static long get_var_number __ARGS((VAR varp)); +static linenr_T get_var_lnum __ARGS((VAR argvars)); +static char_u *get_var_string __ARGS((VAR varp)); +static char_u *get_var_string_buf __ARGS((VAR varp, char_u *buf)); +static VAR find_var __ARGS((char_u *name, int writing)); +static VAR find_var_in_ga __ARGS((garray_T *gap, char_u *varname)); +static garray_T *find_var_ga __ARGS((char_u *name, char_u **varname)); +static void var_free_one __ARGS((VAR v)); +static void list_one_var __ARGS((VAR v, char_u *prefix)); +static void list_vim_var __ARGS((int i)); +static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string)); +static void set_var __ARGS((char_u *name, VAR varp)); +static void copy_var __ARGS((VAR from, VAR to)); +static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags)); +static char_u *trans_function_name __ARGS((char_u **pp, int skip, int internal)); +static int eval_fname_script __ARGS((char_u *p)); +static int eval_fname_sid __ARGS((char_u *p)); +static void list_func_head __ARGS((ufunc_T *fp, int indent)); +static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp)); +static ufunc_T *find_func __ARGS((char_u *name)); +static void call_user_func __ARGS((ufunc_T *fp, int argcount, VAR argvars, VAR retvar, linenr_T firstline, linenr_T lastline)); + +/* Magic braces are always enabled, otherwise Vim scripts would not be + * portable. */ +#define FEAT_MAGIC_BRACES + +#ifdef FEAT_MAGIC_BRACES +static char_u * make_expanded_name __ARGS((char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end)); +#endif + +/* + * Set an internal variable to a string value. Creates the variable if it does + * not already exist. + */ + void +set_internal_string_var(name, value) + char_u *name; + char_u *value; +{ + char_u *val; + VAR varp; + + val = vim_strsave(value); + if (val != NULL) + { + varp = alloc_string_var(val); + if (varp != NULL) + { + set_var(name, varp); + free_var(varp); + } + } +} + +# if defined(FEAT_MBYTE) || defined(PROTO) + int +eval_charconvert(enc_from, enc_to, fname_from, fname_to) + 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; +} +# endif + +# if defined(FEAT_POSTSCRIPT) || defined(PROTO) + int +eval_printexpr(fname, args) + 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) + { + mch_remove(fname); + return FAIL; + } + return OK; +} +# endif + +# if defined(FEAT_DIFF) || defined(PROTO) + void +eval_diff(origfile, newfile, outfile) + 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(origfile, difffile, outfile) + 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); +} +# endif + +/* + * Top level evaluation function, returning a boolean. + * Sets "error" to TRUE if there was an error. + * Return TRUE or FALSE. + */ + int +eval_to_bool(arg, error, nextcmd, skip) + char_u *arg; + int *error; + char_u **nextcmd; + int skip; /* only parse, don't execute */ +{ + var retvar; + int retval = FALSE; + + if (skip) + ++emsg_skip; + if (eval0(arg, &retvar, nextcmd, !skip) == FAIL) + { + *error = TRUE; + } + else + { + *error = FALSE; + if (!skip) + { + retval = (get_var_number(&retvar) != 0); + clear_var(&retvar); + } + } + 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(arg, nextcmd, skip) + char_u *arg; + char_u **nextcmd; + int skip; /* only parse, don't execute */ +{ + var retvar; + char_u *retval; + + if (skip) + ++emsg_skip; + if (eval0(arg, &retvar, nextcmd, !skip) == FAIL || skip) + retval = NULL; + else + { + retval = vim_strsave(get_var_string(&retvar)); + clear_var(&retvar); + } + if (skip) + --emsg_skip; + + return retval; +} + +/* + * Top level evaluation function, returning a string. + * Return pointer to allocated memory, or NULL for failure. + */ + char_u * +eval_to_string(arg, nextcmd) + char_u *arg; + char_u **nextcmd; +{ + var retvar; + char_u *retval; + + if (eval0(arg, &retvar, nextcmd, TRUE) == FAIL) + retval = NULL; + else + { + retval = vim_strsave(get_var_string(&retvar)); + clear_var(&retvar); + } + + return retval; +} + +/* + * Call eval_to_string() with "sandbox" set and not using local variables. + */ + char_u * +eval_to_string_safe(arg, nextcmd) + char_u *arg; + char_u **nextcmd; +{ + char_u *retval; + void *save_funccalp; + + save_funccalp = save_funccal(); + ++sandbox; + retval = eval_to_string(arg, nextcmd); + --sandbox; + restore_funccal(save_funccalp); + return retval; +} + +#if 0 /* not used */ +/* + * Top level evaluation function, returning a string. + * Advances "arg" to the first non-blank after the evaluated expression. + * Return pointer to allocated memory, or NULL for failure. + * Doesn't give error messages. + */ + char_u * +eval_arg_to_string(arg) + char_u **arg; +{ + var retvar; + char_u *retval; + int ret; + + ++emsg_off; + + ret = eval1(arg, &retvar, TRUE); + if (ret == FAIL) + retval = NULL; + else + { + retval = vim_strsave(get_var_string(&retvar)); + clear_var(&retvar); + } + + --emsg_off; + + return retval; +} +#endif + +/* + * Top level evaluation function, returning a number. + * Evaluates "expr" silently. + * Returns -1 for an error. + */ + int +eval_to_number(expr) + char_u *expr; +{ + var retvar; + int retval; + char_u *p = expr; + + ++emsg_off; + + if (eval1(&p, &retvar, TRUE) == FAIL) + retval = -1; + else + { + retval = get_var_number(&retvar); + clear_var(&retvar); + } + --emsg_off; + + return retval; +} + +#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) +/* + * Call some vimL function and return the result as a string + * Uses argv[argc] for the function arguments. + */ + char_u * +call_vim_function(func, argc, argv, safe) + char_u *func; + int argc; + char_u **argv; + int safe; /* use the sandbox */ +{ + char_u *retval = NULL; + var retvar; + VAR argvars; + long n; + int len; + int i; + int doesrange; + void *save_funccalp = NULL; + + argvars = (VAR)alloc((unsigned)(argc * sizeof(var))); + if (argvars == NULL) + return NULL; + + for (i = 0; i < argc; i++) + { + /* 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].var_type = VAR_NUMBER; + argvars[i].var_val.var_number = n; + } + else + { + argvars[i].var_type = VAR_STRING; + argvars[i].var_val.var_string = argv[i]; + } + } + + if (safe) + { + save_funccalp = save_funccal(); + ++sandbox; + } + + retvar.var_type = VAR_UNKNOWN; /* clear_var() uses this */ + if (call_func(func, (int)STRLEN(func), &retvar, argc, argvars, + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &doesrange, TRUE) == OK) + retval = vim_strsave(get_var_string(&retvar)); + + clear_var(&retvar); + vim_free(argvars); + + if (safe) + { + --sandbox; + restore_funccal(save_funccalp); + } + return retval; +} +#endif + +/* + * Save the current function call pointer, and set it to NULL. + * Used when executing autocommands and for ":source". + */ + void * +save_funccal() +{ + struct funccall *fc; + + fc = current_funccal; + current_funccal = NULL; + return (void *)fc; +} + + void +restore_funccal(fc) + void *fc; +{ + current_funccal = (struct funccall *)fc; +} + +#ifdef FEAT_FOLDING +/* + * Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding + * it in "*cp". Doesn't give error messages. + */ + int +eval_foldexpr(arg, cp) + char_u *arg; + int *cp; +{ + var retvar; + int retval; + char_u *s; + + ++emsg_off; + ++sandbox; + *cp = NUL; + if (eval0(arg, &retvar, NULL, TRUE) == FAIL) + retval = 0; + else + { + /* If the result is a number, just return the number. */ + if (retvar.var_type == VAR_NUMBER) + retval = retvar.var_val.var_number; + else if (retvar.var_type == VAR_UNKNOWN + || retvar.var_val.var_string == NULL) + retval = 0; + else + { + /* If the result is a string, check if there is a non-digit before + * the number. */ + s = retvar.var_val.var_string; + if (!VIM_ISDIGIT(*s) && *s != '-') + *cp = *s++; + retval = atol((char *)s); + } + clear_var(&retvar); + } + --emsg_off; + --sandbox; + + return retval; +} +#endif + +#ifdef FEAT_MAGIC_BRACES +/* + * Expands out the 'magic' {}'s in a variable/function name. + * Note that this can call itself recursively, to deal with + * constructs like foo{bar}{baz}{bam} + * The four pointer arguments point to "foo{expre}ss{ion}bar" + * "in_start" ^ + * "expr_start" ^ + * "expr_end" ^ + * "in_end" ^ + * + * Returns a new allocated string, which the caller must free. + * Returns NULL for failure. + */ + static char_u * +make_expanded_name(in_start, expr_start, expr_end, in_end) + char_u *in_start; + char_u *expr_start; + char_u *expr_end; + char_u *in_end; +{ + char_u c1; + char_u *retval = NULL; + char_u *temp_result; + char_u *nextcmd = NULL; + + if (expr_end == NULL || in_end == NULL) + return NULL; + *expr_start = NUL; + *expr_end = NUL; + c1 = *in_end; + *in_end = NUL; + + temp_result = eval_to_string(expr_start + 1, &nextcmd); + if (temp_result != NULL && nextcmd == NULL) + { + retval = alloc((unsigned)(STRLEN(temp_result) + (expr_start - in_start) + + (in_end - expr_end) + 1)); + + if (retval != NULL) + { + STRCPY(retval, in_start); + STRCAT(retval, temp_result); + STRCAT(retval, expr_end + 1); + } + } + vim_free(temp_result); + + *in_end = c1; /* put char back for error messages */ + *expr_start = '{'; + *expr_end = '}'; + + if (retval != NULL) + { + temp_result = find_name_end(retval, &expr_start, &expr_end); + if (expr_start != NULL) + { + /* Further expansion! */ + temp_result = make_expanded_name(retval, expr_start, + expr_end, temp_result); + vim_free(retval); + retval = temp_result; + } + } + + return retval; + +} +#endif /* FEAT_MAGIC_BRACES */ + +/* + * ":let var = expr" assignment command. + * ":let var" list one variable value + * ":let" list all variable values + */ + void +ex_let(eap) + exarg_T *eap; +{ + char_u *arg = eap->arg; + char_u *expr; + char_u *name; + VAR varp; + var retvar; + char_u *p; + int c1 = 0, c2; + int i; + char_u *expr_start; + char_u *expr_end; + char_u *name_end; + + name_end = find_name_end(arg, &expr_start, &expr_end); + expr = vim_strchr(name_end, '='); + if (expr == NULL) + { + if (ends_excmd(*arg)) + { + if (!eap->skip) + { + /* + * List all variables. + */ + for (i = 0; i < variables.ga_len && !got_int; ++i) + if (VAR_ENTRY(i).var_name != NULL) + list_one_var(&VAR_ENTRY(i), (char_u *)""); + for (i = 0; i < curbuf->b_vars.ga_len && !got_int; ++i) + if (BVAR_ENTRY(i).var_name != NULL) + list_one_var(&BVAR_ENTRY(i), (char_u *)"b:"); + for (i = 0; i < curwin->w_vars.ga_len && !got_int; ++i) + if (WVAR_ENTRY(i).var_name != NULL) + list_one_var(&WVAR_ENTRY(i), (char_u *)"w:"); + for (i = 0; i < VV_LEN && !got_int; ++i) + if (vimvars[i].type == VAR_NUMBER || vimvars[i].val != NULL) + list_vim_var(i); + } + } + else + { + int error = FALSE; + + /* + * List variables. + */ + while (!ends_excmd(*arg) && !got_int) + { + char_u *temp_string = NULL; + int arg_len; + + /* Find the end of the name. */ + name_end = find_name_end(arg, &expr_start, &expr_end); + + if (!vim_iswhite(*name_end) && !ends_excmd(*name_end)) + { + emsg_severe = TRUE; + EMSG(_(e_trailing)); + break; + } + if (!error && !eap->skip) + { +#ifdef FEAT_MAGIC_BRACES + if (expr_start != NULL) + { + temp_string = make_expanded_name(arg, expr_start, + expr_end, name_end); + if (temp_string == NULL) + { + /* + * Report an invalid expression in braces, unless + * the expression evaluation has been cancelled due + * to an aborting error, an interrupt, or an + * exception. + */ + if (!aborting()) + { + emsg_severe = TRUE; + EMSG2(_(e_invarg2), arg); + break; + } + error = TRUE; + arg = skipwhite(name_end); + continue; + } + arg = temp_string; + arg_len = STRLEN(temp_string); + } + else +#endif + { + c1 = *name_end; + *name_end = NUL; + arg_len = (int)(name_end - arg); + } + i = find_vim_var(arg, arg_len); + if (i >= 0) + list_vim_var(i); + else if (STRCMP("b:changedtick", arg) == 0) + { + char_u numbuf[NUMBUFLEN]; + + sprintf((char *)numbuf, "%ld", + (long)curbuf->b_changedtick); + list_one_var_a((char_u *)"b:", (char_u *)"changedtick", + VAR_NUMBER, numbuf); + } + else + { + varp = find_var(arg, FALSE); + if (varp == NULL) + { + /* Skip further arguments but do continue to + * search for a trailing command. */ + EMSG2(_("E106: Unknown variable: \"%s\""), arg); + error = TRUE; + } + else + { + name = vim_strchr(arg, ':'); + if (name != NULL) + { + /* "a:" vars have no name stored, use whole + * arg */ + if (arg[0] == 'a' && arg[1] == ':') + c2 = NUL; + else + { + c2 = *++name; + *name = NUL; + } + list_one_var(varp, arg); + if (c2 != NUL) + *name = c2; + } + else + list_one_var(varp, (char_u *)""); + } + } +#ifdef FEAT_MAGIC_BRACES + if (expr_start != NULL) + vim_free(temp_string); + else +#endif + *name_end = c1; + } + arg = skipwhite(name_end); + } + } + eap->nextcmd = check_nextcmd(arg); + } + else + { + if (eap->skip) + ++emsg_skip; + i = eval0(expr + 1, &retvar, &eap->nextcmd, !eap->skip); + if (eap->skip) + { + if (i != FAIL) + clear_var(&retvar); + --emsg_skip; + } + else if (i != FAIL) + { + /* + * ":let $VAR = expr": Set environment variable. + */ + if (*arg == '$') + { + int len; + int cc; + + /* Find the end of the name. */ + ++arg; + name = arg; + len = get_env_len(&arg); + if (len == 0) + EMSG2(_(e_invarg2), name - 1); + else + { + if (*skipwhite(arg) != '=') + EMSG(_(e_letunexp)); + else + { + cc = name[len]; + name[len] = NUL; + p = get_var_string(&retvar); + vim_setenv(name, p); + if (STRICMP(name, "HOME") == 0) + init_homedir(); + else if (didset_vim && STRICMP(name, "VIM") == 0) + didset_vim = FALSE; + else if (didset_vimruntime + && STRICMP(name, "VIMRUNTIME") == 0) + didset_vimruntime = FALSE; + name[len] = cc; + } + } + } + + /* + * ":let &option = expr": Set option value. + * ":let &l:option = expr": Set local option value. + * ":let &g:option = expr": Set global option value. + */ + else if (*arg == '&') + { + int opt_flags; + + /* + * Find the end of the name; + */ + p = find_option_end(&arg, &opt_flags); + if (p == NULL || *skipwhite(p) != '=') + EMSG(_(e_letunexp)); + else + { + c1 = *p; + *p = NUL; + set_option_value(arg, get_var_number(&retvar), + get_var_string(&retvar), opt_flags); + *p = c1; /* put b |