aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/vars.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/vars.c')
-rw-r--r--src/nvim/eval/vars.c297
1 files changed, 170 insertions, 127 deletions
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 5c61762fd5..58fb2211fc 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -3,24 +3,43 @@
// eval/vars.c: functions for dealing with variables
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
-#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/hashtab.h"
+#include "nvim/macros.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/screen.h"
+#include "nvim/os/os.h"
#include "nvim/search.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -62,7 +81,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// Check for the optional 'trim' word before the marker
cmd = skipwhite(cmd);
- if (STRNCMP(cmd, "trim", 4) == 0
+ if (strncmp(cmd, "trim", 4) == 0
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
cmd = skipwhite(cmd + 4);
@@ -87,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;
}
@@ -110,7 +129,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// with "trim": skip the indent matching the :let line to find the
// marker
if (marker_indent_len > 0
- && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
+ && strncmp(theline, *eap->cmdlinep, (size_t)marker_indent_len) == 0) {
mi = marker_indent_len;
}
if (strcmp(marker, theline + mi) == 0) {
@@ -189,8 +208,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
argend--;
}
expr = skipwhite(argend);
- if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
- && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
+ if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
+ && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) {
// ":let" without "=": list variables
if (*arg == '[') {
emsg(_(e_invarg));
@@ -225,17 +244,19 @@ 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++;
}
}
- expr = skipwhite(expr + 2);
+ expr += 2;
} else {
- expr = skipwhite(expr + 1);
+ expr += 1;
}
+ expr = skipwhite(expr);
+
if (eap->skip) {
emsg_skip++;
}
@@ -378,9 +399,8 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
}
}
return p + 1;
- } else {
- return skip_var_one((char *)arg);
}
+ return skip_var_one((char *)arg);
}
/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
@@ -539,8 +559,6 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
return arg;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
///
/// @param[in] arg Start of the variable name.
@@ -558,8 +576,6 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
{
char *arg_end = NULL;
int len;
- int opt_flags;
- char *tofree = NULL;
// ":let $VAR = expr": Set environment variable.
if (*arg == '$') {
@@ -574,18 +590,18 @@ 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;
const char c1 = name[len];
name[len] = NUL;
const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
char *s = vim_getenv(name);
-
if (s != NULL) {
tofree = concat_str(s, p);
p = (const char *)tofree;
@@ -609,10 +625,11 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
return NULL;
}
// Find the end of the name.
- char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
+ int scope;
+ 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;
@@ -621,11 +638,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
char *stringval = NULL;
const char *s = NULL;
bool failed = false;
+ uint32_t opt_p_flags;
+ char *tofree = NULL;
const char c1 = *p;
*p = NUL;
- opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, scope);
if (opt_type == gov_bool
|| opt_type == gov_number
|| opt_type == gov_hidden_bool
@@ -634,8 +653,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
n = (long)tv_get_number(tv);
}
- // Avoid setting a string option to the text "v:false" or similar.
- if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ if ((opt_p_flags & P_FUNC) && tv_is_func(*tv)) {
+ // If the option can be set to a function reference or a lambda
+ // and the passed value is a function reference, then convert it to
+ // the name (string) of the function reference.
+ s = tofree = encode_tv2string(tv, NULL);
+ } else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ // Avoid setting a string option to the text "v:false" or similar.
s = tv_get_string_chk(tv);
}
@@ -672,7 +696,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (!failed) {
if (opt_type != gov_string || s != NULL) {
- char *err = set_option_value(arg, n, s, opt_flags);
+ char *err = set_option_value(arg, n, s, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -683,6 +707,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
}
*p = c1;
xfree(stringval);
+ xfree(tofree);
}
// ":let @r = expr": Set register contents.
} else if (*arg == '@') {
@@ -695,10 +720,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
int regname = utf_ptr2char(arg);
int mblen = utf_ptr2len(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 + mblen)) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + mblen))) == NULL) {
emsg(_(e_letunexp));
} else {
char *s;
@@ -715,7 +740,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
}
if (p != NULL) {
write_reg_contents(*arg == '@' ? '"' : regname,
- (const char_u *)p, (ssize_t)strlen(p), false);
+ p, (ssize_t)strlen(p), false);
arg_end = arg + mblen;
}
xfree(ptofree);
@@ -727,7 +752,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);
@@ -748,8 +773,6 @@ void ex_unlet(exarg_T *eap)
ex_unletlock(eap, eap->arg, 0, do_unlet_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// ":lockvar" and ":unlockvar" commands
void ex_lockvar(exarg_T *eap)
{
@@ -766,8 +789,6 @@ void ex_lockvar(exarg_T *eap)
ex_unletlock(eap, arg, deep, do_lock_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Common parsing logic for :unlet, :lockvar and :unlockvar.
///
/// Invokes `callback` afterwards if successful and `eap->skip == false`.
@@ -832,8 +853,6 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca
eap->nextcmd = check_nextcmd(arg);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Unlet a variable indicated by `lp`.
///
/// @param[in] lp The lvalue.
@@ -850,7 +869,7 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
int cc;
if (lp->ll_tv == NULL) {
- cc = (char_u)(*name_end);
+ cc = (uint8_t)(*name_end);
*name_end = NUL;
// Environment variable, normal name or expanded name.
@@ -863,13 +882,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);
@@ -878,18 +897,17 @@ 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;
lp->ll_n1++;
if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) {
break;
- } else {
- last_li = lp->ll_li;
}
+ last_li = lp->ll_li;
}
tv_list_remove_items(lp->ll_list, first_li, last_li);
} else {
@@ -924,8 +942,6 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
return ret;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// unlet a variable
///
/// @param[in] name Variable name to unlet.
@@ -965,11 +981,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;
}
@@ -996,8 +1012,6 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
return FAIL;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Lock or unlock variable indicated by `lp`.
///
/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
@@ -1014,10 +1028,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);
@@ -1041,9 +1051,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;
@@ -1103,7 +1117,7 @@ int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, boo
/// NULL when it doesn't exist.
///
/// @see tv_get_string() for how long the pointer remains valid.
-char_u *get_var_value(const char *const name)
+char *get_var_value(const char *const name)
{
dictitem_T *v;
@@ -1111,7 +1125,7 @@ char_u *get_var_value(const char *const name)
if (v == NULL) {
return NULL;
}
- return (char_u *)tv_get_string(&v->di_tv);
+ return (char *)tv_get_string(&v->di_tv);
}
/// Clean up a list of internal variables.
@@ -1166,7 +1180,7 @@ void delete_var(hashtab_T *ht, hashitem_T *hi)
static void list_one_var(dictitem_T *v, const char *prefix, int *first)
{
char *const s = encode_tv2echo(&v->di_tv, NULL);
- list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)STRLEN(v->di_key),
+ list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)strlen((char *)v->di_key),
v->di_tv.v_type, (s == NULL ? "" : s), first);
xfree(s);
}
@@ -1262,7 +1276,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = find_var_in_scoped_ht(name, name_len, true);
}
- if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
+ if (tv_is_func(*tv) && var_wrong_func_name(name, v == NULL)) {
return;
}
@@ -1273,12 +1287,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)) {
@@ -1334,7 +1354,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = xmalloc(sizeof(dictitem_T) + strlen(varname));
STRCPY(v->di_key, varname);
- if (tv_dict_add(dict, v) == FAIL) {
+ if (hash_add(ht, (char *)v->di_key) == FAIL) {
xfree(v);
return;
}
@@ -1409,6 +1429,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.
@@ -1443,37 +1483,34 @@ bool var_check_fixed(const int flags, const char *name, size_t name_len)
return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if name is a valid name to assign funcref to
///
/// @param[in] name Possible function/funcref name.
/// @param[in] new_var True if it is a name for a variable.
///
-/// @return false in case of error, true in case of success. Also gives an
+/// @return false in case of success, true in case of failure. Also gives an
/// error message if appropriate.
-bool var_check_func_name(const char *const name, const bool new_var)
+bool var_wrong_func_name(const char *const name, const bool new_var)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
// Allow for w: b: s: and t:.
- if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':')
- && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
- ? name[2] : name[0])) {
+ // Allow autoload variable.
+ 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);
- return false;
+ return true;
}
// Don't allow hiding a function. When "v" is not NULL we might be
// assigning another function to the same var, the type is checked
// below.
if (new_var && function_exists(name, false)) {
semsg(_("E705: Variable name conflicts with existing function: %s"), name);
- return false;
+ return true;
}
- return true;
+ return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if a variable name is valid
///
/// @param[in] varname Variable name to check.
@@ -1648,25 +1685,27 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
const char *varname = tv_get_string_chk(&argvars[off + 1]);
typval_T *varp = &argvars[off + 2];
- if (win != NULL && varname != NULL && varp != NULL) {
- bool need_switch_win = !(tp == curtab && win == curwin);
- switchwin_T switchwin;
- if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
- if (*varname == '&') {
- set_option_from_tv(varname + 1, varp);
- } else {
- const size_t varname_len = strlen(varname);
- char *const winvarname = xmalloc(varname_len + 3);
- memcpy(winvarname, "w:", 2);
- memcpy(winvarname + 2, varname, varname_len + 1);
- set_var(winvarname, varname_len + 2, varp, true);
- xfree(winvarname);
- }
- }
- if (need_switch_win) {
- restore_win(&switchwin, true);
+ if (win == NULL || varname == NULL) {
+ return;
+ }
+
+ bool need_switch_win = !(tp == curtab && win == curwin);
+ switchwin_T switchwin;
+ if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
+ if (*varname == '&') {
+ set_option_from_tv(varname + 1, varp);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const winvarname = xmalloc(varname_len + 3);
+ memcpy(winvarname, "w:", 2);
+ memcpy(winvarname + 2, varname, varname_len + 1);
+ set_var(winvarname, varname_len + 2, varp, true);
+ xfree(winvarname);
}
}
+ if (need_switch_win) {
+ restore_win(&switchwin, true);
+ }
}
bool var_exists(const char *var)
@@ -1749,21 +1788,23 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *const varname = tv_get_string_chk(&argvars[1]);
typval_T *const varp = &argvars[2];
- if (varname != NULL && tp != NULL) {
- tabpage_T *const save_curtab = curtab;
- goto_tabpage_tp(tp, false, false);
+ if (varname == NULL || tp == NULL) {
+ return;
+ }
- const size_t varname_len = strlen(varname);
- char *const tabvarname = xmalloc(varname_len + 3);
- memcpy(tabvarname, "t:", 2);
- memcpy(tabvarname + 2, varname, varname_len + 1);
- set_var(tabvarname, varname_len + 2, varp, true);
- xfree(tabvarname);
-
- // Restore current tabpage.
- if (valid_tabpage(save_curtab)) {
- goto_tabpage_tp(save_curtab, false, false);
- }
+ tabpage_T *const save_curtab = curtab;
+ goto_tabpage_tp(tp, false, false);
+
+ const size_t varname_len = strlen(varname);
+ char *const tabvarname = xmalloc(varname_len + 3);
+ memcpy(tabvarname, "t:", 2);
+ memcpy(tabvarname + 2, varname, varname_len + 1);
+ set_var(tabvarname, varname_len + 2, varp, true);
+ xfree(tabvarname);
+
+ // Restore current tabpage.
+ if (valid_tabpage(save_curtab)) {
+ goto_tabpage_tp(save_curtab, false, false);
}
}
@@ -1790,27 +1831,29 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
buf_T *const buf = tv_get_buf(&argvars[0], false);
typval_T *varp = &argvars[2];
- if (buf != NULL && varname != NULL) {
- if (*varname == '&') {
- aco_save_T aco;
+ if (buf == NULL || varname == NULL) {
+ return;
+ }
- // set curbuf to be our buf, temporarily
- aucmd_prepbuf(&aco, buf);
+ if (*varname == '&') {
+ aco_save_T aco;
- set_option_from_tv(varname + 1, varp);
+ // Set curbuf to be our buf, temporarily.
+ aucmd_prepbuf(&aco, buf);
- // reset notion of buffer
- aucmd_restbuf(&aco);
- } else {
- const size_t varname_len = strlen(varname);
- char *const bufvarname = xmalloc(varname_len + 3);
- buf_T *const save_curbuf = curbuf;
- curbuf = buf;
- memcpy(bufvarname, "b:", 2);
- memcpy(bufvarname + 2, varname, varname_len + 1);
- set_var(bufvarname, varname_len + 2, varp, true);
- xfree(bufvarname);
- curbuf = save_curbuf;
- }
+ set_option_from_tv(varname + 1, varp);
+
+ // reset notion of buffer
+ aucmd_restbuf(&aco);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const bufvarname = xmalloc(varname_len + 3);
+ buf_T *const save_curbuf = curbuf;
+ curbuf = buf;
+ memcpy(bufvarname, "b:", 2);
+ memcpy(bufvarname + 2, varname, varname_len + 1);
+ set_var(bufvarname, varname_len + 2, varp, true);
+ xfree(bufvarname);
+ curbuf = save_curbuf;
}
}