summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2026-04-20 16:14:11 +0800
committerGitHub <noreply@github.com>2026-04-20 08:14:11 +0000
commit2e8f285f6c1be6a55a9aae2fab64421f24bd7df0 (patch)
treea97d560798e5254381e1430a23de8c101761acb5 /src
parent61daad3bbaa30c916ee96dba4747fba3556878e1 (diff)
vim-patch:partial:9.2.0368: too many strlen() calls when adding strings to dicts (#39237)
Problem: too many strlen() calls when adding strings to dicts Solution: Refactor code to use string_T, use dict_add_string_len() instead of dict_add_string() (John Marriott) Additionally: - In textprop.c, in function prop_fill_dict() use a string_T to store local variable text_align. - In popupwin.c, use a string_T to store struct member pp_name in struct poppos_entry_T. - In mark.c, refactor function add_mark() to pass in the length of argument mname. - In insexpand.c: ->Use a string_T to store the elements of static array ctrl_x_mode_names. ->Refactor function trigger_complete_done_event(): ->->change type of argument char_u *word to string_T *word. ->->make one access of array ctrl_x_mode_names instead of two. ->Refactor function ins_compl_mode() to accept a string_T to return the resulting string. - In fileio.c: ->Refactor function getftypewfd() to accept a string_T to return the resulting string. ->In function create_readdirex_item() use a string_T to store local variable q. - In cmdexpand.c, store global cmdline_orig as a string_T. - In autocmd.c, in function f_autocmd_get() use a string_T to store local variables event_name and group_name. Measure their lengths once when they are assigned so they are not remeasured on each call to dict_add_string() in the subsequent for loop. - In channel.c, in function channel_part_info() drop local variable status and use s instead. Make s a string_T. closes: vim/vim#19999 https://github.com/vim/vim/commit/c13232699db413e735f30b5649c78a7f38a9a069 Co-authored-by: John Marriott <basilisk@internode.on.net>
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.h3
-rw-r--r--src/nvim/cmdexpand.c11
-rw-r--r--src/nvim/eval/funcs.c18
-rw-r--r--src/nvim/insexpand.c92
-rw-r--r--src/nvim/mark.c29
-rw-r--r--src/nvim/match.c6
-rw-r--r--src/nvim/memline.c8
-rw-r--r--src/nvim/menu.c11
-rw-r--r--src/nvim/optionstr.c2
-rw-r--r--src/nvim/quickfix.c13
-rw-r--r--src/nvim/sign.c6
11 files changed, 110 insertions, 89 deletions
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 21a8f796b9..0436b05ce5 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -99,7 +99,8 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder;
#define cbuf_as_string(d, s) ((String) { .data = d, .size = s })
-#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 })
+#define STATIC_CSTR_STRING_INIT(s) { .data = s, .size = sizeof("" s) - 1 }
+#define STATIC_CSTR_AS_STRING(s) ((String)STATIC_CSTR_STRING_INIT(s))
/// Create a new String instance, putting data in allocated memory
///
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 0c2c14bdb7..cfcc9c033e 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -96,7 +96,7 @@ static int compl_match_arraysize;
static int compl_startcol;
static int compl_selected;
/// cmdline before expansion
-static char *cmdline_orig = NULL;
+static String cmdline_orig = STRING_INIT;
#define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : matches[m])
@@ -341,8 +341,8 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
// Save cmdline before inserting selected item
if (!wild_navigate && ccline->cmdbuff != NULL) {
- xfree(cmdline_orig);
- cmdline_orig = xstrnsave(ccline->cmdbuff, (size_t)ccline->cmdlen);
+ xfree(cmdline_orig.data);
+ cmdline_orig = cstrn_to_string(ccline->cmdbuff, (size_t)ccline->cmdlen);
}
if (p != NULL && !got_int && !(options & WILD_NOSELECT)) {
@@ -1030,7 +1030,7 @@ void ExpandCleanup(expand_T *xp)
void clear_cmdline_orig(void)
{
- XFREE_CLEAR(cmdline_orig);
+ API_CLEAR_STRING(cmdline_orig);
}
/// Display one line of completion matches. Multiple matches are displayed in
@@ -4040,7 +4040,8 @@ void f_cmdcomplete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
dict_T *retdict = rettv->vval.v_dict;
- int ret = tv_dict_add_str(retdict, S_LEN("cmdline_orig"), cmdline_orig);
+ int ret = tv_dict_add_str_len(retdict, S_LEN("cmdline_orig"),
+ cmdline_orig.data, (int)cmdline_orig.size);
if (ret == OK) {
ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index c21655b7ab..ea017b5954 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -5140,28 +5140,32 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_dict_add_list(dict, S_LEN("regcontents"), list);
char buf[NUMBUFLEN + 2];
- buf[0] = NUL;
- buf[1] = NUL;
+ size_t buflen;
colnr_T reglen = 0;
switch (get_reg_type(regname, &reglen)) {
case kMTLineWise:
buf[0] = 'V';
+ buf[1] = NUL;
+ buflen = 1;
break;
case kMTCharWise:
buf[0] = 'v';
+ buf[1] = NUL;
+ buflen = 1;
break;
case kMTBlockWise:
- vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
+ buflen = vim_snprintf_safelen(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
break;
case kMTUnknown:
abort();
}
- tv_dict_add_str(dict, S_LEN("regtype"), buf);
+ tv_dict_add_str_len(dict, S_LEN("regtype"), buf, (int)buflen);
buf[0] = (char)get_register_name(get_unname_register());
buf[1] = NUL;
+ buflen = buf[0] == NUL ? 0 : 1;
if (regname == '"') {
- tv_dict_add_str(dict, S_LEN("points_to"), buf);
+ tv_dict_add_str_len(dict, S_LEN("points_to"), buf, (int)buflen);
} else {
tv_dict_add_bool(dict, S_LEN("isunnamed"),
regname == buf[0] ? kBoolVarTrue : kBoolVarFalse);
@@ -5170,10 +5174,10 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void return_register(int regname, typval_T *rettv)
{
- char buf[2] = { (char)regname, 0 };
+ char buf[2] = { (char)regname, NUL };
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = xstrdup(buf);
+ rettv->vval.v_string = xmemdupz(buf, buf[0] == NUL ? 0 : 1);
}
/// "reg_executing()" function
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 11794fd747..2be06a359b 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -137,27 +137,27 @@ static char *ctrl_x_msgs[] = {
N_(" Register completion (^N^P)"),
};
-static char *ctrl_x_mode_names[] = {
- "keyword",
- "ctrl_x",
- "scroll",
- "whole_line",
- "files",
- "tags",
- "path_patterns",
- "path_defines",
- "unknown", // CTRL_X_FINISHED
- "dictionary",
- "thesaurus",
- "cmdline",
- "function",
- "omni",
- "spell",
- NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
- "eval",
- "cmdline",
- NULL, // CTRL_X_BUFNAME
- "register",
+static String ctrl_x_mode_names[] = {
+ STATIC_CSTR_STRING_INIT("keyword"),
+ STATIC_CSTR_STRING_INIT("ctrl_x"),
+ STATIC_CSTR_STRING_INIT("scroll"),
+ STATIC_CSTR_STRING_INIT("whole_line"),
+ STATIC_CSTR_STRING_INIT("files"),
+ STATIC_CSTR_STRING_INIT("tags"),
+ STATIC_CSTR_STRING_INIT("path_patterns"),
+ STATIC_CSTR_STRING_INIT("path_defines"),
+ STATIC_CSTR_STRING_INIT("unknown"), // CTRL_X_FINISHED
+ STATIC_CSTR_STRING_INIT("dictionary"),
+ STATIC_CSTR_STRING_INIT("thesaurus"),
+ STATIC_CSTR_STRING_INIT("cmdline"),
+ STATIC_CSTR_STRING_INIT("function"),
+ STATIC_CSTR_STRING_INIT("omni"),
+ STATIC_CSTR_STRING_INIT("spell"),
+ STRING_INIT, // CTRL_X_LOCAL_MSG is only used in "ctrl_x_msgs"
+ STATIC_CSTR_STRING_INIT("eval"),
+ STATIC_CSTR_STRING_INIT("cmdline"),
+ STRING_INIT, // CTRL_X_BUFNAME
+ STATIC_CSTR_STRING_INIT("register"),
};
/// Structure used to store one match for insert completion.
@@ -638,21 +638,25 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_match;
}
-static void do_autocmd_completedone(int c, int mode, char *word)
+static void do_autocmd_completedone(int c, int mode, String *word)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
- mode = mode & ~CTRL_X_WANT_IDENT;
- char *mode_str = NULL;
- if (ctrl_x_mode_names[mode]) {
- mode_str = ctrl_x_mode_names[mode];
+ if (word == NULL || word->data == NULL) {
+ tv_dict_add_str_len(v_event, S_LEN("complete_word"), "", 0);
+ } else {
+ tv_dict_add_str_len(v_event, S_LEN("complete_word"), word->data, (int)word->size);
}
- tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : "");
- tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : "");
+
+ String *mode_str = &ctrl_x_mode_names[mode & ~CTRL_X_WANT_IDENT];
+ tv_dict_add_str_len(v_event, S_LEN("complete_type"),
+ mode_str->data == NULL ? "" : mode_str->data,
+ (int)mode_str->size);
tv_dict_add_str(v_event, S_LEN("reason"),
- (c == Ctrl_Y || word != NULL ? "accept" : (c == Ctrl_E ? "cancel" : "discard")));
+ (c == Ctrl_Y || (word != NULL && word->data != NULL)
+ ? "accept" : (c == Ctrl_E ? "cancel" : "discard")));
tv_dict_set_keys_readonly(v_event);
ins_apply_autocmds(EVENT_COMPLETEDONE);
@@ -1319,13 +1323,13 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
{
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
- tv_dict_add_str(dict, S_LEN("word"), match->cp_str.data);
+ tv_dict_add_str_len(dict, S_LEN("word"), match->cp_str.data, (int)match->cp_str.size);
tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]);
tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]);
tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]);
tv_dict_add_str(dict, S_LEN("info"), match->cp_text[CPT_INFO]);
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
- tv_dict_add_str(dict, S_LEN("user_data"), "");
+ tv_dict_add_str_len(dict, S_LEN("user_data"), "", 0);
} else {
tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data);
}
@@ -2648,14 +2652,14 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
}
- char *word = NULL;
+ String word = STRING_INIT;
// If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) {
- word = xstrdup(compl_shown_match->cp_str.data);
+ word = copy_string(compl_shown_match->cp_str, NULL);
retval = true;
// May need to remove ComplMatchIns highlight.
redrawWinline(curwin, curwin->w_cursor.lnum);
@@ -2665,10 +2669,10 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
// (eg: only one match with 'completeopt' "menu" without "menuone"),
// the user had no opportunity to explicitly accept or dismiss it,
// so treat this as an implicit accept (#38160).
- if (word == NULL && c != Ctrl_E && compl_used_match && compl_match_array == NULL
+ if (word.data == NULL && c != Ctrl_E && compl_used_match && compl_match_array == NULL
&& compl_curr_match != NULL
&& compl_curr_match->cp_str.data != NULL) {
- word = xstrdup(compl_curr_match->cp_str.data);
+ word = copy_string(compl_curr_match->cp_str, NULL);
}
// CTRL-E means completion is Ended, go back to the typed text.
@@ -2731,8 +2735,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- do_autocmd_completedone(c, prev_mode, word);
- xfree(word);
+ do_autocmd_completedone(c, prev_mode, &word);
+ xfree(word.data);
return retval;
}
@@ -3517,12 +3521,13 @@ void f_complete_check(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
/// Return Insert completion mode name string
-static char *ins_compl_mode(void)
+static String ins_compl_mode(void)
{
if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started) {
- return ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
+ String *mode = &ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
+ return cbuf_as_string(mode->data == NULL ? "" : mode->data, mode->size);
}
- return "";
+ return cbuf_as_string("", 0);
}
/// Assign the sequence number to all the completion matches which don't have
@@ -3577,7 +3582,7 @@ static void ins_compl_update_sequence_numbers(void)
/// Fill the dict of complete_info
static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match)
{
- tv_dict_add_str(di, S_LEN("word"), match->cp_str.data);
+ tv_dict_add_str_len(di, S_LEN("word"), match->cp_str.data, (int)match->cp_str.size);
tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]);
tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]);
tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]);
@@ -3587,7 +3592,7 @@ static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match)
}
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
// Add an empty string for backwards compatibility
- tv_dict_add_str(di, S_LEN("user_data"), "");
+ tv_dict_add_str_len(di, S_LEN("user_data"), "", 0);
} else {
tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
}
@@ -3635,7 +3640,8 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
int ret = OK;
if (what_flag & CI_WHAT_MODE) {
- ret = tv_dict_add_str(retdict, S_LEN("mode"), ins_compl_mode());
+ String mode = ins_compl_mode();
+ ret = tv_dict_add_str_len(retdict, S_LEN("mode"), mode.data, (int)mode.size);
}
if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) {
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 100921d682..dd49276edc 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -1912,8 +1912,9 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp)
}
// Add information about mark 'mname' to list 'l'
-static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, const char *fname)
- FUNC_ATTR_NONNULL_ARG(1, 2, 3)
+static int add_mark(list_T *l, const char *mname, size_t mnamelen, const pos_T *pos, int bufnr,
+ const char *fname)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
if (pos->lnum <= 0) {
return OK;
@@ -1929,7 +1930,7 @@ static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, c
tv_list_append_number(lpos, pos->col < MAXCOL ? pos->col + 1 : MAXCOL);
tv_list_append_number(lpos, pos->coladd);
- if (tv_dict_add_str(d, S_LEN("mark"), mname) == FAIL
+ if (tv_dict_add_str_len(d, S_LEN("mark"), mname, (int)mnamelen) == FAIL
|| tv_dict_add_list(d, S_LEN("pos"), lpos) == FAIL
|| (fname != NULL && tv_dict_add_str(d, S_LEN("file"), fname) == FAIL)) {
return FAIL;
@@ -1946,23 +1947,24 @@ void get_buf_local_marks(const buf_T *buf, list_T *l)
FUNC_ATTR_NONNULL_ALL
{
char mname[3] = "' ";
+ size_t mnamelen = STRLEN_LITERAL("' ");
// Marks 'a' to 'z'
for (int i = 0; i < NMARKS; i++) {
mname[1] = (char)('a' + i);
- add_mark(l, mname, &buf->b_namedm[i].mark, buf->b_fnum, NULL);
+ add_mark(l, mname, mnamelen, &buf->b_namedm[i].mark, buf->b_fnum, NULL);
}
// Mark '' is a window local mark and not a buffer local mark
- add_mark(l, "''", &curwin->w_pcmark, curbuf->b_fnum, NULL);
+ add_mark(l, S_LEN("''"), &curwin->w_pcmark, curbuf->b_fnum, NULL);
- add_mark(l, "'\"", &buf->b_last_cursor.mark, buf->b_fnum, NULL);
- add_mark(l, "'[", &buf->b_op_start, buf->b_fnum, NULL);
- add_mark(l, "']", &buf->b_op_end, buf->b_fnum, NULL);
- add_mark(l, "'^", &buf->b_last_insert.mark, buf->b_fnum, NULL);
- add_mark(l, "'.", &buf->b_last_change.mark, buf->b_fnum, NULL);
- add_mark(l, "'<", &buf->b_visual.vi_start, buf->b_fnum, NULL);
- add_mark(l, "'>", &buf->b_visual.vi_end, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'\""), &buf->b_last_cursor.mark, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'["), &buf->b_op_start, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("']"), &buf->b_op_end, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'^"), &buf->b_last_insert.mark, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'."), &buf->b_last_change.mark, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'<"), &buf->b_visual.vi_start, buf->b_fnum, NULL);
+ add_mark(l, S_LEN("'>"), &buf->b_visual.vi_end, buf->b_fnum, NULL);
}
/// Get a global mark
@@ -1982,6 +1984,7 @@ void get_global_marks(list_T *l)
FUNC_ATTR_NONNULL_ALL
{
char mname[3] = "' ";
+ size_t mnamelen = STRLEN_LITERAL("' ");
char *name;
// Marks 'A' to 'Z' and '0' to '9'
@@ -1994,7 +1997,7 @@ void get_global_marks(list_T *l)
if (name != NULL) {
mname[1] = i >= NMARKS ? (char)(i - NMARKS + '0') : (char)(i + 'A');
- add_mark(l, mname, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name);
+ add_mark(l, mname, mnamelen, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name);
if (namedfm[i].fmark.fnum != 0) {
xfree(name);
}
diff --git a/src/nvim/match.c b/src/nvim/match.c
index 5d95d06661..10d02356fd 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -907,9 +907,9 @@ void f_getmatches(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (cur->mit_conceal_char) {
char buf[MB_MAXCHAR + 1];
-
- buf[utf_char2bytes(cur->mit_conceal_char, buf)] = NUL;
- tv_dict_add_str(dict, S_LEN("conceal"), buf);
+ int buflen = utf_char2bytes(cur->mit_conceal_char, buf);
+ buf[buflen] = NUL;
+ tv_dict_add_str_len(dict, S_LEN("conceal"), buf, buflen);
}
tv_list_append_dict(rettv->vval.v_list, dict);
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index a0a9c84d0d..b5ac0cdb28 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1496,9 +1496,9 @@ void swapfile_dict(const char *fname, dict_T *d)
if ((fd = os_open(fname, O_RDONLY, 0)) >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
if (ml_check_b0_id(&b0) == FAIL) {
- tv_dict_add_str(d, S_LEN("error"), "Not a swap file");
+ tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Not a swap file"));
} else if (b0_magic_wrong(&b0)) {
- tv_dict_add_str(d, S_LEN("error"), "Magic number mismatch");
+ tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Magic number mismatch"));
} else {
// We have swap information.
tv_dict_add_str_len(d, S_LEN("version"), b0.b0_version, 10);
@@ -1515,11 +1515,11 @@ void swapfile_dict(const char *fname, dict_T *d)
tv_dict_add_nr(d, S_LEN("inode"), char_to_long(b0.b0_ino));
}
} else {
- tv_dict_add_str(d, S_LEN("error"), "Cannot read file");
+ tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Cannot read file"));
}
close(fd);
} else {
- tv_dict_add_str(d, S_LEN("error"), "Cannot open file");
+ tv_dict_add_str_len(d, S_LEN("error"), S_LEN("Cannot open file"));
}
}
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index d4fd0a067c..db4d325d77 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -674,8 +674,8 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
if (menu->mnemonic) {
char buf[MB_MAXCHAR + 1] = { 0 }; // > max value of utf8_char2bytes
- utf_char2bytes(menu->mnemonic, buf);
- tv_dict_add_str(dict, S_LEN("shortcut"), buf);
+ int buflen = utf_char2bytes(menu->mnemonic, buf);
+ tv_dict_add_str_len(dict, S_LEN("shortcut"), buf, buflen);
}
if (menu->actext) {
@@ -1864,8 +1864,9 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m
tv_dict_add_str(dict, S_LEN("modes"), get_menu_mode_str(menu->modes));
char buf[NUMBUFLEN];
- buf[utf_char2bytes(menu->mnemonic, buf)] = NUL;
- tv_dict_add_str(dict, S_LEN("shortcut"), buf);
+ int buflen = utf_char2bytes(menu->mnemonic, buf);
+ buf[buflen] = NUL;
+ tv_dict_add_str_len(dict, S_LEN("shortcut"), buf, buflen);
if (menu->children == NULL) { // leaf menu
int bit;
@@ -1877,7 +1878,7 @@ static void menuitem_getinfo(const char *menu_name, const vimmenu_T *menu, int m
if (menu->strings[bit] != NULL) {
tv_dict_add_allocated_str(dict, S_LEN("rhs"),
*menu->strings[bit] == NUL
- ? xstrdup("<Nop>")
+ ? xmemdupz(S_LEN("<Nop>"))
: str2special_save(menu->strings[bit], false, false));
}
tv_dict_add_bool(dict, S_LEN("noremenu"), menu->noremap[bit] == REMAP_NONE);
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 91f52bbcd2..274fbb653c 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -2223,7 +2223,7 @@ struct chars_tab {
};
#define CHARSTAB_ENTRY(cp, name, def, fallback) \
- { (cp), { name, STRLEN_LITERAL(name) }, def, fallback }
+ { (cp), STATIC_CSTR_STRING_INIT(name), def, fallback }
static fcs_chars_T fcs_chars;
static const struct chars_tab fcs_tab[] = {
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 1c332d5885..9e90aabc5d 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -6104,6 +6104,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
char buf[2];
buf[0] = qfp->qf_type;
buf[1] = NUL;
+ size_t buflen = (buf[0] == NUL) ? 0 : 1;
if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
|| (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum) == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("end_lnum"), (varnumber_T)qfp->qf_end_lnum) == FAIL)
@@ -6116,7 +6117,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
|| (tv_dict_add_str(dict, S_LEN("pattern"), (qfp->qf_pattern == NULL ? "" : qfp->qf_pattern))
== FAIL)
|| (tv_dict_add_str(dict, S_LEN("text"), (qfp->qf_text == NULL ? "" : qfp->qf_text)) == FAIL)
- || (tv_dict_add_str(dict, S_LEN("type"), buf) == FAIL)
+ || (tv_dict_add_str_len(dict, S_LEN("type"), buf, (int)buflen) == FAIL)
|| (qfp->qf_user_data.v_type != VAR_UNKNOWN
&& tv_dict_add_tv(dict, S_LEN("user_data"), &qfp->qf_user_data) == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid) == FAIL)) {
@@ -6372,7 +6373,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
int status = OK;
if (flags & QF_GETLIST_TITLE) {
- status = tv_dict_add_str(retdict, S_LEN("title"), "");
+ status = tv_dict_add_str_len(retdict, S_LEN("title"), "", 0);
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
list_T *l = tv_list_alloc(kListLenMayKnow);
@@ -6385,7 +6386,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi));
}
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
- status = tv_dict_add_str(retdict, S_LEN("context"), "");
+ status = tv_dict_add_str_len(retdict, S_LEN("context"), "", 0);
}
if ((status == OK) && (flags & QF_GETLIST_ID)) {
status = tv_dict_add_nr(retdict, S_LEN("id"), 0);
@@ -6406,7 +6407,7 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *r
status = qf_getprop_qfbufnr(qi, retdict);
}
if ((status == OK) && (flags & QF_GETLIST_QFTF)) {
- status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), "");
+ status = tv_dict_add_str_len(retdict, S_LEN("quickfixtextfunc"), "", 0);
}
return status;
@@ -6460,7 +6461,7 @@ static int qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
tv_dict_item_free(di);
}
} else {
- status = tv_dict_add_str(retdict, S_LEN("context"), "");
+ status = tv_dict_add_str_len(retdict, S_LEN("context"), "", 0);
}
return status;
@@ -6494,7 +6495,7 @@ static int qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
status = tv_dict_add_tv(retdict, S_LEN("quickfixtextfunc"), &tv);
tv_clear(&tv);
} else {
- status = tv_dict_add_str(retdict, S_LEN("quickfixtextfunc"), "");
+ status = tv_dict_add_str_len(retdict, S_LEN("quickfixtextfunc"), "", 0);
}
return status;
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 882295a7c1..49f56795a1 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -916,7 +916,11 @@ static dict_T *sign_get_info_dict(sign_T *sp)
for (int i = 0; i < 4; i++) {
if (hl[i] > 0) {
const char *p = get_highlight_name_ext(NULL, hl[i] - 1, false);
- tv_dict_add_str(d, arg[i], strlen(arg[i]), p ? p : "NONE");
+ if (p == NULL) {
+ tv_dict_add_str_len(d, arg[i], strlen(arg[i]), S_LEN("NONE"));
+ } else {
+ tv_dict_add_str(d, arg[i], strlen(arg[i]), p);
+ }
}
}
return d;