patch 9.2.0368: too many strlen() calls when adding strings to dicts
Commit:
https://github.com/vim/vim/commit/c13232699db413e735f30b5649c78a7f38a9a069
Author: John Marriott <[email protected]>
Date: Sun Apr 19 20:58:33 2026 +0000
patch 9.2.0368: too many strlen() calls when adding strings to dicts
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: #19999
Signed-off-by: John Marriott <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
diff --git a/src/autocmd.c b/src/autocmd.c
index b27297f79..99d6b3c92 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -3343,7 +3343,7 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
AutoCmd *ac;
list_T *event_list;
dict_T *event_dict;
- char_u *event_name = NULL;
+ string_T event_name = {NULL, 0};
char_u *pat = NULL;
char_u *name = NULL;
int group = AUGROUP_ALL;
@@ -3425,12 +3425,13 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
if (event_arg != NUM_EVENTS && event != event_arg)
continue;
- event_name = event_nr2name(event);
+ event_name.string = event_nr2name(event);
+ event_name.length = STRLEN(event_name.string);
// iterate through all the patterns for this autocmd event
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
{
- char_u *group_name;
+ string_T group_name;
if (ap->pat == NULL) // pattern has been removed
continue;
@@ -3441,7 +3442,14 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
if (pat != NULL && STRCMP(pat, ap->pat) != 0)
continue;
- group_name = get_augroup_name(NULL, ap->group);
+ group_name.string = get_augroup_name(NULL, ap->group);
+ if (group_name.string == NULL)
+ {
+ group_name.string = (char_u *)"";
+ group_name.length = 0;
+ }
+ else
+ group_name.length = STRLEN(group_name.string);
// iterate through all the commands for this pattern and add one
// item for each cmd.
@@ -3455,10 +3463,10 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
return;
}
- if (dict_add_string(event_dict, "event", event_name) == FAIL
- || dict_add_string(event_dict, "group",
- group_name == NULL ? (char_u *)""
- : group_name) == FAIL
+ if (dict_add_string_len(event_dict, "event",
+ event_name.string, (int)event_name.length) == FAIL
+ || dict_add_string_len(event_dict, "group",
+ group_name.string, (int)group_name.length) == FAIL
|| (ap->buflocal_nr != 0
&& (dict_add_number(event_dict, "bufnr",
ap->buflocal_nr) == FAIL))
diff --git a/src/channel.c b/src/channel.c
index d58c69708..56878458e 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3668,46 +3668,98 @@ channel_part_info(channel_T *channel, dict_T *dict,
char *name, ch_part_T part)
chanpart_T *chanpart = &channel->ch_part[part];
char namebuf[20]; // longest is "sock_timeout"
size_t tail;
- char *status;
- char *s = "";
+ string_T s;
vim_strncpy((char_u *)namebuf, (char_u *)name, 4);
- STRCAT(namebuf, "_");
tail = STRLEN(namebuf);
+ STRCPY(namebuf + tail, "_");
+ tail += STRLEN_LITERAL("_");
STRCPY(namebuf + tail, "status");
if (chanpart->ch_fd != INVALID_FD)
- status = "open";
+ {
+ s.string = (char_u *)"open";
+ s.length = STRLEN_LITERAL("open");
+ }
else if (channel_has_readahead(channel, part))
- status = "buffered";
+ {
+ s.string = (char_u *)"buffered";
+ s.length = STRLEN_LITERAL("buffered");
+ }
else
- status = "closed";
- dict_add_string(dict, namebuf, (char_u *)status);
+ {
+ s.string = (char_u *)"closed";
+ s.length = STRLEN_LITERAL("closed");
+ }
+ dict_add_string_len(dict, namebuf, s.string, (int)s.length);
STRCPY(namebuf + tail, "mode");
switch (chanpart->ch_mode)
{
- case CH_MODE_NL: s = "NL"; break;
- case CH_MODE_RAW: s = "RAW"; break;
- case CH_MODE_JSON: s = "JSON"; break;
- case CH_MODE_JS: s = "JS"; break;
- case CH_MODE_LSP: s = "LSP"; break;
- case CH_MODE_DAP: s = "DAP"; break;
+ case CH_MODE_NL:
+ s.string = (char_u *)"NL";
+ s.length = STRLEN_LITERAL("NL");
+ break;
+ case CH_MODE_RAW:
+ s.string = (char_u *)"RAW";
+ s.length = STRLEN_LITERAL("RAW");
+ break;
+ case CH_MODE_JSON:
+ s.string = (char_u *)"JSON";
+ s.length = STRLEN_LITERAL("JSON");
+ break;
+ case CH_MODE_JS:
+ s.string = (char_u *)"JS";
+ s.length = STRLEN_LITERAL("JS");
+ break;
+ case CH_MODE_LSP:
+ s.string = (char_u *)"LSP";
+ s.length = STRLEN_LITERAL("LSP");
+ break;
+ case CH_MODE_DAP:
+ s.string = (char_u *)"DAP";
+ s.length = STRLEN_LITERAL("DAP");
+ break;
+ default:
+ s.string = (char_u *)"";
+ s.length = 0;
+ break;
}
- dict_add_string(dict, namebuf, (char_u *)s);
+ dict_add_string_len(dict, namebuf, s.string, (int)s.length);
STRCPY(namebuf + tail, "io");
if (part == PART_SOCK)
- s = "socket";
+ {
+ s.string = (char_u *)"socket";
+ s.length = STRLEN_LITERAL("socket");
+ }
else switch (chanpart->ch_io)
{
- case JIO_NULL: s = "null"; break;
- case JIO_PIPE: s = "pipe"; break;
- case JIO_FILE: s = "file"; break;
- case JIO_BUFFER: s = "buffer"; break;
- case JIO_OUT: s = "out"; break;
+ case JIO_NULL:
+ s.string = (char_u *)"null";
+ s.length = STRLEN_LITERAL("null");
+ break;
+ case JIO_PIPE:
+ s.string = (char_u *)"pipe";
+ s.length = STRLEN_LITERAL("pipe");
+ break;
+ case JIO_FILE:
+ s.string = (char_u *)"file";
+ s.length = STRLEN_LITERAL("file");
+ break;
+ case JIO_BUFFER:
+ s.string = (char_u *)"buffer";
+ s.length = STRLEN_LITERAL("buffer");
+ break;
+ case JIO_OUT:
+ s.string = (char_u *)"out";
+ s.length = STRLEN_LITERAL("out");
+ break;
+ default:
+ s.string = (char_u *)"";
+ s.length = 0;
}
- dict_add_string(dict, namebuf, (char_u *)s);
+ dict_add_string_len(dict, namebuf, s.string, (int)s.length);
STRCPY(namebuf + tail, "timeout");
dict_add_number(dict, namebuf, chanpart->ch_timeout);
@@ -5066,7 +5118,7 @@ ch_expr_common(typval_T *argvars, typval_T *rettv, int
eval)
id = di->di_tv.vval.v_number;
}
if (ch_mode == CH_MODE_LSP && !dict_has_key(d, "jsonrpc"))
- dict_add_string(d, "jsonrpc", (char_u *)"2.0");
+ dict_add_string_len(d, "jsonrpc", (char_u *)"2.0",
STRLEN_LITERAL("2.0"));
text = json_encode_lsp_msg(&argvars[1]);
}
else
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index 63757179a..befc18c79 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -36,7 +36,7 @@ static int compl_match_arraysize;
static int compl_startcol;
static int compl_selected;
// cmdline before expansion
-static char_u *cmdline_orig = NULL;
+static string_T cmdline_orig = {NULL, 0};
#define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m]) : matches[m])
@@ -338,8 +338,12 @@ nextwild(
// Save cmdline before inserting selected item
if (!wild_navigate && ccline->cmdbuff != NULL)
{
- vim_free(cmdline_orig);
- cmdline_orig = vim_strnsave(ccline->cmdbuff, ccline->cmdlen);
+ vim_free(cmdline_orig.string);
+ cmdline_orig.string = vim_strnsave(ccline->cmdbuff, ccline->cmdlen);
+ if (cmdline_orig.string == NULL)
+ cmdline_orig.length = 0;
+ else
+ cmdline_orig.length = ccline->cmdlen;
}
if (p != NULL && !got_int && !(options & WILD_NOSELECT))
@@ -1188,7 +1192,7 @@ ExpandCleanup(expand_T *xp)
void
clear_cmdline_orig(void)
{
- VIM_CLEAR(cmdline_orig);
+ VIM_CLEAR_STRING(cmdline_orig);
}
/*
@@ -4715,7 +4719,8 @@ f_cmdcomplete_info(typval_T *argvars UNUSED, typval_T
*rettv)
|| ccline->xpc == NULL || ccline->xpc->xp_files == NULL)
return;
retdict = rettv->vval.v_dict;
- ret = dict_add_string(retdict, "cmdline_orig", cmdline_orig);
+ ret = dict_add_string_len(retdict, "cmdline_orig",
+ cmdline_orig.string, (int)cmdline_orig.length);
if (ret == OK)
ret = dict_add_number(retdict, "pum_visible", pum_visible());
if (ret == OK)
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 04774128d..e03dc9b20 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -10416,6 +10416,7 @@ f_getreginfo(typval_T *argvars, typval_T *rettv)
{
int regname;
char_u buf[NUMBUFLEN + 2];
+ size_t buflen;
long reglen = 0;
dict_T *dict;
list_T *list;
@@ -10439,23 +10440,34 @@ f_getreginfo(typval_T *argvars, typval_T *rettv)
return;
(void)dict_add_list(dict, "regcontents", list);
- buf[0] = NUL;
- buf[1] = NUL;
switch (get_reg_type(regname, ®len))
{
- case MLINE: buf[0] = 'V'; break;
- case MCHAR: buf[0] = 'v'; break;
+ case MLINE:
+ buf[0] = 'V';
+ buf[1] = NUL;
+ buflen = 1;
+ break;
+ case MCHAR:
+ buf[0] = 'v';
+ buf[1] = NUL;
+ buflen = 1;
+ break;
case MBLOCK:
- vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
- reglen + 1);
- break;
+ buflen = vim_snprintf_safelen((char *)buf, sizeof(buf),
+ "%c%ld", Ctrl_V, reglen + 1);
+ break;
+ default:
+ buf[0] = NUL;
+ buflen = 0;
+ break;
}
- (void)dict_add_string(dict, (char *)"regtype", buf);
+ (void)dict_add_string_len(dict, (char *)"regtype", buf, (int)buflen);
buf[0] = get_register_name(get_unname_register());
buf[1] = NUL;
+ buflen = (buf[0] == NUL) ? 0 : 1;
if (regname == '"')
- (void)dict_add_string(dict, (char *)"points_to", buf);
+ (void)dict_add_string_len(dict, (char *)"points_to", buf, (int)buflen);
else
{
dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
@@ -10473,11 +10485,11 @@ f_getreginfo(typval_T *argvars, typval_T *rettv)
static void
return_register(int regname, typval_T *rettv)
{
- char_u buf[2] = {0, 0};
+ char_u buf[2] = {NUL, NUL};
buf[0] = (char_u)regname;
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strsave(buf);
+ rettv->vval.v_string = vim_strnsave(buf, (buf[0] == NUL) ? 0 : 1);
}
/*
diff --git a/src/fileio.c b/src/fileio.c
index 1906a4316..b023e5a0d 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4811,8 +4811,8 @@ getfpermwfd(WIN32_FIND_DATAW *wfd, char_u *perm)
return getfpermst(&st, perm);
}
- static char_u *
-getftypewfd(WIN32_FIND_DATAW *wfd)
+ static void
+getftypewfd(WIN32_FIND_DATAW *wfd, string_T *ret)
{
DWORD flag = wfd->dwFileAttributes;
DWORD tag = wfd->dwReserved0;
@@ -4820,20 +4820,40 @@ getftypewfd(WIN32_FIND_DATAW *wfd)
if (flag & FILE_ATTRIBUTE_REPARSE_POINT)
{
if (tag == IO_REPARSE_TAG_MOUNT_POINT)
- return (char_u*)"junction";
+ {
+ ret->string = (char_u *)"junction";
+ ret->length = STRLEN_LITERAL("junction");
+ return;
+ }
if (tag == IO_REPARSE_TAG_SYMLINK)
{
if (flag & FILE_ATTRIBUTE_DIRECTORY)
- return (char_u*)"linkd";
+ {
+ ret->string = (char_u *)"linkd";
+ ret->length = STRLEN_LITERAL("linkd");
+ return;
+ }
- return (char_u*)"link";
+ ret->string = (char_u *)"link";
+ ret->length = STRLEN_LITERAL("link");
+ return;
}
- return (char_u*)"reparse"; // unknown reparse point type
+
+ // unknown reparse point type
+ ret->string = (char_u *)"reparse";
+ ret->length = STRLEN_LITERAL("reparse");
+ return;
}
+
if (flag & FILE_ATTRIBUTE_DIRECTORY)
- return (char_u*)"dir";
+ {
+ ret->string = (char_u *)"dir";
+ ret->length = STRLEN_LITERAL("dir");
+ return;
+ }
- return (char_u*)"file";
+ ret->string = (char_u *)"file";
+ ret->length = STRLEN_LITERAL("file");
}
static dict_T *
@@ -4843,6 +4863,7 @@ create_readdirex_item(WIN32_FIND_DATAW *wfd)
char_u *p;
varnumber_T size, time;
char_u permbuf[] = "---------";
+ string_T s;
item = dict_alloc();
if (item == NULL)
@@ -4870,14 +4891,15 @@ create_readdirex_item(WIN32_FIND_DATAW *wfd)
if (dict_add_number(item, "time", time) == FAIL)
goto theend;
- if (dict_add_string(item, "type", getftypewfd(wfd)) == FAIL)
+ getftypewfd(wfd, &s);
+ if (dict_add_string_len(item, "type", s.string, (int)s.length) == FAIL)
goto theend;
if (dict_add_string(item, "perm", getfpermwfd(wfd, permbuf)) == FAIL)
goto theend;
- if (dict_add_string(item, "user", (char_u*)"") == FAIL)
+ if (dict_add_string_len(item, "user", (char_u *)"", 0) == FAIL)
goto theend;
- if (dict_add_string(item, "group", (char_u*)"") == FAIL)
+ if (dict_add_string_len(item, "group", (char_u *)"", 0) == FAIL)
goto theend;
return item;
@@ -4893,11 +4915,12 @@ create_readdirex_item(char_u *path, char_u *name)
dict_T *item;
char *p;
size_t pathlen, len;
+ size_t namelen;
stat_T st;
int ret, link = FALSE;
varnumber_T size;
char_u permbuf[] = "---------";
- char_u *q = NULL;
+ string_T q = {NULL, 0};
struct passwd *pw;
struct group *gr;
@@ -4907,7 +4930,8 @@ create_readdirex_item(char_u *path, char_u *name)
item->dv_refcount++;
pathlen = STRLEN(path);
- len = pathlen + 1 + STRLEN(name) + 1;
+ namelen = STRLEN(name);
+ len = pathlen + 1 + namelen + 1;
p = alloc(len);
if (p == NULL)
goto theend;
@@ -4921,11 +4945,14 @@ create_readdirex_item(char_u *path, char_u *name)
link = TRUE;
ret = mch_stat(p, &st);
if (ret < 0)
- q = (char_u*)"link";
+ {
+ q.string = (char_u *)"link";
+ q.length = STRLEN_LITERAL("link");
+ }
}
vim_free(p);
- if (dict_add_string(item, "name", name) == FAIL)
+ if (dict_add_string_len(item, "name", name, (int)namelen) == FAIL)
goto theend;
if (ret >= 0)
@@ -4944,32 +4971,53 @@ create_readdirex_item(char_u *path, char_u *name)
if (link)
{
if (S_ISDIR(st.st_mode))
- q = (char_u*)"linkd";
+ {
+ q.string = (char_u *)"linkd";
+ q.length = STRLEN_LITERAL("linkd");
+ }
else
- q = (char_u*)"link";
+ {
+ q.string = (char_u *)"link";
+ q.length = STRLEN_LITERAL("link");
+ }
}
else
- q = getftypest(&st);
- if (dict_add_string(item, "type", q) == FAIL)
+ {
+ q.string = getftypest(&st);
+ q.length = STRLEN(q.string);
+ }
+ if (dict_add_string_len(item, "type", q.string, (int)q.length) == FAIL)
goto theend;
if (dict_add_string(item, "perm", getfpermst(&st, permbuf)) == FAIL)
goto theend;
pw = getpwuid(st.st_uid);
if (pw == NULL)
- q = (char_u*)"";
+ {
+ q.string = (char_u *)"";
+ q.length = 0;
+ }
else
- q = (char_u*)pw->pw_name;
- if (dict_add_string(item, "user", q) == FAIL)
+ {
+ q.string = (char_u *)pw->pw_name;
+ q.length = STRLEN(q.string);
+ }
+ if (dict_add_string_len(item, "user", q.string, (int)q.length) == FAIL)
goto theend;
# if !defined(VMS) || (defined(VMS) && defined(HAVE_XOS_R_H))
gr = getgrgid(st.st_gid);
if (gr == NULL)
- q = (char_u*)"";
+ {
+ q.string = (char_u *)"";
+ q.length = 0;
+ }
else
- q = (char_u*)gr->gr_name;
+ {
+ q.string = (char_u *)gr->gr_name;
+ q.length = STRLEN(q.string);
+ }
# endif
- if (dict_add_string(item, "group", q) == FAIL)
+ if (dict_add_string_len(item, "group", q.string, (int)q.length) == FAIL)
goto theend;
}
else
@@ -4978,13 +5026,21 @@ create_readdirex_item(char_u *path, char_u *name)
goto theend;
if (dict_add_number(item, "time", -1) == FAIL)
goto theend;
- if (dict_add_string(item, "type", q == NULL ? (char_u*)"" : q) == FAIL)
- goto theend;
- if (dict_add_string(item, "perm", (char_u*)"") == FAIL)
+ if (q.string == NULL)
+ {
+ if (dict_add_string_len(item, "type", (char_u *)"", 0) == FAIL)
+ goto theend;
+ }
+ else
+ {
+ if (dict_add_string_len(item, "type", q.string, (int)q.length) ==
FAIL)
+ goto theend;
+ }
+ if (dict_add_string_len(item, "perm", (char_u *)"", 0) == FAIL)
goto theend;
- if (dict_add_string(item, "user", (char_u*)"") == FAIL)
+ if (dict_add_string_len(item, "user", (char_u *)"", 0) == FAIL)
goto theend;
- if (dict_add_string(item, "group", (char_u*)"") == FAIL)
+ if (dict_add_string_len(item, "group", (char_u *)"", 0) == FAIL)
goto theend;
}
return item;
diff --git a/src/insexpand.c b/src/insexpand.c
index eb9420a19..72c323777 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -67,27 +67,30 @@ static char *ctrl_x_msgs[] =
};
#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
-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",
- "register",
+# define STRING_INIT(s) \
+ {(char_u *)(s), STRLEN_LITERAL(s)}
+static string_T ctrl_x_mode_names[] = {
+ STRING_INIT("keyword"),
+ STRING_INIT("ctrl_x"),
+ STRING_INIT("scroll"),
+ STRING_INIT("whole_line"),
+ STRING_INIT("files"),
+ STRING_INIT("tags"),
+ STRING_INIT("path_patterns"),
+ STRING_INIT("path_defines"),
+ STRING_INIT("unknown"), // CTRL_X_FINISHED
+ STRING_INIT("dictionary"),
+ STRING_INIT("thesaurus"),
+ STRING_INIT("cmdline"),
+ STRING_INIT("function"),
+ STRING_INIT("omni"),
+ STRING_INIT("spell"),
+ {NULL, 0}, // CTRL_X_LOCAL_MSG is only used in "ctrl_x_msgs"
+ STRING_INIT("eval"),
+ STRING_INIT("cmdline"),
+ STRING_INIT("register"),
};
+# undef STRING_INIT
#endif
/*
@@ -1386,13 +1389,13 @@ ins_compl_dict_alloc(compl_T *match)
if (dict == NULL)
return NULL;
- dict_add_string(dict, "word", match->cp_str.string);
+ dict_add_string_len(dict, "word", match->cp_str.string,
(int)match->cp_str.length);
dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
if (match->cp_user_data.v_type == VAR_UNKNOWN)
- dict_add_string(dict, "user_data", (char_u *)"");
+ dict_add_string_len(dict, "user_data", (char_u *)"", 0);
else
dict_add_tv(dict, "user_data", &match->cp_user_data);
@@ -2888,21 +2891,21 @@ set_ctrl_x_mode(int c)
* Trigger CompleteDone event and adds relevant information to v:event
*/
static void
-trigger_complete_done_event(int mode UNUSED, char_u *word UNUSED)
+trigger_complete_done_event(int mode UNUSED, string_T *word UNUSED)
{
#if defined(FEAT_EVAL)
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
- char_u *mode_str = NULL;
+ string_T *mode_str;
- mode = mode & ~CTRL_X_WANT_IDENT;
- if (ctrl_x_mode_names[mode])
- mode_str = (char_u *)ctrl_x_mode_names[mode];
+ if (word == NULL || word->string == NULL)
+ (void)dict_add_string_len(v_event, "complete_word", (char_u *)"", 0);
+ else
+ (void)dict_add_string_len(v_event, "complete_word", word->string,
(int)word->length);
- (void)dict_add_string(v_event, "complete_word",
- word == NULL ? (char_u *)"" : word);
- (void)dict_add_string(v_event, "complete_type",
- mode_str != NULL ? mode_str : (char_u *)"");
+ mode_str = &ctrl_x_mode_names[mode & ~CTRL_X_WANT_IDENT];
+ (void)dict_add_string_len(v_event, "complete_type",
+ (mode_str->string == NULL) ? (char_u *)"" : mode_str->string,
(int)mode_str->length);
dict_set_items_ro(v_event);
#endif
@@ -2920,7 +2923,7 @@ trigger_complete_done_event(int mode UNUSED, char_u *word
UNUSED)
ins_compl_stop(int c, int prev_mode, int retval)
{
int want_cindent;
- char_u *word = NULL;
+ string_T word = {NULL, 0};
// Remove pre-inserted text when present.
if (ins_compl_preinsert_effect() && ins_compl_win_active(curwin))
@@ -2979,7 +2982,12 @@ ins_compl_stop(int c, int prev_mode, int retval)
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible())
{
- word = vim_strsave(compl_shown_match->cp_str.string);
+ word.string = vim_strnsave(compl_shown_match->cp_str.string,
+ compl_shown_match->cp_str.length);
+ if (word.string == NULL)
+ word.length = 0;
+ else
+ word.length = compl_shown_match->cp_str.length;
retval = TRUE;
}
@@ -3045,8 +3053,8 @@ ins_compl_stop(int c, int prev_mode, int retval)
do_c_expr_indent();
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- trigger_complete_done_event(prev_mode, word);
- vim_free(word);
+ trigger_complete_done_event(prev_mode, &word);
+ vim_free(word.string);
return retval;
}
@@ -3956,13 +3964,22 @@ f_complete_check(typval_T *argvars UNUSED, typval_T
*rettv)
/*
* Return Insert completion mode name string
*/
- static char_u *
-ins_compl_mode(void)
+ static void
+ins_compl_mode(string_T *ret)
{
if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started)
- return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
+ {
+ string_T *mode;
- return (char_u *)"";
+ mode = &ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
+ ret->string = (mode->string == NULL) ? (char_u *)"" : mode->string;
+ ret->length = mode->length;
+ }
+ else
+ {
+ ret->string = (char_u *)"";
+ ret->length = 0;
+ }
}
/*
@@ -4025,7 +4042,7 @@ ins_compl_update_sequence_numbers(void)
static void
fill_complete_info_dict(dict_T *di, compl_T *match, int add_match)
{
- dict_add_string(di, "word", match->cp_str.string);
+ dict_add_string_len(di, "word", match->cp_str.string,
(int)match->cp_str.length);
dict_add_string(di, "abbr", match->cp_text[CPT_ABBR]);
dict_add_string(di, "menu", match->cp_text[CPT_MENU]);
dict_add_string(di, "kind", match->cp_text[CPT_KIND]);
@@ -4034,7 +4051,7 @@ fill_complete_info_dict(dict_T *di, compl_T *match, int
add_match)
dict_add_bool(di, "match", match->cp_in_match_array);
if (match->cp_user_data.v_type == VAR_UNKNOWN)
// Add an empty string for backwards compatibility
- dict_add_string(di, "user_data", (char_u *)"");
+ dict_add_string_len(di, "user_data", (char_u *)"", 0);
else
dict_add_tv(di, "user_data", &match->cp_user_data);
}
@@ -4085,7 +4102,12 @@ get_complete_info(list_T *what_list, dict_T *retdict)
}
if (ret == OK && (what_flag & CI_WHAT_MODE))
- ret = dict_add_string(retdict, "mode", ins_compl_mode());
+ {
+ string_T mode;
+
+ ins_compl_mode(&mode);
+ ret = dict_add_string_len(retdict, "mode", mode.string,
(int)mode.length);
+ }
if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE))
ret = dict_add_number(retdict, "pum_visible", pum_visible());
diff --git a/src/mark.c b/src/mark.c
index 7cd4f31bc..eb77d8af9 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -1454,7 +1454,7 @@ get_namedfm(void)
* Add information about mark 'mname' to list 'l'
*/
static int
-add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr, char_u *fname)
+add_mark(list_T *l, char_u *mname, size_t mnamelen, pos_T *pos, int bufnr,
char_u *fname)
{
dict_T *d;
list_T *lpos;
@@ -1481,7 +1481,7 @@ add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr,
char_u *fname)
list_append_number(lpos, pos->col < MAXCOL ? pos->col + 1 : MAXCOL);
list_append_number(lpos, pos->coladd);
- if (dict_add_string(d, "mark", mname) == FAIL
+ if (dict_add_string_len(d, "mark", mname, (int)mnamelen) == FAIL
|| dict_add_list(d, "pos", lpos) == FAIL
|| (fname != NULL && dict_add_string(d, "file", fname) == FAIL))
{
@@ -1500,25 +1500,26 @@ add_mark(list_T *l, char_u *mname, pos_T *pos, int
bufnr, char_u *fname)
get_buf_local_marks(buf_T *buf, list_T *l)
{
char_u mname[3] = "' ";
+ size_t mnamelen = STRLEN_LITERAL("' ");
int i;
// Marks 'a' to 'z'
for (i = 0; i < NMARKS; ++i)
{
mname[1] = 'a' + i;
- add_mark(l, mname, &buf->b_namedm[i], buf->b_fnum, NULL);
+ add_mark(l, mname, mnamelen, &buf->b_namedm[i], buf->b_fnum, NULL);
}
// Mark '' is a window local mark and not a buffer local mark
- add_mark(l, (char_u *)"''", &curwin->w_pcmark, curbuf->b_fnum, NULL);
-
- add_mark(l, (char_u *)"'\"", &buf->b_last_cursor, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"'[", &buf->b_op_start, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"']", &buf->b_op_end, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"'^", &buf->b_last_insert, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"'.", &buf->b_last_change, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"'<", &buf->b_visual.vi_start, buf->b_fnum, NULL);
- add_mark(l, (char_u *)"'>", &buf->b_visual.vi_end, buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"''", STRLEN_LITERAL("''"), &curwin->w_pcmark,
curbuf->b_fnum, NULL);
+
+ add_mark(l, (char_u *)"'\"", STRLEN_LITERAL("'\""), &buf->b_last_cursor,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"'[", STRLEN_LITERAL("'["), &buf->b_op_start,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"']", STRLEN_LITERAL("']"), &buf->b_op_end,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"'^", STRLEN_LITERAL("'^"), &buf->b_last_insert,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"'.", STRLEN_LITERAL("'."), &buf->b_last_change,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"'<", STRLEN_LITERAL("'<"), &buf->b_visual.vi_start,
buf->b_fnum, NULL);
+ add_mark(l, (char_u *)"'>", STRLEN_LITERAL("'>"), &buf->b_visual.vi_end,
buf->b_fnum, NULL);
}
/*
@@ -1528,6 +1529,7 @@ get_buf_local_marks(buf_T *buf, list_T *l)
get_global_marks(list_T *l)
{
char_u mname[3] = "' ";
+ size_t mnamelen = STRLEN_LITERAL("' ");
int i;
char_u *name;
@@ -1541,7 +1543,7 @@ get_global_marks(list_T *l)
if (name != NULL)
{
mname[1] = i >= NMARKS ? i - NMARKS + '0' : i + 'A';
- add_mark(l, mname, &namedfm[i].fmark.mark,
+ add_mark(l, mname, mnamelen, &namedfm[i].fmark.mark,
namedfm[i].fmark.fnum, name);
if (namedfm[i].fmark.fnum != 0)
vim_free(name);
diff --git a/src/match.c b/src/match.c
index 912abfd74..709ac3049 100644
--- a/src/match.c
+++ b/src/match.c
@@ -1048,10 +1048,12 @@ f_getmatches(typval_T *argvars UNUSED, typval_T *rettv
UNUSED)
# if defined(FEAT_CONCEAL)
if (cur->mit_conceal_char)
{
- char_u buf[MB_MAXBYTES + 1];
+ char_u buf[MB_MAXBYTES + 1];
+ int buflen;
- buf[(*mb_char2bytes)(cur->mit_conceal_char, buf)] = NUL;
- dict_add_string(dict, "conceal", (char_u *)&buf);
+ buflen = (*mb_char2bytes)(cur->mit_conceal_char, buf);
+ buf[buflen] = NUL;
+ dict_add_string_len(dict, "conceal", (char_u *)&buf, buflen);
}
# endif
list_append_dict(rettv->vval.v_list, dict);
diff --git a/src/memline.c b/src/memline.c
index 8152a03a5..b374971e2 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -2225,9 +2225,11 @@ get_b0_dict(char_u *fname, dict_T *d)
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
{
if (ml_check_b0_id(&b0) == FAIL)
- dict_add_string(d, "error", (char_u *)"Not a swap file");
+ dict_add_string_len(d, "error",
+ (char_u *)"Not a swap file", STRLEN_LITERAL("Not a swap
file"));
else if (b0_magic_wrong(&b0))
- dict_add_string(d, "error", (char_u *)"Magic number mismatch");
+ dict_add_string_len(d, "error",
+ (char_u *)"Magic number mismatch", STRLEN_LITERAL("Magic
number mismatch"));
else
{
// we have swap information
@@ -2245,11 +2247,11 @@ get_b0_dict(char_u *fname, dict_T *d)
}
}
else
- dict_add_string(d, "error", (char_u *)"Cannot read file");
+ dict_add_string_len(d, "error", (char_u *)"Cannot read file",
STRLEN_LITERAL("Cannot read file"));
close(fd);
}
else
- dict_add_string(d, "error", (char_u *)"Cannot open file");
+ dict_add_string_len(d, "error", (char_u *)"Cannot open file",
STRLEN_LITERAL("Cannot open file"));
}
#endif
diff --git a/src/menu.c b/src/menu.c
index 3c0dfca67..861d78711 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -2892,15 +2892,17 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu,
int modes, dict_T *dict)
if (status == OK)
{
char_u buf[NUMBUFLEN];
+ int buflen;
if (has_mbyte)
- buf[utf_char2bytes(menu->mnemonic, buf)] = NUL;
+ buflen = utf_char2bytes(menu->mnemonic, buf);
else
{
buf[0] = (char_u)menu->mnemonic;
- buf[1] = NUL;
+ buflen = (buf[0] == NUL) ? 0 : 1;
}
- status = dict_add_string(dict, "shortcut", buf);
+ buf[buflen] = NUL;
+ status = dict_add_string_len(dict, "shortcut", buf, buflen);
}
if (status == OK && menu->children == NULL)
{
@@ -2913,14 +2915,17 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu,
int modes, dict_T *dict)
{
if (menu->strings[bit] != NULL)
{
- char_u *tofree = NULL;
-
- status = dict_add_string(dict, "rhs",
- *menu->strings[bit] == NUL
- ? (char_u *)"<Nop>"
- : (tofree = str2special_save(
- menu->strings[bit], FALSE, FALSE)));
- vim_free(tofree);
+ if (*menu->strings[bit] == NUL)
+ status = dict_add_string_len(dict, "rhs",
+ (char_u *)"<Nop>", STRLEN_LITERAL("<Nop>"));
+ else
+ {
+ char_u *tofree = NULL;
+
+ status = dict_add_string(dict, "rhs",
+ tofree = str2special_save(menu->strings[bit], FALSE,
FALSE));
+ vim_free(tofree);
+ }
}
if (status == OK)
status = dict_add_bool(dict, "noremenu",
diff --git a/src/mouse.c b/src/mouse.c
index 45ffd4b51..04a420e4b 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -1731,7 +1731,7 @@ stl_click_handler_regions(
else
button_str[0] = 'm';
button_str[1] = NUL;
- dict_add_string(info, "button", button_str);
+ dict_add_string_len(info, "button", button_str, 1);
// Modifiers.
if (mods & MOD_MASK_SHIFT)
@@ -1741,7 +1741,7 @@ stl_click_handler_regions(
if (mods & MOD_MASK_ALT)
mods_str[mi++] = 'a';
mods_str[mi] = NUL;
- dict_add_string(info, "mods", mods_str);
+ dict_add_string_len(info, "mods", mods_str, mi);
dict_add_number(info, "winid", winid);
diff --git a/src/popupwin.c b/src/popupwin.c
index 20d7708c6..35bcd4c80 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -16,17 +16,20 @@
#if defined(FEAT_PROP_POPUP)
typedef struct {
- char *pp_name;
+ string_T pp_name;
poppos_T pp_val;
} poppos_entry_T;
+#define STRING_INIT(s) \
+ {(char_u *)(s), STRLEN_LITERAL(s)}
static poppos_entry_T poppos_entries[] = {
- {"botleft", POPPOS_BOTLEFT},
- {"topleft", POPPOS_TOPLEFT},
- {"botright", POPPOS_BOTRIGHT},
- {"topright", POPPOS_TOPRIGHT},
- {"center", POPPOS_CENTER}
+ {STRING_INIT("botleft"), POPPOS_BOTLEFT},
+ {STRING_INIT("topleft"), POPPOS_TOPLEFT},
+ {STRING_INIT("botright"), POPPOS_BOTRIGHT},
+ {STRING_INIT("topright"), POPPOS_TOPRIGHT},
+ {STRING_INIT("center"), POPPOS_CENTER}
};
+#undef STRING_INIT
#ifdef HAS_MESSAGE_WINDOW
// Window used for ":echowindow"
@@ -474,7 +477,7 @@ get_pos_entry(dict_T *d, int give_error)
return POPPOS_NONE;
for (nr = 0; nr < (int)ARRAY_LENGTH(poppos_entries); ++nr)
- if (STRCMP(str, poppos_entries[nr].pp_name) == 0)
+ if (STRCMP(str, poppos_entries[nr].pp_name.string) == 0)
return poppos_entries[nr].pp_val;
if (give_error)
@@ -3887,14 +3890,18 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
for (i = 0; i < (int)ARRAY_LENGTH(poppos_entries); ++i)
if (wp->w_popup_pos == poppos_entries[i].pp_val)
{
- dict_add_string(dict, "pos",
- (char_u *)poppos_entries[i].pp_name);
+ dict_add_string_len(dict, "pos",
+ poppos_entries[i].pp_name.string,
+ (int)poppos_entries[i].pp_name.length);
break;
}
- dict_add_string(dict, "close", (char_u *)(
- wp->w_popup_close == POPCLOSE_BUTTON ? "button"
- : wp->w_popup_close == POPCLOSE_CLICK ? "click" : "none"));
+ if (wp->w_popup_close == POPCLOSE_BUTTON)
+ dict_add_string_len(dict, "close", (char_u *)"button",
STRLEN_LITERAL("button"));
+ else if (wp->w_popup_close == POPCLOSE_CLICK)
+ dict_add_string_len(dict, "close", (char_u *)"click",
STRLEN_LITERAL("click"));
+ else
+ dict_add_string_len(dict, "close", (char_u *)"none",
STRLEN_LITERAL("none"));
#if defined(FEAT_TIMERS)
dict_add_number(dict, "time", wp->w_popup_timer != NULL
diff --git a/src/quickfix.c b/src/quickfix.c
index 46665e8ca..28f3655e1 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -7176,6 +7176,7 @@ get_qfline_items(qfline_T *qfp, list_T *list)
int bufnum;
dict_T *dict;
char_u buf[2];
+ size_t buflen;
// Handle entries with a non-existing buffer number.
bufnum = qfp->qf_fnum;
@@ -7189,6 +7190,7 @@ get_qfline_items(qfline_T *qfp, list_T *list)
buf[0] = qfp->qf_type;
buf[1] = NUL;
+ buflen = (buf[0] == NUL) ? 0 : 1;
if (dict_add_number(dict, "bufnr", (long)bufnum) == FAIL
|| dict_add_number(dict, "lnum", (long)qfp->qf_lnum) == FAIL
|| dict_add_number(dict, "end_lnum", (long)qfp->qf_end_lnum) == FAIL
@@ -7199,7 +7201,7 @@ get_qfline_items(qfline_T *qfp, list_T *list)
|| dict_add_string(dict, "module", qfp->qf_module) == FAIL
|| dict_add_string(dict, "pattern", qfp->qf_pattern) == FAIL
|| dict_add_string(dict, "text", qfp->qf_text) == FAIL
- || dict_add_string(dict, "type", buf) == FAIL
+ || dict_add_string_len(dict, "type", buf, (int)buflen) == FAIL
|| (qfp->qf_user_data.v_type != VAR_UNKNOWN
&& dict_add_tv(dict, "user_data", &qfp->qf_user_data) == FAIL )
|| dict_add_number(dict, "valid", (long)qfp->qf_valid) == FAIL)
@@ -7484,7 +7486,7 @@ qf_getprop_defaults(qf_info_T *qi, int flags, int
locstack, dict_T *retdict)
int status = OK;
if (flags & QF_GETLIST_TITLE)
- status = dict_add_string(retdict, "title", (char_u *)"");
+ status = dict_add_string_len(retdict, "title", (char_u *)"", 0);
if ((status == OK) && (flags & QF_GETLIST_ITEMS))
{
list_T *l = list_alloc();
@@ -7498,7 +7500,7 @@ qf_getprop_defaults(qf_info_T *qi, int flags, int
locstack, dict_T *retdict)
if ((status == OK) && (flags & QF_GETLIST_WINID))
status = dict_add_number(retdict, "winid", qf_winid(qi));
if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
- status = dict_add_string(retdict, "context", (char_u *)"");
+ status = dict_add_string_len(retdict, "context", (char_u *)"", 0);
if ((status == OK) && (flags & QF_GETLIST_ID))
status = dict_add_number(retdict, "id", 0);
if ((status == OK) && (flags & QF_GETLIST_IDX))
@@ -7512,7 +7514,7 @@ qf_getprop_defaults(qf_info_T *qi, int flags, int
locstack, dict_T *retdict)
if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
status = qf_getprop_qfbufnr(qi, retdict);
if ((status == OK) && (flags & QF_GETLIST_QFTF))
- status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
+ status = dict_add_string_len(retdict, "quickfixtextfunc", (char_u *)"",
0);
return status;
}
@@ -7589,7 +7591,7 @@ qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
status = FAIL;
}
else
- status = dict_add_string(retdict, "context", (char_u *)"");
+ status = dict_add_string_len(retdict, "context", (char_u *)"", 0);
return status;
}
@@ -7628,7 +7630,7 @@ qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
clear_tv(&tv);
}
else
- status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
+ status = dict_add_string_len(retdict, "quickfixtextfunc", (char_u *)"",
0);
return status;
}
diff --git a/src/register.c b/src/register.c
index 0215f0153..f7a02e8d9 100644
--- a/src/register.c
+++ b/src/register.c
@@ -1093,6 +1093,7 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
list_T *list;
int n;
char_u buf[NUMBUFLEN + 2];
+ size_t buflen;
long reglen = 0;
save_v_event_T save_v_event;
@@ -1114,7 +1115,8 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
// register name or empty string for unnamed operation
buf[0] = (char_u)oap->regname;
buf[1] = NUL;
- (void)dict_add_string(v_event, "regname", buf);
+ buflen = (buf[0] == NUL) ? 0 : 1;
+ (void)dict_add_string_len(v_event, "regname", buf, (int)buflen);
// motion type: inclusive or exclusive
(void)dict_add_bool(v_event, "inclusive", oap->inclusive);
@@ -1123,21 +1125,32 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
buf[0] = get_op_char(oap->op_type);
buf[1] = get_extra_op_char(oap->op_type);
buf[2] = NUL;
- (void)dict_add_string(v_event, "operator", buf);
+ buflen = (buf[0] == NUL) ? 0 : (buf[1] == NUL) ? 1 : 2;
+ (void)dict_add_string_len(v_event, "operator", buf, (int)buflen);
// register type
- buf[0] = NUL;
- buf[1] = NUL;
switch (get_reg_type(oap->regname, ®len))
{
- case MLINE: buf[0] = 'V'; break;
- case MCHAR: buf[0] = 'v'; break;
+ case MLINE:
+ buf[0] = 'V';
+ buf[1] = NUL;
+ buflen = 1;
+ break;
+ case MCHAR:
+ buf[0] = 'v';
+ buf[1] = NUL;
+ buflen = 1;
+ break;
case MBLOCK:
- vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
- reglen + 1);
- break;
+ buflen = vim_snprintf_safelen((char *)buf, sizeof(buf),
+ "%c%ld", Ctrl_V, reglen + 1);
+ break;
+ default:
+ buf[0] = NUL;
+ buflen = 0;
+ break;
}
- (void)dict_add_string(v_event, "regtype", buf);
+ (void)dict_add_string_len(v_event, "regtype", buf, (int)buflen);
// selection type - visual or not
(void)dict_add_bool(v_event, "visual", oap->is_VIsual);
diff --git a/src/sign.c b/src/sign.c
index 6477af307..a8dfd05ee 100644
--- a/src/sign.c
+++ b/src/sign.c
@@ -322,9 +322,10 @@ sign_get_info(sign_entry_T *sign)
return NULL;
dict_add_number(d, "id", sign->se_id);
- dict_add_string(d, "group",
- (sign->se_group == NULL) ? (char_u *)""
- : sign->se_group->sg_name);
+ if (sign->se_group == NULL)
+ dict_add_string_len(d, "group", (char_u *)"", 0);
+ else
+ dict_add_string(d, "group", sign->se_group->sg_name);
dict_add_number(d, "lnum", sign->se_lnum);
dict_add_string(d, "name", sign_typenr2name(sign->se_typenr));
dict_add_number(d, "priority", sign->se_priority);
@@ -1777,32 +1778,40 @@ sign_getinfo(sign_T *sp, dict_T *retdict)
{
char_u *p = get_highlight_name_ext(NULL, sp->sn_line_hl - 1, FALSE);
if (p == NULL)
- p = (char_u *)"NONE";
- dict_add_string(retdict, "linehl", p);
+ dict_add_string_len(retdict, "linehl",
+ (char_u *)"NONE", STRLEN_LITERAL("NONE"));
+ else
+ dict_add_string(retdict, "linehl", p);
}
if (sp->sn_text_hl > 0)
{
char_u *p = get_highlight_name_ext(NULL, sp->sn_text_hl - 1, FALSE);
if (p == NULL)
- p = (char_u *)"NONE";
- dict_add_string(retdict, "texthl", p);
+ dict_add_string_len(retdict, "texthl",
+ (char_u *)"NONE", STRLEN_LITERAL("NONE"));
+ else
+ dict_add_string(retdict, "texthl", p);
}
if (sp->sn_cul_hl > 0)
{
char_u *p = get_highlight_name_ext(NULL, sp->sn_cul_hl - 1, FALSE);
if (p == NULL)
- p = (char_u *)"NONE";
- dict_add_string(retdict, "culhl", p);
+ dict_add_string_len(retdict, "culhl",
+ (char_u *)"NONE", STRLEN_LITERAL("NONE"));
+ else
+ dict_add_string(retdict, "culhl", p);
}
if (sp->sn_num_hl > 0)
{
char_u *p = get_highlight_name_ext(NULL, sp->sn_num_hl - 1, FALSE);
if (p == NULL)
- p = (char_u *)"NONE";
- dict_add_string(retdict, "numhl", p);
+ dict_add_string_len(retdict, "numhl",
+ (char_u *)"NONE", STRLEN_LITERAL("NONE"));
+ else
+ dict_add_string(retdict, "numhl", p);
}
}
diff --git a/src/term.c b/src/term.c
index 468a7eb48..882df6655 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1587,7 +1587,8 @@ f_terminalprops(typval_T *argvars UNUSED, typval_T *rettv)
value[0] = term_props[i].tpr_status;
value[1] = NUL;
- dict_add_string(rettv->vval.v_dict, term_props[i].tpr_name, value);
+ dict_add_string_len(rettv->vval.v_dict, term_props[i].tpr_name,
+ value, (value[0] == NUL) ? 0 : 1);
}
# endif
}
diff --git a/src/terminal.c b/src/terminal.c
index 92c889fc2..7e812fc97 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -6784,14 +6784,14 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
VTermScreenCellAttrs attrs;
VTermColor fg, bg;
char_u rgb[8];
+ size_t rgblen;
char_u mbs[MB_MAXBYTES * VTERM_MAX_CHARS_PER_CELL + 1];
- int off = 0;
+ size_t mbslen;
int i;
if (screen == NULL)
{
cellattr_T *cellattr;
- int len;
// vterm has finished, get the cell from scrollback
if (pos.col >= line->sb_cols)
@@ -6801,10 +6801,10 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
attrs = cellattr->attrs;
fg = cellattr->fg;
bg = cellattr->bg;
- len = mb_ptr2len(p);
- mch_memmove(mbs, p, len);
- mbs[len] = NUL;
- p += len;
+ mbslen = mb_ptr2len(p);
+ mch_memmove(mbs, p, mbslen);
+ mbs[mbslen] = NUL;
+ p += mbslen;
}
else
{
@@ -6812,13 +6812,15 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
if (vterm_screen_get_cell(screen, pos, &cell) == 0)
break;
+
+ mbslen = 0;
for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i)
{
if (cell.chars[i] == 0)
break;
- off += (*utf_char2bytes)((int)cell.chars[i], mbs + off);
+ mbslen += (*utf_char2bytes)((int)cell.chars[i], mbs + mbslen);
}
- mbs[off] = NUL;
+ mbs[mbslen] = NUL;
width = cell.width;
attrs = cell.attrs;
fg = cell.fg;
@@ -6829,14 +6831,14 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
break;
list_append_dict(l, dcell);
- dict_add_string(dcell, "chars", mbs);
+ dict_add_string_len(dcell, "chars", mbs, (int)mbslen);
- vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
- fg.red, fg.green, fg.blue);
- dict_add_string(dcell, "fg", rgb);
- vim_snprintf((char *)rgb, 8, "#%02x%02x%02x",
- bg.red, bg.green, bg.blue);
- dict_add_string(dcell, "bg", rgb);
+ rgblen = vim_snprintf_safelen((char *)rgb, sizeof(rgb),
+ "#%02x%02x%02x", fg.red, fg.green, fg.blue);
+ dict_add_string_len(dcell, "fg", rgb, (int)rgblen);
+ rgblen = vim_snprintf_safelen((char *)rgb, sizeof(rgb),
+ "#%02x%02x%02x", bg.red, bg.green, bg.blue);
+ dict_add_string_len(dcell, "bg", rgb, (int)rgblen);
dict_add_number(dcell, "attr",
cell2attr(term, NULL, &attrs, &fg, &bg));
diff --git a/src/textprop.c b/src/textprop.c
index 78e9276e5..782701aff 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -1727,23 +1727,35 @@ prop_fill_dict(dict_T *dict, textprop_T *prop, buf_T
*buf)
dict_add_number(dict, "type_bufnr", 0);
if (virtualtext_prop)
{
+ string_T text_align = {NULL, 0};
+
// virtual text property - u.tp_text must be set by caller
dict_add_string(dict, "text", prop->u.tp_text);
// text_align
- char_u *text_align = NULL;
if (prop->tp_flags & TP_FLAG_ALIGN_RIGHT)
- text_align = (char_u *)"right";
+ {
+ text_align.string = (char_u *)"right";
+ text_align.length = STRLEN_LITERAL("right");
+ }
else if (prop->tp_flags & TP_FLAG_ALIGN_ABOVE)
- text_align = (char_u *)"above";
+ {
+ text_align.string = (char_u *)"above";
+ text_align.length = STRLEN_LITERAL("above");
+ }
else if (prop->tp_flags & TP_FLAG_ALIGN_BELOW)
- text_align = (char_u *)"below";
- if (text_align != NULL)
- dict_add_string(dict, "text_align", text_align);
+ {
+ text_align.string = (char_u *)"below";
+ text_align.length = STRLEN_LITERAL("below");
+ }
+ if (text_align.string != NULL)
+ dict_add_string_len(dict, "text_align",
+ text_align.string, (int)text_align.length);
// text_wrap
if (prop->tp_flags & TP_FLAG_WRAP)
- dict_add_string(dict, "text_wrap", (char_u *)"wrap");
+ dict_add_string_len(dict, "text_wrap",
+ (char_u *)"wrap", STRLEN_LITERAL("wrap"));
if (prop->tp_padleft != 0)
dict_add_number(dict, "text_padding_left", prop->tp_padleft);
}
diff --git a/src/version.c b/src/version.c
index 20e593ac8..9c634f7da 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 368,
/**/
367,
/**/
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1wEZTs-00B6Pv-NJ%40256bit.org.