neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

vars.c (109425B)


      1 // eval/vars.c: functions for dealing with variables
      2 
      3 #include <assert.h>
      4 #include <ctype.h>
      5 #include <stdbool.h>
      6 #include <stddef.h>
      7 #include <stdint.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <uv.h>
     11 
     12 #include "nvim/ascii_defs.h"
     13 #include "nvim/autocmd.h"
     14 #include "nvim/autocmd_defs.h"
     15 #include "nvim/buffer_defs.h"
     16 #include "nvim/charset.h"
     17 #include "nvim/drawscreen.h"
     18 #include "nvim/errors.h"
     19 #include "nvim/eval.h"
     20 #include "nvim/eval/encode.h"
     21 #include "nvim/eval/funcs.h"
     22 #include "nvim/eval/typval.h"
     23 #include "nvim/eval/typval_defs.h"
     24 #include "nvim/eval/userfunc.h"
     25 #include "nvim/eval/vars.h"
     26 #include "nvim/eval/window.h"
     27 #include "nvim/eval_defs.h"
     28 #include "nvim/ex_cmds.h"
     29 #include "nvim/ex_cmds_defs.h"
     30 #include "nvim/ex_docmd.h"
     31 #include "nvim/ex_eval.h"
     32 #include "nvim/garray.h"
     33 #include "nvim/gettext_defs.h"
     34 #include "nvim/globals.h"
     35 #include "nvim/hashtab.h"
     36 #include "nvim/lua/executor.h"
     37 #include "nvim/macros_defs.h"
     38 #include "nvim/mbyte.h"
     39 #include "nvim/memory.h"
     40 #include "nvim/message.h"
     41 #include "nvim/option.h"
     42 #include "nvim/option_defs.h"
     43 #include "nvim/os/os.h"
     44 #include "nvim/register.h"
     45 #include "nvim/runtime.h"
     46 #include "nvim/search.h"
     47 #include "nvim/strings.h"
     48 #include "nvim/types_defs.h"
     49 #include "nvim/version.h"
     50 #include "nvim/vim_defs.h"
     51 #include "nvim/window.h"
     52 
     53 typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int);
     54 
     55 #include "eval/vars.c.generated.h"
     56 
     57 // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
     58 
     59 #define DICT_MAXNEST 100        // maximum nesting of lists and dicts
     60 
     61 static const char *e_letunexp = N_("E18: Unexpected characters in :let");
     62 static const char e_double_semicolon_in_list_of_variables[]
     63  = N_("E452: Double ; in list of variables");
     64 static const char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s");
     65 static const char e_setting_v_str_to_value_with_wrong_type[]
     66  = N_("E963: Setting v:%s to value with wrong type");
     67 static const char e_missing_end_marker_str[] = N_("E990: Missing end marker '%s'");
     68 static const char e_cannot_use_heredoc_here[] = N_("E991: Cannot use =<< here");
     69 
     70 /// Variable used for g:
     71 static ScopeDictDictItem globvars_var;
     72 static dict_T globvardict;                  // Dict with g: variables
     73 /// g: value
     74 #define globvarht globvardict.dv_hashtab
     75 
     76 /// Old Vim variables such as "v:version" are also available without the "v:".
     77 /// Also in functions.  We need a special hashtable for them.
     78 static hashtab_T compat_hashtab;
     79 
     80 // values for vv_flags:
     81 #define VV_COMPAT       1       // compatible, also used without "v:"
     82 #define VV_RO           2       // read-only
     83 #define VV_RO_SBX       4       // read-only in the sandbox
     84 
     85 #define VV(idx, name, type, flags) \
     86  [idx] = { \
     87    .vv_name = (name), \
     88    .vv_di = { \
     89      .di_tv = { .v_type = (type) }, \
     90      .di_flags = 0, \
     91      .di_key = { 0 }, \
     92    }, \
     93    .vv_flags = (flags), \
     94  }
     95 
     96 #define VIMVAR_KEY_LEN 16  // Maximum length of the key of v:variables
     97 
     98 // Array to hold the value of v: variables.
     99 // The value is in a dictitem, so that it can also be used in the v: scope.
    100 // The reason to use this table anyway is for very quick access to the
    101 // variables with the VV_ defines.
    102 static struct vimvar {
    103  char *vv_name;  ///< Name of the variable, without v:.
    104  TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di;  ///< Value and name for key (max 16 chars).
    105  char vv_flags;  ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
    106 } vimvars[] = {
    107  // VV_ tails differing from upcased string literals:
    108  // VV_CC_FROM "charconvert_from"
    109  // VV_CC_TO "charconvert_to"
    110  // VV_SEND_SERVER "servername"
    111  // VV_REG "register"
    112  // VV_OP "operator"
    113  VV(VV_COUNT,            "count",            VAR_NUMBER, VV_RO),
    114  VV(VV_COUNT1,           "count1",           VAR_NUMBER, VV_RO),
    115  VV(VV_PREVCOUNT,        "prevcount",        VAR_NUMBER, VV_RO),
    116  VV(VV_ERRMSG,           "errmsg",           VAR_STRING, 0),
    117  VV(VV_WARNINGMSG,       "warningmsg",       VAR_STRING, 0),
    118  VV(VV_STATUSMSG,        "statusmsg",        VAR_STRING, 0),
    119  VV(VV_SHELL_ERROR,      "shell_error",      VAR_NUMBER, VV_RO),
    120  VV(VV_THIS_SESSION,     "this_session",     VAR_STRING, 0),
    121  VV(VV_VERSION,          "version",          VAR_NUMBER, VV_COMPAT + VV_RO),
    122  VV(VV_LNUM,             "lnum",             VAR_NUMBER, VV_RO_SBX),
    123  VV(VV_TERMRESPONSE,     "termresponse",     VAR_STRING, VV_RO),
    124  VV(VV_TERMREQUEST,      "termrequest",      VAR_STRING, VV_RO),
    125  VV(VV_FNAME,            "fname",            VAR_STRING, VV_RO),
    126  VV(VV_LANG,             "lang",             VAR_STRING, VV_RO),
    127  VV(VV_LC_TIME,          "lc_time",          VAR_STRING, VV_RO),
    128  VV(VV_CTYPE,            "ctype",            VAR_STRING, VV_RO),
    129  VV(VV_CC_FROM,          "charconvert_from", VAR_STRING, VV_RO),
    130  VV(VV_CC_TO,            "charconvert_to",   VAR_STRING, VV_RO),
    131  VV(VV_FNAME_IN,         "fname_in",         VAR_STRING, VV_RO),
    132  VV(VV_FNAME_OUT,        "fname_out",        VAR_STRING, VV_RO),
    133  VV(VV_FNAME_NEW,        "fname_new",        VAR_STRING, VV_RO),
    134  VV(VV_FNAME_DIFF,       "fname_diff",       VAR_STRING, VV_RO),
    135  VV(VV_CMDARG,           "cmdarg",           VAR_STRING, VV_RO),
    136  VV(VV_FOLDSTART,        "foldstart",        VAR_NUMBER, VV_RO_SBX),
    137  VV(VV_FOLDEND,          "foldend",          VAR_NUMBER, VV_RO_SBX),
    138  VV(VV_FOLDDASHES,       "folddashes",       VAR_STRING, VV_RO_SBX),
    139  VV(VV_FOLDLEVEL,        "foldlevel",        VAR_NUMBER, VV_RO_SBX),
    140  VV(VV_PROGNAME,         "progname",         VAR_STRING, VV_RO),
    141  VV(VV_SEND_SERVER,      "servername",       VAR_STRING, VV_RO),
    142  VV(VV_DYING,            "dying",            VAR_NUMBER, VV_RO),
    143  VV(VV_EXCEPTION,        "exception",        VAR_STRING, VV_RO),
    144  VV(VV_THROWPOINT,       "throwpoint",       VAR_STRING, VV_RO),
    145  VV(VV_REG,              "register",         VAR_STRING, VV_RO),
    146  VV(VV_CMDBANG,          "cmdbang",          VAR_NUMBER, VV_RO),
    147  VV(VV_INSERTMODE,       "insertmode",       VAR_STRING, VV_RO),
    148  VV(VV_VAL,              "val",              VAR_UNKNOWN, VV_RO),
    149  VV(VV_KEY,              "key",              VAR_UNKNOWN, VV_RO),
    150  VV(VV_PROFILING,        "profiling",        VAR_NUMBER, VV_RO),
    151  VV(VV_FCS_REASON,       "fcs_reason",       VAR_STRING, VV_RO),
    152  VV(VV_FCS_CHOICE,       "fcs_choice",       VAR_STRING, 0),
    153  VV(VV_BEVAL_BUFNR,      "beval_bufnr",      VAR_NUMBER, VV_RO),
    154  VV(VV_BEVAL_WINNR,      "beval_winnr",      VAR_NUMBER, VV_RO),
    155  VV(VV_BEVAL_WINID,      "beval_winid",      VAR_NUMBER, VV_RO),
    156  VV(VV_BEVAL_LNUM,       "beval_lnum",       VAR_NUMBER, VV_RO),
    157  VV(VV_BEVAL_COL,        "beval_col",        VAR_NUMBER, VV_RO),
    158  VV(VV_BEVAL_TEXT,       "beval_text",       VAR_STRING, VV_RO),
    159  VV(VV_SCROLLSTART,      "scrollstart",      VAR_STRING, 0),
    160  VV(VV_SWAPNAME,         "swapname",         VAR_STRING, VV_RO),
    161  VV(VV_SWAPCHOICE,       "swapchoice",       VAR_STRING, 0),
    162  VV(VV_SWAPCOMMAND,      "swapcommand",      VAR_STRING, VV_RO),
    163  VV(VV_CHAR,             "char",             VAR_STRING, 0),
    164  VV(VV_MOUSE_WIN,        "mouse_win",        VAR_NUMBER, 0),
    165  VV(VV_MOUSE_WINID,      "mouse_winid",      VAR_NUMBER, 0),
    166  VV(VV_MOUSE_LNUM,       "mouse_lnum",       VAR_NUMBER, 0),
    167  VV(VV_MOUSE_COL,        "mouse_col",        VAR_NUMBER, 0),
    168  VV(VV_OP,               "operator",         VAR_STRING, VV_RO),
    169  VV(VV_SEARCHFORWARD,    "searchforward",    VAR_NUMBER, 0),
    170  VV(VV_HLSEARCH,         "hlsearch",         VAR_NUMBER, 0),
    171  VV(VV_OLDFILES,         "oldfiles",         VAR_LIST, 0),
    172  VV(VV_WINDOWID,         "windowid",         VAR_NUMBER, VV_RO_SBX),
    173  VV(VV_PROGPATH,         "progpath",         VAR_STRING, VV_RO),
    174  VV(VV_COMPLETED_ITEM,   "completed_item",   VAR_DICT, 0),
    175  VV(VV_OPTION_NEW,       "option_new",       VAR_STRING, VV_RO),
    176  VV(VV_OPTION_OLD,       "option_old",       VAR_STRING, VV_RO),
    177  VV(VV_OPTION_OLDLOCAL,  "option_oldlocal",  VAR_STRING, VV_RO),
    178  VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
    179  VV(VV_OPTION_COMMAND,   "option_command",   VAR_STRING, VV_RO),
    180  VV(VV_OPTION_TYPE,      "option_type",      VAR_STRING, VV_RO),
    181  VV(VV_ERRORS,           "errors",           VAR_LIST, 0),
    182  VV(VV_FALSE,            "false",            VAR_BOOL, VV_RO),
    183  VV(VV_TRUE,             "true",             VAR_BOOL, VV_RO),
    184  VV(VV_NULL,             "null",             VAR_SPECIAL, VV_RO),
    185  VV(VV_NUMBERMAX,        "numbermax",        VAR_NUMBER, VV_RO),
    186  VV(VV_NUMBERMIN,        "numbermin",        VAR_NUMBER, VV_RO),
    187  VV(VV_NUMBERSIZE,       "numbersize",       VAR_NUMBER, VV_RO),
    188  VV(VV_VIM_DID_ENTER,    "vim_did_enter",    VAR_NUMBER, VV_RO),
    189  VV(VV_TESTING,          "testing",          VAR_NUMBER, 0),
    190  VV(VV_TYPE_NUMBER,      "t_number",         VAR_NUMBER, VV_RO),
    191  VV(VV_TYPE_STRING,      "t_string",         VAR_NUMBER, VV_RO),
    192  VV(VV_TYPE_FUNC,        "t_func",           VAR_NUMBER, VV_RO),
    193  VV(VV_TYPE_LIST,        "t_list",           VAR_NUMBER, VV_RO),
    194  VV(VV_TYPE_DICT,        "t_dict",           VAR_NUMBER, VV_RO),
    195  VV(VV_TYPE_FLOAT,       "t_float",          VAR_NUMBER, VV_RO),
    196  VV(VV_TYPE_BOOL,        "t_bool",           VAR_NUMBER, VV_RO),
    197  VV(VV_TYPE_BLOB,        "t_blob",           VAR_NUMBER, VV_RO),
    198  VV(VV_EVENT,            "event",            VAR_DICT, VV_RO),
    199  VV(VV_VERSIONLONG,      "versionlong",      VAR_NUMBER, VV_RO),
    200  VV(VV_ECHOSPACE,        "echospace",        VAR_NUMBER, VV_RO),
    201  VV(VV_ARGF,             "argf",             VAR_LIST, VV_RO),
    202  VV(VV_ARGV,             "argv",             VAR_LIST, VV_RO),
    203  VV(VV_COLLATE,          "collate",          VAR_STRING, VV_RO),
    204  VV(VV_EXITING,          "exiting",          VAR_NUMBER, VV_RO),
    205  VV(VV_MAXCOL,           "maxcol",           VAR_NUMBER, VV_RO),
    206  VV(VV_STACKTRACE,       "stacktrace",       VAR_LIST, VV_RO),
    207  VV(VV_VIM_DID_INIT,     "vim_did_init",     VAR_NUMBER, VV_RO),
    208  // Neovim
    209  VV(VV_STDERR,           "stderr",           VAR_NUMBER, VV_RO),
    210  VV(VV_MSGPACK_TYPES,    "msgpack_types",    VAR_DICT, VV_RO),
    211  VV(VV__NULL_STRING,     "_null_string",     VAR_STRING, VV_RO),
    212  VV(VV__NULL_LIST,       "_null_list",       VAR_LIST, VV_RO),
    213  VV(VV__NULL_DICT,       "_null_dict",       VAR_DICT, VV_RO),
    214  VV(VV__NULL_BLOB,       "_null_blob",       VAR_BLOB, VV_RO),
    215  VV(VV_LUA,              "lua",              VAR_PARTIAL, VV_RO),
    216  VV(VV_RELNUM,           "relnum",           VAR_NUMBER, VV_RO),
    217  VV(VV_VIRTNUM,          "virtnum",          VAR_NUMBER, VV_RO),
    218 };
    219 #undef VV
    220 
    221 // shorthand
    222 #define vv_type         vv_di.di_tv.v_type
    223 #define vv_str          vv_di.di_tv.vval.v_string
    224 #define vv_list         vv_di.di_tv.vval.v_list
    225 #define vv_tv           vv_di.di_tv
    226 
    227 /// Variable used for v:
    228 static ScopeDictDictItem vimvars_var;
    229 static dict_T vimvardict;                   // Dict with v: variables
    230 /// v: hashtab
    231 #define vimvarht  vimvardict.dv_hashtab
    232 
    233 static const char *const msgpack_type_names[] = {
    234  [kMPNil] = "nil",
    235  [kMPBoolean] = "boolean",
    236  [kMPInteger] = "integer",
    237  [kMPFloat] = "float",
    238  [kMPString] = "string",
    239  [kMPArray] = "array",
    240  [kMPMap] = "map",
    241  [kMPExt] = "ext",
    242 };
    243 const list_T *eval_msgpack_type_lists[] = {
    244  [kMPNil] = NULL,
    245  [kMPBoolean] = NULL,
    246  [kMPInteger] = NULL,
    247  [kMPFloat] = NULL,
    248  [kMPString] = NULL,
    249  [kMPArray] = NULL,
    250  [kMPMap] = NULL,
    251  [kMPExt] = NULL,
    252 };
    253 
    254 #define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars)
    255 #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
    256 
    257 void evalvars_init(void)
    258 {
    259  init_var_dict(get_globvar_dict(), &globvars_var, VAR_DEF_SCOPE);
    260  init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
    261  vimvardict.dv_lock = VAR_FIXED;
    262  hash_init(&compat_hashtab);
    263 
    264  for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
    265    struct vimvar *p = &vimvars[i];
    266    assert(strlen(p->vv_name) <= VIMVAR_KEY_LEN);
    267    STRCPY(p->vv_di.di_key, p->vv_name);
    268    if (p->vv_flags & VV_RO) {
    269      p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
    270    } else if (p->vv_flags & VV_RO_SBX) {
    271      p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
    272    } else {
    273      p->vv_di.di_flags = DI_FLAGS_FIX;
    274    }
    275 
    276    // add to v: scope dict, unless the value is not always available
    277    if (p->vv_type != VAR_UNKNOWN) {
    278      hash_add(&vimvarht, p->vv_di.di_key);
    279    }
    280    if (p->vv_flags & VV_COMPAT) {
    281      // add to compat scope dict
    282      hash_add(&compat_hashtab, p->vv_di.di_key);
    283    }
    284  }
    285  const int vim_version = min_vim_version();
    286  set_vim_var_nr(VV_VERSION, vim_version);
    287  set_vim_var_nr(VV_VERSIONLONG, vim_version * 10000 + highest_patch());
    288 
    289  dict_T *const msgpack_types_dict = tv_dict_alloc();
    290  for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
    291    list_T *const type_list = tv_list_alloc(0);
    292    tv_list_set_lock(type_list, VAR_FIXED);
    293    tv_list_ref(type_list);
    294    dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
    295    di->di_flags |= DI_FLAGS_RO|DI_FLAGS_FIX;
    296    di->di_tv = (typval_T) {
    297      .v_type = VAR_LIST,
    298      .vval = { .v_list = type_list, },
    299    };
    300    eval_msgpack_type_lists[i] = type_list;
    301    if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
    302      // There must not be duplicate items in this dictionary by definition.
    303      abort();
    304    }
    305  }
    306  msgpack_types_dict->dv_lock = VAR_FIXED;
    307 
    308  set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
    309  set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
    310 
    311  set_vim_var_dict(VV_EVENT, tv_dict_alloc_lock(VAR_FIXED));
    312  set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
    313  set_vim_var_nr(VV_STDERR,   CHAN_STDERR);
    314  set_vim_var_nr(VV_SEARCHFORWARD, 1);
    315  set_vim_var_nr(VV_HLSEARCH, 1);
    316  set_vim_var_nr(VV_COUNT1, 1);
    317  set_vim_var_special(VV_EXITING, kSpecialVarNull);
    318 
    319  set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
    320  set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
    321  set_vim_var_nr(VV_TYPE_FUNC,   VAR_TYPE_FUNC);
    322  set_vim_var_nr(VV_TYPE_LIST,   VAR_TYPE_LIST);
    323  set_vim_var_nr(VV_TYPE_DICT,   VAR_TYPE_DICT);
    324  set_vim_var_nr(VV_TYPE_FLOAT,  VAR_TYPE_FLOAT);
    325  set_vim_var_nr(VV_TYPE_BOOL,   VAR_TYPE_BOOL);
    326  set_vim_var_nr(VV_TYPE_BLOB,   VAR_TYPE_BLOB);
    327 
    328  set_vim_var_bool(VV_FALSE, kBoolVarFalse);
    329  set_vim_var_bool(VV_TRUE, kBoolVarTrue);
    330  set_vim_var_special(VV_NULL, kSpecialVarNull);
    331  set_vim_var_nr(VV_NUMBERMAX, VARNUMBER_MAX);
    332  set_vim_var_nr(VV_NUMBERMIN, VARNUMBER_MIN);
    333  set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8);
    334  set_vim_var_nr(VV_MAXCOL, MAXCOL);
    335 
    336  set_vim_var_nr(VV_ECHOSPACE,    sc_col - 1);
    337 
    338  // vimvars[VV_LUA].vv_type = VAR_PARTIAL;
    339  partial_T *vvlua_partial = xcalloc(1, sizeof(partial_T));
    340  // this value shouldn't be printed, but if it is, do not crash
    341  vvlua_partial->pt_name = xmallocz(0);
    342  vvlua_partial->pt_refcount++;
    343  set_vim_var_partial(VV_LUA, vvlua_partial);
    344 
    345  set_reg_var(0);  // default for v:register is not 0 but '"'
    346 }
    347 
    348 #if defined(EXITFREE)
    349 void evalvars_clear(void)
    350 {
    351  for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
    352    struct vimvar *p = &vimvars[i];
    353    if (p->vv_di.di_tv.v_type == VAR_STRING) {
    354      XFREE_CLEAR(p->vv_str);
    355    } else if (p->vv_di.di_tv.v_type == VAR_LIST) {
    356      tv_list_unref(p->vv_list);
    357      p->vv_list = NULL;
    358    }
    359  }
    360 
    361  partial_unref(get_vim_var_partial(VV_LUA));
    362  set_vim_var_partial(VV_LUA, NULL);
    363  hash_clear(&vimvarht);
    364  hash_init(&vimvarht);    // garbage_collect() will access it
    365  hash_clear(&compat_hashtab);
    366 
    367  // global variables
    368  vars_clear(get_globvar_ht());
    369 
    370  // Script-local variables. Clear all the variables here.
    371  // The scriptvar_T is cleared later in free_scriptnames(), because a
    372  // variable in one script might hold a reference to the whole scope of
    373  // another script.
    374  for (int i = 1; i <= script_items.ga_len; i++) {
    375    vars_clear(&SCRIPT_VARS(i));
    376  }
    377 }
    378 #endif
    379 
    380 int garbage_collect_globvars(int copyID)
    381 {
    382  return set_ref_in_ht(&globvarht, copyID, NULL);
    383 }
    384 
    385 bool garbage_collect_vimvars(int copyID)
    386 {
    387  return set_ref_in_ht(&vimvarht, copyID, NULL);
    388 }
    389 
    390 bool garbage_collect_scriptvars(int copyID)
    391 {
    392  bool abort = false;
    393 
    394  for (int i = 1; i <= script_items.ga_len; i++) {
    395    abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
    396  }
    397 
    398  return abort;
    399 }
    400 
    401 /// Set an internal variable to a string value. Creates the variable if it does
    402 /// not already exist.
    403 void set_internal_string_var(const char *name, char *value)  // NOLINT(readability-non-const-parameter)
    404  FUNC_ATTR_NONNULL_ARG(1)
    405 {
    406  typval_T tv = {
    407    .v_type = VAR_STRING,
    408    .vval.v_string = value,
    409  };
    410 
    411  set_var(name, strlen(name), &tv, true);
    412 }
    413 
    414 int eval_charconvert(const char *const enc_from, const char *const enc_to,
    415                     const char *const fname_from, const char *const fname_to)
    416 {
    417  const sctx_T saved_sctx = current_sctx;
    418 
    419  set_vim_var_string(VV_CC_FROM, enc_from, -1);
    420  set_vim_var_string(VV_CC_TO, enc_to, -1);
    421  set_vim_var_string(VV_FNAME_IN, fname_from, -1);
    422  set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
    423  sctx_T *ctx = get_option_sctx(kOptCharconvert);
    424  if (ctx != NULL) {
    425    current_sctx = *ctx;
    426  }
    427 
    428  bool err = false;
    429  if (eval_to_bool(p_ccv, &err, NULL, false, true)) {
    430    err = true;
    431  }
    432 
    433  set_vim_var_string(VV_CC_FROM, NULL, -1);
    434  set_vim_var_string(VV_CC_TO, NULL, -1);
    435  set_vim_var_string(VV_FNAME_IN, NULL, -1);
    436  set_vim_var_string(VV_FNAME_OUT, NULL, -1);
    437  current_sctx = saved_sctx;
    438 
    439  if (err) {
    440    return FAIL;
    441  }
    442  return OK;
    443 }
    444 
    445 void eval_diff(const char *const origfile, const char *const newfile, const char *const outfile)
    446 {
    447  const sctx_T saved_sctx = current_sctx;
    448  set_vim_var_string(VV_FNAME_IN, origfile, -1);
    449  set_vim_var_string(VV_FNAME_NEW, newfile, -1);
    450  set_vim_var_string(VV_FNAME_OUT, outfile, -1);
    451 
    452  sctx_T *ctx = get_option_sctx(kOptDiffexpr);
    453  if (ctx != NULL) {
    454    current_sctx = *ctx;
    455  }
    456 
    457  // errors are ignored
    458  typval_T *tv = eval_expr_ext(p_dex, NULL, true);
    459  tv_free(tv);
    460 
    461  set_vim_var_string(VV_FNAME_IN, NULL, -1);
    462  set_vim_var_string(VV_FNAME_NEW, NULL, -1);
    463  set_vim_var_string(VV_FNAME_OUT, NULL, -1);
    464  current_sctx = saved_sctx;
    465 }
    466 
    467 void eval_patch(const char *const origfile, const char *const difffile, const char *const outfile)
    468 {
    469  const sctx_T saved_sctx = current_sctx;
    470  set_vim_var_string(VV_FNAME_IN, origfile, -1);
    471  set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
    472  set_vim_var_string(VV_FNAME_OUT, outfile, -1);
    473 
    474  sctx_T *ctx = get_option_sctx(kOptPatchexpr);
    475  if (ctx != NULL) {
    476    current_sctx = *ctx;
    477  }
    478 
    479  // errors are ignored
    480  typval_T *tv = eval_expr_ext(p_pex, NULL, true);
    481  tv_free(tv);
    482 
    483  set_vim_var_string(VV_FNAME_IN, NULL, -1);
    484  set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
    485  set_vim_var_string(VV_FNAME_OUT, NULL, -1);
    486  current_sctx = saved_sctx;
    487 }
    488 
    489 /// Evaluate an expression to a list with suggestions.
    490 /// For the "expr:" part of 'spellsuggest'.
    491 ///
    492 /// @return  NULL when there is an error.
    493 list_T *eval_spell_expr(char *badword, char *expr)
    494 {
    495  typval_T save_val;
    496  typval_T rettv;
    497  list_T *list = NULL;
    498  char *p = skipwhite(expr);
    499  const sctx_T saved_sctx = current_sctx;
    500 
    501  // Set "v:val" to the bad word.
    502  prepare_vimvar(VV_VAL, &save_val);
    503  set_vim_var_string(VV_VAL, badword, -1);
    504  if (p_verbose == 0) {
    505    emsg_off++;
    506  }
    507  sctx_T *ctx = get_option_sctx(kOptSpellsuggest);
    508  if (ctx != NULL) {
    509    current_sctx = *ctx;
    510  }
    511 
    512  int r = may_call_simple_func(p, &rettv);
    513  if (r == NOTDONE) {
    514    r = eval1(&p, &rettv, &EVALARG_EVALUATE);
    515  }
    516  if (r == OK) {
    517    if (rettv.v_type != VAR_LIST) {
    518      tv_clear(&rettv);
    519    } else {
    520      list = rettv.vval.v_list;
    521    }
    522  }
    523 
    524  if (p_verbose == 0) {
    525    emsg_off--;
    526  }
    527  tv_clear(get_vim_var_tv(VV_VAL));
    528  restore_vimvar(VV_VAL, &save_val);
    529  current_sctx = saved_sctx;
    530 
    531  return list;
    532 }
    533 
    534 /// Get spell word from an entry from spellsuggest=expr:
    535 ///
    536 /// Entry in question is supposed to be a list (to be checked by the caller)
    537 /// with two items: a word and a score represented as an unsigned number
    538 /// (whether it actually is unsigned is not checked).
    539 ///
    540 /// Used to get the good word and score from the eval_spell_expr() result.
    541 ///
    542 /// @param[in]  list  List to get values from.
    543 /// @param[out]  ret_word  Suggested word. Not initialized if return value is
    544 ///                        -1.
    545 ///
    546 /// @return -1 in case of error, score otherwise.
    547 int get_spellword(list_T *const list, const char **ret_word)
    548 {
    549  if (tv_list_len(list) != 2) {
    550    emsg(_("E5700: Expression from 'spellsuggest' must yield lists with "
    551           "exactly two values"));
    552    return -1;
    553  }
    554  *ret_word = tv_list_find_str(list, 0);
    555  if (*ret_word == NULL) {
    556    return -1;
    557  }
    558  return (int)tv_list_find_nr(list, -1, NULL);
    559 }
    560 
    561 /// Prepare v: variable "idx" to be used.
    562 /// Save the current typeval in "save_tv" and clear it.
    563 /// When not used yet add the variable to the v: hashtable.
    564 void prepare_vimvar(int idx, typval_T *save_tv)
    565 {
    566  *save_tv = vimvars[idx].vv_tv;
    567  vimvars[idx].vv_str = NULL;  // don't free it now
    568  if (vimvars[idx].vv_type == VAR_UNKNOWN) {
    569    hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
    570  }
    571 }
    572 
    573 /// Restore v: variable "idx" to typeval "save_tv".
    574 /// Note that the v: variable must have been cleared already.
    575 /// When no longer defined, remove the variable from the v: hashtable.
    576 void restore_vimvar(int idx, typval_T *save_tv)
    577 {
    578  vimvars[idx].vv_tv = *save_tv;
    579  if (vimvars[idx].vv_type != VAR_UNKNOWN) {
    580    return;
    581  }
    582 
    583  hashitem_T *hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
    584  if (HASHITEM_EMPTY(hi)) {
    585    internal_error("restore_vimvar()");
    586  } else {
    587    hash_remove(&vimvarht, hi);
    588  }
    589 }
    590 
    591 /// List Vim variables.
    592 static void list_vim_vars(int *first)
    593 {
    594  list_hashtable_vars(&vimvarht, "v:", false, first);
    595 }
    596 
    597 /// List script-local variables, if there is a script.
    598 static void list_script_vars(int *first)
    599 {
    600  if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) {
    601    list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
    602  }
    603 }
    604 
    605 /// Evaluate one Vim expression {expr} in string "p" and append the
    606 /// resulting string to "gap".  "p" points to the opening "{".
    607 /// When "evaluate" is false only skip over the expression.
    608 /// Return a pointer to the character after "}", NULL for an error.
    609 char *eval_one_expr_in_str(char *p, garray_T *gap, bool evaluate)
    610 {
    611  char *block_start = skipwhite(p + 1);  // skip the opening {
    612  char *block_end = block_start;
    613 
    614  if (*block_start == NUL) {
    615    semsg(_(e_missing_close_curly_str), p);
    616    return NULL;
    617  }
    618  if (skip_expr(&block_end, NULL) == FAIL) {
    619    return NULL;
    620  }
    621  block_end = skipwhite(block_end);
    622  if (*block_end != '}') {
    623    semsg(_(e_missing_close_curly_str), p);
    624    return NULL;
    625  }
    626  if (evaluate) {
    627    *block_end = NUL;
    628    char *expr_val = eval_to_string(block_start, false, false);
    629    *block_end = '}';
    630    if (expr_val == NULL) {
    631      return NULL;
    632    }
    633    ga_concat(gap, expr_val);
    634    xfree(expr_val);
    635  }
    636 
    637  return block_end + 1;
    638 }
    639 
    640 /// Evaluate all the Vim expressions {expr} in "str" and return the resulting
    641 /// string in allocated memory.  "{{" is reduced to "{" and "}}" to "}".
    642 /// Used for a heredoc assignment.
    643 /// Returns NULL for an error.
    644 static char *eval_all_expr_in_str(char *str)
    645 {
    646  garray_T ga;
    647  ga_init(&ga, 1, 80);
    648  char *p = str;
    649 
    650  while (*p != NUL) {
    651    bool escaped_brace = false;
    652 
    653    // Look for a block start.
    654    char *lit_start = p;
    655    while (*p != '{' && *p != '}' && *p != NUL) {
    656      p++;
    657    }
    658 
    659    if (*p != NUL && *p == p[1]) {
    660      // Escaped brace, unescape and continue.
    661      // Include the brace in the literal string.
    662      p++;
    663      escaped_brace = true;
    664    } else if (*p == '}') {
    665      semsg(_(e_stray_closing_curly_str), str);
    666      ga_clear(&ga);
    667      return NULL;
    668    }
    669 
    670    // Append the literal part.
    671    ga_concat_len(&ga, lit_start, (size_t)(p - lit_start));
    672 
    673    if (*p == NUL) {
    674      break;
    675    }
    676 
    677    if (escaped_brace) {
    678      // Skip the second brace.
    679      p++;
    680      continue;
    681    }
    682 
    683    // Evaluate the expression and append the result.
    684    p = eval_one_expr_in_str(p, &ga, true);
    685    if (p == NULL) {
    686      ga_clear(&ga);
    687      return NULL;
    688    }
    689  }
    690  ga_append(&ga, NUL);
    691 
    692  return ga.ga_data;
    693 }
    694 
    695 /// Get a list of lines from a HERE document. The here document is a list of
    696 /// lines surrounded by a marker.
    697 ///     cmd << {marker}
    698 ///       {line1}
    699 ///       {line2}
    700 ///       ....
    701 ///     {marker}
    702 ///
    703 /// The {marker} is a string. If the optional 'trim' word is supplied before the
    704 /// marker, then the leading indentation before the lines (matching the
    705 /// indentation in the 'cmd' line) is stripped.
    706 ///
    707 /// When getting lines for an embedded script (e.g. python, lua, perl, ruby,
    708 /// tcl, mzscheme), "script_get" is set to true. In this case, if the marker is
    709 /// missing, then '.' is accepted as a marker.
    710 ///
    711 /// @return  a List with {lines} or NULL on failure.
    712 list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get)
    713 {
    714  char *marker;
    715  int marker_indent_len = 0;
    716  int text_indent_len = 0;
    717  char *text_indent = NULL;
    718  char dot[] = ".";
    719  bool heredoc_in_string = false;
    720  char *line_arg = NULL;
    721  char *nl_ptr = vim_strchr(cmd, '\n');
    722 
    723  if (nl_ptr != NULL) {
    724    heredoc_in_string = true;
    725    line_arg = nl_ptr + 1;
    726    *nl_ptr = NUL;
    727  } else if (eap->ea_getline == NULL) {
    728    emsg(_(e_cannot_use_heredoc_here));
    729    return NULL;
    730  }
    731 
    732  // Check for the optional 'trim' word before the marker
    733  cmd = skipwhite(cmd);
    734  bool evalstr = false;
    735  bool eval_failed = false;
    736  while (true) {
    737    if (strncmp(cmd, "trim", 4) == 0
    738        && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
    739      cmd = skipwhite(cmd + 4);
    740 
    741      // Trim the indentation from all the lines in the here document.
    742      // The amount of indentation trimmed is the same as the indentation
    743      // of the first line after the :let command line.  To find the end
    744      // marker the indent of the :let command line is trimmed.
    745      char *p = *eap->cmdlinep;
    746      while (ascii_iswhite(*p)) {
    747        p++;
    748        marker_indent_len++;
    749      }
    750      text_indent_len = -1;
    751 
    752      continue;
    753    }
    754    if (strncmp(cmd, "eval", 4) == 0
    755        && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
    756      cmd = skipwhite(cmd + 4);
    757      evalstr = true;
    758      continue;
    759    }
    760    break;
    761  }
    762 
    763  const char comment_char = '"';
    764  // The marker is the next word.
    765  if (*cmd != NUL && *cmd != comment_char) {
    766    marker = skipwhite(cmd);
    767    char *p = skiptowhite(marker);
    768    if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char) {
    769      semsg(_(e_trailing_arg), p);
    770      return NULL;
    771    }
    772    *p = NUL;
    773    if (!script_get && islower((uint8_t)(*marker))) {
    774      emsg(_("E221: Marker cannot start with lower case letter"));
    775      return NULL;
    776    }
    777  } else {
    778    // When getting lines for an embedded script, if the marker is missing,
    779    // accept '.' as the marker.
    780    if (script_get) {
    781      marker = dot;
    782    } else {
    783      emsg(_("E172: Missing marker"));
    784      return NULL;
    785    }
    786  }
    787 
    788  char *theline = NULL;
    789  list_T *l = tv_list_alloc(0);
    790  while (true) {
    791    int mi = 0;
    792    int ti = 0;
    793 
    794    if (heredoc_in_string) {
    795      // heredoc in a string separated by newlines.  Get the next line
    796      // from the string.
    797 
    798      if (*line_arg == NUL) {
    799        if (!script_get) {
    800          semsg(_(e_missing_end_marker_str), marker);
    801        }
    802        break;
    803      }
    804 
    805      theline = line_arg;
    806      char *next_line = vim_strchr(theline, '\n');
    807      if (next_line == NULL) {
    808        line_arg += strlen(line_arg);
    809      } else {
    810        *next_line = NUL;
    811        line_arg = next_line + 1;
    812      }
    813    } else {
    814      xfree(theline);
    815      theline = eap->ea_getline(NUL, eap->cookie, 0, false);
    816      if (theline == NULL) {
    817        if (!script_get) {
    818          semsg(_(e_missing_end_marker_str), marker);
    819        }
    820        break;
    821      }
    822    }
    823 
    824    // with "trim": skip the indent matching the :let line to find the
    825    // marker
    826    if (marker_indent_len > 0
    827        && strncmp(theline, *eap->cmdlinep, (size_t)marker_indent_len) == 0) {
    828      mi = marker_indent_len;
    829    }
    830    if (strcmp(marker, theline + mi) == 0) {
    831      break;
    832    }
    833 
    834    // If expression evaluation failed in the heredoc, then skip till the
    835    // end marker.
    836    if (eval_failed) {
    837      continue;
    838    }
    839 
    840    if (text_indent_len == -1 && *theline != NUL) {
    841      // set the text indent from the first line.
    842      char *p = theline;
    843      text_indent_len = 0;
    844      while (ascii_iswhite(*p)) {
    845        p++;
    846        text_indent_len++;
    847      }
    848      text_indent = xmemdupz(theline, (size_t)text_indent_len);
    849    }
    850    // with "trim": skip the indent matching the first line
    851    if (text_indent != NULL) {
    852      for (ti = 0; ti < text_indent_len; ti++) {
    853        if (theline[ti] != text_indent[ti]) {
    854          break;
    855        }
    856      }
    857    }
    858 
    859    char *str = theline + ti;
    860    if (evalstr && !eap->skip) {
    861      str = eval_all_expr_in_str(str);
    862      if (str == NULL) {
    863        // expression evaluation failed
    864        eval_failed = true;
    865        continue;
    866      }
    867      tv_list_append_allocated_string(l, str);
    868    } else {
    869      tv_list_append_string(l, str, -1);
    870    }
    871  }
    872  if (heredoc_in_string) {
    873    // Next command follows the heredoc in the string.
    874    eap->nextcmd = line_arg;
    875  } else {
    876    xfree(theline);
    877  }
    878  xfree(text_indent);
    879 
    880  if (eval_failed) {
    881    // expression evaluation in the heredoc failed
    882    tv_list_free(l);
    883    return NULL;
    884  }
    885  return l;
    886 }
    887 
    888 /// ":let" list all variable values
    889 /// ":let var1 var2" list variable values
    890 /// ":let var = expr" assignment command.
    891 /// ":let var += expr" assignment command.
    892 /// ":let var -= expr" assignment command.
    893 /// ":let var *= expr" assignment command.
    894 /// ":let var /= expr" assignment command.
    895 /// ":let var %= expr" assignment command.
    896 /// ":let var .= expr" assignment command.
    897 /// ":let var ..= expr" assignment command.
    898 /// ":let [var1, var2] = expr" unpack list.
    899 /// ":let [name, ..., ; lastname] = expr" unpack list.
    900 ///
    901 /// ":cons[t] var = expr1" define constant
    902 /// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
    903 /// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
    904 void ex_let(exarg_T *eap)
    905 {
    906  const bool is_const = eap->cmdidx == CMD_const;
    907  char *arg = eap->arg;
    908  char *expr = NULL;
    909  typval_T rettv;
    910  int var_count = 0;
    911  int semicolon = 0;
    912  char op[2];
    913  const char *argend;
    914  int first = true;
    915 
    916  argend = skip_var_list(arg, &var_count, &semicolon, false);
    917  if (argend == NULL) {
    918    return;
    919  }
    920  expr = skipwhite(argend);
    921  bool concat = strncmp(expr, "..=", 3) == 0;
    922  bool has_assign = *expr == '=' || (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
    923                                     && expr[1] == '=');
    924  if (!has_assign && !concat) {
    925    // ":let" without "=": list variables
    926    if (*arg == '[') {
    927      emsg(_(e_invarg));
    928    } else if (!ends_excmd(*arg)) {
    929      // ":let var1 var2"
    930      arg = (char *)list_arg_vars(eap, arg, &first);
    931    } else if (!eap->skip) {
    932      // ":let"
    933      list_glob_vars(&first);
    934      list_buf_vars(&first);
    935      list_win_vars(&first);
    936      list_tab_vars(&first);
    937      list_script_vars(&first);
    938      list_func_vars(&first);
    939      list_vim_vars(&first);
    940    }
    941    eap->nextcmd = check_nextcmd(arg);
    942    return;
    943  }
    944 
    945  if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
    946    // HERE document
    947    list_T *l = heredoc_get(eap, expr + 3, false);
    948    if (l != NULL) {
    949      tv_list_set_ret(&rettv, l);
    950      if (!eap->skip) {
    951        op[0] = '=';
    952        op[1] = NUL;
    953        ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
    954      }
    955      tv_clear(&rettv);
    956    }
    957    return;
    958  }
    959 
    960  rettv.v_type = VAR_UNKNOWN;
    961 
    962  op[0] = '=';
    963  op[1] = NUL;
    964  if (*expr != '=') {
    965    if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) {
    966      op[0] = *expr;  // +=, -=, *=, /=, %= or .=
    967      if (expr[0] == '.' && expr[1] == '.') {  // ..=
    968        expr++;
    969      }
    970    }
    971    expr += 2;
    972  } else {
    973    expr += 1;
    974  }
    975 
    976  expr = skipwhite(expr);
    977 
    978  if (eap->skip) {
    979    emsg_skip++;
    980  }
    981  evalarg_T evalarg;
    982  fill_evalarg_from_eap(&evalarg, eap, eap->skip);
    983  int eval_res = eval0(expr, &rettv, eap, &evalarg);
    984  if (eap->skip) {
    985    emsg_skip--;
    986  }
    987  clear_evalarg(&evalarg, eap);
    988 
    989  if (!eap->skip && eval_res != FAIL) {
    990    ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
    991  }
    992  if (eval_res != FAIL) {
    993    tv_clear(&rettv);
    994  }
    995 }
    996 
    997 /// Assign the typevalue "tv" to the variable or variables at "arg_start".
    998 /// Handles both "var" with any type and "[var, var; var]" with a list type.
    999 /// When "op" is not NULL it points to a string with characters that
   1000 /// must appear after the variable(s).  Use "+", "-" or "." for add, subtract
   1001 /// or concatenate.
   1002 ///
   1003 /// @param copy  copy values from "tv", don't move
   1004 /// @param semicolon  from skip_var_list()
   1005 /// @param var_count  from skip_var_list()
   1006 /// @param is_const  lock variables for :const
   1007 ///
   1008 /// @return  OK or FAIL;
   1009 int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int is_const,
   1010                char *op)
   1011 {
   1012  char *arg = arg_start;
   1013  typval_T ltv;
   1014 
   1015  if (*arg != '[') {
   1016    // ":let var = expr" or ":for var in list"
   1017    if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL) {
   1018      return FAIL;
   1019    }
   1020    return OK;
   1021  }
   1022 
   1023  // ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
   1024  if (tv->v_type != VAR_LIST) {
   1025    emsg(_(e_listreq));
   1026    return FAIL;
   1027  }
   1028  list_T *const l = tv->vval.v_list;
   1029 
   1030  const int len = tv_list_len(l);
   1031  if (semicolon == 0 && var_count < len) {
   1032    emsg(_("E687: Less targets than List items"));
   1033    return FAIL;
   1034  }
   1035  if (var_count - semicolon > len) {
   1036    emsg(_("E688: More targets than List items"));
   1037    return FAIL;
   1038  }
   1039  // List l may actually be NULL, but it should fail with E688 or even earlier
   1040  // if you try to do ":let [] = v:_null_list".
   1041  assert(l != NULL);
   1042 
   1043  listitem_T *item = tv_list_first(l);
   1044  size_t rest_len = (size_t)tv_list_len(l);
   1045  while (*arg != ']') {
   1046    arg = skipwhite(arg + 1);
   1047    arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const, ",;]", op);
   1048    if (arg == NULL) {
   1049      return FAIL;
   1050    }
   1051    rest_len--;
   1052 
   1053    item = TV_LIST_ITEM_NEXT(l, item);
   1054    arg = skipwhite(arg);
   1055    if (*arg == ';') {
   1056      // Put the rest of the list (may be empty) in the var after ';'.
   1057      // Create a new list for this.
   1058      list_T *const rest_list = tv_list_alloc((ptrdiff_t)rest_len);
   1059      while (item != NULL) {
   1060        tv_list_append_tv(rest_list, TV_LIST_ITEM_TV(item));
   1061        item = TV_LIST_ITEM_NEXT(l, item);
   1062      }
   1063 
   1064      ltv.v_type = VAR_LIST;
   1065      ltv.v_lock = VAR_UNLOCKED;
   1066      ltv.vval.v_list = rest_list;
   1067      tv_list_ref(rest_list);
   1068 
   1069      arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const, "]", op);
   1070      tv_clear(&ltv);
   1071      if (arg == NULL) {
   1072        return FAIL;
   1073      }
   1074      break;
   1075    } else if (*arg != ',' && *arg != ']') {
   1076      internal_error("ex_let_vars()");
   1077      return FAIL;
   1078    }
   1079  }
   1080 
   1081  return OK;
   1082 }
   1083 
   1084 /// Skip over assignable variable "var" or list of variables "[var, var]".
   1085 /// Used for ":let varvar = expr" and ":for varvar in expr".
   1086 /// For "[var, var]" increment "*var_count" for each variable.
   1087 /// for "[var, var; var]" set "semicolon" to 1.
   1088 /// If "silent" is true do not give an "invalid argument" error message.
   1089 ///
   1090 /// @return  NULL for an error.
   1091 const char *skip_var_list(const char *arg, int *var_count, int *semicolon, bool silent)
   1092 {
   1093  if (*arg == '[') {
   1094    const char *s;
   1095    // "[var, var]": find the matching ']'.
   1096    const char *p = arg;
   1097    while (true) {
   1098      p = skipwhite(p + 1);             // skip whites after '[', ';' or ','
   1099      s = skip_var_one(p);
   1100      if (s == p) {
   1101        if (!silent) {
   1102          semsg(_(e_invarg2), p);
   1103        }
   1104        return NULL;
   1105      }
   1106      (*var_count)++;
   1107 
   1108      p = skipwhite(s);
   1109      if (*p == ']') {
   1110        break;
   1111      } else if (*p == ';') {
   1112        if (*semicolon == 1) {
   1113          if (!silent) {
   1114            emsg(_(e_double_semicolon_in_list_of_variables));
   1115          }
   1116          return NULL;
   1117        }
   1118        *semicolon = 1;
   1119      } else if (*p != ',') {
   1120        if (!silent) {
   1121          semsg(_(e_invarg2), p);
   1122        }
   1123        return NULL;
   1124      }
   1125    }
   1126    return p + 1;
   1127  }
   1128  return skip_var_one(arg);
   1129 }
   1130 
   1131 /// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
   1132 /// l[idx].
   1133 static const char *skip_var_one(const char *arg)
   1134 {
   1135  if (*arg == '@' && arg[1] != NUL) {
   1136    return arg + 2;
   1137  }
   1138  return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
   1139                       NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
   1140 }
   1141 
   1142 /// List variables for hashtab "ht" with prefix "prefix".
   1143 ///
   1144 /// @param empty  if true also list NULL strings as empty strings.
   1145 void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *first)
   1146 {
   1147  hashitem_T *hi;
   1148  dictitem_T *di;
   1149  int todo;
   1150 
   1151  todo = (int)ht->ht_used;
   1152  for (hi = ht->ht_array; todo > 0 && !got_int; hi++) {
   1153    if (!HASHITEM_EMPTY(hi)) {
   1154      todo--;
   1155      di = TV_DICT_HI2DI(hi);
   1156      char buf[IOSIZE];
   1157 
   1158      // apply :filter /pat/ to variable name
   1159      xstrlcpy(buf, prefix, IOSIZE);
   1160      xstrlcat(buf, di->di_key, IOSIZE);
   1161      if (message_filtered(buf)) {
   1162        continue;
   1163      }
   1164 
   1165      if (empty || di->di_tv.v_type != VAR_STRING
   1166          || di->di_tv.vval.v_string != NULL) {
   1167        list_one_var(di, prefix, first);
   1168      }
   1169    }
   1170  }
   1171 }
   1172 
   1173 /// List global variables.
   1174 static void list_glob_vars(int *first)
   1175 {
   1176  list_hashtable_vars(&globvarht, "", true, first);
   1177 }
   1178 
   1179 /// List buffer variables.
   1180 static void list_buf_vars(int *first)
   1181 {
   1182  list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", true, first);
   1183 }
   1184 
   1185 /// List window variables.
   1186 static void list_win_vars(int *first)
   1187 {
   1188  list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", true, first);
   1189 }
   1190 
   1191 /// List tab page variables.
   1192 static void list_tab_vars(int *first)
   1193 {
   1194  list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", true, first);
   1195 }
   1196 
   1197 /// List variables in "arg".
   1198 static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
   1199 {
   1200  bool error = false;
   1201  int len;
   1202  const char *name;
   1203  const char *name_start;
   1204  typval_T tv;
   1205 
   1206  while (!ends_excmd(*arg) && !got_int) {
   1207    if (error || eap->skip) {
   1208      arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
   1209      if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) {
   1210        emsg_severe = true;
   1211        semsg(_(e_trailing_arg), arg);
   1212        break;
   1213      }
   1214    } else {
   1215      // get_name_len() takes care of expanding curly braces
   1216      name_start = name = arg;
   1217      char *tofree;
   1218      len = get_name_len(&arg, &tofree, true, true);
   1219      if (len <= 0) {
   1220        // This is mainly to keep test 49 working: when expanding
   1221        // curly braces fails overrule the exception error message.
   1222        if (len < 0 && !aborting()) {
   1223          emsg_severe = true;
   1224          semsg(_(e_invarg2), arg);
   1225          break;
   1226        }
   1227        error = true;
   1228      } else {
   1229        if (tofree != NULL) {
   1230          name = tofree;
   1231        }
   1232        if (eval_variable(name, len, &tv, NULL, true, false) == FAIL) {
   1233          error = true;
   1234        } else {
   1235          // handle d.key, l[idx], f(expr)
   1236          const char *const arg_subsc = arg;
   1237          if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, true) == FAIL) {
   1238            error = true;
   1239          } else {
   1240            if (arg == arg_subsc && len == 2 && name[1] == ':') {
   1241              switch (*name) {
   1242              case 'g':
   1243                list_glob_vars(first); break;
   1244              case 'b':
   1245                list_buf_vars(first); break;
   1246              case 'w':
   1247                list_win_vars(first); break;
   1248              case 't':
   1249                list_tab_vars(first); break;
   1250              case 'v':
   1251                list_vim_vars(first); break;
   1252              case 's':
   1253                list_script_vars(first); break;
   1254              case 'l':
   1255                list_func_vars(first); break;
   1256              default:
   1257                semsg(_("E738: Can't list variables for %s"), name);
   1258              }
   1259            } else {
   1260              char *const s = encode_tv2echo(&tv, NULL);
   1261              const char *const used_name = (arg == arg_subsc
   1262                                             ? name
   1263                                             : name_start);
   1264              assert(used_name != NULL);
   1265              const ptrdiff_t name_size = (used_name == tofree
   1266                                           ? (ptrdiff_t)strlen(used_name)
   1267                                           : (arg - used_name));
   1268              list_one_var_a("", used_name, name_size,
   1269                             tv.v_type, s == NULL ? "" : s, first);
   1270              xfree(s);
   1271            }
   1272            tv_clear(&tv);
   1273          }
   1274        }
   1275      }
   1276 
   1277      xfree(tofree);
   1278    }
   1279 
   1280    arg = skipwhite(arg);
   1281  }
   1282 
   1283  return arg;
   1284 }
   1285 
   1286 /// Set an environment variable, part of ex_let_one().
   1287 static char *ex_let_env(char *arg, typval_T *const tv, const bool is_const,
   1288                        const char *const endchars, const char *const op)
   1289  FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
   1290 {
   1291  if (is_const) {
   1292    emsg(_("E996: Cannot lock an environment variable"));
   1293    return NULL;
   1294  }
   1295 
   1296  // Find the end of the name.
   1297  char *arg_end = NULL;
   1298  arg++;
   1299  char *name = arg;
   1300  int len = get_env_len((const char **)&arg);
   1301  if (len == 0) {
   1302    semsg(_(e_invarg2), name - 1);
   1303  } else {
   1304    if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
   1305      semsg(_(e_letwrong), op);
   1306    } else if (endchars != NULL
   1307               && vim_strchr(endchars, (uint8_t)(*skipwhite(arg))) == NULL) {
   1308      emsg(_(e_letunexp));
   1309    } else if (!check_secure()) {
   1310      char *tofree = NULL;
   1311      const char c1 = name[len];
   1312      name[len] = NUL;
   1313      const char *p = tv_get_string_chk(tv);
   1314      if (p != NULL && op != NULL && *op == '.') {
   1315        char *s = vim_getenv(name);
   1316        if (s != NULL) {
   1317          tofree = concat_str(s, p);
   1318          p = tofree;
   1319          xfree(s);
   1320        }
   1321      }
   1322      if (p != NULL) {
   1323        vim_setenv_ext(name, p);
   1324        arg_end = arg;
   1325      }
   1326      name[len] = c1;
   1327      xfree(tofree);
   1328    }
   1329  }
   1330  return arg_end;
   1331 }
   1332 
   1333 /// Set an option, part of ex_let_one().
   1334 static char *ex_let_option(char *arg, typval_T *const tv, const bool is_const,
   1335                           const char *const endchars, const char *const op)
   1336  FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
   1337 {
   1338  if (is_const) {
   1339    emsg(_("E996: Cannot lock an option"));
   1340    return NULL;
   1341  }
   1342 
   1343  // Find the end of the name.
   1344  char *arg_end = NULL;
   1345  OptIndex opt_idx;
   1346  int opt_flags;
   1347 
   1348  char *const p = (char *)find_option_var_end((const char **)&arg, &opt_idx, &opt_flags);
   1349 
   1350  if (p == NULL || (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
   1351    emsg(_(e_letunexp));
   1352    return NULL;
   1353  }
   1354 
   1355  const char c1 = *p;
   1356  *p = NUL;
   1357 
   1358  bool is_tty_opt = is_tty_option(arg);
   1359  bool hidden = is_option_hidden(opt_idx);
   1360  OptVal curval = is_tty_opt ? get_tty_option(arg) : get_option_value(opt_idx, opt_flags);
   1361  OptVal newval = NIL_OPTVAL;
   1362 
   1363  if (curval.type == kOptValTypeNil) {
   1364    semsg(_(e_unknown_option2), arg);
   1365    goto theend;
   1366  }
   1367  if (op != NULL && *op != '='
   1368      && ((curval.type != kOptValTypeString && *op == '.')
   1369          || (curval.type == kOptValTypeString && *op != '.'))) {
   1370    semsg(_(e_letwrong), op);
   1371    goto theend;
   1372  }
   1373 
   1374  bool error;
   1375  newval = tv_to_optval(tv, opt_idx, arg, &error);
   1376  if (error) {
   1377    goto theend;
   1378  }
   1379 
   1380  // Current value and new value must have the same type.
   1381  assert(curval.type == newval.type);
   1382  const bool is_num = curval.type == kOptValTypeNumber || curval.type == kOptValTypeBoolean;
   1383  const bool is_string = curval.type == kOptValTypeString;
   1384 
   1385  if (op != NULL && *op != '=') {
   1386    if (!hidden && is_num) {  // number or bool
   1387      OptInt cur_n = curval.type == kOptValTypeNumber ? curval.data.number : curval.data.boolean;
   1388      OptInt new_n = newval.type == kOptValTypeNumber ? newval.data.number : newval.data.boolean;
   1389 
   1390      switch (*op) {
   1391      case '+':
   1392        new_n = cur_n + new_n; break;
   1393      case '-':
   1394        new_n = cur_n - new_n; break;
   1395      case '*':
   1396        new_n = cur_n * new_n; break;
   1397      case '/':
   1398        new_n = num_divide(cur_n, new_n); break;
   1399      case '%':
   1400        new_n = num_modulus(cur_n, new_n); break;
   1401      }
   1402 
   1403      if (curval.type == kOptValTypeNumber) {
   1404        newval = NUMBER_OPTVAL(new_n);
   1405      } else {
   1406        newval = BOOLEAN_OPTVAL(TRISTATE_FROM_INT(new_n));
   1407      }
   1408    } else if (!hidden && is_string) {  // string
   1409      const char *curval_data = curval.data.string.data;
   1410      const char *newval_data = newval.data.string.data;
   1411 
   1412      if (curval_data != NULL && newval_data != NULL) {
   1413        OptVal newval_old = newval;
   1414        newval = CSTR_AS_OPTVAL(concat_str(curval_data, newval_data));
   1415        optval_free(newval_old);
   1416      }
   1417    }
   1418  }
   1419 
   1420  const char *err = set_option_value_handle_tty(arg, opt_idx, newval, opt_flags);
   1421  arg_end = p;
   1422  if (err != NULL) {
   1423    emsg(_(err));
   1424  }
   1425 
   1426 theend:
   1427  *p = c1;
   1428  optval_free(curval);
   1429  optval_free(newval);
   1430  return arg_end;
   1431 }
   1432 
   1433 /// Set a register, part of ex_let_one().
   1434 static char *ex_let_register(char *arg, typval_T *const tv, const bool is_const,
   1435                             const char *const endchars, const char *const op)
   1436  FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
   1437 {
   1438  if (is_const) {
   1439    emsg(_("E996: Cannot lock a register"));
   1440    return NULL;
   1441  }
   1442 
   1443  char *arg_end = NULL;
   1444  arg++;
   1445  if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
   1446    semsg(_(e_letwrong), op);
   1447  } else if (endchars != NULL
   1448             && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) {
   1449    emsg(_(e_letunexp));
   1450  } else {
   1451    char *ptofree = NULL;
   1452    const char *p = tv_get_string_chk(tv);
   1453    if (p != NULL && op != NULL && *op == '.') {
   1454      char *s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
   1455      if (s != NULL) {
   1456        ptofree = concat_str(s, p);
   1457        p = ptofree;
   1458        xfree(s);
   1459      }
   1460    }
   1461    if (p != NULL) {
   1462      write_reg_contents(*arg == '@' ? '"' : *arg, p, (ssize_t)strlen(p), false);
   1463      arg_end = arg + 1;
   1464    }
   1465    xfree(ptofree);
   1466  }
   1467  return arg_end;
   1468 }
   1469 
   1470 /// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
   1471 ///
   1472 /// @param[in]  arg  Start of the variable name.
   1473 /// @param[in]  tv  Value to assign to the variable.
   1474 /// @param[in]  copy  If true, copy value from `tv`.
   1475 /// @param[in]  endchars  Valid characters after variable name or NULL.
   1476 /// @param[in]  op  Operation performed: *op is `+`, `-`, `.` for `+=`, etc.
   1477 ///                 NULL for `=`.
   1478 ///
   1479 /// @return a pointer to the char just after the var name or NULL in case of
   1480 ///         error.
   1481 static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bool is_const,
   1482                        const char *const endchars, const char *const op)
   1483  FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
   1484 {
   1485  char *arg_end = NULL;
   1486 
   1487  if (*arg == '$') {
   1488    // ":let $VAR = expr": Set environment variable.
   1489    return ex_let_env(arg, tv, is_const, endchars, op);
   1490  } else if (*arg == '&') {
   1491    // ":let &option = expr": Set option value.
   1492    // ":let &l:option = expr": Set local option value.
   1493    // ":let &g:option = expr": Set global option value.
   1494    return ex_let_option(arg, tv, is_const, endchars, op);
   1495  } else if (*arg == '@') {
   1496    // ":let @r = expr": Set register contents.
   1497    return ex_let_register(arg, tv, is_const, endchars, op);
   1498  } else if (eval_isnamec1(*arg) || *arg == '{') {
   1499    // ":let var = expr": Set internal variable.
   1500    // ":let {expr} = expr": Idem, name made with curly braces
   1501    lval_T lv;
   1502    char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
   1503    if (p != NULL && lv.ll_name != NULL) {
   1504      if (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL) {
   1505        emsg(_(e_letunexp));
   1506      } else {
   1507        set_var_lval(&lv, p, tv, copy, is_const, op);
   1508        arg_end = p;
   1509      }
   1510    }
   1511    clear_lval(&lv);
   1512  } else {
   1513    semsg(_(e_invarg2), arg);
   1514  }
   1515 
   1516  return arg_end;
   1517 }
   1518 
   1519 /// ":unlet[!] var1 ... " command.
   1520 void ex_unlet(exarg_T *eap)
   1521 {
   1522  ex_unletlock(eap, eap->arg, 0, eap->forceit ? GLV_QUIET : 0, do_unlet_var);
   1523 }
   1524 
   1525 /// ":lockvar" and ":unlockvar" commands
   1526 void ex_lockvar(exarg_T *eap)
   1527 {
   1528  char *arg = eap->arg;
   1529  int deep = 2;
   1530 
   1531  if (eap->forceit) {
   1532    deep = -1;
   1533  } else if (ascii_isdigit(*arg)) {
   1534    deep = getdigits_int(&arg, false, -1);
   1535    arg = skipwhite(arg);
   1536  }
   1537 
   1538  ex_unletlock(eap, arg, deep, 0, do_lock_var);
   1539 }
   1540 
   1541 /// Common parsing logic for :unlet, :lockvar and :unlockvar.
   1542 ///
   1543 /// Invokes `callback` afterwards if successful and `eap->skip == false`.
   1544 ///
   1545 /// @param[in]  eap  Ex command arguments for the command.
   1546 /// @param[in]  argstart  Start of the string argument for the command.
   1547 /// @param[in]  deep  Levels to (un)lock for :(un)lockvar, -1 to (un)lock
   1548 ///                   everything.
   1549 /// @param[in]  callback  Appropriate handler for the command.
   1550 static void ex_unletlock(exarg_T *eap, char *argstart, int deep, int glv_flags,
   1551                         ex_unletlock_callback callback)
   1552  FUNC_ATTR_NONNULL_ALL
   1553 {
   1554  char *arg = argstart;
   1555  char *name_end;
   1556  bool error = false;
   1557  lval_T lv;
   1558 
   1559  do {
   1560    if (*arg == '$') {
   1561      lv.ll_name = arg;
   1562      lv.ll_tv = NULL;
   1563      arg++;
   1564      if (get_env_len((const char **)&arg) == 0) {
   1565        semsg(_(e_invarg2), arg - 1);
   1566        return;
   1567      }
   1568      assert(*lv.ll_name == '$');  // suppress clang "Uninitialized argument value"
   1569      if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) {
   1570        error = true;
   1571      }
   1572      name_end = arg;
   1573    } else {
   1574      // Parse the name and find the end.
   1575      name_end = get_lval(arg, NULL, &lv, true, eap->skip || error,
   1576                          glv_flags, FNE_CHECK_START);
   1577      if (lv.ll_name == NULL) {
   1578        error = true;  // error, but continue parsing.
   1579      }
   1580      if (name_end == NULL
   1581          || (!ascii_iswhite(*name_end) && !ends_excmd(*name_end))) {
   1582        if (name_end != NULL) {
   1583          emsg_severe = true;
   1584          semsg(_(e_trailing_arg), name_end);
   1585        }
   1586        if (!(eap->skip || error)) {
   1587          clear_lval(&lv);
   1588        }
   1589        break;
   1590      }
   1591 
   1592      if (!error && !eap->skip && callback(&lv, name_end, eap, deep) == FAIL) {
   1593        error = true;
   1594      }
   1595 
   1596      if (!eap->skip) {
   1597        clear_lval(&lv);
   1598      }
   1599    }
   1600    arg = skipwhite(name_end);
   1601  } while (!ends_excmd(*arg));
   1602 
   1603  eap->nextcmd = check_nextcmd(arg);
   1604 }
   1605 
   1606 /// Unlet a variable indicated by `lp`.
   1607 ///
   1608 /// @param[in]  lp  The lvalue.
   1609 /// @param[in]  name_end  End of the string argument for the command.
   1610 /// @param[in]  eap  Ex command arguments for :unlet.
   1611 /// @param[in]  deep  Unused.
   1612 ///
   1613 /// @return OK on success, or FAIL on failure.
   1614 static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ATTR_UNUSED)
   1615  FUNC_ATTR_NONNULL_ALL
   1616 {
   1617  int forceit = eap->forceit;
   1618  int ret = OK;
   1619 
   1620  if (lp->ll_tv == NULL) {
   1621    int cc = (uint8_t)(*name_end);
   1622    *name_end = NUL;
   1623 
   1624    // Environment variable, normal name or expanded name.
   1625    if (*lp->ll_name == '$') {
   1626      vim_unsetenv_ext(lp->ll_name + 1);
   1627    } else if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) {
   1628      ret = FAIL;
   1629    }
   1630    *name_end = (char)cc;
   1631  } else if ((lp->ll_list != NULL
   1632              // ll_list is not NULL when lvalue is not in a list, NULL lists
   1633              // yield E689.
   1634              && value_check_lock(tv_list_locked(lp->ll_list),
   1635                                  lp->ll_name,
   1636                                  lp->ll_name_len))
   1637             || (lp->ll_dict != NULL
   1638                 && value_check_lock(lp->ll_dict->dv_lock,
   1639                                     lp->ll_name,
   1640                                     lp->ll_name_len))) {
   1641    return FAIL;
   1642  } else if (lp->ll_range) {
   1643    tv_list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_n1, !lp->ll_empty2, lp->ll_n2);
   1644  } else if (lp->ll_list != NULL) {
   1645    // unlet a List item.
   1646    tv_list_item_remove(lp->ll_list, lp->ll_li);
   1647  } else {
   1648    // unlet a Dict item.
   1649    dict_T *d = lp->ll_dict;
   1650    assert(d != NULL);
   1651    dictitem_T *di = lp->ll_di;
   1652    bool watched = tv_dict_is_watched(d);
   1653    char *key = NULL;
   1654    typval_T oldtv;
   1655 
   1656    if (watched) {
   1657      tv_copy(&di->di_tv, &oldtv);
   1658      // need to save key because dictitem_remove will free it
   1659      key = xstrdup(di->di_key);
   1660    }
   1661 
   1662    tv_dict_item_remove(d, di);
   1663 
   1664    if (watched) {
   1665      tv_dict_watcher_notify(d, key, NULL, &oldtv);
   1666      tv_clear(&oldtv);
   1667      xfree(key);
   1668    }
   1669  }
   1670 
   1671  return ret;
   1672 }
   1673 
   1674 /// Unlet one item or a range of items from a list.
   1675 /// Return OK or FAIL.
   1676 static void tv_list_unlet_range(list_T *const l, listitem_T *const li_first, const int n1_arg,
   1677                                const bool has_n2, const int n2)
   1678 {
   1679  assert(l != NULL);
   1680  // Delete a range of List items.
   1681  listitem_T *li_last = li_first;
   1682  int n1 = n1_arg;
   1683  while (true) {
   1684    listitem_T *const li = TV_LIST_ITEM_NEXT(l, li_last);
   1685    n1++;
   1686    if (li == NULL || (has_n2 && n2 < n1)) {
   1687      break;
   1688    }
   1689    li_last = li;
   1690  }
   1691  tv_list_remove_items(l, li_first, li_last);
   1692 }
   1693 
   1694 /// unlet a variable
   1695 ///
   1696 /// @param[in]  name  Variable name to unlet.
   1697 /// @param[in]  name_len  Variable name length.
   1698 /// @param[in]  forceit  If true, do not complain if variable doesn’t exist.
   1699 ///
   1700 /// @return OK if it existed, FAIL otherwise.
   1701 int do_unlet(const char *const name, const size_t name_len, const bool forceit)
   1702  FUNC_ATTR_NONNULL_ALL
   1703 {
   1704  const char *varname = NULL;  // init to shut up gcc
   1705  dict_T *dict;
   1706  hashtab_T *ht = find_var_ht_dict(name, name_len, &varname, &dict);
   1707 
   1708  if (ht != NULL && *varname != NUL) {
   1709    dict_T *d = get_current_funccal_dict(ht);
   1710    if (d == NULL) {
   1711      if (ht == &globvarht) {
   1712        d = &globvardict;
   1713      } else if (ht == &compat_hashtab) {
   1714        d = &vimvardict;
   1715      } else {
   1716        dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
   1717        d = di->di_tv.vval.v_dict;
   1718      }
   1719      if (d == NULL) {
   1720        internal_error("do_unlet()");
   1721        return FAIL;
   1722      }
   1723    }
   1724 
   1725    hashitem_T *hi = hash_find(ht, varname);
   1726    if (HASHITEM_EMPTY(hi)) {
   1727      hi = find_hi_in_scoped_ht(name, &ht);
   1728    }
   1729    if (hi != NULL && !HASHITEM_EMPTY(hi)) {
   1730      dictitem_T *const di = TV_DICT_HI2DI(hi);
   1731      if (var_check_fixed(di->di_flags, name, TV_CSTRING)
   1732          || var_check_ro(di->di_flags, name, TV_CSTRING)
   1733          || value_check_lock(d->dv_lock, name, TV_CSTRING)) {
   1734        return FAIL;
   1735      }
   1736 
   1737      if (value_check_lock(d->dv_lock, name, TV_CSTRING)) {
   1738        return FAIL;
   1739      }
   1740 
   1741      typval_T oldtv;
   1742      bool watched = tv_dict_is_watched(dict);
   1743 
   1744      if (watched) {
   1745        tv_copy(&di->di_tv, &oldtv);
   1746      }
   1747 
   1748      delete_var(ht, hi);
   1749 
   1750      if (watched) {
   1751        tv_dict_watcher_notify(dict, varname, NULL, &oldtv);
   1752        tv_clear(&oldtv);
   1753      }
   1754      return OK;
   1755    }
   1756  }
   1757  if (forceit) {
   1758    return OK;
   1759  }
   1760  semsg(_("E108: No such variable: \"%s\""), name);
   1761  return FAIL;
   1762 }
   1763 
   1764 /// Lock or unlock variable indicated by `lp`.
   1765 ///
   1766 /// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
   1767 ///
   1768 /// @param[in]  lp  The lvalue.
   1769 /// @param[in]  name_end  Unused.
   1770 /// @param[in]  eap  Ex command arguments for :(un)lockvar.
   1771 /// @param[in]  deep  Levels to (un)lock, -1 to (un)lock everything.
   1772 ///
   1773 /// @return OK on success, or FAIL on failure.
   1774 static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap, int deep)
   1775  FUNC_ATTR_NONNULL_ARG(1, 3)
   1776 {
   1777  bool lock = eap->cmdidx == CMD_lockvar;
   1778  int ret = OK;
   1779 
   1780  if (lp->ll_tv == NULL) {
   1781    if (*lp->ll_name == '$') {
   1782      semsg(_(e_lock_unlock), lp->ll_name);
   1783      ret = FAIL;
   1784    } else {
   1785      // Normal name or expanded name.
   1786      dictitem_T *const di = find_var(lp->ll_name, lp->ll_name_len, NULL,
   1787                                      true);
   1788      if (di == NULL) {
   1789        ret = FAIL;
   1790      } else if ((di->di_flags & DI_FLAGS_FIX)
   1791                 && di->di_tv.v_type != VAR_DICT
   1792                 && di->di_tv.v_type != VAR_LIST) {
   1793        // For historical reasons this error is not given for Lists and
   1794        // Dictionaries. E.g. b: dictionary may be locked/unlocked.
   1795        semsg(_(e_lock_unlock), lp->ll_name);
   1796        ret = FAIL;
   1797      } else {
   1798        if (lock) {
   1799          di->di_flags |= DI_FLAGS_LOCK;
   1800        } else {
   1801          di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK);
   1802        }
   1803        if (deep != 0) {
   1804          tv_item_lock(&di->di_tv, deep, lock, false);
   1805        }
   1806      }
   1807    }
   1808  } else if (deep == 0) {
   1809    // nothing to do
   1810  } else if (lp->ll_range) {
   1811    listitem_T *li = lp->ll_li;
   1812 
   1813    // (un)lock a range of List items.
   1814    while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
   1815      tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock, false);
   1816      li = TV_LIST_ITEM_NEXT(lp->ll_list, li);
   1817      lp->ll_n1++;
   1818    }
   1819  } else if (lp->ll_list != NULL) {
   1820    // (un)lock a List item.
   1821    tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock, false);
   1822  } else {
   1823    // (un)lock a Dict item.
   1824    tv_item_lock(&lp->ll_di->di_tv, deep, lock, false);
   1825  }
   1826 
   1827  return ret;
   1828 }
   1829 
   1830 /// Delete all "menutrans_" variables.
   1831 void del_menutrans_vars(void)
   1832 {
   1833  hash_lock(&globvarht);
   1834  HASHTAB_ITER(&globvarht, hi, {
   1835    if (strncmp(hi->hi_key, "menutrans_", 10) == 0) {
   1836      delete_var(&globvarht, hi);
   1837    }
   1838  });
   1839  hash_unlock(&globvarht);
   1840 }
   1841 
   1842 /// @return  global variable dictionary
   1843 dict_T *get_globvar_dict(void)
   1844  FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
   1845 {
   1846  return &globvardict;
   1847 }
   1848 
   1849 /// @return  global variable hash table
   1850 hashtab_T *get_globvar_ht(void)
   1851 {
   1852  return &globvarht;
   1853 }
   1854 
   1855 /// @return  v: variable dictionary
   1856 dict_T *get_vimvar_dict(void)
   1857  FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
   1858 {
   1859  return &vimvardict;
   1860 }
   1861 
   1862 /// Set v:variable to tv.
   1863 ///
   1864 /// @param[in]  idx  Index of variable to set.
   1865 /// @param[in]  val  Value to set to. Will be copied.
   1866 void set_vim_var_tv(const VimVarIndex idx, typval_T *const tv)
   1867 {
   1868  typval_T *tv_out = get_vim_var_tv(idx);
   1869  tv_clear(tv_out);
   1870  tv_copy(tv, tv_out);
   1871 }
   1872 
   1873 char *get_vim_var_name(const VimVarIndex idx)
   1874  FUNC_ATTR_NONNULL_RET
   1875 {
   1876  return vimvars[idx].vv_name;
   1877 }
   1878 
   1879 /// Get typval_T v: variable value.
   1880 typval_T *get_vim_var_tv(const VimVarIndex idx)
   1881 {
   1882  return &vimvars[idx].vv_tv;
   1883 }
   1884 
   1885 /// Get number v: variable value.
   1886 varnumber_T get_vim_var_nr(const VimVarIndex idx) FUNC_ATTR_PURE
   1887 {
   1888  typval_T *tv = get_vim_var_tv(idx);
   1889  return tv->vval.v_number;
   1890 }
   1891 
   1892 /// Get List v: variable value.  Caller must take care of reference count when
   1893 /// needed.
   1894 list_T *get_vim_var_list(const VimVarIndex idx) FUNC_ATTR_PURE
   1895 {
   1896  typval_T *tv = get_vim_var_tv(idx);
   1897  return tv->vval.v_list;
   1898 }
   1899 
   1900 /// Get Dictionary v: variable value.  Caller must take care of reference count
   1901 /// when needed.
   1902 dict_T *get_vim_var_dict(const VimVarIndex idx) FUNC_ATTR_PURE
   1903 {
   1904  typval_T *tv = get_vim_var_tv(idx);
   1905  return tv->vval.v_dict;
   1906 }
   1907 
   1908 /// Get string v: variable value.  Uses a static buffer, can only be used once.
   1909 /// If the String variable has never been set, return an empty string.
   1910 /// Never returns NULL.
   1911 char *get_vim_var_str(const VimVarIndex idx)
   1912  FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
   1913 {
   1914  return (char *)tv_get_string(get_vim_var_tv(idx));
   1915 }
   1916 
   1917 /// Get Partial v: variable value.  Caller must take care of reference count
   1918 /// when needed.
   1919 partial_T *get_vim_var_partial(const VimVarIndex idx) FUNC_ATTR_PURE
   1920 {
   1921  typval_T *tv = get_vim_var_tv(idx);
   1922  return tv->vval.v_partial;
   1923 }
   1924 
   1925 /// Local string buffer for the next two functions to store a variable name
   1926 /// with its prefix. Allocated in cat_prefix_varname(), freed later in
   1927 /// get_user_var_name().
   1928 
   1929 static char *varnamebuf = NULL;
   1930 static size_t varnamebuflen = 0;
   1931 
   1932 /// Function to concatenate a prefix and a variable name.
   1933 char *cat_prefix_varname(int prefix, const char *name)
   1934  FUNC_ATTR_NONNULL_ALL
   1935 {
   1936  size_t len = strlen(name) + 3;
   1937 
   1938  if (len > varnamebuflen) {
   1939    xfree(varnamebuf);
   1940    len += 10;                          // some additional space
   1941    varnamebuf = xmalloc(len);
   1942    varnamebuflen = len;
   1943  }
   1944  *varnamebuf = (char)prefix;
   1945  varnamebuf[1] = ':';
   1946  STRCPY(varnamebuf + 2, name);
   1947  return varnamebuf;
   1948 }
   1949 
   1950 /// Function given to ExpandGeneric() to obtain the list of user defined
   1951 /// (global/buffer/window/built-in) variable names.
   1952 char *get_user_var_name(expand_T *xp, int idx)
   1953 {
   1954  static size_t gdone;
   1955  static size_t bdone;
   1956  static size_t wdone;
   1957  static size_t tdone;
   1958  static size_t vidx;
   1959  static hashitem_T *hi;
   1960 
   1961  if (idx == 0) {
   1962    gdone = bdone = wdone = vidx = 0;
   1963    tdone = 0;
   1964  }
   1965 
   1966  // Global variables
   1967  if (gdone < globvarht.ht_used) {
   1968    if (gdone++ == 0) {
   1969      hi = globvarht.ht_array;
   1970    } else {
   1971      hi++;
   1972    }
   1973    while (HASHITEM_EMPTY(hi)) {
   1974      hi++;
   1975    }
   1976    if (strncmp("g:", xp->xp_pattern, 2) == 0) {
   1977      return cat_prefix_varname('g', hi->hi_key);
   1978    }
   1979    return hi->hi_key;
   1980  }
   1981 
   1982  // b: variables
   1983  const hashtab_T *ht = &prevwin_curwin()->w_buffer->b_vars->dv_hashtab;
   1984  if (bdone < ht->ht_used) {
   1985    if (bdone++ == 0) {
   1986      hi = ht->ht_array;
   1987    } else {
   1988      hi++;
   1989    }
   1990    while (HASHITEM_EMPTY(hi)) {
   1991      hi++;
   1992    }
   1993    return cat_prefix_varname('b', hi->hi_key);
   1994  }
   1995 
   1996  // w: variables
   1997  ht = &prevwin_curwin()->w_vars->dv_hashtab;
   1998  if (wdone < ht->ht_used) {
   1999    if (wdone++ == 0) {
   2000      hi = ht->ht_array;
   2001    } else {
   2002      hi++;
   2003    }
   2004    while (HASHITEM_EMPTY(hi)) {
   2005      hi++;
   2006    }
   2007    return cat_prefix_varname('w', hi->hi_key);
   2008  }
   2009 
   2010  // t: variables
   2011  ht = &curtab->tp_vars->dv_hashtab;
   2012  if (tdone < ht->ht_used) {
   2013    if (tdone++ == 0) {
   2014      hi = ht->ht_array;
   2015    } else {
   2016      hi++;
   2017    }
   2018    while (HASHITEM_EMPTY(hi)) {
   2019      hi++;
   2020    }
   2021    return cat_prefix_varname('t', hi->hi_key);
   2022  }
   2023 
   2024  // v: variables
   2025  if (vidx < ARRAY_SIZE(vimvars)) {
   2026    return cat_prefix_varname('v', get_vim_var_name((VimVarIndex)vidx++));
   2027  }
   2028 
   2029  XFREE_CLEAR(varnamebuf);
   2030  varnamebuflen = 0;
   2031  return NULL;
   2032 }
   2033 
   2034 /// Set type of v: variable to the given type.
   2035 ///
   2036 /// @param[in]  idx  Index of variable to set.
   2037 /// @param[in]  type  Type to set to.
   2038 void set_vim_var_type(const VimVarIndex idx, const VarType type)
   2039 {
   2040  typval_T *tv = get_vim_var_tv(idx);
   2041  tv->v_type = type;
   2042 }
   2043 
   2044 /// Set number v: variable to the given value
   2045 /// Note that this does not set the type, use set_vim_var_type() for that.
   2046 ///
   2047 /// @param[in]  idx  Index of variable to set.
   2048 /// @param[in]  val  Value to set to.
   2049 void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
   2050 {
   2051  typval_T *tv = get_vim_var_tv(idx);
   2052  tv_clear(tv);
   2053  tv->vval.v_number = val;
   2054 }
   2055 
   2056 /// Set boolean v: {true, false} to the given value
   2057 ///
   2058 /// @param[in]  idx  Index of variable to set.
   2059 /// @param[in]  val  Value to set to.
   2060 void set_vim_var_bool(const VimVarIndex idx, const BoolVarValue val)
   2061 {
   2062  typval_T *tv = get_vim_var_tv(idx);
   2063  tv_clear(tv);
   2064  tv->v_type = VAR_BOOL;
   2065  tv->vval.v_bool = val;
   2066 }
   2067 
   2068 /// Set special v: variable to the given value
   2069 ///
   2070 /// @param[in]  idx  Index of variable to set.
   2071 /// @param[in]  val  Value to set to.
   2072 void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
   2073 {
   2074  typval_T *tv = get_vim_var_tv(idx);
   2075  tv_clear(tv);
   2076  tv->v_type = VAR_SPECIAL;
   2077  tv->vval.v_special = val;
   2078 }
   2079 
   2080 /// Set v:char to character "c".
   2081 void set_vim_var_char(int c)
   2082 {
   2083  char buf[MB_MAXCHAR + 1];
   2084 
   2085  buf[utf_char2bytes(c, buf)] = NUL;
   2086  set_vim_var_string(VV_CHAR, buf, -1);
   2087 }
   2088 
   2089 /// Set string v: variable to the given string
   2090 ///
   2091 /// @param[in]  idx  Index of variable to set.
   2092 /// @param[in]  val  Value to set to. Will be copied.
   2093 /// @param[in]  len  Length of that value or -1 in which case strlen() will be
   2094 ///                  used.
   2095 void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len)
   2096 {
   2097  typval_T *tv = get_vim_var_tv(idx);
   2098  tv_clear(tv);
   2099  tv->v_type = VAR_STRING;
   2100  if (val == NULL) {
   2101    tv->vval.v_string = NULL;
   2102  } else if (len == -1) {
   2103    tv->vval.v_string = xstrdup(val);
   2104  } else {
   2105    tv->vval.v_string = xstrndup(val, (size_t)len);
   2106  }
   2107 }
   2108 
   2109 /// Set list v: variable to the given list
   2110 ///
   2111 /// @param[in]  idx  Index of variable to set.
   2112 /// @param[in,out]  val  Value to set to. Reference count will be incremented.
   2113 void set_vim_var_list(const VimVarIndex idx, list_T *const val)
   2114 {
   2115  typval_T *tv = get_vim_var_tv(idx);
   2116  tv_clear(tv);
   2117  tv->v_type = VAR_LIST;
   2118  tv->vval.v_list = val;
   2119  if (val != NULL) {
   2120    tv_list_ref(val);
   2121  }
   2122 }
   2123 
   2124 /// Set Dictionary v: variable to the given dictionary
   2125 ///
   2126 /// @param[in]  idx  Index of variable to set.
   2127 /// @param[in,out]  val  Value to set to. Reference count will be incremented.
   2128 ///                      Also keys of the dictionary will be made read-only.
   2129 void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
   2130 {
   2131  typval_T *tv = get_vim_var_tv(idx);
   2132  tv_clear(tv);
   2133  tv->v_type = VAR_DICT;
   2134  tv->vval.v_dict = val;
   2135  if (val == NULL) {
   2136    return;
   2137  }
   2138 
   2139  val->dv_refcount++;
   2140  // Set readonly
   2141  tv_dict_set_keys_readonly(val);
   2142 }
   2143 
   2144 /// Set partial v: variable to the given value
   2145 /// Note that this does not set the type, use set_vim_var_type() for that.
   2146 ///
   2147 /// @param[in]  idx  Index of variable to set.
   2148 /// @param[in]  val  Value to set to.
   2149 void set_vim_var_partial(const VimVarIndex idx, partial_T *val)
   2150 {
   2151  typval_T *tv = get_vim_var_tv(idx);
   2152  tv->vval.v_partial = val;
   2153 }
   2154 
   2155 /// Set v:register if needed.
   2156 void set_reg_var(int c)
   2157 {
   2158  char regname;
   2159 
   2160  if (c == 0 || c == ' ') {
   2161    regname = '"';
   2162  } else {
   2163    regname = (char)c;
   2164  }
   2165  // Avoid free/alloc when the value is already right.
   2166  typval_T *tv = get_vim_var_tv(VV_REG);
   2167  if (tv->vval.v_string == NULL || tv->vval.v_string[0] != c) {
   2168    set_vim_var_string(VV_REG, &regname, 1);
   2169  }
   2170 }
   2171 
   2172 /// Get or set v:exception.  If "oldval" == NULL, return the current value.
   2173 /// Otherwise, restore the value to "oldval" and return NULL.
   2174 /// Must always be called in pairs to save and restore v:exception!  Does not
   2175 /// take care of memory allocations.
   2176 char *v_exception(char *oldval)
   2177 {
   2178  typval_T *tv = get_vim_var_tv(VV_EXCEPTION);
   2179  if (oldval == NULL) {
   2180    return tv->vval.v_string;
   2181  }
   2182 
   2183  tv->vval.v_string = oldval;
   2184  return NULL;
   2185 }
   2186 
   2187 /// Set v:cmdarg.
   2188 /// If "eap" != NULL, use "eap" to generate the value and return the old value.
   2189 /// If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
   2190 /// Must always be called in pairs!
   2191 char *set_cmdarg(exarg_T *eap, char *oldarg)
   2192 {
   2193  typval_T *tv = get_vim_var_tv(VV_CMDARG);
   2194  char *oldval = tv->vval.v_string;
   2195  if (eap == NULL) {
   2196    goto error;
   2197  }
   2198 
   2199  size_t len = 0;
   2200  if (eap->force_bin == FORCE_BIN) {
   2201    len += 6;  // " ++bin"
   2202  } else if (eap->force_bin == FORCE_NOBIN) {
   2203    len += 8;  // " ++nobin"
   2204  }
   2205 
   2206  if (eap->read_edit) {
   2207    len += 7;  // " ++edit"
   2208  }
   2209 
   2210  if (eap->force_ff != 0) {
   2211    len += 10;  // " ++ff=unix"
   2212  }
   2213  if (eap->force_enc != 0) {
   2214    len += strlen(eap->cmd + eap->force_enc) + 7;
   2215  }
   2216  if (eap->bad_char != 0) {
   2217    len += 7 + 4;  // " ++bad=" + "keep" or "drop"
   2218  }
   2219  if (eap->mkdir_p != 0) {
   2220    len += 4;  // " ++p"
   2221  }
   2222 
   2223  const size_t newval_len = len + 1;
   2224  char *newval = xmalloc(newval_len);
   2225  size_t xlen = 0;
   2226  int rc = 0;
   2227 
   2228  if (eap->force_bin == FORCE_BIN) {
   2229    rc = snprintf(newval, newval_len, " ++bin");
   2230  } else if (eap->force_bin == FORCE_NOBIN) {
   2231    rc = snprintf(newval, newval_len, " ++nobin");
   2232  } else {
   2233    *newval = NUL;
   2234  }
   2235  if (rc < 0) {
   2236    goto error;
   2237  }
   2238  xlen += (size_t)rc;
   2239 
   2240  if (eap->read_edit) {
   2241    rc = snprintf(newval + xlen, newval_len - xlen, " ++edit");
   2242    if (rc < 0) {
   2243      goto error;
   2244    }
   2245    xlen += (size_t)rc;
   2246  }
   2247 
   2248  if (eap->force_ff != 0) {
   2249    rc = snprintf(newval + xlen,
   2250                  newval_len - xlen,
   2251                  " ++ff=%s",
   2252                  eap->force_ff == 'u' ? "unix"
   2253                                       : eap->force_ff == 'd' ? "dos" : "mac");
   2254    if (rc < 0) {
   2255      goto error;
   2256    }
   2257    xlen += (size_t)rc;
   2258  }
   2259  if (eap->force_enc != 0) {
   2260    rc = snprintf(newval + (xlen), newval_len - xlen, " ++enc=%s", eap->cmd + eap->force_enc);
   2261    if (rc < 0) {
   2262      goto error;
   2263    }
   2264    xlen += (size_t)rc;
   2265  }
   2266 
   2267  if (eap->bad_char == BAD_KEEP) {
   2268    rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=keep");
   2269    if (rc < 0) {
   2270      goto error;
   2271    }
   2272    xlen += (size_t)rc;
   2273  } else if (eap->bad_char == BAD_DROP) {
   2274    rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=drop");
   2275    if (rc < 0) {
   2276      goto error;
   2277    }
   2278    xlen += (size_t)rc;
   2279  } else if (eap->bad_char != 0) {
   2280    rc = snprintf(newval + xlen, newval_len - xlen, " ++bad=%c", eap->bad_char);
   2281    if (rc < 0) {
   2282      goto error;
   2283    }
   2284    xlen += (size_t)rc;
   2285  }
   2286 
   2287  if (eap->mkdir_p != 0) {
   2288    rc = snprintf(newval + xlen, newval_len - xlen, " ++p");
   2289    if (rc < 0) {
   2290      goto error;
   2291    }
   2292    xlen += (size_t)rc;
   2293  }
   2294  assert(xlen <= newval_len);
   2295 
   2296  tv->vval.v_string = newval;
   2297  return oldval;
   2298 
   2299 error:
   2300  xfree(oldval);
   2301  tv->vval.v_string = oldarg;
   2302  return NULL;
   2303 }
   2304 
   2305 /// Get or set v:throwpoint.  If "oldval" == NULL, return the current value.
   2306 /// Otherwise, restore the value to "oldval" and return NULL.
   2307 /// Must always be called in pairs to save and restore v:throwpoint!  Does not
   2308 /// take care of memory allocations.
   2309 char *v_throwpoint(char *oldval)
   2310 {
   2311  typval_T *tv = get_vim_var_tv(VV_THROWPOINT);
   2312  if (oldval == NULL) {
   2313    return tv->vval.v_string;
   2314  }
   2315 
   2316  tv->vval.v_string = oldval;
   2317  return NULL;
   2318 }
   2319 
   2320 /// Set v:count to "count" and v:count1 to "count1".
   2321 ///
   2322 /// @param set_prevcount  if true, first set v:prevcount from v:count.
   2323 void set_vcount(int64_t count, int64_t count1, bool set_prevcount)
   2324 {
   2325  if (set_prevcount) {
   2326    get_vim_var_tv(VV_PREVCOUNT)->vval.v_number = get_vim_var_nr(VV_COUNT);
   2327  }
   2328  get_vim_var_tv(VV_COUNT)->vval.v_number = count;
   2329  get_vim_var_tv(VV_COUNT1)->vval.v_number = count1;
   2330 }
   2331 
   2332 /// Get the value of internal variable "name".
   2333 /// Return OK or FAIL.  If OK is returned "rettv" must be cleared.
   2334 ///
   2335 /// @param len  length of "name"
   2336 /// @param rettv  NULL when only checking existence
   2337 /// @param dip  non-NULL when typval's dict item is needed
   2338 /// @param verbose  may give error message
   2339 /// @param no_autoload  do not use script autoloading
   2340 int eval_variable(const char *name, int len, typval_T *rettv, dictitem_T **dip, bool verbose,
   2341                  bool no_autoload)
   2342 {
   2343  int ret = OK;
   2344  typval_T *tv = NULL;
   2345  dictitem_T *v;
   2346 
   2347  v = find_var(name, (size_t)len, NULL, no_autoload);
   2348  if (v != NULL) {
   2349    tv = &v->di_tv;
   2350    if (dip != NULL) {
   2351      *dip = v;
   2352    }
   2353  }
   2354 
   2355  if (tv == NULL) {
   2356    if (rettv != NULL && verbose) {
   2357      semsg(_("E121: Undefined variable: %.*s"), len, name);
   2358    }
   2359    ret = FAIL;
   2360  } else if (rettv != NULL) {
   2361    tv_copy(tv, rettv);
   2362  }
   2363 
   2364  return ret;
   2365 }
   2366 
   2367 /// Check if variable "name[len]" is a local variable or an argument.
   2368 /// If so, "*eval_lavars_used" is set to true.
   2369 void check_vars(const char *name, size_t len)
   2370 {
   2371  if (eval_lavars_used == NULL) {
   2372    return;
   2373  }
   2374 
   2375  const char *varname;
   2376  hashtab_T *ht = find_var_ht(name, len, &varname);
   2377 
   2378  if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht()) {
   2379    if (find_var(name, len, NULL, true) != NULL) {
   2380      *eval_lavars_used = true;
   2381    }
   2382  }
   2383 }
   2384 
   2385 /// Find variable "name" in the list of variables.
   2386 /// Careful: "a:0" variables don't have a name.
   2387 /// When "htp" is not NULL we are writing to the variable, set "htp" to the
   2388 /// hashtab_T used.
   2389 ///
   2390 /// @return  a pointer to it if found, NULL if not found.
   2391 dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **htp,
   2392                     int no_autoload)
   2393 {
   2394  const char *varname;
   2395  hashtab_T *const ht = find_var_ht(name, name_len, &varname);
   2396  if (htp != NULL) {
   2397    *htp = ht;
   2398  }
   2399  if (ht == NULL) {
   2400    return NULL;
   2401  }
   2402  dictitem_T *const ret = find_var_in_ht(ht, *name,
   2403                                         varname,
   2404                                         name_len - (size_t)(varname - name),
   2405                                         no_autoload || htp != NULL);
   2406  if (ret != NULL) {
   2407    return ret;
   2408  }
   2409 
   2410  // Search in parent scope for lambda
   2411  return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL);
   2412 }
   2413 
   2414 /// Find variable in hashtab.
   2415 /// When "varname" is empty returns curwin/curtab/etc vars dictionary.
   2416 ///
   2417 /// @param[in]  ht  Hashtab to find variable in.
   2418 /// @param[in]  htname  Hashtab name (first character).
   2419 /// @param[in]  varname  Variable name.
   2420 /// @param[in]  varname_len  Variable name length.
   2421 /// @param[in]  no_autoload  If true then autoload scripts will not be sourced
   2422 ///                          if autoload variable was not found.
   2423 ///
   2424 /// @return pointer to the dictionary item with the found variable or NULL if it
   2425 ///         was not found.
   2426 dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const varname,
   2427                           const size_t varname_len, int no_autoload)
   2428  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
   2429 {
   2430  if (varname_len == 0) {
   2431    // Must be something like "s:", otherwise "ht" would be NULL.
   2432    switch (htname) {
   2433    case 's':
   2434      return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
   2435    case 'g':
   2436      return (dictitem_T *)&globvars_var;
   2437    case 'v':
   2438      return (dictitem_T *)&vimvars_var;
   2439    case 'b':
   2440      return (dictitem_T *)&curbuf->b_bufvar;
   2441    case 'w':
   2442      return (dictitem_T *)&curwin->w_winvar;
   2443    case 't':
   2444      return (dictitem_T *)&curtab->tp_winvar;
   2445    case 'l':
   2446      return get_funccal_local_var();
   2447    case 'a':
   2448      return get_funccal_args_var();
   2449    }
   2450    return NULL;
   2451  }
   2452 
   2453  hashitem_T *hi = hash_find_len(ht, varname, varname_len);
   2454  if (HASHITEM_EMPTY(hi)) {
   2455    // For global variables we may try auto-loading the script.  If it
   2456    // worked find the variable again.  Don't auto-load a script if it was
   2457    // loaded already, otherwise it would be loaded every time when
   2458    // checking if a function name is a Funcref variable.
   2459    if (ht == get_globvar_ht() && !no_autoload) {
   2460      // Note: script_autoload() may make "hi" invalid. It must either
   2461      // be obtained again or not used.
   2462      if (!script_autoload(varname, varname_len, false) || aborting()) {
   2463        return NULL;
   2464      }
   2465      hi = hash_find_len(ht, varname, varname_len);
   2466    }
   2467    if (HASHITEM_EMPTY(hi)) {
   2468      return NULL;
   2469    }
   2470  }
   2471  return TV_DICT_HI2DI(hi);
   2472 }
   2473 
   2474 /// Finds the dict (g:, l:, s:, …) and hashtable used for a variable.
   2475 ///
   2476 /// Assigns SID if s: scope is accessed from Lua or anonymous Vimscript. #15994
   2477 ///
   2478 /// @param[in]  name  Variable name, possibly with scope prefix.
   2479 /// @param[in]  name_len  Variable name length.
   2480 /// @param[out]  varname  Will be set to the start of the name without scope
   2481 ///                       prefix.
   2482 /// @param[out]  d  Scope dictionary.
   2483 ///
   2484 /// @return Scope hashtab, NULL if name is not valid.
   2485 static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
   2486                                   dict_T **d)
   2487 {
   2488  *d = NULL;
   2489 
   2490  if (name_len == 0) {
   2491    return NULL;
   2492  }
   2493  if (name_len == 1 || name[1] != ':') {
   2494    // name has implicit scope
   2495    if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
   2496      // The name must not start with a colon or #.
   2497      return NULL;
   2498    }
   2499    *varname = name;
   2500 
   2501    // "version" is "v:version" in all scopes
   2502    hashitem_T *hi = hash_find_len(&compat_hashtab, name, name_len);
   2503    if (!HASHITEM_EMPTY(hi)) {
   2504      return &compat_hashtab;
   2505    }
   2506 
   2507    *d = get_funccal_local_dict();
   2508    if (*d != NULL) {  // local variable
   2509      goto end;
   2510    }
   2511 
   2512    *d = get_globvar_dict();  // global variable
   2513    goto end;
   2514  }
   2515 
   2516  *varname = name + 2;
   2517  if (*name == 'g') {  // global variable
   2518    *d = get_globvar_dict();
   2519  } else if (name_len > 2
   2520             && (memchr(name + 2, ':', name_len - 2) != NULL
   2521                 || memchr(name + 2, AUTOLOAD_CHAR, name_len - 2) != NULL)) {
   2522    // There must be no ':' or '#' in the rest of the name if g: was not used
   2523    return NULL;
   2524  }
   2525 
   2526  if (*name == 'b') {  // buffer variable
   2527    *d = curbuf->b_vars;
   2528  } else if (*name == 'w') {  // window variable
   2529    *d = curwin->w_vars;
   2530  } else if (*name == 't') {  // tab page variable
   2531    *d = curtab->tp_vars;
   2532  } else if (*name == 'v') {  // v: variable
   2533    *d = get_vimvar_dict();
   2534  } else if (*name == 'a') {  // a: function argument
   2535    *d = get_funccal_args_dict();
   2536  } else if (*name == 'l') {  // l: local variable
   2537    *d = get_funccal_local_dict();
   2538  } else if (*name == 's'  // script variable
   2539             && (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR
   2540                 || current_sctx.sc_sid == SID_LUA)
   2541             && current_sctx.sc_sid <= script_items.ga_len) {
   2542    // For anonymous scripts without a script item, create one now so script vars can be used
   2543    // Try to resolve lua filename & linenr so it can be shown in last-set messages.
   2544    nlua_set_sctx(&current_sctx);
   2545    if (current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) {
   2546      // Create SID if s: scope is accessed from Lua or anon Vimscript. #15994
   2547      new_script_item(NULL, &current_sctx.sc_sid);
   2548    }
   2549    *d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
   2550  }
   2551 
   2552 end:
   2553  return *d ? &(*d)->dv_hashtab : NULL;
   2554 }
   2555 
   2556 /// Find the hashtable used for a variable
   2557 ///
   2558 /// @param[in]  name  Variable name, possibly with scope prefix.
   2559 /// @param[in]  name_len  Variable name length.
   2560 /// @param[out]  varname  Will be set to the start of the name without scope
   2561 ///                       prefix.
   2562 ///
   2563 /// @return Scope hashtab, NULL if name is not valid.
   2564 hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **varname)
   2565 {
   2566  dict_T *d;
   2567  return find_var_ht_dict(name, name_len, varname, &d);
   2568 }
   2569 
   2570 /// @return  the string value of a (global/local) variable or
   2571 ///          NULL when it doesn't exist.
   2572 ///
   2573 /// @see  tv_get_string() for how long the pointer remains valid.
   2574 char *get_var_value(const char *const name)
   2575 {
   2576  dictitem_T *v;
   2577 
   2578  v = find_var(name, strlen(name), NULL, false);
   2579  if (v == NULL) {
   2580    return NULL;
   2581  }
   2582  return (char *)tv_get_string(&v->di_tv);
   2583 }
   2584 
   2585 /// Allocate a new hashtab for a sourced script.  It will be used while
   2586 /// sourcing this script and when executing functions defined in the script.
   2587 void new_script_vars(scid_T id)
   2588 {
   2589  scriptvar_T *sv = xcalloc(1, sizeof(scriptvar_T));
   2590  init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
   2591  SCRIPT_ITEM(id)->sn_vars = sv;
   2592 }
   2593 
   2594 /// Initialize dictionary "dict" as a scope and set variable "dict_var" to
   2595 /// point to it.
   2596 void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, ScopeType scope)
   2597 {
   2598  hash_init(&dict->dv_hashtab);
   2599  dict->dv_lock = VAR_UNLOCKED;
   2600  dict->dv_scope = scope;
   2601  dict->dv_refcount = DO_NOT_FREE_CNT;
   2602  dict->dv_copyID = 0;
   2603  dict_var->di_tv.vval.v_dict = dict;
   2604  dict_var->di_tv.v_type = VAR_DICT;
   2605  dict_var->di_tv.v_lock = VAR_FIXED;
   2606  dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
   2607  dict_var->di_key[0] = NUL;
   2608  QUEUE_INIT(&dict->watchers);
   2609 }
   2610 
   2611 /// Unreference a dictionary initialized by init_var_dict().
   2612 void unref_var_dict(dict_T *dict)
   2613 {
   2614  // Now the dict needs to be freed if no one else is using it, go back to
   2615  // normal reference counting.
   2616  dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
   2617  tv_dict_unref(dict);
   2618 }
   2619 
   2620 /// Clean up a list of internal variables.
   2621 /// Frees all allocated variables and the value they contain.
   2622 /// Clears hashtab "ht", does not free it.
   2623 void vars_clear(hashtab_T *ht)
   2624 {
   2625  vars_clear_ext(ht, true);
   2626 }
   2627 
   2628 /// Like vars_clear(), but only free the value if "free_val" is true.
   2629 void vars_clear_ext(hashtab_T *ht, bool free_val)
   2630 {
   2631  int todo;
   2632  hashitem_T *hi;
   2633  dictitem_T *v;
   2634 
   2635  hash_lock(ht);
   2636  todo = (int)ht->ht_used;
   2637  for (hi = ht->ht_array; todo > 0; hi++) {
   2638    if (!HASHITEM_EMPTY(hi)) {
   2639      todo--;
   2640 
   2641      // Free the variable.  Don't remove it from the hashtab,
   2642      // ht_array might change then.  hash_clear() takes care of it
   2643      // later.
   2644      v = TV_DICT_HI2DI(hi);
   2645      if (free_val) {
   2646        tv_clear(&v->di_tv);
   2647      }
   2648      if (v->di_flags & DI_FLAGS_ALLOC) {
   2649        xfree(v);
   2650      }
   2651    }
   2652  }
   2653  hash_clear(ht);
   2654  hash_init(ht);
   2655 }
   2656 
   2657 /// Delete a variable from hashtab "ht" at item "hi".
   2658 /// Clear the variable value and free the dictitem.
   2659 static void delete_var(hashtab_T *ht, hashitem_T *hi)
   2660 {
   2661  dictitem_T *di = TV_DICT_HI2DI(hi);
   2662 
   2663  hash_remove(ht, hi);
   2664  tv_clear(&di->di_tv);
   2665  xfree(di);
   2666 }
   2667 
   2668 /// List the value of one internal variable.
   2669 static void list_one_var(dictitem_T *v, const char *prefix, int *first)
   2670 {
   2671  char *const s = encode_tv2echo(&v->di_tv, NULL);
   2672  list_one_var_a(prefix, v->di_key, (ptrdiff_t)strlen(v->di_key),
   2673                 v->di_tv.v_type, (s == NULL ? "" : s), first);
   2674  xfree(s);
   2675 }
   2676 
   2677 /// @param[in]  name_len  Length of the name. May be -1, in this case strlen()
   2678 ///                       will be used.
   2679 /// @param[in,out]  first  When true clear rest of screen and set to false.
   2680 static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t name_len,
   2681                           const VarType type, const char *string, int *first)
   2682 {
   2683  if (*first) {
   2684    msg_ext_set_kind("list_cmd");
   2685    msg_start();
   2686  } else {
   2687    msg_putchar('\n');
   2688  }
   2689  // don't use msg() to avoid overwriting "v:statusmsg"
   2690  if (*prefix != NUL) {
   2691    msg_puts(prefix);
   2692  }
   2693  if (name != NULL) {  // "a:" vars don't have a name stored
   2694    msg_puts_len(name, name_len, 0, false);
   2695  }
   2696  msg_putchar(' ');
   2697  msg_advance(22);
   2698  if (type == VAR_NUMBER) {
   2699    msg_putchar('#');
   2700  } else if (type == VAR_FUNC || type == VAR_PARTIAL) {
   2701    msg_putchar('*');
   2702  } else if (type == VAR_LIST) {
   2703    msg_putchar('[');
   2704    if (*string == '[') {
   2705      string++;
   2706    }
   2707  } else if (type == VAR_DICT) {
   2708    msg_putchar('{');
   2709    if (*string == '{') {
   2710      string++;
   2711    }
   2712  } else {
   2713    msg_putchar(' ');
   2714  }
   2715 
   2716  msg_outtrans(string, 0, false);
   2717 
   2718  if (type == VAR_FUNC || type == VAR_PARTIAL) {
   2719    msg_puts("()");
   2720  }
   2721  if (*first) {
   2722    msg_clr_eos();
   2723    *first = false;
   2724  }
   2725 }
   2726 
   2727 /// Additional handling for setting a v: variable.
   2728 ///
   2729 /// @return  true if the variable should be set normally,
   2730 ///          false if nothing else needs to be done.
   2731 bool before_set_vvar(const char *const varname, dictitem_T *const di, typval_T *const tv,
   2732                     const bool copy, const bool watched, bool *const type_error)
   2733 {
   2734  if (di->di_tv.v_type == VAR_STRING) {
   2735    typval_T oldtv = TV_INITIAL_VALUE;
   2736    if (watched) {
   2737      tv_copy(&di->di_tv, &oldtv);
   2738    }
   2739    XFREE_CLEAR(di->di_tv.vval.v_string);
   2740    if (copy || tv->v_type != VAR_STRING) {
   2741      const char *const val = tv_get_string(tv);
   2742      // Careful: when assigning to v:errmsg and tv_get_string()
   2743      // causes an error message the variable will already be set.
   2744      if (di->di_tv.vval.v_string == NULL) {
   2745        di->di_tv.vval.v_string = xstrdup(val);
   2746      }
   2747    } else {
   2748      // Take over the string to avoid an extra alloc/free.
   2749      di->di_tv.vval.v_string = tv->vval.v_string;
   2750      tv->vval.v_string = NULL;
   2751    }
   2752    // Notify watchers
   2753    if (watched) {
   2754      tv_dict_watcher_notify(&vimvardict, varname, &di->di_tv, &oldtv);
   2755      tv_clear(&oldtv);
   2756    }
   2757    return false;
   2758  } else if (di->di_tv.v_type == VAR_NUMBER) {
   2759    typval_T oldtv = TV_INITIAL_VALUE;
   2760    if (watched) {
   2761      tv_copy(&di->di_tv, &oldtv);
   2762    }
   2763    di->di_tv.vval.v_number = tv_get_number(tv);
   2764    if (strcmp(varname, "searchforward") == 0) {
   2765      set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
   2766    } else if (strcmp(varname, "hlsearch") == 0) {
   2767      no_hlsearch = !di->di_tv.vval.v_number;
   2768      redraw_all_later(UPD_SOME_VALID);
   2769    }
   2770    // Notify watchers
   2771    if (watched) {
   2772      tv_dict_watcher_notify(&vimvardict, varname, &di->di_tv, &oldtv);
   2773      tv_clear(&oldtv);
   2774    }
   2775    return false;
   2776  } else if (di->di_tv.v_type != tv->v_type) {
   2777    *type_error = true;
   2778    return false;
   2779  }
   2780  return true;
   2781 }
   2782 
   2783 /// Set variable to the given value
   2784 ///
   2785 /// If the variable already exists, the value is updated. Otherwise the variable
   2786 /// is created.
   2787 ///
   2788 /// @param[in]  name  Variable name to set.
   2789 /// @param[in]  name_len  Length of the variable name.
   2790 /// @param  tv  Variable value.
   2791 /// @param[in]  copy  True if value in tv is to be copied.
   2792 void set_var(const char *name, const size_t name_len, typval_T *const tv, const bool copy)
   2793  FUNC_ATTR_NONNULL_ALL
   2794 {
   2795  set_var_const(name, name_len, tv, copy, false);
   2796 }
   2797 
   2798 /// Set variable to the given value
   2799 ///
   2800 /// If the variable already exists, the value is updated. Otherwise the variable
   2801 /// is created.
   2802 ///
   2803 /// @param[in]  name  Variable name to set.
   2804 /// @param[in]  name_len  Length of the variable name.
   2805 /// @param  tv  Variable value.
   2806 /// @param[in]  copy  True if value in tv is to be copied.
   2807 /// @param[in]  is_const  True if value in tv is to be locked.
   2808 void set_var_const(const char *name, const size_t name_len, typval_T *const tv, const bool copy,
   2809                   const bool is_const)
   2810  FUNC_ATTR_NONNULL_ALL
   2811 {
   2812  const char *varname;
   2813  dict_T *dict;
   2814  hashtab_T *ht = find_var_ht_dict(name, name_len, &varname, &dict);
   2815  const bool watched = tv_dict_is_watched(dict);
   2816 
   2817  if (ht == NULL || *varname == NUL) {
   2818    semsg(_(e_illvar), name);
   2819    return;
   2820  }
   2821  const size_t varname_len = name_len - (size_t)(varname - name);
   2822  dictitem_T *di = find_var_in_ht(ht, 0, varname, varname_len, true);
   2823 
   2824  // Search in parent scope which is possible to reference from lambda
   2825  if (di == NULL) {
   2826    di = find_var_in_scoped_ht(name, name_len, true);
   2827  }
   2828 
   2829  if (tv_is_func(*tv) && var_wrong_func_name(name, di == NULL)) {
   2830    return;
   2831  }
   2832 
   2833  typval_T oldtv = TV_INITIAL_VALUE;
   2834  if (di != NULL) {
   2835    if (is_const) {
   2836      emsg(_(e_cannot_mod));
   2837      return;
   2838    }
   2839 
   2840    // Check in this order for backwards compatibility:
   2841    // - Whether the variable is read-only
   2842    // - Whether the variable value is locked
   2843    // - Whether the variable is locked
   2844    if (var_check_ro(di->di_flags, name, name_len)
   2845        || value_check_lock(di->di_tv.v_lock, name, name_len)
   2846        || var_check_lock(di->di_flags, name, name_len)) {
   2847      return;
   2848    }
   2849 
   2850    // existing variable, need to clear the value
   2851 
   2852    // Handle setting internal v: variables separately where needed to
   2853    // prevent changing the type.
   2854    bool type_error = false;
   2855    if (ht == &vimvarht
   2856        && !before_set_vvar(varname, di, tv, copy, watched, &type_error)) {
   2857      if (type_error) {
   2858        semsg(_(e_setting_v_str_to_value_with_wrong_type), varname);
   2859      }
   2860      return;
   2861    }
   2862 
   2863    if (watched) {
   2864      tv_copy(&di->di_tv, &oldtv);
   2865    }
   2866    tv_clear(&di->di_tv);
   2867  } else {  // Add a new variable.
   2868    // Can't add "v:" or "a:" variable.
   2869    if (ht == &vimvarht || ht == get_funccal_args_ht()) {
   2870      semsg(_(e_illvar), name);
   2871      return;
   2872    }
   2873 
   2874    // Make sure the variable name is valid.
   2875    if (!valid_varname(varname)) {
   2876      return;
   2877    }
   2878 
   2879    // Make sure dict is valid
   2880    assert(dict != NULL);
   2881 
   2882    di = xmalloc(offsetof(dictitem_T, di_key) + varname_len + 1);
   2883    memcpy(di->di_key, varname, varname_len + 1);
   2884    if (hash_add(ht, di->di_key) == FAIL) {
   2885      xfree(di);
   2886      return;
   2887    }
   2888    di->di_flags = DI_FLAGS_ALLOC;
   2889    if (is_const) {
   2890      di->di_flags |= DI_FLAGS_LOCK;
   2891    }
   2892  }
   2893 
   2894  if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
   2895    tv_copy(tv, &di->di_tv);
   2896  } else {
   2897    di->di_tv = *tv;
   2898    di->di_tv.v_lock = VAR_UNLOCKED;
   2899    tv_init(tv);
   2900  }
   2901 
   2902  if (watched) {
   2903    tv_dict_watcher_notify(dict, di->di_key, &di->di_tv, &oldtv);
   2904    tv_clear(&oldtv);
   2905  }
   2906 
   2907  if (is_const) {
   2908    // Like :lockvar! name: lock the value and what it contains, but only
   2909    // if the reference count is up to one.  That locks only literal
   2910    // values.
   2911    tv_item_lock(&di->di_tv, DICT_MAXNEST, true, true);
   2912  }
   2913 }
   2914 
   2915 /// Check whether variable is read-only (DI_FLAGS_RO, DI_FLAGS_RO_SBX)
   2916 ///
   2917 /// Also gives an error message.
   2918 ///
   2919 /// @param[in]  flags  di_flags attribute value.
   2920 /// @param[in]  name  Variable name, for use in error message.
   2921 /// @param[in]  name_len  Variable name length. Use #TV_TRANSLATE to translate
   2922 ///                       variable name and compute the length. Use #TV_CSTRING
   2923 ///                       to compute the length with strlen() without
   2924 ///                       translating.
   2925 ///
   2926 ///                       Both #TV_… values are used for optimization purposes:
   2927 ///                       variable name with its length is needed only in case
   2928 ///                       of error, when no error occurs computing them is
   2929 ///                       a waste of CPU resources. This especially applies to
   2930 ///                       gettext.
   2931 ///
   2932 /// @return True if variable is read-only: either always or in sandbox when
   2933 ///         sandbox is enabled, false otherwise.
   2934 bool var_check_ro(const int flags, const char *name, size_t name_len)
   2935  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
   2936 {
   2937  const char *error_message = NULL;
   2938  if (flags & DI_FLAGS_RO) {
   2939    error_message = N_(e_cannot_change_readonly_variable_str);
   2940  } else if ((flags & DI_FLAGS_RO_SBX) && sandbox) {
   2941    error_message = N_(e_cannot_set_variable_in_sandbox_str);
   2942  }
   2943 
   2944  if (error_message == NULL) {
   2945    return false;
   2946  }
   2947  if (name_len == TV_TRANSLATE) {
   2948    name = _(name);
   2949    name_len = strlen(name);
   2950  } else if (name_len == TV_CSTRING) {
   2951    name_len = strlen(name);
   2952  }
   2953 
   2954  semsg(_(error_message), (int)name_len, name);
   2955 
   2956  return true;
   2957 }
   2958 
   2959 /// Return true if di_flags "flags" indicates variable "name" is locked.
   2960 /// Also give an error message.
   2961 bool var_check_lock(const int flags, const char *name, size_t name_len)
   2962 {
   2963  if (!(flags & DI_FLAGS_LOCK)) {
   2964    return false;
   2965  }
   2966 
   2967  if (name_len == TV_TRANSLATE) {
   2968    name = _(name);
   2969    name_len = strlen(name);
   2970  } else if (name_len == TV_CSTRING) {
   2971    name_len = strlen(name);
   2972  }
   2973 
   2974  semsg(_("E1122: Variable is locked: %.*s"), (int)name_len, name);
   2975 
   2976  return true;
   2977 }
   2978 
   2979 /// Check whether variable is fixed (DI_FLAGS_FIX)
   2980 ///
   2981 /// Also gives an error message.
   2982 ///
   2983 /// @param[in]  flags  di_flags attribute value.
   2984 /// @param[in]  name  Variable name, for use in error message.
   2985 /// @param[in]  name_len  Variable name length. Use #TV_TRANSLATE to translate
   2986 ///                       variable name and compute the length. Use #TV_CSTRING
   2987 ///                       to compute the length with strlen() without
   2988 ///                       translating.
   2989 ///
   2990 ///                       Both #TV_… values are used for optimization purposes:
   2991 ///                       variable name with its length is needed only in case
   2992 ///                       of error, when no error occurs computing them is
   2993 ///                       a waste of CPU resources. This especially applies to
   2994 ///                       gettext.
   2995 ///
   2996 /// @return True if variable is fixed, false otherwise.
   2997 bool var_check_fixed(const int flags, const char *name, size_t name_len)
   2998  FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
   2999 {
   3000  if (flags & DI_FLAGS_FIX) {
   3001    if (name_len == TV_TRANSLATE) {
   3002      name = _(name);
   3003      name_len = strlen(name);
   3004    } else if (name_len == TV_CSTRING) {
   3005      name_len = strlen(name);
   3006    }
   3007    semsg(_(e_cannot_delete_variable_str), (int)name_len, name);
   3008    return true;
   3009  }
   3010  return false;
   3011 }
   3012 
   3013 /// Check if name is a valid name to assign funcref to
   3014 ///
   3015 /// @param[in]  name  Possible function/funcref name.
   3016 /// @param[in]  new_var  True if it is a name for a variable.
   3017 ///
   3018 /// @return false in case of success, true in case of failure. Also gives an
   3019 ///         error message if appropriate.
   3020 bool var_wrong_func_name(const char *const name, const bool new_var)
   3021  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
   3022 {
   3023  // Allow for w: b: s: and t:.
   3024  // Allow autoload variable.
   3025  if (!(vim_strchr("wbst", (uint8_t)name[0]) != NULL && name[1] == ':')
   3026      && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2] : name[0])
   3027      && vim_strchr(name, '#') == NULL) {
   3028    semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
   3029    return true;
   3030  }
   3031  // Don't allow hiding a function.  When "v" is not NULL we might be
   3032  // assigning another function to the same var, the type is checked
   3033  // below.
   3034  if (new_var && function_exists(name, false)) {
   3035    semsg(_("E705: Variable name conflicts with existing function: %s"), name);
   3036    return true;
   3037  }
   3038  return false;
   3039 }
   3040 
   3041 /// Check if a variable name is valid
   3042 ///
   3043 /// @param[in]  varname  Variable name to check.
   3044 ///
   3045 /// @return false when variable name is not valid, true when it is. Also gives
   3046 ///         an error message if appropriate.
   3047 bool valid_varname(const char *varname)
   3048  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
   3049 {
   3050  for (const char *p = varname; *p != NUL; p++) {
   3051    if (!eval_isnamec1((int)(uint8_t)(*p))
   3052        && (p == varname || !ascii_isdigit(*p))
   3053        && *p != AUTOLOAD_CHAR) {
   3054      semsg(_(e_illvar), varname);
   3055      return false;
   3056    }
   3057  }
   3058  return true;
   3059 }
   3060 
   3061 /// Implements the logic to retrieve local variable and option values.
   3062 /// Used by "getwinvar()" "gettabvar()" "gettabwinvar()" "getbufvar()".
   3063 ///
   3064 /// @param deftv   default value if not found
   3065 /// @param htname  't'ab, 'w'indow or 'b'uffer local
   3066 /// @param tp      can be NULL
   3067 /// @param buf     ignored if htname is not 'b'
   3068 static void get_var_from(const char *varname, typval_T *rettv, typval_T *deftv, int htname,
   3069                         tabpage_T *tp, win_T *win, buf_T *buf)
   3070 {
   3071  bool done = false;
   3072  const bool do_change_curbuf = buf != NULL && htname == 'b';
   3073 
   3074  emsg_off++;
   3075 
   3076  rettv->v_type = VAR_STRING;
   3077  rettv->vval.v_string = NULL;
   3078 
   3079  if (varname != NULL && tp != NULL && win != NULL && (htname != 'b' || buf != NULL)) {
   3080    // Set curwin to be our win, temporarily.  Also set the tabpage,
   3081    // otherwise the window is not valid. Only do this when needed,
   3082    // autocommands get blocked.
   3083    // If we have a buffer reference avoid the switching, we're saving and
   3084    // restoring curbuf directly.
   3085    const bool need_switch_win = !(tp == curtab && win == curwin) && !do_change_curbuf;
   3086    switchwin_T switchwin;
   3087    if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
   3088      if (*varname == '&' && htname != 't') {
   3089        buf_T *const save_curbuf = curbuf;
   3090 
   3091        // Change curbuf so the option is read from the correct buffer.
   3092        if (do_change_curbuf) {
   3093          curbuf = buf;
   3094        }
   3095 
   3096        if (varname[1] == NUL) {
   3097          // get all window-local or buffer-local options in a dict
   3098          dict_T *opts = get_winbuf_options(htname == 'b');
   3099 
   3100          if (opts != NULL) {
   3101            tv_dict_set_ret(rettv, opts);
   3102            done = true;
   3103          }
   3104        } else if (eval_option(&varname, rettv, true) == OK) {
   3105          // Local option
   3106          done = true;
   3107        }
   3108 
   3109        curbuf = save_curbuf;
   3110      } else if (*varname == NUL) {
   3111        const ScopeDictDictItem *v;
   3112        // Empty string: return a dict with all the local variables.
   3113        if (htname == 'b') {
   3114          v = &buf->b_bufvar;
   3115        } else if (htname == 'w') {
   3116          v = &win->w_winvar;
   3117        } else {
   3118          v = &tp->tp_winvar;
   3119        }
   3120        tv_copy(&v->di_tv, rettv);
   3121        done = true;
   3122      } else {
   3123        hashtab_T *ht;
   3124 
   3125        if (htname == 'b') {
   3126          ht = &buf->b_vars->dv_hashtab;
   3127        } else if (htname == 'w') {
   3128          ht = &win->w_vars->dv_hashtab;
   3129        } else {
   3130          ht = &tp->tp_vars->dv_hashtab;
   3131        }
   3132 
   3133        // Look up the variable.
   3134        const dictitem_T *const v = find_var_in_ht(ht, htname, varname, strlen(varname), false);
   3135        if (v != NULL) {
   3136          tv_copy(&v->di_tv, rettv);
   3137          done = true;
   3138        }
   3139      }
   3140    }
   3141 
   3142    if (need_switch_win) {
   3143      // restore previous notion of curwin
   3144      restore_win(&switchwin, true);
   3145    }
   3146  }
   3147 
   3148  if (!done && deftv->v_type != VAR_UNKNOWN) {
   3149    // use the default value
   3150    tv_copy(deftv, rettv);
   3151  }
   3152 
   3153  emsg_off--;
   3154 }
   3155 
   3156 /// getwinvar() and gettabwinvar()
   3157 ///
   3158 /// @param off  1 for gettabwinvar()
   3159 static void getwinvar(typval_T *argvars, typval_T *rettv, int off)
   3160 {
   3161  tabpage_T *tp;
   3162 
   3163  if (off == 1) {
   3164    tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
   3165  } else {
   3166    tp = curtab;
   3167  }
   3168  win_T *const win = find_win_by_nr(&argvars[off], tp);
   3169  const char *const varname = tv_get_string_chk(&argvars[off + 1]);
   3170 
   3171  get_var_from(varname, rettv, &argvars[off + 2], 'w', tp, win, NULL);
   3172 }
   3173 
   3174 /// Convert typval to option value for a particular option.
   3175 ///
   3176 /// @param[in]   tv      typval to convert.
   3177 /// @param[in]   option  Option name.
   3178 /// @param[in]   flags   Option flags.
   3179 /// @param[out]  error   Whether an error occurred.
   3180 ///
   3181 /// @return  Typval converted to OptVal. Must be freed by caller.
   3182 ///          Returns NIL_OPTVAL for invalid option name.
   3183 static OptVal tv_to_optval(typval_T *tv, OptIndex opt_idx, const char *option, bool *error)
   3184 {
   3185  OptVal value = NIL_OPTVAL;
   3186  char nbuf[NUMBUFLEN];
   3187  bool err = false;
   3188  const bool is_tty_opt = is_tty_option(option);
   3189  const bool option_has_bool = !is_tty_opt && option_has_type(opt_idx, kOptValTypeBoolean);
   3190  const bool option_has_num = !is_tty_opt && option_has_type(opt_idx, kOptValTypeNumber);
   3191  const bool option_has_str = is_tty_opt || option_has_type(opt_idx, kOptValTypeString);
   3192 
   3193  if (!is_tty_opt && (get_option(opt_idx)->flags & kOptFlagFunc) && tv_is_func(*tv)) {
   3194    // If the option can be set to a function reference or a lambda
   3195    // and the passed value is a function reference, then convert it to
   3196    // the name (string) of the function reference.
   3197    char *strval = encode_tv2string(tv, NULL);
   3198    err = strval == NULL;
   3199    value = CSTR_AS_OPTVAL(strval);
   3200  } else if (option_has_bool || option_has_num) {
   3201    varnumber_T n = option_has_num ? tv_get_number_chk(tv, &err) : tv_get_bool_chk(tv, &err);
   3202    // This could be either "0" or a string that's not a number.
   3203    // So we need to check if it's actually a number.
   3204    if (!err && tv->v_type == VAR_STRING && n == 0) {
   3205      unsigned idx;
   3206      for (idx = 0; tv->vval.v_string[idx] == '0'; idx++) {}
   3207      if (tv->vval.v_string[idx] != NUL || idx == 0) {
   3208        // There's another character after zeros or the string is empty.
   3209        // In both cases, we are trying to set a num option using a string.
   3210        err = true;
   3211        semsg(_("E521: Number required: &%s = '%s'"), option, tv->vval.v_string);
   3212      }
   3213    }
   3214    value = option_has_num ? NUMBER_OPTVAL((OptInt)n) : BOOLEAN_OPTVAL(TRISTATE_FROM_INT(n));
   3215  } else if (option_has_str) {
   3216    // Avoid setting string option to a boolean or a special value.
   3217    if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
   3218      const char *strval = tv_get_string_buf_chk(tv, nbuf);
   3219      err = strval == NULL;
   3220      value = CSTR_TO_OPTVAL(strval);
   3221    } else if (!is_tty_opt) {
   3222      err = true;
   3223      emsg(_(e_string_required));
   3224    }
   3225  } else {
   3226    abort();  // This should never happen.
   3227  }
   3228 
   3229  if (error != NULL) {
   3230    *error = err;
   3231  }
   3232  return value;
   3233 }
   3234 
   3235 /// Convert an option value to typval.
   3236 ///
   3237 /// @param[in]  value    Option value to convert.
   3238 /// @param      numbool  Whether to convert boolean values to number.
   3239 ///                      Used for backwards compatibility.
   3240 ///
   3241 /// @return  OptVal converted to typval.
   3242 typval_T optval_as_tv(OptVal value, bool numbool)
   3243 {
   3244  typval_T rettv = { .v_type = VAR_SPECIAL, .vval = { .v_special = kSpecialVarNull } };
   3245 
   3246  switch (value.type) {
   3247  case kOptValTypeNil:
   3248    break;
   3249  case kOptValTypeBoolean:
   3250    if (numbool) {
   3251      rettv.v_type = VAR_NUMBER;
   3252      rettv.vval.v_number = value.data.boolean;
   3253    } else if (value.data.boolean != kNone) {
   3254      rettv.v_type = VAR_BOOL;
   3255      rettv.vval.v_bool = value.data.boolean == kTrue;
   3256    }
   3257    break;  // return v:null for None boolean value.
   3258  case kOptValTypeNumber:
   3259    rettv.v_type = VAR_NUMBER;
   3260    rettv.vval.v_number = value.data.number;
   3261    break;
   3262  case kOptValTypeString:
   3263    rettv.v_type = VAR_STRING;
   3264    rettv.vval.v_string = value.data.string.data;
   3265    break;
   3266  }
   3267 
   3268  return rettv;
   3269 }
   3270 
   3271 /// Set option "varname" to the value of "varp" for the current buffer/window.
   3272 static void set_option_from_tv(const char *varname, typval_T *varp)
   3273 {
   3274  OptIndex opt_idx = find_option(varname);
   3275  if (opt_idx == kOptInvalid) {
   3276    semsg(_(e_unknown_option2), varname);
   3277    return;
   3278  }
   3279 
   3280  bool error = false;
   3281  OptVal value = tv_to_optval(varp, opt_idx, varname, &error);
   3282 
   3283  if (!error) {
   3284    const char *errmsg = set_option_value_handle_tty(varname, opt_idx, value, OPT_LOCAL);
   3285 
   3286    if (errmsg) {
   3287      emsg(errmsg);
   3288    }
   3289  }
   3290  optval_free(value);
   3291 }
   3292 
   3293 /// "setwinvar()" and "settabwinvar()" functions
   3294 static void setwinvar(typval_T *argvars, int off)
   3295 {
   3296  if (check_secure()) {
   3297    return;
   3298  }
   3299 
   3300  tabpage_T *tp = NULL;
   3301  if (off == 1) {
   3302    tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
   3303  } else {
   3304    tp = curtab;
   3305  }
   3306  win_T *const win = find_win_by_nr(&argvars[off], tp);
   3307  const char *varname = tv_get_string_chk(&argvars[off + 1]);
   3308  typval_T *varp = &argvars[off + 2];
   3309 
   3310  if (win == NULL || varname == NULL) {
   3311    return;
   3312  }
   3313 
   3314  bool need_switch_win = !(tp == curtab && win == curwin);
   3315  switchwin_T switchwin;
   3316  if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
   3317    if (*varname == '&') {
   3318      set_option_from_tv(varname + 1, varp);
   3319    } else {
   3320      const size_t varname_len = strlen(varname);
   3321      char *const winvarname = xmalloc(varname_len + 3);
   3322      memcpy(winvarname, "w:", 2);
   3323      memcpy(winvarname + 2, varname, varname_len + 1);
   3324      set_var(winvarname, varname_len + 2, varp, true);
   3325      xfree(winvarname);
   3326    }
   3327  }
   3328  if (need_switch_win) {
   3329    restore_win(&switchwin, true);
   3330  }
   3331 }
   3332 
   3333 // reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
   3334 // v:option_type, and v:option_command.
   3335 void reset_v_option_vars(void)
   3336 {
   3337  set_vim_var_string(VV_OPTION_NEW, NULL, -1);
   3338  set_vim_var_string(VV_OPTION_OLD, NULL, -1);
   3339  set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
   3340  set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
   3341  set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
   3342  set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
   3343 }
   3344 
   3345 /// Add an assert error to v:errors.
   3346 void assert_error(garray_T *gap)
   3347 {
   3348  typval_T *tv = get_vim_var_tv(VV_ERRORS);
   3349 
   3350  if (tv->v_type != VAR_LIST || tv->vval.v_list == NULL) {
   3351    // Make sure v:errors is a list.
   3352    set_vim_var_list(VV_ERRORS, tv_list_alloc(1));
   3353  }
   3354  tv_list_append_string(get_vim_var_list(VV_ERRORS), gap->ga_data, (ptrdiff_t)gap->ga_len);
   3355 }
   3356 
   3357 bool var_exists(const char *var)
   3358  FUNC_ATTR_NONNULL_ALL
   3359 {
   3360  char *tofree;
   3361  bool n = false;
   3362 
   3363  // get_name_len() takes care of expanding curly braces
   3364  const char *name = var;
   3365  const int len = get_name_len(&var, &tofree, true, false);
   3366  if (len > 0) {
   3367    typval_T tv;
   3368 
   3369    if (tofree != NULL) {
   3370      name = tofree;
   3371    }
   3372    n = eval_variable(name, len, &tv, NULL, false, true) == OK;
   3373    if (n) {
   3374      // Handle d.key, l[idx], f(expr).
   3375      n = handle_subscript(&var, &tv, &EVALARG_EVALUATE, false) == OK;
   3376      if (n) {
   3377        tv_clear(&tv);
   3378      }
   3379    }
   3380  }
   3381  if (*var != NUL) {
   3382    n = false;
   3383  }
   3384 
   3385  xfree(tofree);
   3386  return n;
   3387 }
   3388 
   3389 static lval_T *redir_lval = NULL;
   3390 static garray_T redir_ga;  // Only valid when redir_lval is not NULL.
   3391 static char *redir_endp = NULL;
   3392 static char *redir_varname = NULL;
   3393 
   3394 /// Start recording command output to a variable
   3395 ///
   3396 /// @param append  append to an existing variable
   3397 ///
   3398 /// @return  OK if successfully completed the setup.  FAIL otherwise.
   3399 int var_redir_start(char *name, bool append)
   3400 {
   3401  // Catch a bad name early.
   3402  if (!eval_isnamec1(*name)) {
   3403    emsg(_(e_invarg));
   3404    return FAIL;
   3405  }
   3406 
   3407  // Make a copy of the name, it is used in redir_lval until redir ends.
   3408  redir_varname = xstrdup(name);
   3409 
   3410  redir_lval = xcalloc(1, sizeof(lval_T));
   3411 
   3412  // The output is stored in growarray "redir_ga" until redirection ends.
   3413  ga_init(&redir_ga, (int)sizeof(char), 500);
   3414 
   3415  // Parse the variable name (can be a dict or list entry).
   3416  redir_endp = get_lval(redir_varname, NULL, redir_lval, false, false,
   3417                        0, FNE_CHECK_START);
   3418  if (redir_endp == NULL || redir_lval->ll_name == NULL
   3419      || *redir_endp != NUL) {
   3420    clear_lval(redir_lval);
   3421    if (redir_endp != NULL && *redir_endp != NUL) {
   3422      // Trailing characters are present after the variable name
   3423      semsg(_(e_trailing_arg), redir_endp);
   3424    } else {
   3425      semsg(_(e_invarg2), name);
   3426    }
   3427    redir_endp = NULL;      // don't store a value, only cleanup
   3428    var_redir_stop();
   3429    return FAIL;
   3430  }
   3431 
   3432  // check if we can write to the variable: set it to or append an empty
   3433  // string
   3434  const int called_emsg_before = called_emsg;
   3435  did_emsg = false;
   3436  typval_T tv;
   3437  tv.v_type = VAR_STRING;
   3438  tv.vval.v_string = "";
   3439  if (append) {
   3440    set_var_lval(redir_lval, redir_endp, &tv, true, false, ".");
   3441  } else {
   3442    set_var_lval(redir_lval, redir_endp, &tv, true, false, "=");
   3443  }
   3444  clear_lval(redir_lval);
   3445  if (called_emsg > called_emsg_before) {
   3446    redir_endp = NULL;      // don't store a value, only cleanup
   3447    var_redir_stop();
   3448    return FAIL;
   3449  }
   3450 
   3451  return OK;
   3452 }
   3453 
   3454 /// Append "value[value_len]" to the variable set by var_redir_start().
   3455 /// The actual appending is postponed until redirection ends, because the value
   3456 /// appended may in fact be the string we write to, changing it may cause freed
   3457 /// memory to be used:
   3458 ///   :redir => foo
   3459 ///   :let foo
   3460 ///   :redir END
   3461 void var_redir_str(const char *value, int value_len)
   3462 {
   3463  if (redir_lval == NULL) {
   3464    return;
   3465  }
   3466 
   3467  int len;
   3468  if (value_len == -1) {
   3469    len = (int)strlen(value);           // Append the entire string
   3470  } else {
   3471    len = value_len;                    // Append only "value_len" characters
   3472  }
   3473 
   3474  ga_grow(&redir_ga, len);
   3475  memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, (size_t)len);
   3476  redir_ga.ga_len += len;
   3477 }
   3478 
   3479 /// Stop redirecting command output to a variable.
   3480 /// Frees the allocated memory.
   3481 void var_redir_stop(void)
   3482 {
   3483  if (redir_lval != NULL) {
   3484    // If there was no error: assign the text to the variable.
   3485    if (redir_endp != NULL) {
   3486      ga_append(&redir_ga, NUL);        // Append the trailing NUL.
   3487      typval_T tv;
   3488      tv.v_type = VAR_STRING;
   3489      tv.vval.v_string = redir_ga.ga_data;
   3490      // Call get_lval() again, if it's inside a Dict or List it may
   3491      // have changed.
   3492      redir_endp = get_lval(redir_varname, NULL, redir_lval,
   3493                            false, false, 0, FNE_CHECK_START);
   3494      if (redir_endp != NULL && redir_lval->ll_name != NULL) {
   3495        set_var_lval(redir_lval, redir_endp, &tv, false, false, ".");
   3496      }
   3497      clear_lval(redir_lval);
   3498    }
   3499 
   3500    // free the collected output
   3501    XFREE_CLEAR(redir_ga.ga_data);
   3502 
   3503    XFREE_CLEAR(redir_lval);
   3504  }
   3505  XFREE_CLEAR(redir_varname);
   3506 }
   3507 
   3508 /// "gettabvar()" function
   3509 void f_gettabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3510 {
   3511  const char *const varname = tv_get_string_chk(&argvars[1]);
   3512  tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
   3513  win_T *win = NULL;
   3514 
   3515  if (tp != NULL) {
   3516    win = tp == curtab || tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin;
   3517  }
   3518 
   3519  get_var_from(varname, rettv, &argvars[2], 't', tp, win, NULL);
   3520 }
   3521 
   3522 /// "gettabwinvar()" function
   3523 void f_gettabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3524 {
   3525  getwinvar(argvars, rettv, 1);
   3526 }
   3527 
   3528 /// "getwinvar()" function
   3529 void f_getwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3530 {
   3531  getwinvar(argvars, rettv, 0);
   3532 }
   3533 
   3534 /// "getbufvar()" function
   3535 void f_getbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3536 {
   3537  const char *const varname = tv_get_string_chk(&argvars[1]);
   3538  buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
   3539 
   3540  get_var_from(varname, rettv, &argvars[2], 'b', curtab, curwin, buf);
   3541 }
   3542 
   3543 /// "settabvar()" function
   3544 void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3545 {
   3546  if (check_secure()) {
   3547    return;
   3548  }
   3549 
   3550  tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
   3551  const char *const varname = tv_get_string_chk(&argvars[1]);
   3552  typval_T *const varp = &argvars[2];
   3553 
   3554  if (varname == NULL || tp == NULL) {
   3555    return;
   3556  }
   3557 
   3558  tabpage_T *const save_curtab = curtab;
   3559  tabpage_T *const save_lu_tp = lastused_tabpage;
   3560  goto_tabpage_tp(tp, false, false);
   3561 
   3562  const size_t varname_len = strlen(varname);
   3563  char *const tabvarname = xmalloc(varname_len + 3);
   3564  memcpy(tabvarname, "t:", 2);
   3565  memcpy(tabvarname + 2, varname, varname_len + 1);
   3566  set_var(tabvarname, varname_len + 2, varp, true);
   3567  xfree(tabvarname);
   3568 
   3569  // Restore current tabpage and last accessed tabpage.
   3570  if (valid_tabpage(save_curtab)) {
   3571    goto_tabpage_tp(save_curtab, false, false);
   3572    if (valid_tabpage(save_lu_tp)) {
   3573      lastused_tabpage = save_lu_tp;
   3574    }
   3575  }
   3576 }
   3577 
   3578 /// "settabwinvar()" function
   3579 void f_settabwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3580 {
   3581  setwinvar(argvars, 1);
   3582 }
   3583 
   3584 /// "setwinvar()" function
   3585 void f_setwinvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3586 {
   3587  setwinvar(argvars, 0);
   3588 }
   3589 
   3590 /// "setbufvar()" function
   3591 void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
   3592 {
   3593  if (check_secure()
   3594      || !tv_check_str_or_nr(&argvars[0])) {
   3595    return;
   3596  }
   3597  const char *varname = tv_get_string_chk(&argvars[1]);
   3598  buf_T *const buf = tv_get_buf(&argvars[0], false);
   3599  typval_T *varp = &argvars[2];
   3600 
   3601  if (buf == NULL || varname == NULL) {
   3602    return;
   3603  }
   3604 
   3605  if (*varname == '&') {
   3606    aco_save_T aco;
   3607 
   3608    // Set curbuf to be our buf, temporarily.
   3609    aucmd_prepbuf(&aco, buf);
   3610 
   3611    set_option_from_tv(varname + 1, varp);
   3612 
   3613    // reset notion of buffer
   3614    aucmd_restbuf(&aco);
   3615  } else {
   3616    const size_t varname_len = strlen(varname);
   3617    char *const bufvarname = xmalloc(varname_len + 3);
   3618    buf_T *const save_curbuf = curbuf;
   3619    curbuf = buf;
   3620    memcpy(bufvarname, "b:", 2);
   3621    memcpy(bufvarname + 2, varname, varname_len + 1);
   3622    set_var(bufvarname, varname_len + 2, varp, true);
   3623    xfree(bufvarname);
   3624    curbuf = save_curbuf;
   3625  }
   3626 }