diff options
Diffstat (limited to 'src/nvim/eval/vars.c')
-rw-r--r-- | src/nvim/eval/vars.c | 84 |
1 files changed, 55 insertions, 29 deletions
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 206df03381..9ed245d6c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -106,7 +106,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd) return NULL; } *p = NUL; - if (islower(*marker)) { + if (islower((uint8_t)(*marker))) { emsg(_("E221: Marker cannot start with lower case letter")); return NULL; } @@ -208,7 +208,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const) argend--; } expr = skipwhite(argend); - if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL + if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) { // ":let" without "=": list variables if (*arg == '[') { @@ -244,7 +244,7 @@ static void ex_let_const(exarg_T *eap, const bool is_const) op[0] = '='; op[1] = NUL; if (*expr != '=') { - if (vim_strchr("+-*/%.", *expr) != NULL) { + if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) { op[0] = *expr; // +=, -=, *=, /=, %= or .= if (expr[0] == '.' && expr[1] == '.') { // ..= expr++; @@ -590,10 +590,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo if (len == 0) { semsg(_(e_invarg2), name - 1); } else { - if (op != NULL && vim_strchr("+-*/%", *op) != NULL) { + if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { semsg(_(e_letwrong), op); } else if (endchars != NULL - && vim_strchr(endchars, *skipwhite(arg)) == NULL) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(arg))) == NULL) { emsg(_(e_letunexp)); } else if (!check_secure()) { char *tofree = NULL; @@ -629,7 +629,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo char *const p = (char *)find_option_end((const char **)&arg, &scope); if (p == NULL || (endchars != NULL - && vim_strchr(endchars, *skipwhite(p)) == NULL)) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) { emsg(_(e_letunexp)); } else { varnumber_T n = 0; @@ -716,10 +716,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo return NULL; } arg++; - if (op != NULL && vim_strchr("+-*/%", *op) != NULL) { + if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { semsg(_(e_letwrong), op); } else if (endchars != NULL - && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) { + && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) { emsg(_(e_letunexp)); } else { char *s; @@ -747,7 +747,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START); if (p != NULL && lv.ll_name != NULL) { - if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) { + if (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL) { emsg(_(e_letunexp)); } else { set_var_lval(&lv, p, tv, copy, is_const, op); @@ -877,13 +877,13 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ } else if ((lp->ll_list != NULL // ll_list is not NULL when lvalue is not in a list, NULL lists // yield E689. - && var_check_lock(tv_list_locked(lp->ll_list), - lp->ll_name, - lp->ll_name_len)) + && value_check_lock(tv_list_locked(lp->ll_list), + lp->ll_name, + lp->ll_name_len)) || (lp->ll_dict != NULL - && var_check_lock(lp->ll_dict->dv_lock, - lp->ll_name, - lp->ll_name_len))) { + && value_check_lock(lp->ll_dict->dv_lock, + lp->ll_name, + lp->ll_name_len))) { return FAIL; } else if (lp->ll_range) { assert(lp->ll_list != NULL); @@ -892,9 +892,9 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ listitem_T *last_li = first_li; for (;;) { listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li); - if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock, - lp->ll_name, - lp->ll_name_len)) { + if (value_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock, + lp->ll_name, + lp->ll_name_len)) { return false; } lp->ll_li = li; @@ -976,11 +976,11 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit) dictitem_T *const di = TV_DICT_HI2DI(hi); if (var_check_fixed(di->di_flags, name, TV_CSTRING) || var_check_ro(di->di_flags, name, TV_CSTRING) - || var_check_lock(d->dv_lock, name, TV_CSTRING)) { + || value_check_lock(d->dv_lock, name, TV_CSTRING)) { return FAIL; } - if (var_check_lock(d->dv_lock, name, TV_CSTRING)) { + if (value_check_lock(d->dv_lock, name, TV_CSTRING)) { return FAIL; } @@ -1023,10 +1023,6 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap bool lock = eap->cmdidx == CMD_lockvar; int ret = OK; - if (deep == 0) { // Nothing to do. - return OK; - } - if (lp->ll_tv == NULL) { if (*lp->ll_name == '$') { semsg(_(e_lock_unlock), lp->ll_name); @@ -1050,9 +1046,13 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap } else { di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK); } - tv_item_lock(&di->di_tv, deep, lock, false); + if (deep != 0) { + tv_item_lock(&di->di_tv, deep, lock, false); + } } } + } else if (deep == 0) { + // nothing to do } else if (lp->ll_range) { listitem_T *li = lp->ll_li; @@ -1282,12 +1282,18 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, return; } - // existing variable, need to clear the value + // Check in this order for backwards compatibility: + // - Whether the variable is read-only + // - Whether the variable value is locked + // - Whether the variable is locked if (var_check_ro(v->di_flags, name, name_len) - || var_check_lock(v->di_tv.v_lock, name, name_len)) { + || value_check_lock(v->di_tv.v_lock, name, name_len) + || var_check_lock(v->di_flags, name, name_len)) { return; } + // existing variable, need to clear the value + // Handle setting internal v: variables separately where needed to // prevent changing the type. if (is_vimvarht(ht)) { @@ -1341,7 +1347,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv, // Make sure dict is valid assert(dict != NULL); - v = xmalloc(sizeof(dictitem_T) + strlen(varname)); + v = xmalloc(offsetof(dictitem_T, di_key) + strlen(varname) + 1); STRCPY(v->di_key, varname); if (hash_add(ht, (char *)v->di_key) == FAIL) { xfree(v); @@ -1418,6 +1424,26 @@ bool var_check_ro(const int flags, const char *name, size_t name_len) return true; } +/// Return true if di_flags "flags" indicates variable "name" is locked. +/// Also give an error message. +bool var_check_lock(const int flags, const char *name, size_t name_len) +{ + if (!(flags & DI_FLAGS_LOCK)) { + return false; + } + + if (name_len == TV_TRANSLATE) { + name = _(name); + name_len = strlen(name); + } else if (name_len == TV_CSTRING) { + name_len = strlen(name); + } + + semsg(_("E1122: Variable is locked: %*s"), (int)name_len, name); + + return true; +} + /// Check whether variable is fixed (DI_FLAGS_FIX) /// /// Also gives an error message. @@ -1464,7 +1490,7 @@ bool var_wrong_func_name(const char *const name, const bool new_var) { // Allow for w: b: s: and t:. // Allow autoload variable. - if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':') + if (!(vim_strchr("wbst", (uint8_t)name[0]) != NULL && name[1] == ':') && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2] : name[0]) && vim_strchr(name, '#') == NULL) { semsg(_("E704: Funcref variable name must start with a capital: %s"), name); |