Patch 8.1.1939
Problem: Code for handling v: variables in generic eval file.
Solution: Move v: variables to evalvars.c. (Yegappan Lakshmanan,
closes #4872)
Files: src/eval.c, src/evalvars.c, src/proto/
eval.pro,
src/proto/
evalvars.pro
*** ../vim-8.1.1938/src/eval.c 2019-08-27 22:48:12.737480696 +0200
--- src/eval.c 2019-08-29 22:02:16.891931613 +0200
***************
*** 29,42 ****
#define NAMESPACE_CHAR (char_u *)"abglstvw"
- static dictitem_T globvars_var; /* variable used for g: */
-
- /*
- * 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.
--- 29,34 ----
***************
*** 44,63 ****
*/
static int current_copyID = 0;
- /*
- * 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" */
/* The names of packages that once were loaded are remembered. */
--- 36,41 ----
***************
*** 76,215 ****
blob_T *fi_blob; /* blob being used */
} forinfo_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.
- */
-
- /* 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}}
-
- static struct vimvar
- {
- char *vv_name; /* name of variable, without v: */
- dictitem16_T vv_di; /* value and name for key (max 16 chars!) */
- 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_winid", 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_winid", 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("completed_item", VAR_DICT), VV_RO},
- {VV_NAME("option_new", VAR_STRING), VV_RO},
- {VV_NAME("option_old", VAR_STRING), VV_RO},
- {VV_NAME("option_oldlocal", VAR_STRING), VV_RO},
- {VV_NAME("option_oldglobal", VAR_STRING), VV_RO},
- {VV_NAME("option_command", VAR_STRING), VV_RO},
- {VV_NAME("option_type", VAR_STRING), VV_RO},
- {VV_NAME("errors", VAR_LIST), 0},
- {VV_NAME("false", VAR_SPECIAL), VV_RO},
- {VV_NAME("true", VAR_SPECIAL), VV_RO},
- {VV_NAME("null", VAR_SPECIAL), VV_RO},
- {VV_NAME("none", VAR_SPECIAL), VV_RO},
- {VV_NAME("vim_did_enter", VAR_NUMBER), VV_RO},
- {VV_NAME("testing", VAR_NUMBER), 0},
- {VV_NAME("t_number", VAR_NUMBER), VV_RO},
- {VV_NAME("t_string", VAR_NUMBER), VV_RO},
- {VV_NAME("t_func", VAR_NUMBER), VV_RO},
- {VV_NAME("t_list", VAR_NUMBER), VV_RO},
- {VV_NAME("t_dict", VAR_NUMBER), VV_RO},
- {VV_NAME("t_float", VAR_NUMBER), VV_RO},
- {VV_NAME("t_bool", VAR_NUMBER), VV_RO},
- {VV_NAME("t_none", VAR_NUMBER), VV_RO},
- {VV_NAME("t_job", VAR_NUMBER), VV_RO},
- {VV_NAME("t_channel", VAR_NUMBER), VV_RO},
- {VV_NAME("t_blob", VAR_NUMBER), VV_RO},
- {VV_NAME("termrfgresp", VAR_STRING), VV_RO},
- {VV_NAME("termrbgresp", VAR_STRING), VV_RO},
- {VV_NAME("termu7resp", VAR_STRING), VV_RO},
- {VV_NAME("termstyleresp", VAR_STRING), VV_RO},
- {VV_NAME("termblinkresp", VAR_STRING), VV_RO},
- {VV_NAME("event", VAR_DICT), VV_RO},
- {VV_NAME("versionlong", VAR_NUMBER), VV_RO},
- {VV_NAME("echospace", VAR_NUMBER), VV_RO},
- };
-
- /* 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_dict vv_di.di_tv.vval.v_dict
- #define vv_blob vv_di.di_tv.vval.v_blob
- #define vv_tv vv_di.di_tv
-
- static dictitem_T vimvars_var; /* variable used for v: */
- #define vimvarht vimvardict.dv_hashtab
-
static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
static int eval2(char_u **arg, typval_T *rettv, int evaluate);
static int eval3(char_u **arg, typval_T *rettv, int evaluate);
--- 54,59 ----
***************
*** 224,236 ****
static int free_unref_items(int copyID);
static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
- static void check_vars(char_u *name, int len);
- static typval_T *alloc_string_tv(char_u *string);
static int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
- /* for VIM_VERSION_ defines */
- #include "version.h"
-
/*
* Return "n1" divided by "n2", taking care of dividing by zero.
*/
--- 68,75 ----
***************
*** 264,270 ****
return (n2 == 0) ? 0 : (n1 % n2);
}
-
#if defined(EBCDIC) || defined(PROTO)
/*
* Compare struct fst by function name.
--- 103,108 ----
***************
*** 292,366 ****
}
#endif
-
/*
* 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);
func_init();
- for (i = 0; i < VV_LEN; ++i)
- {
- p = &vimvars[i];
- if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
- {
- iemsg("INTERNAL: name too long, increase size of dictitem16_T");
- getout(1);
- }
- 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);
- }
- vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
- vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
-
- set_vim_var_nr(VV_SEARCHFORWARD, 1L);
- set_vim_var_nr(VV_HLSEARCH, 1L);
- set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
- set_vim_var_list(VV_ERRORS, list_alloc());
- set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
-
- set_vim_var_nr(VV_FALSE, VVAL_FALSE);
- set_vim_var_nr(VV_TRUE, VVAL_TRUE);
- set_vim_var_nr(VV_NONE, VVAL_NONE);
- set_vim_var_nr(VV_NULL, VVAL_NULL);
-
- set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
- set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
- set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
- set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
- set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
- set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
- set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
- set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
- set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
- set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
- set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
-
- set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
-
- set_reg_var(0); /* default for v:register is not 0 but '"' */
-
#ifdef EBCDIC
/*
* Sort the function table, to enable binary search.
--- 130,144 ----
}
#endif
/*
* Initialize the global and v: variables.
*/
void
eval_init(void)
{
! evalvars_init();
func_init();
#ifdef EBCDIC
/*
* Sort the function table, to enable binary search.
***************
*** 373,414 ****
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)
! VIM_CLEAR(p->vv_str);
! 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)
- vim_free(SCRIPT_SV(i));
- ga_clear(&ga_scripts);
-
// unreferenced lists and dicts
(void)garbage_collect(FALSE);
--- 151,164 ----
void
eval_clear(void)
{
! evalvars_clear();
free_scriptnames();
free_locales();
/* autoloaded script names */
ga_clear_strings(&ga_loaded);
// unreferenced lists and dicts
(void)garbage_collect(FALSE);
***************
*** 417,445 ****
}
#endif
-
- /*
- * 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;
- typval_T *tvp;
-
- val = vim_strsave(value);
- if (val != NULL)
- {
- tvp = alloc_string_tv(val);
- if (tvp != NULL)
- {
- set_var(name, tvp, FALSE);
- free_tv(tvp);
- }
- }
- }
-
static lval_T *redir_lval = NULL;
#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
static garray_T redir_ga; /* only valid when redir_lval is not NULL */
--- 167,172 ----
***************
*** 944,1014 ****
return retval;
}
- /*
- * List Vim variables.
- */
- void
- list_vim_vars(int *first)
- {
- list_hashtable_vars(&vimvarht, "v:", FALSE, first);
- }
-
- /*
- * List script-local variables, if there is a script.
- */
- void
- list_script_vars(int *first)
- {
- if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
- list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
- "s:", FALSE, first);
- }
-
- int
- is_vimvarht(hashtab_T *ht)
- {
- return ht == &vimvarht;
- }
-
- int
- is_compatht(hashtab_T *ht)
- {
- return ht == &compat_hashtab;
- }
-
- /*
- * 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.
- */
- 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.
- */
- 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))
- internal_error("restore_vimvar()");
- else
- hash_remove(&vimvarht, hi);
- }
- }
-
#if defined(FEAT_SPELL) || defined(PROTO)
/*
* Evaluate an expression to a list with suggestions.
--- 671,676 ----
***************
*** 1025,1032 ****
/* 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;
--- 687,693 ----
/* Set "v:val" to the bad word. */
prepare_vimvar(VV_VAL, &save_val);
! set_vim_var_string(VV_VAL, badword, -1);
if (p_verbose == 0)
++emsg_off;
***************
*** 1040,1045 ****
--- 701,707 ----
if (p_verbose == 0)
--emsg_off;
+ clear_tv(get_vim_var_tv(VV_VAL));
restore_vimvar(VV_VAL, &save_val);
return list;
***************
*** 1085,1091 ****
return tv;
}
-
/*
* Call some Vim script function and return the result in "*rettv".
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
--- 747,752 ----
***************
*** 1186,1192 ****
return rettv.vval.v_list;
}
-
#ifdef FEAT_FOLDING
/*
* Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding
--- 847,852 ----
***************
*** 2287,2411 ****
#endif
/*
- * Local string buffer for the next two functions to store a variable name
- * with its prefix. Allocated in cat_prefix_varname(), freed later in
- * get_user_var_name().
- */
-
- static char_u *varnamebuf = NULL;
- static int varnamebuflen = 0;
-
- /*
- * Function to concatenate a prefix and a variable name.
- */
- static char_u *
- cat_prefix_varname(int prefix, char_u *name)
- {
- int len;
-
- len = (int)STRLEN(name) + 3;
- if (len > varnamebuflen)
- {
- vim_free(varnamebuf);
- len += 10; /* some additional space */
- varnamebuf = alloc(len);
- if (varnamebuf == NULL)
- {
- varnamebuflen = 0;
- return NULL;
- }
- varnamebuflen = len;
- }
- *varnamebuf = prefix;
- varnamebuf[1] = ':';
- STRCPY(varnamebuf + 2, name);
- return varnamebuf;
- }
-
- /*
- * Function given to ExpandGeneric() to obtain the list of user defined
- * (global/buffer/window/built-in) variable names.
- */
- char_u *
- get_user_var_name(expand_T *xp, int idx)
- {
- static long_u gdone;
- static long_u bdone;
- static long_u wdone;
- static long_u tdone;
- static int vidx;
- static hashitem_T *hi;
- hashtab_T *ht;
-
- if (idx == 0)
- {
- gdone = bdone = wdone = vidx = 0;
- tdone = 0;
- }
-
- /* Global variables */
- if (gdone < globvarht.ht_used)
- {
- if (gdone++ == 0)
- hi = globvarht.ht_array;
- else
- ++hi;
- while (HASHITEM_EMPTY(hi))
- ++hi;
- if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
- return cat_prefix_varname('g', hi->hi_key);
- return hi->hi_key;
- }
-
- /* b: variables */
- ht = &curbuf->b_vars->dv_hashtab;
- if (bdone < ht->ht_used)
- {
- if (bdone++ == 0)
- hi = ht->ht_array;
- else
- ++hi;
- while (HASHITEM_EMPTY(hi))
- ++hi;
- return cat_prefix_varname('b', hi->hi_key);
- }
-
- /* w: variables */
- ht = &curwin->w_vars->dv_hashtab;
- if (wdone < ht->ht_used)
- {
- if (wdone++ == 0)
- hi = ht->ht_array;
- else
- ++hi;
- while (HASHITEM_EMPTY(hi))
- ++hi;
- return cat_prefix_varname('w', hi->hi_key);
- }
-
- /* t: variables */
- ht = &curtab->tp_vars->dv_hashtab;
- if (tdone < ht->ht_used)
- {
- if (tdone++ == 0)
- hi = ht->ht_array;
- else
- ++hi;
- while (HASHITEM_EMPTY(hi))
- ++hi;
- return cat_prefix_varname('t', hi->hi_key);
- }
-
- /* v: variables */
- if (vidx < VV_LEN)
- return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
-
- VIM_CLEAR(varnamebuf);
- varnamebuflen = 0;
- return NULL;
- }
-
- /*
* Return TRUE if "pat" matches "text".
* Does not use 'cpo' and always uses 'magic'.
*/
--- 1947,1952 ----
***************
*** 4619,4625 ****
int abort = FALSE;
buf_T *buf;
win_T *wp;
- int i;
int did_free = FALSE;
tabpage_T *tp;
--- 4160,4165 ----
***************
*** 4646,4653 ****
abort = abort || set_ref_in_previous_funccal(copyID);
/* script-local variables */
! for (i = 1; i <= ga_scripts.ga_len; ++i)
! abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
/* buffer-local variables */
FOR_ALL_BUFFERS(buf)
--- 4186,4192 ----
abort = abort || set_ref_in_previous_funccal(copyID);
/* script-local variables */
! abort = abort || garbage_collect_scriptvars(copyID);
/* buffer-local variables */
FOR_ALL_BUFFERS(buf)
***************
*** 4688,4694 ****
abort = abort || set_ref_in_func_args(copyID);
/* v: vars */
! abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL);
// callbacks in buffers
abort = abort || set_ref_in_buffers(copyID);
--- 4227,4233 ----
abort = abort || set_ref_in_func_args(copyID);
/* v: vars */
! abort = abort || garbage_collect_vimvars(copyID);
// callbacks in buffers
abort = abort || set_ref_in_buffers(copyID);
***************
*** 5475,5482 ****
return OK;
}
-
-
/*
* Translate a String variable into a position.
* Returns NULL when there is an error.
--- 5014,5019 ----
***************
*** 5957,6272 ****
}
/*
- * Set number v: variable to "val".
- */
- void
- set_vim_var_nr(int idx, varnumber_T val)
- {
- vimvars[idx].vv_nr = val;
- }
-
- /*
- * Get typval_T v: variable value.
- */
- typval_T *
- get_vim_var_tv(int idx)
- {
- return &vimvars[idx].vv_tv;
- }
-
- /*
- * Get number v: variable value.
- */
- varnumber_T
- get_vim_var_nr(int idx)
- {
- return vimvars[idx].vv_nr;
- }
-
- /*
- * Get string v: variable value. Uses a static buffer, can only be used once.
- * If the String variable has never been set, return an empty string.
- * Never returns NULL;
- */
- char_u *
- get_vim_var_str(int idx)
- {
- return tv_get_string(&vimvars[idx].vv_tv);
- }
-
- /*
- * Get List v: variable value. Caller must take care of reference count when
- * needed.
- */
- list_T *
- get_vim_var_list(int idx)
- {
- return vimvars[idx].vv_list;
- }
-
- /*
- * Get Dict v: variable value. Caller must take care of reference count when
- * needed.
- */
- dict_T *
- get_vim_var_dict(int idx)
- {
- return vimvars[idx].vv_dict;
- }
-
- /*
- * Set v:char to character "c".
- */
- void
- set_vim_var_char(int c)
- {
- char_u buf[MB_MAXBYTES + 1];
-
- if (has_mbyte)
- buf[(*mb_char2bytes)(c, buf)] = NUL;
- else
- {
- buf[0] = c;
- buf[1] = NUL;
- }
- set_vim_var_string(VV_CHAR, buf, -1);
- }
-
- /*
- * Set v:count to "count" and v:count1 to "count1".
- * When "set_prevcount" is TRUE first set v:prevcount from v:count.
- */
- void
- set_vcount(
- long count,
- long count1,
- int set_prevcount)
- {
- if (set_prevcount)
- vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
- vimvars[VV_COUNT].vv_nr = count;
- vimvars[VV_COUNT1].vv_nr = count1;
- }
-
- /*
- * Save variables that might be changed as a side effect. Used when executing
- * a timer callback.
- */
- void
- save_vimvars(vimvars_save_T *vvsave)
- {
- vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
- vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
- vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
- }
-
- /*
- * Restore variables saved by save_vimvars().
- */
- void
- restore_vimvars(vimvars_save_T *vvsave)
- {
- vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
- vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
- vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
- }
-
- /*
- * Set string v: variable to a copy of "val".
- */
- void
- set_vim_var_string(
- int idx,
- char_u *val,
- int len) /* length of "val" to use or -1 (whole string) */
- {
- clear_tv(&vimvars[idx].vv_di.di_tv);
- vimvars[idx].vv_type = VAR_STRING;
- if (val == NULL)
- vimvars[idx].vv_str = NULL;
- else if (len == -1)
- vimvars[idx].vv_str = vim_strsave(val);
- else
- vimvars[idx].vv_str = vim_strnsave(val, len);
- }
-
- /*
- * Set List v: variable to "val".
- */
- void
- set_vim_var_list(int idx, list_T *val)
- {
- clear_tv(&vimvars[idx].vv_di.di_tv);
- vimvars[idx].vv_type = VAR_LIST;
- vimvars[idx].vv_list = val;
- if (val != NULL)
- ++val->lv_refcount;
- }
-
- /*
- * Set Dictionary v: variable to "val".
- */
- void
- set_vim_var_dict(int idx, dict_T *val)
- {
- clear_tv(&vimvars[idx].vv_di.di_tv);
- vimvars[idx].vv_type = VAR_DICT;
- vimvars[idx].vv_dict = val;
- if (val != NULL)
- {
- ++val->dv_refcount;
- dict_set_items_ro(val);
- }
- }
-
- /*
- * Set v:register if needed.
- */
- void
- set_reg_var(int c)
- {
- char_u regname;
-
- if (c == 0 || c == ' ')
- regname = '"';
- else
- regname = c;
- /* Avoid free/alloc when the value is already right. */
- if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
- set_vim_var_string(VV_REG, ®name, 1);
- }
-
- /*
- * Get or set v:exception. If "oldval" == NULL, return the current value.
- * Otherwise, restore the value to "oldval" and return NULL.
- * Must always be called in pairs to save and restore v:exception! Does not
- * take care of memory allocations.
- */
- char_u *
- v_exception(char_u *oldval)
- {
- if (oldval == NULL)
- return vimvars[VV_EXCEPTION].vv_str;
-
- vimvars[VV_EXCEPTION].vv_str = oldval;
- return NULL;
- }
-
- /*
- * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
- * Otherwise, restore the value to "oldval" and return NULL.
- * Must always be called in pairs to save and restore v:throwpoint! Does not
- * take care of memory allocations.
- */
- char_u *
- v_throwpoint(char_u *oldval)
- {
- if (oldval == NULL)
- return vimvars[VV_THROWPOINT].vv_str;
-
- vimvars[VV_THROWPOINT].vv_str = oldval;
- return NULL;
- }
-
- /*
- * Set v:cmdarg.
- * If "eap" != NULL, use "eap" to generate the value and return the old value.
- * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
- * Must always be called in pairs!
- */
- char_u *
- set_cmdarg(exarg_T *eap, char_u *oldarg)
- {
- char_u *oldval;
- char_u *newval;
- unsigned len;
-
- oldval = vimvars[VV_CMDARG].vv_str;
- if (eap == NULL)
- {
- vim_free(oldval);
- vimvars[VV_CMDARG].vv_str = oldarg;
- return NULL;
- }
-
- if (eap->force_bin == FORCE_BIN)
- len = 6;
- else if (eap->force_bin == FORCE_NOBIN)
- len = 8;
- else
- len = 0;
-
- if (eap->read_edit)
- len += 7;
-
- if (eap->force_ff != 0)
- len += 10; /* " ++ff=unix" */
- if (eap->force_enc != 0)
- len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
- if (eap->bad_char != 0)
- len += 7 + 4; /* " ++bad=" + "keep" or "drop" */
-
- newval = alloc(len + 1);
- if (newval == NULL)
- return NULL;
-
- if (eap->force_bin == FORCE_BIN)
- sprintf((char *)newval, " ++bin");
- else if (eap->force_bin == FORCE_NOBIN)
- sprintf((char *)newval, " ++nobin");
- else
- *newval = NUL;
-
- if (eap->read_edit)
- STRCAT(newval, " ++edit");
-
- if (eap->force_ff != 0)
- sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
- eap->force_ff == 'u' ? "unix"
- : eap->force_ff == 'd' ? "dos"
- : "mac");
- if (eap->force_enc != 0)
- sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
- eap->cmd + eap->force_enc);
- if (eap->bad_char == BAD_KEEP)
- STRCPY(newval + STRLEN(newval), " ++bad=keep");
- else if (eap->bad_char == BAD_DROP)
- STRCPY(newval + STRLEN(newval), " ++bad=drop");
- else if (eap->bad_char != 0)
- sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
- vimvars[VV_CMDARG].vv_str = newval;
- return oldval;
- }
-
- /*
- * Check if variable "name[len]" is a local variable or an argument.
- * If so, "*eval_lavars_used" is set to TRUE.
- */
- static void
- check_vars(char_u *name, int len)
- {
- int cc;
- char_u *varname;
- hashtab_T *ht;
-
- if (eval_lavars_used == NULL)
- return;
-
- /* truncate the name, so that we can use strcmp() */
- cc = name[len];
- name[len] = NUL;
-
- ht = find_var_ht(name, &varname);
- if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
- {
- if (find_var(name, NULL, TRUE) != NULL)
- *eval_lavars_used = TRUE;
- }
-
- name[len] = cc;
- }
-
- /*
* Handle:
* - expr[expr], expr[expr:expr] subscript
* - ".name" lookup
--- 5494,5499 ----
***************
*** 6380,6386 ****
* The string "s" must have been allocated, it is consumed.
* Return NULL for out of memory, the variable otherwise.
*/
! static typval_T *
alloc_string_tv(char_u *s)
{
typval_T *rettv;
--- 5607,5613 ----
* The string "s" must have been allocated, it is consumed.
* Return NULL for out of memory, the variable otherwise.
*/
! typval_T *
alloc_string_tv(char_u *s)
{
typval_T *rettv;
***************
*** 6777,6985 ****
}
/*
- * Find variable "name" in the list of variables.
- * Return a pointer to it if found, NULL if not found.
- * Careful: "a:0" variables don't have a name.
- * When "htp" is not NULL we are writing to the variable, set "htp" to the
- * hashtab_T used.
- */
- dictitem_T *
- find_var(char_u *name, hashtab_T **htp, int no_autoload)
- {
- char_u *varname;
- hashtab_T *ht;
- dictitem_T *ret = NULL;
-
- ht = find_var_ht(name, &varname);
- if (htp != NULL)
- *htp = ht;
- if (ht == NULL)
- return NULL;
- ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
- if (ret != NULL)
- return ret;
-
- /* Search in parent scope for lambda */
- return find_var_in_scoped_ht(name, no_autoload || htp != NULL);
- }
-
- /*
- * Find variable "varname" in hashtab "ht" with name "htname".
- * Returns NULL if not found.
- */
- dictitem_T *
- find_var_in_ht(
- hashtab_T *ht,
- int htname,
- char_u *varname,
- int no_autoload)
- {
- hashitem_T *hi;
-
- if (*varname == NUL)
- {
- /* Must be something like "s:", otherwise "ht" would be NULL. */
- switch (htname)
- {
- case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
- case 'g': return &globvars_var;
- case 'v': return &vimvars_var;
- case 'b': return &curbuf->b_bufvar;
- case 'w': return &curwin->w_winvar;
- case 't': return &curtab->tp_winvar;
- case 'l': return get_funccal_local_var();
- case 'a': return get_funccal_args_var();
- }
- return NULL;
- }
-
- hi = hash_find(ht, varname);
- if (HASHITEM_EMPTY(hi))
- {
- /* For global variables we may try auto-loading the script. If it
- * worked find the variable again. Don't auto-load a script if it was
- * loaded already, otherwise it would be loaded every time when
- * checking if a function name is a Funcref variable. */
- if (ht == &globvarht && !no_autoload)
- {
- /* Note: script_autoload() may make "hi" invalid. It must either
- * be obtained again or not used. */
- if (!script_autoload(varname, FALSE) || aborting())
- return NULL;
- hi = hash_find(ht, varname);
- }
- if (HASHITEM_EMPTY(hi))
- return NULL;
- }
- return HI2DI(hi);
- }
-
- /*
- * Find the hashtab used for a variable name.
- * Return NULL if the name is not valid.
- * Set "varname" to the start of name without ':'.
- */
- hashtab_T *
- find_var_ht(char_u *name, char_u **varname)
- {
- hashitem_T *hi;
- hashtab_T *ht;
-
- if (name[0] == NUL)
- return NULL;
- if (name[1] != ':')
- {
- /* The name must not start with a colon or #. */
- if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
- return NULL;
- *varname = name;
-
- // "version" is "v:version" in all scopes if scriptversion < 3.
- // Same for a few other variables marked with VV_COMPAT.
- if (current_sctx.sc_version < 3)
- {
- hi = hash_find(&compat_hashtab, name);
- if (!HASHITEM_EMPTY(hi))
- return &compat_hashtab;
- }
-
- ht = get_funccal_local_ht();
- if (ht == NULL)
- return &globvarht; /* global variable */
- return ht; /* local variable */
- }
- *varname = name + 2;
- if (*name == 'g') /* global variable */
- return &globvarht;
- // There must be no ':' or '#' in the rest of the name, unless g: is used
- if (vim_strchr(name + 2, ':') != NULL
- || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
- return NULL;
- if (*name == 'b') /* buffer variable */
- return &curbuf->b_vars->dv_hashtab;
- if (*name == 'w') /* window variable */
- return &curwin->w_vars->dv_hashtab;
- if (*name == 't') /* tab page variable */
- return &curtab->tp_vars->dv_hashtab;
- if (*name == 'v') /* v: variable */
- return &vimvarht;
- if (*name == 'a') /* a: function argument */
- return get_funccal_args_ht();
- if (*name == 'l') /* l: local function variable */
- return get_funccal_local_ht();
- if (*name == 's' /* script variable */
- && current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
- return &SCRIPT_VARS(current_sctx.sc_sid);
- return NULL;
- }
-
- /*
- * Allocate a new hashtab for a sourced script. It will be used while
- * sourcing this script and when executing functions defined in the script.
- */
- void
- new_script_vars(scid_T id)
- {
- int i;
- hashtab_T *ht;
- scriptvar_T *sv;
-
- if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
- {
- /* Re-allocating ga_data means that an ht_array pointing to
- * ht_smallarray becomes invalid. We can recognize this: ht_mask is
- * at its init value. Also reset "v_dict", it's always the same. */
- for (i = 1; i <= ga_scripts.ga_len; ++i)
- {
- ht = &SCRIPT_VARS(i);
- if (ht->ht_mask == HT_INIT_SIZE - 1)
- ht->ht_array = ht->ht_smallarray;
- sv = SCRIPT_SV(i);
- sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
- }
-
- while (ga_scripts.ga_len < id)
- {
- sv = SCRIPT_SV(ga_scripts.ga_len + 1) =
- ALLOC_CLEAR_ONE(scriptvar_T);
- init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
- ++ga_scripts.ga_len;
- }
- }
- }
-
- /*
- * Initialize dictionary "dict" as a scope and set variable "dict_var" to
- * point to it.
- */
- void
- init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
- {
- hash_init(&dict->dv_hashtab);
- dict->dv_lock = 0;
- dict->dv_scope = scope;
- dict->dv_refcount = DO_NOT_FREE_CNT;
- dict->dv_copyID = 0;
- dict_var->di_tv.vval.v_dict = dict;
- dict_var->di_tv.v_type = VAR_DICT;
- dict_var->di_tv.v_lock = VAR_FIXED;
- dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- dict_var->di_key[0] = NUL;
- }
-
- /*
- * Unreference a dictionary initialized by init_var_dict().
- */
- void
- unref_var_dict(dict_T *dict)
- {
- /* Now the dict needs to be freed if no one else is using it, go back to
- * normal reference counting. */
- dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
- dict_unref(dict);
- }
-
- /*
* Return TRUE if typeval "tv" and its value are set to be locked (immutable).
* Also give an error message, using "name" or _("name") when use_gettext is
* TRUE.
--- 6004,6009 ----
***************
*** 7730,7763 ****
}
/*
- * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
- * v:option_type, and v:option_command.
- */
- void
- reset_v_option_vars(void)
- {
- set_vim_var_string(VV_OPTION_NEW, NULL, -1);
- set_vim_var_string(VV_OPTION_OLD, NULL, -1);
- set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
- set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
- set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
- set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
- }
-
- /*
- * Add an assert error to v:errors.
- */
- void
- assert_error(garray_T *gap)
- {
- struct vimvar *vp = &vimvars[VV_ERRORS];
-
- if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
- /* Make sure v:errors is a list. */
- set_vim_var_list(VV_ERRORS, list_alloc());
- list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
- }
- /*
* Compare "typ1" and "typ2". Put the result in "typ1".
*/
int
--- 6754,6759 ----
***************
*** 8000,8006 ****
#endif /* FEAT_EVAL */
-
#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
#ifdef MSWIN
--- 6996,7001 ----
***************
*** 8754,8762 ****
typval_T argv[3];
int retval = FAIL;
! copy_tv(tv, &vimvars[VV_VAL].vv_tv);
! argv[0] = vimvars[VV_KEY].vv_tv;
! argv[1] = vimvars[VV_VAL].vv_tv;
if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
goto theend;
if (map)
--- 7749,7757 ----
typval_T argv[3];
int retval = FAIL;
! copy_tv(tv, get_vim_var_tv(VV_VAL));
! argv[0] = *get_vim_var_tv(VV_KEY);
! argv[1] = *get_vim_var_tv(VV_VAL);
if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
goto theend;
if (map)
***************
*** 8780,8790 ****
}
retval = OK;
theend:
! clear_tv(&vimvars[VV_VAL].vv_tv);
return retval;
}
-
/*
* Implementation of map() and filter().
*/
--- 7775,7784 ----
}
retval = OK;
theend:
! clear_tv(get_vim_var_tv(VV_VAL));
return retval;
}
/*
* Implementation of map() and filter().
*/
***************
*** 8848,8855 ****
prepare_vimvar(VV_KEY, &save_key);
if (argvars[0].v_type == VAR_DICT)
{
- vimvars[VV_KEY].vv_type = VAR_STRING;
-
ht = &d->dv_hashtab;
hash_lock(ht);
todo = (int)ht->ht_used;
--- 7842,7847 ----
***************
*** 8866,8874 ****
|| var_check_ro(di->di_flags,
arg_errmsg, TRUE)))
break;
! vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
r = filter_map_one(&di->di_tv, expr, map, &rem);
! clear_tv(&vimvars[VV_KEY].vv_tv);
if (r == FAIL || did_emsg)
break;
if (!map && rem)
--- 7858,7866 ----
|| var_check_ro(di->di_flags,
arg_errmsg, TRUE)))
break;
! set_vim_var_string(VV_KEY, di->di_key, -1);
r = filter_map_one(&di->di_tv, expr, map, &rem);
! clear_tv(get_vim_var_tv(VV_KEY));
if (r == FAIL || did_emsg)
break;
if (!map && rem)
***************
*** 8887,8898 ****
int i;
typval_T tv;
- vimvars[VV_KEY].vv_type = VAR_NUMBER;
for (i = 0; i < b->bv_ga.ga_len; i++)
{
tv.v_type = VAR_NUMBER;
tv.vval.v_number = blob_get(b, i);
! vimvars[VV_KEY].vv_nr = idx;
if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
break;
if (tv.v_type != VAR_NUMBER)
--- 7879,7889 ----
int i;
typval_T tv;
for (i = 0; i < b->bv_ga.ga_len; i++)
{
tv.v_type = VAR_NUMBER;
tv.vval.v_number = blob_get(b, i);
! set_vim_var_nr(VV_KEY, idx);
if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
break;
if (tv.v_type != VAR_NUMBER)
***************
*** 8916,8929 ****
else
{
// argvars[0].v_type == VAR_LIST
- vimvars[VV_KEY].vv_type = VAR_NUMBER;
-
for (li = l->lv_first; li != NULL; li = nli)
{
if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
break;
nli = li->li_next;
! vimvars[VV_KEY].vv_nr = idx;
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
|| did_emsg)
break;
--- 7907,7918 ----
else
{
// argvars[0].v_type == VAR_LIST
for (li = l->lv_first; li != NULL; li = nli)
{
if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
break;
nli = li->li_next;
! set_vim_var_nr(VV_KEY, idx);
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
|| did_emsg)
break;
*** ../vim-8.1.1938/src/evalvars.c 2019-08-27 22:48:12.741480663 +0200
--- src/evalvars.c 2019-08-29 22:09:20.628579500 +0200
***************
*** 17,22 ****
--- 17,180 ----
static char *e_letunexp = N_("E18: Unexpected characters in :let");
+ static dictitem_T globvars_var; // variable used for g:
+
+ /*
+ * 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;
+
+ /*
+ * 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.
+ */
+
+ // 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}}
+
+ static struct vimvar
+ {
+ char *vv_name; // name of variable, without v:
+ dictitem16_T vv_di; // value and name for key (max 16 chars!)
+ 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_winid", 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_winid", 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("completed_item", VAR_DICT), VV_RO},
+ {VV_NAME("option_new", VAR_STRING), VV_RO},
+ {VV_NAME("option_old", VAR_STRING), VV_RO},
+ {VV_NAME("option_oldlocal", VAR_STRING), VV_RO},
+ {VV_NAME("option_oldglobal", VAR_STRING), VV_RO},
+ {VV_NAME("option_command", VAR_STRING), VV_RO},
+ {VV_NAME("option_type", VAR_STRING), VV_RO},
+ {VV_NAME("errors", VAR_LIST), 0},
+ {VV_NAME("false", VAR_SPECIAL), VV_RO},
+ {VV_NAME("true", VAR_SPECIAL), VV_RO},
+ {VV_NAME("null", VAR_SPECIAL), VV_RO},
+ {VV_NAME("none", VAR_SPECIAL), VV_RO},
+ {VV_NAME("vim_did_enter", VAR_NUMBER), VV_RO},
+ {VV_NAME("testing", VAR_NUMBER), 0},
+ {VV_NAME("t_number", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_string", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_func", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_list", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_dict", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_float", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_bool", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_none", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_job", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_channel", VAR_NUMBER), VV_RO},
+ {VV_NAME("t_blob", VAR_NUMBER), VV_RO},
+ {VV_NAME("termrfgresp", VAR_STRING), VV_RO},
+ {VV_NAME("termrbgresp", VAR_STRING), VV_RO},
+ {VV_NAME("termu7resp", VAR_STRING), VV_RO},
+ {VV_NAME("termstyleresp", VAR_STRING), VV_RO},
+ {VV_NAME("termblinkresp", VAR_STRING), VV_RO},
+ {VV_NAME("event", VAR_DICT), VV_RO},
+ {VV_NAME("versionlong", VAR_NUMBER), VV_RO},
+ {VV_NAME("echospace", VAR_NUMBER), VV_RO},
+ };
+
+ // 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_dict vv_di.di_tv.vval.v_dict
+ #define vv_blob vv_di.di_tv.vval.v_blob
+ #define vv_tv vv_di.di_tv
+
+ static dictitem_T vimvars_var; // variable used for v:
+ #define vimvarht vimvardict.dv_hashtab
+
+ // for VIM_VERSION_ defines
+ #include "version.h"
+
+ /*
+ * 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 void ex_let_const(exarg_T *eap, int is_const);
static char_u *skip_var_one(char_u *arg);
static void list_glob_vars(int *first);
***************
*** 33,38 ****
--- 191,396 ----
static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
/*
+ * Initialize global and vim special variables
+ */
+ void
+ evalvars_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);
+
+ for (i = 0; i < VV_LEN; ++i)
+ {
+ p = &vimvars[i];
+ if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
+ {
+ iemsg("INTERNAL: name too long, increase size of dictitem16_T");
+ getout(1);
+ }
+ 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);
+ }
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+ vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
+
+ set_vim_var_nr(VV_SEARCHFORWARD, 1L);
+ set_vim_var_nr(VV_HLSEARCH, 1L);
+ set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
+ set_vim_var_list(VV_ERRORS, list_alloc());
+ set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
+
+ set_vim_var_nr(VV_FALSE, VVAL_FALSE);
+ set_vim_var_nr(VV_TRUE, VVAL_TRUE);
+ set_vim_var_nr(VV_NONE, VVAL_NONE);
+ set_vim_var_nr(VV_NULL, VVAL_NULL);
+
+ set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
+ set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
+ set_vim_var_nr(VV_TYPE_FUNC, VAR_TYPE_FUNC);
+ set_vim_var_nr(VV_TYPE_LIST, VAR_TYPE_LIST);
+ set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
+ set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
+ set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
+ set_vim_var_nr(VV_TYPE_NONE, VAR_TYPE_NONE);
+ set_vim_var_nr(VV_TYPE_JOB, VAR_TYPE_JOB);
+ set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
+ set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
+
+ set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
+
+ set_reg_var(0); // default for v:register is not 0 but '"'
+ }
+
+ #if defined(EXITFREE) || defined(PROTO)
+ /*
+ * Free all vim variables information on exit
+ */
+ void
+ evalvars_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)
+ VIM_CLEAR(p->vv_str);
+ 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);
+
+ // global variables
+ vars_clear(&globvarht);
+
+ // 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)
+ vim_free(SCRIPT_SV(i));
+ ga_clear(&ga_scripts);
+ }
+ #endif
+
+ int
+ garbage_collect_vimvars(int copyID)
+ {
+ return set_ref_in_ht(&vimvarht, copyID, NULL);
+ }
+
+ int
+ garbage_collect_scriptvars(int copyID)
+ {
+ int i;
+ int abort = FALSE;
+
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
+
+ return abort;
+ }
+
+ /*
+ * 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;
+ typval_T *tvp;
+
+ val = vim_strsave(value);
+ if (val != NULL)
+ {
+ tvp = alloc_string_tv(val);
+ if (tvp != NULL)
+ {
+ set_var(name, tvp, FALSE);
+ free_tv(tvp);
+ }
+ }
+ }
+
+ /*
+ * 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.
+ */
+ 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.
+ */
+ 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))
+ internal_error("restore_vimvar()");
+ else
+ hash_remove(&vimvarht, hi);
+ }
+ }
+
+ /*
+ * List Vim variables.
+ */
+ static void
+ list_vim_vars(int *first)
+ {
+ list_hashtable_vars(&vimvarht, "v:", FALSE, first);
+ }
+
+ /*
+ * List script-local variables, if there is a script.
+ */
+ static void
+ list_script_vars(int *first)
+ {
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
+ "s:", FALSE, first);
+ }
+
+ /*
* Get a list of lines from a HERE document. The here document is a list of
* lines surrounded by a marker.
* cmd << {marker}
***************
*** 1024,1030 ****
{
if (ht == &globvarht)
d = &globvardict;
! else if (is_compatht(ht))
d = &vimvardict;
else
{
--- 1382,1388 ----
{
if (ht == &globvarht)
d = &globvardict;
! else if (ht == &compat_hashtab)
d = &vimvardict;
else
{
***************
*** 1214,1219 ****
--- 1572,1980 ----
}
/*
+ * Local string buffer for the next two functions to store a variable name
+ * with its prefix. Allocated in cat_prefix_varname(), freed later in
+ * get_user_var_name().
+ */
+
+ static char_u *varnamebuf = NULL;
+ static int varnamebuflen = 0;
+
+ /*
+ * Function to concatenate a prefix and a variable name.
+ */
+ static char_u *
+ cat_prefix_varname(int prefix, char_u *name)
+ {
+ int len;
+
+ len = (int)STRLEN(name) + 3;
+ if (len > varnamebuflen)
+ {
+ vim_free(varnamebuf);
+ len += 10; /* some additional space */
+ varnamebuf = alloc(len);
+ if (varnamebuf == NULL)
+ {
+ varnamebuflen = 0;
+ return NULL;
+ }
+ varnamebuflen = len;
+ }
+ *varnamebuf = prefix;
+ varnamebuf[1] = ':';
+ STRCPY(varnamebuf + 2, name);
+ return varnamebuf;
+ }
+
+ /*
+ * Function given to ExpandGeneric() to obtain the list of user defined
+ * (global/buffer/window/built-in) variable names.
+ */
+ char_u *
+ get_user_var_name(expand_T *xp, int idx)
+ {
+ static long_u gdone;
+ static long_u bdone;
+ static long_u wdone;
+ static long_u tdone;
+ static int vidx;
+ static hashitem_T *hi;
+ hashtab_T *ht;
+
+ if (idx == 0)
+ {
+ gdone = bdone = wdone = vidx = 0;
+ tdone = 0;
+ }
+
+ // Global variables
+ if (gdone < globvarht.ht_used)
+ {
+ if (gdone++ == 0)
+ hi = globvarht.ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
+ return cat_prefix_varname('g', hi->hi_key);
+ return hi->hi_key;
+ }
+
+ // b: variables
+ ht = &curbuf->b_vars->dv_hashtab;
+ if (bdone < ht->ht_used)
+ {
+ if (bdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('b', hi->hi_key);
+ }
+
+ // w: variables
+ ht = &curwin->w_vars->dv_hashtab;
+ if (wdone < ht->ht_used)
+ {
+ if (wdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('w', hi->hi_key);
+ }
+
+ // t: variables
+ ht = &curtab->tp_vars->dv_hashtab;
+ if (tdone < ht->ht_used)
+ {
+ if (tdone++ == 0)
+ hi = ht->ht_array;
+ else
+ ++hi;
+ while (HASHITEM_EMPTY(hi))
+ ++hi;
+ return cat_prefix_varname('t', hi->hi_key);
+ }
+
+ // v: variables
+ if (vidx < VV_LEN)
+ return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
+
+ VIM_CLEAR(varnamebuf);
+ varnamebuflen = 0;
+ return NULL;
+ }
+
+ /*
+ * Set number v: variable to "val".
+ */
+ void
+ set_vim_var_nr(int idx, varnumber_T val)
+ {
+ vimvars[idx].vv_type = VAR_NUMBER;
+ vimvars[idx].vv_nr = val;
+ }
+
+ /*
+ * Get typval_T v: variable value.
+ */
+ typval_T *
+ get_vim_var_tv(int idx)
+ {
+ return &vimvars[idx].vv_tv;
+ }
+
+ /*
+ * Get number v: variable value.
+ */
+ varnumber_T
+ get_vim_var_nr(int idx)
+ {
+ return vimvars[idx].vv_nr;
+ }
+
+ /*
+ * Get string v: variable value. Uses a static buffer, can only be used once.
+ * If the String variable has never been set, return an empty string.
+ * Never returns NULL;
+ */
+ char_u *
+ get_vim_var_str(int idx)
+ {
+ return tv_get_string(&vimvars[idx].vv_tv);
+ }
+
+ /*
+ * Get List v: variable value. Caller must take care of reference count when
+ * needed.
+ */
+ list_T *
+ get_vim_var_list(int idx)
+ {
+ return vimvars[idx].vv_list;
+ }
+
+ /*
+ * Get Dict v: variable value. Caller must take care of reference count when
+ * needed.
+ */
+ dict_T *
+ get_vim_var_dict(int idx)
+ {
+ return vimvars[idx].vv_dict;
+ }
+
+ /*
+ * Set v:char to character "c".
+ */
+ void
+ set_vim_var_char(int c)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ if (has_mbyte)
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
+ else
+ {
+ buf[0] = c;
+ buf[1] = NUL;
+ }
+ set_vim_var_string(VV_CHAR, buf, -1);
+ }
+
+ /*
+ * Set v:count to "count" and v:count1 to "count1".
+ * When "set_prevcount" is TRUE first set v:prevcount from v:count.
+ */
+ void
+ set_vcount(
+ long count,
+ long count1,
+ int set_prevcount)
+ {
+ if (set_prevcount)
+ vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
+ vimvars[VV_COUNT].vv_nr = count;
+ vimvars[VV_COUNT1].vv_nr = count1;
+ }
+
+ /*
+ * Save variables that might be changed as a side effect. Used when executing
+ * a timer callback.
+ */
+ void
+ save_vimvars(vimvars_save_T *vvsave)
+ {
+ vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
+ vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
+ vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
+ }
+
+ /*
+ * Restore variables saved by save_vimvars().
+ */
+ void
+ restore_vimvars(vimvars_save_T *vvsave)
+ {
+ vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
+ vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
+ vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
+ }
+
+ /*
+ * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
+ * value.
+ */
+ void
+ set_vim_var_string(
+ int idx,
+ char_u *val,
+ int len) // length of "val" to use or -1 (whole string)
+ {
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_STRING;
+ if (val == NULL)
+ vimvars[idx].vv_str = NULL;
+ else if (len == -1)
+ vimvars[idx].vv_str = vim_strsave(val);
+ else
+ vimvars[idx].vv_str = vim_strnsave(val, len);
+ }
+
+ /*
+ * Set List v: variable to "val".
+ */
+ void
+ set_vim_var_list(int idx, list_T *val)
+ {
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_LIST;
+ vimvars[idx].vv_list = val;
+ if (val != NULL)
+ ++val->lv_refcount;
+ }
+
+ /*
+ * Set Dictionary v: variable to "val".
+ */
+ void
+ set_vim_var_dict(int idx, dict_T *val)
+ {
+ clear_tv(&vimvars[idx].vv_di.di_tv);
+ vimvars[idx].vv_type = VAR_DICT;
+ vimvars[idx].vv_dict = val;
+ if (val != NULL)
+ {
+ ++val->dv_refcount;
+ dict_set_items_ro(val);
+ }
+ }
+
+ /*
+ * Set v:register if needed.
+ */
+ void
+ set_reg_var(int c)
+ {
+ char_u regname;
+
+ if (c == 0 || c == ' ')
+ regname = '"';
+ else
+ regname = c;
+ // Avoid free/alloc when the value is already right.
+ if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
+ set_vim_var_string(VV_REG, ®name, 1);
+ }
+
+ /*
+ * Get or set v:exception. If "oldval" == NULL, return the current value.
+ * Otherwise, restore the value to "oldval" and return NULL.
+ * Must always be called in pairs to save and restore v:exception! Does not
+ * take care of memory allocations.
+ */
+ char_u *
+ v_exception(char_u *oldval)
+ {
+ if (oldval == NULL)
+ return vimvars[VV_EXCEPTION].vv_str;
+
+ vimvars[VV_EXCEPTION].vv_str = oldval;
+ return NULL;
+ }
+
+ /*
+ * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
+ * Otherwise, restore the value to "oldval" and return NULL.
+ * Must always be called in pairs to save and restore v:throwpoint! Does not
+ * take care of memory allocations.
+ */
+ char_u *
+ v_throwpoint(char_u *oldval)
+ {
+ if (oldval == NULL)
+ return vimvars[VV_THROWPOINT].vv_str;
+
+ vimvars[VV_THROWPOINT].vv_str = oldval;
+ return NULL;
+ }
+
+ /*
+ * Set v:cmdarg.
+ * If "eap" != NULL, use "eap" to generate the value and return the old value.
+ * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
+ * Must always be called in pairs!
+ */
+ char_u *
+ set_cmdarg(exarg_T *eap, char_u *oldarg)
+ {
+ char_u *oldval;
+ char_u *newval;
+ unsigned len;
+
+ oldval = vimvars[VV_CMDARG].vv_str;
+ if (eap == NULL)
+ {
+ vim_free(oldval);
+ vimvars[VV_CMDARG].vv_str = oldarg;
+ return NULL;
+ }
+
+ if (eap->force_bin == FORCE_BIN)
+ len = 6;
+ else if (eap->force_bin == FORCE_NOBIN)
+ len = 8;
+ else
+ len = 0;
+
+ if (eap->read_edit)
+ len += 7;
+
+ if (eap->force_ff != 0)
+ len += 10; // " ++ff=unix"
+ if (eap->force_enc != 0)
+ len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
+ if (eap->bad_char != 0)
+ len += 7 + 4; // " ++bad=" + "keep" or "drop"
+
+ newval = alloc(len + 1);
+ if (newval == NULL)
+ return NULL;
+
+ if (eap->force_bin == FORCE_BIN)
+ sprintf((char *)newval, " ++bin");
+ else if (eap->force_bin == FORCE_NOBIN)
+ sprintf((char *)newval, " ++nobin");
+ else
+ *newval = NUL;
+
+ if (eap->read_edit)
+ STRCAT(newval, " ++edit");
+
+ if (eap->force_ff != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
+ eap->force_ff == 'u' ? "unix"
+ : eap->force_ff == 'd' ? "dos"
+ : "mac");
+ if (eap->force_enc != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
+ eap->cmd + eap->force_enc);
+ if (eap->bad_char == BAD_KEEP)
+ STRCPY(newval + STRLEN(newval), " ++bad=keep");
+ else if (eap->bad_char == BAD_DROP)
+ STRCPY(newval + STRLEN(newval), " ++bad=drop");
+ else if (eap->bad_char != 0)
+ sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
+ vimvars[VV_CMDARG].vv_str = newval;
+ return oldval;
+ }
+
+ /*
* Get the value of internal variable "name".
* Return OK or FAIL. If OK is returned "rettv" must be cleared.
*/
***************
*** 1259,1264 ****
--- 2020,2191 ----
}
/*
+ * Check if variable "name[len]" is a local variable or an argument.
+ * If so, "*eval_lavars_used" is set to TRUE.
+ */
+ void
+ check_vars(char_u *name, int len)
+ {
+ int cc;
+ char_u *varname;
+ hashtab_T *ht;
+
+ if (eval_lavars_used == NULL)
+ return;
+
+ // truncate the name, so that we can use strcmp()
+ cc = name[len];
+ name[len] = NUL;
+
+ ht = find_var_ht(name, &varname);
+ if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
+ {
+ if (find_var(name, NULL, TRUE) != NULL)
+ *eval_lavars_used = TRUE;
+ }
+
+ name[len] = cc;
+ }
+
+ /*
+ * Find variable "name" in the list of variables.
+ * Return a pointer to it if found, NULL if not found.
+ * Careful: "a:0" variables don't have a name.
+ * When "htp" is not NULL we are writing to the variable, set "htp" to the
+ * hashtab_T used.
+ */
+ dictitem_T *
+ find_var(char_u *name, hashtab_T **htp, int no_autoload)
+ {
+ char_u *varname;
+ hashtab_T *ht;
+ dictitem_T *ret = NULL;
+
+ ht = find_var_ht(name, &varname);
+ if (htp != NULL)
+ *htp = ht;
+ if (ht == NULL)
+ return NULL;
+ ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
+ if (ret != NULL)
+ return ret;
+
+ /* Search in parent scope for lambda */
+ return find_var_in_scoped_ht(name, no_autoload || htp != NULL);
+ }
+
+ /*
+ * Find variable "varname" in hashtab "ht" with name "htname".
+ * Returns NULL if not found.
+ */
+ dictitem_T *
+ find_var_in_ht(
+ hashtab_T *ht,
+ int htname,
+ char_u *varname,
+ int no_autoload)
+ {
+ hashitem_T *hi;
+
+ if (*varname == NUL)
+ {
+ // Must be something like "s:", otherwise "ht" would be NULL.
+ switch (htname)
+ {
+ case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
+ case 'g': return &globvars_var;
+ case 'v': return &vimvars_var;
+ case 'b': return &curbuf->b_bufvar;
+ case 'w': return &curwin->w_winvar;
+ case 't': return &curtab->tp_winvar;
+ case 'l': return get_funccal_local_var();
+ case 'a': return get_funccal_args_var();
+ }
+ return NULL;
+ }
+
+ hi = hash_find(ht, varname);
+ if (HASHITEM_EMPTY(hi))
+ {
+ // For global variables we may try auto-loading the script. If it
+ // worked find the variable again. Don't auto-load a script if it was
+ // loaded already, otherwise it would be loaded every time when
+ // checking if a function name is a Funcref variable.
+ if (ht == &globvarht && !no_autoload)
+ {
+ // Note: script_autoload() may make "hi" invalid. It must either
+ // be obtained again or not used.
+ if (!script_autoload(varname, FALSE) || aborting())
+ return NULL;
+ hi = hash_find(ht, varname);
+ }
+ if (HASHITEM_EMPTY(hi))
+ return NULL;
+ }
+ return HI2DI(hi);
+ }
+
+ /*
+ * Find the hashtab used for a variable name.
+ * Return NULL if the name is not valid.
+ * Set "varname" to the start of name without ':'.
+ */
+ hashtab_T *
+ find_var_ht(char_u *name, char_u **varname)
+ {
+ hashitem_T *hi;
+ hashtab_T *ht;
+
+ if (name[0] == NUL)
+ return NULL;
+ if (name[1] != ':')
+ {
+ // The name must not start with a colon or #.
+ if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
+ return NULL;
+ *varname = name;
+
+ // "version" is "v:version" in all scopes if scriptversion < 3.
+ // Same for a few other variables marked with VV_COMPAT.
+ if (current_sctx.sc_version < 3)
+ {
+ hi = hash_find(&compat_hashtab, name);
+ if (!HASHITEM_EMPTY(hi))
+ return &compat_hashtab;
+ }
+
+ ht = get_funccal_local_ht();
+ if (ht == NULL)
+ return &globvarht; // global variable
+ return ht; // local variable
+ }
+ *varname = name + 2;
+ if (*name == 'g') // global variable
+ return &globvarht;
+ // There must be no ':' or '#' in the rest of the name, unless g: is used
+ if (vim_strchr(name + 2, ':') != NULL
+ || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
+ return NULL;
+ if (*name == 'b') // buffer variable
+ return &curbuf->b_vars->dv_hashtab;
+ if (*name == 'w') // window variable
+ return &curwin->w_vars->dv_hashtab;
+ if (*name == 't') // tab page variable
+ return &curtab->tp_vars->dv_hashtab;
+ if (*name == 'v') // v: variable
+ return &vimvarht;
+ if (*name == 'a') // a: function argument
+ return get_funccal_args_ht();
+ if (*name == 'l') // l: local function variable
+ return get_funccal_local_ht();
+ if (*name == 's' // script variable
+ && current_sctx.sc_sid > 0
+ && current_sctx.sc_sid <= ga_scripts.ga_len)
+ return &SCRIPT_VARS(current_sctx.sc_sid);
+ return NULL;
+ }
+
+ /*
* Get the string value of a (global/local) variable.
* Note: see tv_get_string() for how long the pointer remains valid.
* Returns NULL when it doesn't exist.
***************
*** 1275,1280 ****
--- 2202,2273 ----
}
/*
+ * Allocate a new hashtab for a sourced script. It will be used while
+ * sourcing this script and when executing functions defined in the script.
+ */
+ void
+ new_script_vars(scid_T id)
+ {
+ int i;
+ hashtab_T *ht;
+ scriptvar_T *sv;
+
+ if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
+ {
+ /* Re-allocating ga_data means that an ht_array pointing to
+ * ht_smallarray becomes invalid. We can recognize this: ht_mask is
+ * at its init value. Also reset "v_dict", it's always the same. */
+ for (i = 1; i <= ga_scripts.ga_len; ++i)
+ {
+ ht = &SCRIPT_VARS(i);
+ if (ht->ht_mask == HT_INIT_SIZE - 1)
+ ht->ht_array = ht->ht_smallarray;
+ sv = SCRIPT_SV(i);
+ sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
+ }
+
+ while (ga_scripts.ga_len < id)
+ {
+ sv = SCRIPT_SV(ga_scripts.ga_len + 1) =
+ ALLOC_CLEAR_ONE(scriptvar_T);
+ init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
+ ++ga_scripts.ga_len;
+ }
+ }
+ }
+
+ /*
+ * Initialize dictionary "dict" as a scope and set variable "dict_var" to
+ * point to it.
+ */
+ void
+ init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
+ {
+ hash_init(&dict->dv_hashtab);
+ dict->dv_lock = 0;
+ dict->dv_scope = scope;
+ dict->dv_refcount = DO_NOT_FREE_CNT;
+ dict->dv_copyID = 0;
+ dict_var->di_tv.vval.v_dict = dict;
+ dict_var->di_tv.v_type = VAR_DICT;
+ dict_var->di_tv.v_lock = VAR_FIXED;
+ dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ dict_var->di_key[0] = NUL;
+ }
+
+ /*
+ * Unreference a dictionary initialized by init_var_dict().
+ */
+ void
+ unref_var_dict(dict_T *dict)
+ {
+ /* Now the dict needs to be freed if no one else is using it, go back to
+ * normal reference counting. */
+ dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
+ dict_unref(dict);
+ }
+
+ /*
* Clean up a list of internal variables.
* Frees all allocated variables and the value they contain.
* Clears hashtab "ht", does not free it.
***************
*** 1453,1459 ****
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
! if (is_vimvarht(ht))
{
if (v->di_tv.v_type == VAR_STRING)
{
--- 2446,2452 ----
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
! if (ht == &vimvarht)
{
if (v->di_tv.v_type == VAR_STRING)
{
***************
*** 1501,1507 ****
else // add a new variable
{
// Can't add "v:" or "a:" variable.
! if (is_vimvarht(ht) || ht == get_funccal_args_ht())
{
semsg(_(e_illvar), name);
return;
--- 2494,2500 ----
else // add a new variable
{
// Can't add "v:" or "a:" variable.
! if (ht == &vimvarht || ht == get_funccal_args_ht())
{
semsg(_(e_illvar), name);
return;
***************
*** 1792,1797 ****
--- 2785,2819 ----
}
}
+ /*
+ * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
+ * v:option_type, and v:option_command.
+ */
+ void
+ reset_v_option_vars(void)
+ {
+ set_vim_var_string(VV_OPTION_NEW, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
+ set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
+ }
+
+ /*
+ * Add an assert error to v:errors.
+ */
+ void
+ assert_error(garray_T *gap)
+ {
+ struct vimvar *vp = &vimvars[VV_ERRORS];
+
+ if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
+ /* Make sure v:errors is a list. */
+ set_vim_var_list(VV_ERRORS, list_alloc());
+ list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
+ }
+
int
var_exists(char_u *var)
{
*** ../vim-8.1.1938/src/proto/
eval.pro 2019-08-27 22:48:12.741480663 +0200
--- src/proto/
eval.pro 2019-08-29 22:02:16.891931613 +0200
***************
*** 3,9 ****
varnumber_T num_modulus(varnumber_T n1, varnumber_T n2);
void eval_init(void);
void eval_clear(void);
- void set_internal_string_var(char_u *name, char_u *value);
int var_redir_start(char_u *name, int append);
void var_redir_str(char_u *value, int value_len);
void var_redir_stop(void);
--- 3,8 ----
***************
*** 19,30 ****
char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox);
varnumber_T eval_to_number(char_u *expr);
- void list_vim_vars(int *first);
- void list_script_vars(int *first);
- int is_vimvarht(hashtab_T *ht);
- int is_compatht(hashtab_T *ht);
- void prepare_vimvar(int idx, typval_T *save_tv);
- void restore_vimvar(int idx, typval_T *save_tv);
list_T *eval_spell_expr(char_u *badword, char_u *expr);
int get_spellword(list_T *list, char_u **pp);
typval_T *eval_expr(char_u *arg, char_u **nextcmd);
--- 18,23 ----
***************
*** 41,47 ****
void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
void del_menutrans_vars(void);
- char_u *get_user_var_name(expand_T *xp, int idx);
int pattern_match(char_u *pat, char_u *text, int ic);
int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
int eval1(char_u **arg, typval_T *rettv, int evaluate);
--- 34,39 ----
***************
*** 69,93 ****
char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
int eval_isnamec(int c);
int eval_isnamec1(int c);
- void set_vim_var_nr(int idx, varnumber_T val);
- typval_T *get_vim_var_tv(int idx);
- varnumber_T get_vim_var_nr(int idx);
- char_u *get_vim_var_str(int idx);
- list_T *get_vim_var_list(int idx);
- dict_T *get_vim_var_dict(int idx);
- void set_vim_var_char(int c);
- void set_vcount(long count, long count1, int set_prevcount);
- void save_vimvars(vimvars_save_T *vvsave);
- void restore_vimvars(vimvars_save_T *vvsave);
- void set_vim_var_string(int idx, char_u *val, int len);
- void set_vim_var_list(int idx, list_T *val);
- void set_vim_var_dict(int idx, dict_T *val);
- void set_reg_var(int c);
- char_u *v_exception(char_u *oldval);
- char_u *v_throwpoint(char_u *oldval);
- char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose, char_u *start_leader, char_u **end_leaderp);
typval_T *alloc_tv(void);
void free_tv(typval_T *varp);
void clear_tv(typval_T *varp);
void init_tv(typval_T *varp);
--- 61,69 ----
char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
int eval_isnamec(int c);
int eval_isnamec1(int c);
int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose, char_u *start_leader, char_u **end_leaderp);
typval_T *alloc_tv(void);
+ typval_T *alloc_string_tv(char_u *s);
void free_tv(typval_T *varp);
void clear_tv(typval_T *varp);
void init_tv(typval_T *varp);
***************
*** 98,109 ****
char_u *tv_get_string_buf(typval_T *varp, char_u *buf);
char_u *tv_get_string_chk(typval_T *varp);
char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf);
- dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
- dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
- hashtab_T *find_var_ht(char_u *name, char_u **varname);
- void new_script_vars(scid_T id);
- void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
- void unref_var_dict(dict_T *dict);
void copy_tv(typval_T *from, typval_T *to);
int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog, int secret);
--- 74,79 ----
***************
*** 117,124 ****
char_u *autoload_name(char_u *name);
int script_autoload(char_u *name, int reload);
void last_set_msg(sctx_T script_ctx);
- void reset_v_option_vars(void);
- void assert_error(garray_T *gap);
int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int type_is, int ic);
char_u *typval_tostring(typval_T *arg);
int modify_fname(char_u *src, int tilde_file, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen);
--- 87,92 ----
*** ../vim-8.1.1938/src/proto/
evalvars.pro 2019-08-27 22:48:12.741480663 +0200
--- src/proto/
evalvars.pro 2019-08-29 22:02:16.891931613 +0200
***************
*** 1,4 ****
--- 1,11 ----
/* evalvars.c */
+ void evalvars_init(void);
+ void evalvars_clear(void);
+ int garbage_collect_vimvars(int copyID);
+ int garbage_collect_scriptvars(int copyID);
+ void set_internal_string_var(char_u *name, char_u *value);
+ void prepare_vimvar(int idx, typval_T *save_tv);
+ void restore_vimvar(int idx, typval_T *save_tv);
void ex_let(exarg_T *eap);
void ex_const(exarg_T *eap);
int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int is_const, char_u *op);
***************
*** 7,14 ****
--- 14,46 ----
void ex_unlet(exarg_T *eap);
void ex_lockvar(exarg_T *eap);
int do_unlet(char_u *name, int forceit);
+ char_u *get_user_var_name(expand_T *xp, int idx);
+ void set_vim_var_nr(int idx, varnumber_T val);
+ typval_T *get_vim_var_tv(int idx);
+ varnumber_T get_vim_var_nr(int idx);
+ char_u *get_vim_var_str(int idx);
+ list_T *get_vim_var_list(int idx);
+ dict_T *get_vim_var_dict(int idx);
+ void set_vim_var_char(int c);
+ void set_vcount(long count, long count1, int set_prevcount);
+ void save_vimvars(vimvars_save_T *vvsave);
+ void restore_vimvars(vimvars_save_T *vvsave);
+ void set_vim_var_string(int idx, char_u *val, int len);
+ void set_vim_var_list(int idx, list_T *val);
+ void set_vim_var_dict(int idx, dict_T *val);
+ void set_reg_var(int c);
+ char_u *v_exception(char_u *oldval);
+ char_u *v_throwpoint(char_u *oldval);
+ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload);
+ void check_vars(char_u *name, int len);
+ dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
+ dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
+ hashtab_T *find_var_ht(char_u *name, char_u **varname);
char_u *get_var_value(char_u *name);
+ void new_script_vars(scid_T id);
+ void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
+ void unref_var_dict(dict_T *dict);
void vars_clear(hashtab_T *ht);
void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi);
***************
*** 19,24 ****
--- 51,58 ----
int var_check_func_name(char_u *name, int new_var);
int var_check_lock(int lock, char_u *name, int use_gettext);
int valid_varname(char_u *varname);
+ void reset_v_option_vars(void);
+ void assert_error(garray_T *gap);
int var_exists(char_u *var);
void f_gettabvar(typval_T *argvars, typval_T *rettv);
void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.1938/src/version.c 2019-08-29 21:32:52.248093098 +0200
--- src/version.c 2019-08-29 22:05:49.498124809 +0200
***************
*** 763,764 ****
--- 763,766 ----
{ /* Add new patch number below this line */
+ /**/
+ 1939,
/**/
--
hundred-and-one symptoms of being an internet addict:
133. You communicate with people on other continents more than you
do with your own neighbors.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///