aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c650
1 files changed, 425 insertions, 225 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a5a8671697..b011ee9d54 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1147,7 +1147,7 @@ int call_vim_function(
len = 0;
} else {
// Recognize a number argument, the others must be strings.
- vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL);
+ vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
}
if (len != 0 && len == (int)STRLEN(argv[i])) {
argvars[i].v_type = VAR_NUMBER;
@@ -1700,12 +1700,13 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first)
}
error = TRUE;
} else {
- if (tofree != NULL)
+ if (tofree != NULL) {
name = tofree;
- if (get_var_tv(name, len, &tv, TRUE, FALSE) == FAIL)
- error = TRUE;
- else {
- /* handle d.key, l[idx], f(expr) */
+ }
+ if (get_var_tv(name, len, &tv, NULL, true, false) == FAIL) {
+ error = true;
+ } else {
+ // handle d.key, l[idx], f(expr)
arg_subsc = arg;
if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL)
error = TRUE;
@@ -2176,10 +2177,10 @@ get_lval (
if (len == -1)
clear_tv(&var1);
break;
- }
- /* existing variable, need to check if it can be changed */
- else if (var_check_ro(lp->ll_di->di_flags, name))
+ } else if (var_check_ro(lp->ll_di->di_flags, name, false)) {
+ // existing variable, need to check if it can be changed
return NULL;
+ }
if (len == -1)
clear_tv(&var1);
@@ -2274,11 +2275,16 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
if (op != NULL && *op != '=') {
typval_T tv;
- /* handle +=, -= and .= */
+ // handle +=, -= and .=
+ di = NULL;
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
- &tv, TRUE, FALSE) == OK) {
- if (tv_op(&tv, rettv, op) == OK)
- set_var(lp->ll_name, &tv, FALSE);
+ &tv, &di, true, false) == OK) {
+ if ((di == NULL
+ || (!var_check_ro(di->di_flags, lp->ll_name, false) &&
+ !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
+ && tv_op(&tv, rettv, op) == OK) {
+ set_var(lp->ll_name, &tv, false);
+ }
clear_tv(&tv);
}
} else
@@ -2286,16 +2292,17 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
*endp = cc;
}
} else if (tv_check_lock(lp->ll_newkey == NULL
- ? lp->ll_tv->v_lock
- : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name))
- ;
- else if (lp->ll_range) {
+ ? lp->ll_tv->v_lock
+ : lp->ll_tv->vval.v_dict->dv_lock,
+ lp->ll_name, false)) {
+ } else if (lp->ll_range) {
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
// Check whether any of the list items is locked
- for (listitem_T *ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) {
- if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) {
+ for (listitem_T *ri = rettv->vval.v_list->lv_first;
+ ri != NULL && ll_li != NULL; ) {
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) {
return;
}
ri = ri->li_next;
@@ -2890,16 +2897,19 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
else if (do_unlet(lp->ll_name, forceit) == FAIL)
ret = FAIL;
*name_end = cc;
- } else if (tv_check_lock(lp->ll_tv->v_lock, lp->ll_name))
+ } else if ((lp->ll_list != NULL
+ && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name, false))
+ || (lp->ll_dict != NULL
+ && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name, false))) {
return FAIL;
- else if (lp->ll_range) {
+ } else if (lp->ll_range) {
listitem_T *li;
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) {
li = ll_li->li_next;
- if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) {
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) {
return false;
}
ll_li = li;
@@ -2953,17 +2963,30 @@ int do_unlet(char_u *name, int forceit)
hashtab_T *ht;
hashitem_T *hi;
char_u *varname;
+ dict_T *d;
dictitem_T *di;
dict_T *dict;
ht = find_var_ht_dict(name, &varname, &dict);
if (ht != NULL && *varname != NUL) {
+ if (ht == &globvarht) {
+ d = &globvardict;
+ } else if (current_funccal != NULL
+ && ht == &current_funccal->l_vars.dv_hashtab) {
+ d = &current_funccal->l_vars;
+ } else {
+ di = find_var_in_ht(ht, *name, (char_u *)"", false);
+ d = di->di_tv.vval.v_dict;
+ }
+
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi)) {
di = HI2DI(hi);
- if (var_check_fixed(di->di_flags, name)
- || var_check_ro(di->di_flags, name))
+ if (var_check_fixed(di->di_flags, name, false)
+ || var_check_ro(di->di_flags, name, false)
+ || tv_check_lock(d->dv_lock, name, false)) {
return FAIL;
+ }
typval_T oldtv;
bool watched = is_watched(dict);
@@ -3029,12 +3052,13 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
li = li->li_next;
++lp->ll_n1;
}
- } else if (lp->ll_list != NULL)
- /* (un)lock a List item. */
+ } else if (lp->ll_list != NULL) {
+ // (un)lock a List item.
item_lock(&lp->ll_li->li_tv, deep, lock);
- else
- /* un(lock) a Dictionary item. */
+ } else {
+ // (un)lock a Dictionary item.
item_lock(&lp->ll_di->di_tv, deep, lock);
+ }
return ret;
}
@@ -3556,9 +3580,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
type = TYPE_SEQUAL;
break;
case 'i': if (p[1] == 's') {
- if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
+ if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') {
len = 5;
- if (!vim_isIDc(p[len])) {
+ }
+ if (!isalnum(p[len]) && p[len] != '_') {
type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL;
type_is = TRUE;
}
@@ -4122,7 +4147,7 @@ static int eval7(
rettv->vval.v_float = f;
}
} else {
- vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL);
+ vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -4223,7 +4248,7 @@ static int eval7(
ret = FAIL;
}
} else if (evaluate) {
- ret = get_var_tv(s, len, rettv, true, false);
+ ret = get_var_tv(s, len, rettv, NULL, true, false);
} else {
ret = OK;
}
@@ -4638,10 +4663,13 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
int n, nr;
int c = toupper(*p);
- if (c == 'X')
+ if (c == 'X') {
n = 2;
- else
+ } else if (*p == 'u') {
n = 4;
+ } else {
+ n = 8;
+ }
nr = 0;
while (--n >= 0 && ascii_isxdigit(p[1])) {
++p;
@@ -6052,7 +6080,7 @@ dictitem_T *dictitem_alloc(char_u *key) FUNC_ATTR_NONNULL_RET
#ifndef __clang_analyzer__
STRCPY(di->di_key, key);
#endif
- di->di_flags = 0;
+ di->di_flags = DI_FLAGS_ALLOC;
return di;
}
@@ -6064,7 +6092,7 @@ static dictitem_T *dictitem_copy(dictitem_T *org) FUNC_ATTR_NONNULL_RET
dictitem_T *di = xmalloc(sizeof(dictitem_T) + STRLEN(org->di_key));
STRCPY(di->di_key, org->di_key);
- di->di_flags = 0;
+ di->di_flags = DI_FLAGS_ALLOC;
copy_tv(&org->di_tv, &di->di_tv);
return di;
@@ -6092,7 +6120,9 @@ static void dictitem_remove(dict_T *dict, dictitem_T *item)
void dictitem_free(dictitem_T *item)
{
clear_tv(&item->di_tv);
- xfree(item);
+ if (item->di_flags & DI_FLAGS_ALLOC) {
+ xfree(item);
+ }
}
/// Make a copy of dictionary
@@ -7188,9 +7218,9 @@ static struct fst {
{ "getwinposx", 0, 0, f_getwinposx },
{ "getwinposy", 0, 0, f_getwinposy },
{ "getwinvar", 2, 3, f_getwinvar },
- { "glob", 1, 3, f_glob },
+ { "glob", 1, 4, f_glob },
{ "glob2regpat", 1, 1, f_glob2regpat },
- { "globpath", 2, 4, f_globpath },
+ { "globpath", 2, 5, f_globpath },
{ "has", 1, 1, f_has },
{ "has_key", 2, 2, f_has_key },
{ "haslocaldir", 0, 0, f_haslocaldir },
@@ -7241,8 +7271,8 @@ static struct fst {
{ "maparg", 1, 4, f_maparg },
{ "mapcheck", 1, 3, f_mapcheck },
{ "match", 2, 4, f_match },
- { "matchadd", 2, 4, f_matchadd },
- { "matchaddpos", 2, 4, f_matchaddpos },
+ { "matchadd", 2, 5, f_matchadd },
+ { "matchaddpos", 2, 5, f_matchaddpos },
{ "matcharg", 1, 1, f_matcharg },
{ "matchdelete", 1, 1, f_matchdelete },
{ "matchend", 2, 4, f_matchend },
@@ -7316,7 +7346,7 @@ static struct fst {
{ "sqrt", 1, 1, f_sqrt },
{ "str2float", 1, 1, f_str2float },
{ "str2nr", 1, 2, f_str2nr },
- { "strchars", 1, 1, f_strchars },
+ { "strchars", 1, 2, f_strchars },
{ "strdisplaywidth", 1, 2, f_strdisplaywidth },
{ "strftime", 1, 2, f_strftime },
{ "stridx", 2, 3, f_stridx },
@@ -7834,7 +7864,8 @@ static void f_add(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1; /* Default: Failed */
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("add() argument"))) {
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("add() argument"), true)) {
list_append_tv(l, &argvars[1]);
copy_tv(&argvars[0], rettv);
}
@@ -9109,9 +9140,10 @@ static void f_exists(typval_T *argvars, typval_T *rettv)
name = p;
len = get_name_len(&p, &tofree, TRUE, FALSE);
if (len > 0) {
- if (tofree != NULL)
+ if (tofree != NULL) {
name = tofree;
- n = (get_var_tv(name, len, &tv, FALSE, TRUE) == OK);
+ }
+ n = (get_var_tv(name, len, &tv, NULL, false, true) == OK);
if (n) {
/* handle d.key, l[idx], f(expr) */
n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
@@ -9209,6 +9241,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
hashitem_T *hi2;
int todo;
bool watched = is_watched(d1);
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
todo = (int)d2->dv_hashtab.ht_used;
for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) {
@@ -9242,6 +9275,11 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
} else if (*action == 'f' && HI2DI(hi2) != di1) {
typval_T oldtv;
+ if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, true)
+ || var_check_ro(di1->di_flags, arg_errmsg, true)) {
+ break;
+ }
+
if (watched) {
copy_tv(&di1->di_tv, &oldtv);
}
@@ -9264,7 +9302,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
*/
static void f_extend(typval_T *argvars, typval_T *rettv)
{
- char *arg_errmsg = N_("extend() argument");
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
list_T *l1, *l2;
@@ -9274,7 +9312,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv)
l1 = argvars[0].vval.v_list;
l2 = argvars[1].vval.v_list;
- if (l1 != NULL && !tv_check_lock(l1->lv_lock, (char_u *)_(arg_errmsg))
+ if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, true)
&& l2 != NULL) {
if (argvars[2].v_type != VAR_UNKNOWN) {
before = get_tv_number_chk(&argvars[2], &error);
@@ -9304,7 +9342,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv)
d1 = argvars[0].vval.v_dict;
d2 = argvars[1].vval.v_dict;
- if (d1 != NULL && !tv_check_lock(d1->dv_lock, (char_u *)_(arg_errmsg))
+ if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, true)
&& d2 != NULL) {
/* Check the third argument. */
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -9450,19 +9488,21 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
int rem;
int todo;
char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
- char *arg_errmsg = (map ? N_("map() argument")
- : N_("filter() argument"));
+ char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
+ : N_("filter() argument"));
int save_did_emsg;
int idx = 0;
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) == NULL
- || tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))
+ || (!map && tv_check_lock(l->lv_lock, arg_errmsg, true))) {
return;
+ }
} else if (argvars[0].v_type == VAR_DICT) {
if ((d = argvars[0].vval.v_dict) == NULL
- || tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))
+ || (!map && tv_check_lock(d->dv_lock, arg_errmsg, true))) {
return;
+ }
} else {
EMSG2(_(e_listdictarg), ermsg);
return;
@@ -9491,17 +9531,26 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
for (hi = ht->ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
--todo;
+
di = HI2DI(hi);
- if (tv_check_lock(di->di_tv.v_lock,
- (char_u *)_(arg_errmsg)))
+ if (map
+ && (tv_check_lock(di->di_tv.v_lock, arg_errmsg, true)
+ || var_check_ro(di->di_flags, arg_errmsg, true))) {
break;
+ }
+
vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
int r = filter_map_one(&di->di_tv, expr, map, &rem);
clear_tv(&vimvars[VV_KEY].vv_tv);
if (r == FAIL || did_emsg)
break;
- if (!map && rem)
+ if (!map && rem) {
+ if (var_check_fixed(di->di_flags, arg_errmsg, true)
+ || var_check_ro(di->di_flags, arg_errmsg, true)) {
+ break;
+ }
dictitem_remove(d, di);
+ }
}
}
hash_unlock(ht);
@@ -9509,8 +9558,9 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
vimvars[VV_KEY].vv_type = VAR_NUMBER;
for (li = l->lv_first; li != NULL; li = nli) {
- if (tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg)))
+ if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, true)) {
break;
+ }
nli = li->li_next;
vimvars[VV_KEY].vv_nr = idx;
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
@@ -10373,6 +10423,14 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv)
dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
dict_add_nr_str(dict, "id", (long)cur->id, NULL);
+
+ if (cur->conceal_char) {
+ char_u buf[MB_MAXBYTES + 1];
+
+ buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
+ dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
+ }
+
list_append_dict(rettv->vval.v_list, dict);
cur = cur->next;
}
@@ -10544,9 +10602,10 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv)
varname = get_tv_string_chk(&argvars[1]);
tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
if (tp != NULL && varname != NULL) {
- /* Set tp to be our tabpage, temporarily. Also set the window to the
- * first window in the tabpage, otherwise the window is not valid. */
- if (switch_win(&oldcurwin, &oldtabpage, tp->tp_firstwin, tp, TRUE) == OK) {
+ // Set tp to be our tabpage, temporarily. Also set the window to the
+ // first window in the tabpage, otherwise the window is not valid.
+ win_T *window = tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin;
+ if (switch_win(&oldcurwin, &oldtabpage, window, tp, true) == OK) {
// look up the variable
// Let gettabvar({nr}, "") return the "t:" dictionary.
v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
@@ -10639,11 +10698,11 @@ getwinvar (
int off /* 1 for gettabwinvar() */
)
{
- win_T *win, *oldcurwin;
- char_u *varname;
- dictitem_T *v;
- tabpage_T *tp = NULL;
- tabpage_T *oldtabpage = NULL;
+ win_T *win, *oldcurwin;
+ char_u *varname;
+ dictitem_T *v;
+ tabpage_T *tp = NULL;
+ tabpage_T *oldtabpage = NULL;
bool done = false;
if (off == 1)
@@ -10658,12 +10717,16 @@ getwinvar (
rettv->vval.v_string = NULL;
if (win != NULL && varname != NULL) {
- /* Set curwin to be our win, temporarily. Also set the tabpage,
- * otherwise the window is not valid. */
- if (switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) {
- if (*varname == '&') { /* window-local-option */
- if (get_option_tv(&varname, rettv, 1) == OK)
+ // Set curwin to be our win, temporarily. Also set the tabpage,
+ // otherwise the window is not valid. Only do this when needed,
+ // autocommands get blocked.
+ bool need_switch_win = tp != curtab || win != curwin;
+ if (!need_switch_win
+ || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) {
+ if (*varname == '&') { // window-local-option
+ if (get_option_tv(&varname, rettv, 1) == OK) {
done = true;
+ }
} else {
// Look up the variable.
// Let getwinvar({nr}, "") return the "w:" dictionary.
@@ -10675,8 +10738,10 @@ getwinvar (
}
}
- /* restore previous notion of curwin */
- restore_win(oldcurwin, oldtabpage, TRUE);
+ if (need_switch_win) {
+ // restore previous notion of curwin
+ restore_win(oldcurwin, oldtabpage, true);
+ }
}
if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
@@ -10701,10 +10766,15 @@ static void f_glob(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (get_tv_number_chk(&argvars[1], &error))
options |= WILD_KEEP_ALL;
- if (argvars[2].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[2], &error)) {
- rettv->v_type = VAR_LIST;
- rettv->vval.v_list = NULL;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ if (get_tv_number_chk(&argvars[2], &error)) {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = NULL;
+ }
+ if (argvars[3].v_type != VAR_UNKNOWN
+ && get_tv_number_chk(&argvars[3], &error)) {
+ options |= WILD_ALLLINKS;
+ }
}
}
if (!error) {
@@ -10743,10 +10813,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv)
flags |= WILD_KEEP_ALL;
}
- if (argvars[3].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[3], &error)) {
- rettv->v_type = VAR_LIST;
- rettv->vval.v_list = NULL;
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ if (get_tv_number_chk(&argvars[3], &error)) {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = NULL;
+ }
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && get_tv_number_chk(&argvars[4], &error)) {
+ flags |= WILD_ALLLINKS;
+ }
}
}
@@ -10773,15 +10848,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv)
}
}
-/*
- * "glob2regpat()" function
- */
+// "glob2regpat()" function
static void f_glob2regpat(typval_T *argvars, typval_T *rettv)
{
- char_u *pat = get_tv_string_chk(&argvars[0]);
+ char_u *pat = get_tv_string_chk(&argvars[0]); // NULL on type error
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (pat == NULL)
+ ? NULL
+ : file_pat_to_reg_pat(pat, NULL, NULL, false);
}
/*
@@ -10881,6 +10956,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
#if !defined(UNIX)
"system", // TODO(SplinterOfChaos): This IS defined for UNIX!
#endif
+ "tablineat",
"tag_binary",
"tag_old_static",
"termresponse",
@@ -10938,8 +11014,6 @@ static void f_has(typval_T *argvars, typval_T *rettv)
#endif
} else if (STRICMP(name, "syntax_items") == 0) {
n = syntax_present(curwin);
- } else if (STRICMP(name, "gui_running") == 0) {
- n = ui_rgb_attached();
}
}
@@ -11394,14 +11468,18 @@ static void f_insert(typval_T *argvars, typval_T *rettv)
list_T *l;
int error = FALSE;
- if (argvars[0].v_type != VAR_LIST)
+ if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "insert()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("insert() argument"))) {
- if (argvars[2].v_type != VAR_UNKNOWN)
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("insert() argument"), true)) {
+ if (argvars[2].v_type != VAR_UNKNOWN) {
before = get_tv_number_chk(&argvars[2], &error);
- if (error)
- return; /* type error; errmsg already given */
+ }
+ if (error) {
+ // type error; errmsg already given
+ return;
+ }
if (before == l->lv_len)
item = NULL;
@@ -12424,7 +12502,8 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv)
char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
int prio = 10; /* default priority */
int id = -1;
- int error = FALSE;
+ int error = false;
+ char_u *conceal_char = NULL;
rettv->vval.v_number = -1;
@@ -12432,17 +12511,31 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv)
return;
if (argvars[2].v_type != VAR_UNKNOWN) {
prio = get_tv_number_chk(&argvars[2], &error);
- if (argvars[3].v_type != VAR_UNKNOWN)
+ if (argvars[3].v_type != VAR_UNKNOWN) {
id = get_tv_number_chk(&argvars[3], &error);
+ if (argvars[4].v_type != VAR_UNKNOWN) {
+ if (argvars[4].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ if (dict_find(argvars[4].vval.v_dict,
+ (char_u *)"conceal", -1) != NULL) {
+ conceal_char = get_dict_string(argvars[4].vval.v_dict,
+ (char_u *)"conceal", false);
+ }
+ }
+ }
}
- if (error == TRUE)
+ if (error == true) {
return;
+ }
if (id >= 1 && id <= 3) {
EMSGN("E798: ID is reserved for \":match\": %" PRId64, id);
return;
}
- rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+ rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
+ conceal_char);
}
static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL
@@ -12470,12 +12563,24 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_
int error = false;
int prio = 10;
int id = -1;
+ char_u *conceal_char = NULL;
if (argvars[2].v_type != VAR_UNKNOWN) {
- prio = get_tv_number_chk(&argvars[2], &error);
- if (argvars[3].v_type != VAR_UNKNOWN) {
- id = get_tv_number_chk(&argvars[3], &error);
+ prio = get_tv_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ id = get_tv_number_chk(&argvars[3], &error);
+ if (argvars[4].v_type != VAR_UNKNOWN) {
+ if (argvars[4].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ if (dict_find(argvars[4].vval.v_dict,
+ (char_u *)"conceal", -1) != NULL) {
+ conceal_char = get_dict_string(argvars[4].vval.v_dict,
+ (char_u *)"conceal", false);
+ }
}
+ }
}
if (error == true) {
return;
@@ -12487,7 +12592,8 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_
return;
}
- rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l);
+ rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
+ conceal_char);
}
/*
@@ -13855,19 +13961,20 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
char_u *key;
dict_T *d;
dictitem_T *di;
- char *arg_errmsg = N_("remove() argument");
+ char_u *arg_errmsg = (char_u *)N_("remove() argument");
if (argvars[0].v_type == VAR_DICT) {
- if (argvars[2].v_type != VAR_UNKNOWN)
+ if (argvars[2].v_type != VAR_UNKNOWN) {
EMSG2(_(e_toomanyarg), "remove()");
- else if ((d = argvars[0].vval.v_dict) != NULL
- && !tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg))) {
+ } else if ((d = argvars[0].vval.v_dict) != NULL
+ && !tv_check_lock(d->dv_lock, arg_errmsg, true)) {
key = get_tv_string_chk(&argvars[1]);
if (key != NULL) {
di = dict_find(d, key, -1);
- if (di == NULL)
+ if (di == NULL) {
EMSG2(_(e_dictkey), key);
- else {
+ } else if (!var_check_fixed(di->di_flags, arg_errmsg, true)
+ && !var_check_ro(di->di_flags, arg_errmsg, true)) {
*rettv = di->di_tv;
init_tv(&di->di_tv);
dictitem_remove(d, di);
@@ -13877,11 +13984,11 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
}
}
}
- } else if (argvars[0].v_type != VAR_LIST)
+ } else if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listdictarg), "remove()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg))) {
- int error = FALSE;
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock, arg_errmsg, true)) {
+ int error = (int)false;
idx = get_tv_number_chk(&argvars[1], &error);
if (error)
@@ -14155,10 +14262,11 @@ static void f_reverse(typval_T *argvars, typval_T *rettv)
list_T *l;
listitem_T *li, *ni;
- if (argvars[0].v_type != VAR_LIST)
+ if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "reverse()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("reverse() argument"))) {
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("reverse() argument"), true)) {
li = l->lv_last;
l->lv_first = l->lv_last = NULL;
l->lv_len = 0;
@@ -15159,6 +15267,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
list_T *l;
listitem_T *li;
dict_T *d;
+ list_T *s = NULL;
rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_LIST) {
@@ -15177,7 +15286,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
return;
}
if (!(dict_find(d, (char_u *)"group", -1) != NULL
- && dict_find(d, (char_u *)"pattern", -1) != NULL
+ && (dict_find(d, (char_u *)"pattern", -1) != NULL
+ || dict_find(d, (char_u *)"pos1", -1) != NULL)
&& dict_find(d, (char_u *)"priority", -1) != NULL
&& dict_find(d, (char_u *)"id", -1) != NULL)) {
EMSG(_(e_invarg));
@@ -15189,11 +15299,51 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
clear_matches(curwin);
li = l->lv_first;
while (li != NULL) {
+ int i = 0;
+ char_u buf[5];
+ dictitem_T *di;
+
d = li->li_tv.vval.v_dict;
- match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
- get_dict_string(d, (char_u *)"pattern", FALSE),
- (int)get_dict_number(d, (char_u *)"priority"),
- (int)get_dict_number(d, (char_u *)"id"), NULL);
+ if (dict_find(d, (char_u *)"pattern", -1) == NULL) {
+ if (s == NULL) {
+ s = list_alloc();
+ if (s == NULL) {
+ return;
+ }
+ }
+
+ // match from matchaddpos()
+ for (i = 1; i < 9; ++i) {
+ snprintf((char *)buf, sizeof(buf), (char *)"pos%d", i);
+ if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) {
+ if (di->di_tv.v_type != VAR_LIST) {
+ return;
+ }
+
+ list_append_tv(s, &di->di_tv);
+ s->lv_refcount++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ char_u *group = get_dict_string(d, (char_u *)"group", false);
+ int priority = get_dict_number(d, (char_u *)"priority");
+ int id = get_dict_number(d, (char_u *)"id");
+ char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
+ ? get_dict_string(d, (char_u *)"conceal",
+ false)
+ : NULL;
+ if (i == 0) {
+ match_add(curwin, group,
+ get_dict_string(d, (char_u *)"pattern", false),
+ priority, id, NULL, conceal);
+ } else {
+ match_add(curwin, group, NULL, priority, id, s, conceal);
+ list_unref(s);
+ s = NULL;
+ }
li = li->li_next;
}
rettv->vval.v_number = 0;
@@ -15416,26 +15566,32 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
varname = get_tv_string_chk(&argvars[off + 1]);
varp = &argvars[off + 2];
- if (win != NULL && varname != NULL && varp != NULL
- && switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) {
- if (*varname == '&') {
- long numval;
- char_u *strval;
- int error = FALSE;
-
- ++varname;
- numval = get_tv_number_chk(varp, &error);
- strval = get_tv_string_buf_chk(varp, nbuf);
- if (!error && strval != NULL)
- set_option_value(varname, numval, strval, OPT_LOCAL);
- } else {
- winvarname = xmalloc(STRLEN(varname) + 3);
- STRCPY(winvarname, "w:");
- STRCPY(winvarname + 2, varname);
- set_var(winvarname, varp, TRUE);
- xfree(winvarname);
+ if (win != NULL && varname != NULL && varp != NULL) {
+ bool need_switch_win = tp != curtab || win != curwin;
+ if (!need_switch_win
+ || switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) {
+ if (*varname == '&') {
+ long numval;
+ char_u *strval;
+ int error = false;
+
+ ++varname;
+ numval = get_tv_number_chk(varp, &error);
+ strval = get_tv_string_buf_chk(varp, nbuf);
+ if (!error && strval != NULL) {
+ set_option_value(varname, numval, strval, OPT_LOCAL);
+ }
+ } else {
+ winvarname = xmalloc(STRLEN(varname) + 3);
+ STRCPY(winvarname, "w:");
+ STRCPY(winvarname + 2, varname);
+ set_var(winvarname, varp, true);
+ xfree(winvarname);
+ }
+ }
+ if (need_switch_win) {
+ restore_win(save_curwin, save_curtab, true);
}
- restore_win(save_curwin, save_curtab, TRUE);
}
}
@@ -15654,8 +15810,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
l = argvars[0].vval.v_list;
- if (l == NULL || tv_check_lock(l->lv_lock,
- (char_u *)(sort ? _("sort() argument") : _("uniq() argument")))) {
+ if (l == NULL ||
+ tv_check_lock(l->lv_lock,
+ (char_u *)(sort
+ ? N_("sort() argument")
+ : N_("uniq() argument")),
+ true)) {
return;
}
rettv->vval.v_list = l;
@@ -15987,6 +16147,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
int base = 10;
char_u *p;
long n;
+ int what;
if (argvars[1].v_type != VAR_UNKNOWN) {
base = get_tv_number(&argvars[1]);
@@ -16000,11 +16161,20 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
if (*p == '+') {
p = skipwhite(p + 1);
}
- vim_str2nr(p, NULL, NULL,
- base == 2 ? 2 : 0,
- base == 8 ? 2 : 0,
- base == 16 ? 2 : 0,
- &n, NULL);
+ switch (base) {
+ case 2:
+ what = STR2NR_BIN + STR2NR_FORCE;
+ break;
+ case 8:
+ what = STR2NR_OCT + STR2NR_FORCE;
+ break;
+ case 16:
+ what = STR2NR_HEX + STR2NR_FORCE;
+ break;
+ default:
+ what = 0;
+ }
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
rettv->vval.v_number = n;
}
@@ -16116,13 +16286,23 @@ static void f_strlen(typval_T *argvars, typval_T *rettv)
static void f_strchars(typval_T *argvars, typval_T *rettv)
{
char_u *s = get_tv_string(&argvars[0]);
+ int skipcc = 0;
varnumber_T len = 0;
+ int (*func_mb_ptr2char_adv)(char_u **pp);
- while (*s != NUL) {
- mb_cptr2char_adv(&s);
- ++len;
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ skipcc = get_tv_number_chk(&argvars[1], NULL);
+ }
+ if (skipcc < 0 || skipcc > 1) {
+ EMSG(_(e_invarg));
+ } else {
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL) {
+ func_mb_ptr2char_adv(&s);
+ ++len;
+ }
+ rettv->vval.v_number = len;
}
- rettv->vval.v_number = len;
}
/*
@@ -17924,23 +18104,23 @@ void set_vim_var_list(int idx, list_T *val)
}
/// Set Dictionary v: variable to "val".
-void set_vim_var_dict(int idx, dict_T *val) FUNC_ATTR_NONNULL_ALL
+void set_vim_var_dict(int idx, dict_T *val)
{
dict_unref(vimvars[idx].vv_dict);
+ vimvars[idx].vv_dict = val;
- // Set readonly
- int todo = (int)val->dv_hashtab.ht_used;
- for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) {
- if (HASHITEM_EMPTY(hi)) {
- continue;
+ if (val != NULL) {
+ ++val->dv_refcount;
+ // Set readonly
+ size_t todo = val->dv_hashtab.ht_used;
+ for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) {
+ if (HASHITEM_EMPTY(hi)) {
+ continue;
+ }
+ --todo;
+ HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
}
-
- --todo;
- HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
}
-
- vimvars[idx].vv_dict = val;
- ++val->dv_refcount;
}
/*
@@ -18058,10 +18238,11 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
static int
get_var_tv (
char_u *name,
- int len, /* length of "name" */
- typval_T *rettv, /* NULL when only checking existence */
- int verbose, /* may give error message */
- int no_autoload /* do not use script autoloading */
+ int len, // length of "name"
+ typval_T *rettv, // NULL when only checking existence
+ dictitem_T **dip, // non-NULL when typval's dict item is needed
+ int verbose, // may give error message
+ int no_autoload // do not use script autoloading
)
{
int ret = OK;
@@ -18087,8 +18268,12 @@ get_var_tv (
*/
else {
v = find_var(name, NULL, no_autoload);
- if (v != NULL)
+ if (v != NULL) {
tv = &v->di_tv;
+ if (dip != NULL) {
+ *dip = v;
+ }
+ }
}
if (tv == NULL) {
@@ -18286,7 +18471,7 @@ long get_tv_number_chk(typval_T *varp, int *denote)
case VAR_STRING:
if (varp->vval.v_string != NULL) {
vim_str2nr(varp->vval.v_string, NULL, NULL,
- true, true, true, &n, NULL);
+ STR2NR_ALL, &n, NULL, 0);
}
return n;
case VAR_LIST:
@@ -18479,6 +18664,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
hashitem_T *hi;
*d = NULL;
+ if (name[0] == NUL) {
+ return NULL;
+ }
if (name[1] != ':') {
// name has implicit scope
if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
@@ -18528,6 +18716,7 @@ end:
}
// Find the hashtab used for a variable name.
+// Return NULL if the name is not valid.
// Set "varname" to the start of name without ':'.
static hashtab_T *find_var_ht(uint8_t *name, uint8_t **varname)
{
@@ -18635,14 +18824,16 @@ static void vars_clear_ext(hashtab_T *ht, int free_val)
if (!HASHITEM_EMPTY(hi)) {
--todo;
- /* Free the variable. Don't remove it from the hashtab,
- * ht_array might change then. hash_clear() takes care of it
- * later. */
+ // Free the variable. Don't remove it from the hashtab,
+ // ht_array might change then. hash_clear() takes care of it
+ // later.
v = HI2DI(hi);
- if (free_val)
+ if (free_val) {
clear_tv(&v->di_tv);
- if ((v->di_flags & DI_FLAGS_FIX) == 0)
+ }
+ if (v->di_flags & DI_FLAGS_ALLOC) {
xfree(v);
+ }
}
}
hash_clear(ht);
@@ -18749,10 +18940,11 @@ set_var (
return;
if (v != NULL) {
- /* existing variable, need to clear the value */
- if (var_check_ro(v->di_flags, name)
- || tv_check_lock(v->di_tv.v_lock, name))
+ // existing variable, need to clear the value
+ if (var_check_ro(v->di_flags, name, false)
+ || tv_check_lock(v->di_tv.v_lock, name, false)) {
return;
+ }
if (v->di_tv.v_type != tv->v_type
&& !((v->di_tv.v_type == VAR_STRING
|| v->di_tv.v_type == VAR_NUMBER)
@@ -18767,10 +18959,8 @@ set_var (
return;
}
- /*
- * Handle setting internal v: variables separately: we don't change
- * the type.
- */
+ // Handle setting internal v: variables separately where needed to
+ // prevent changing the type.
if (ht == &vimvarht) {
if (v->di_tv.v_type == VAR_STRING) {
xfree(v->di_tv.vval.v_string);
@@ -18781,9 +18971,8 @@ set_var (
v->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
- } else if (v->di_tv.v_type != VAR_NUMBER)
- EMSG2(_(e_intern2), "set_var()");
- else {
+ return;
+ } else if (v->di_tv.v_type == VAR_NUMBER) {
v->di_tv.vval.v_number = get_tv_number(tv);
if (STRCMP(varname, "searchforward") == 0)
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
@@ -18791,8 +18980,10 @@ set_var (
no_hlsearch = !v->di_tv.vval.v_number;
redraw_all_later(SOME_VALID);
}
+ return;
+ } else if (v->di_tv.v_type != tv->v_type) {
+ EMSG2(_(e_intern2), "set_var()");
}
- return;
}
if (watched) {
@@ -18816,7 +19007,7 @@ set_var (
xfree(v);
return;
}
- v->di_flags = 0;
+ v->di_flags = DI_FLAGS_ALLOC;
}
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
@@ -18837,34 +19028,31 @@ set_var (
}
}
-/*
- * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
- * Also give an error message.
- */
-static int var_check_ro(int flags, char_u *name)
+// Return true if di_flags "flags" indicates variable "name" is read-only.
+// Also give an error message.
+static bool var_check_ro(int flags, char_u *name, bool use_gettext)
{
if (flags & DI_FLAGS_RO) {
- EMSG2(_(e_readonlyvar), name);
- return TRUE;
+ EMSG2(_(e_readonlyvar), use_gettext ? (char_u *)_(name) : name);
+ return true;
}
if ((flags & DI_FLAGS_RO_SBX) && sandbox) {
- EMSG2(_(e_readonlysbx), name);
- return TRUE;
+ EMSG2(_(e_readonlysbx), use_gettext ? (char_u *)_(name) : name);
+ return true;
}
- return FALSE;
+ return false;
}
-/*
- * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
- * Also give an error message.
- */
-static int var_check_fixed(int flags, char_u *name)
+// Return true if di_flags "flags" indicates variable "name" is fixed.
+// Also give an error message.
+static bool var_check_fixed(int flags, char_u *name, bool use_gettext)
{
if (flags & DI_FLAGS_FIX) {
- EMSG2(_("E795: Cannot delete variable %s"), name);
- return TRUE;
+ EMSG2(_("E795: Cannot delete variable %s"),
+ use_gettext ? (char_u *)_(name) : name);
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -18912,23 +19100,28 @@ static int valid_varname(char_u *varname)
return TRUE;
}
-/*
- * Return TRUE if typeval "tv" is set to be locked (immutable).
- * Also give an error message, using "name".
- */
-static int tv_check_lock(int lock, char_u *name)
+// Return true if typeval "tv" is set to be locked (immutable).
+// Also give an error message, using "name" or _("name") when use_gettext is
+// true.
+static bool tv_check_lock(int lock, char_u *name, bool use_gettext)
{
if (lock & VAR_LOCKED) {
EMSG2(_("E741: Value is locked: %s"),
- name == NULL ? (char_u *)_("Unknown") : name);
- return TRUE;
+ name == NULL
+ ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return true;
}
if (lock & VAR_FIXED) {
EMSG2(_("E742: Cannot change value of %s"),
- name == NULL ? (char_u *)_("Unknown") : name);
- return TRUE;
+ name == NULL
+ ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -19521,7 +19714,10 @@ void ex_function(exarg_T *eap)
break;
}
}
- ++p; /* skip the ')' */
+ if (*p != ')') {
+ goto erret;
+ }
+ ++p; // skip the ')'
/* find extra arguments "range", "dict" and "abort" */
for (;; ) {
@@ -19745,13 +19941,14 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fudi.fd_di == NULL) {
- /* Can't add a function to a locked dictionary */
- if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg))
+ if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg, false)) {
+ // Can't add a function to a locked dictionary
goto erret;
- }
- /* Can't change an existing function if it is locked */
- else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg))
+ }
+ } else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, false)) {
+ // Can't change an existing function if it is locked
goto erret;
+ }
/* Give the function a sequential number. Can only be used with a
* Funcref! */
@@ -20707,7 +20904,7 @@ call_user_func (
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
} else {
v = xmalloc(sizeof(dictitem_T) + STRLEN(name));
- v->di_flags = DI_FLAGS_RO;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC;
}
STRCPY(v->di_key, name);
hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
@@ -20729,14 +20926,18 @@ call_user_func (
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 1;
- sourcing_name = xmalloc((save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
- + STRLEN(fp->uf_name) + 13);
+ // need space for function name + ("function " + 3) or "[number]"
+ size_t len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
+ + STRLEN(fp->uf_name) + 20;
+ sourcing_name = xmalloc(len);
{
if (save_sourcing_name != NULL
- && STRNCMP(save_sourcing_name, "function ", 9) == 0)
- sprintf((char *)sourcing_name, "%s..", save_sourcing_name);
- else
+ && STRNCMP(save_sourcing_name, "function ", 9) == 0) {
+ vim_snprintf((char *)sourcing_name, len, "%s[%zu]..",
+ save_sourcing_name, save_sourcing_lnum);
+ } else {
STRCPY(sourcing_name, "function ");
+ }
cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
if (p_verbose >= 12) {
@@ -22002,7 +22203,6 @@ static void on_process_exit(Process *proc, int status, void *d)
char msg[22];
snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status);
terminal_close(data->term, msg);
- apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, curbuf);
}
if (data->status_ptr) {