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