aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-05-21 06:22:23 +0800
committerzeertzjq <zeertzjq@outlook.com>2024-05-22 06:37:26 +0800
commitb86381f425223adf0ff91fa0746914a5774ddabb (patch)
tree3a954980956a6ac250fc2e1a875802d5057bddde /src
parent879d17ea8d62c199ea0c91c5f37a4f25495be7ce (diff)
downloadrneovim-b86381f425223adf0ff91fa0746914a5774ddabb.tar.gz
rneovim-b86381f425223adf0ff91fa0746914a5774ddabb.tar.bz2
rneovim-b86381f425223adf0ff91fa0746914a5774ddabb.zip
vim-patch:9.1.0426: too many strlen() calls in search.c
Problem: too many strlen() calls in search.c Solution: refactor code and remove more strlen() calls, use explicit variable to remember strlen (John Marriott) closes: vim/vim#14796 https://github.com/vim/vim/commit/8c85a2a49acf80e4f53ec51e6ff2a5f3830eeddb Co-authored-by: John Marriott <basilisk@internode.on.net>
Diffstat (limited to 'src')
-rw-r--r--src/nvim/cmdhist.c9
-rw-r--r--src/nvim/eval/funcs.c27
-rw-r--r--src/nvim/ex_cmds.c22
-rw-r--r--src/nvim/ex_docmd.c4
-rw-r--r--src/nvim/ex_getln.c9
-rw-r--r--src/nvim/insexpand.c36
-rw-r--r--src/nvim/normal.c80
-rw-r--r--src/nvim/quickfix.c2
-rw-r--r--src/nvim/search.c250
-rw-r--r--src/nvim/search.h1
-rw-r--r--src/nvim/spell.c8
-rw-r--r--src/nvim/tag.c18
12 files changed, 275 insertions, 191 deletions
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index 6a9290270a..eb1658aa1f 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -294,7 +294,7 @@ static int last_maptick = -1; // last seen maptick
/// @param histype may be one of the HIST_ values.
/// @param in_map consider maptick when inside a mapping
/// @param sep separator character used (search hist)
-void add_to_history(int histype, const char *new_entry, int in_map, int sep)
+void add_to_history(int histype, const char *new_entry, size_t new_entrylen, bool in_map, int sep)
{
histentry_T *hisptr;
@@ -334,11 +334,10 @@ void add_to_history(int histype, const char *new_entry, int in_map, int sep)
hist_free_entry(hisptr);
// Store the separator after the NUL of the string.
- size_t len = strlen(new_entry);
- hisptr->hisstr = xstrnsave(new_entry, len + 2);
+ hisptr->hisstr = xstrnsave(new_entry, new_entrylen + 2);
hisptr->timestamp = os_time();
hisptr->additional_elements = NULL;
- hisptr->hisstr[len + 1] = (char)sep;
+ hisptr->hisstr[new_entrylen + 1] = (char)sep;
hisptr->hisnum = ++hisnum[histype];
if (histype == HIST_SEARCH && in_map) {
@@ -536,7 +535,7 @@ void f_histadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
init_history();
- add_to_history(histype, str, false, NUL);
+ add_to_history(histype, str, strlen(str), false, NUL);
rettv->vval.v_number = true;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 0240e08dad..1d01f3ad98 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -7076,12 +7076,13 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
.sa_tm = &tm,
};
+ const size_t patlen = strlen(pat);
int subpatnum;
// Repeat until {skip} returns false.
while (true) {
- subpatnum
- = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia);
+ subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, patlen, 1,
+ options, RE_SEARCH, &sia);
// finding the first match again means there is no match where {skip}
// evaluates to zero.
if (firstpos.lnum != 0 && equalpos(pos, firstpos)) {
@@ -7636,16 +7637,20 @@ int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir,
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
- const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
- char *pat2 = xmalloc(pat2_len);
- const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
- char *pat3 = xmalloc(pat3_len);
- snprintf(pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
+ const size_t spatlen = strlen(spat);
+ const size_t epatlen = strlen(epat);
+ const size_t pat2size = spatlen + epatlen + 17;
+ char *pat2 = xmalloc(pat2size);
+ const size_t pat3size = spatlen + strlen(mpat) + epatlen + 25;
+ char *pat3 = xmalloc(pat3size);
+ int pat2len = snprintf(pat2, pat2size, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
+ int pat3len;
if (*mpat == NUL) {
STRCPY(pat3, pat2);
+ pat3len = pat2len;
} else {
- snprintf(pat3, pat3_len,
- "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat);
+ pat3len = snprintf(pat3, pat3size,
+ "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat);
}
if (flags & SP_START) {
options |= SEARCH_START;
@@ -7662,13 +7667,15 @@ int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir,
pos_T foundpos;
clearpos(&foundpos);
char *pat = pat3;
+ assert(pat3len >= 0);
+ size_t patlen = (size_t)pat3len;
while (true) {
searchit_arg_T sia = {
.sa_stop_lnum = lnum_stop,
.sa_tm = &tm,
};
- int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1,
+ int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, patlen, 1,
options, RE_SEARCH, &sia);
if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) {
// didn't find it or found the first match again: FAIL
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 55d94e165a..834cc6698a 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3099,8 +3099,9 @@ void sub_set_replacement(SubReplacementString sub)
/// @param[in] save Save pattern to options, history
///
/// @returns true if :substitute can be replaced with a join command
-static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const char *cmd, bool save)
- FUNC_ATTR_NONNULL_ARG(1, 3, 4)
+static bool sub_joining_lines(exarg_T *eap, char *pat, size_t patlen, const char *sub,
+ const char *cmd, bool save)
+ FUNC_ATTR_NONNULL_ARG(1, 4, 5)
{
// TODO(vim): find a generic solution to make line-joining operations more
// efficient, avoid allocating a string that grows in size.
@@ -3138,10 +3139,10 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const ch
if (save) {
if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) {
- save_re_pat(RE_SUBST, pat, magic_isset());
+ save_re_pat(RE_SUBST, pat, patlen, magic_isset());
}
// put pattern in history
- add_to_history(HIST_SEARCH, pat, true, NUL);
+ add_to_history(HIST_SEARCH, pat, patlen, true, NUL);
}
return true;
@@ -3332,6 +3333,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
};
char *pat = NULL;
char *sub = NULL; // init for GCC
+ size_t patlen = 0;
int delimiter;
bool has_second_delim = false;
int sublen;
@@ -3383,12 +3385,14 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
which_pat = RE_SEARCH; // use last '/' pattern
}
pat = ""; // empty search pattern
+ patlen = 0;
delimiter = (uint8_t)(*cmd++); // remember delimiter character
has_second_delim = true;
} else { // find the end of the regexp
which_pat = RE_LAST; // use last used regexp
delimiter = (uint8_t)(*cmd++); // remember delimiter character
pat = cmd; // remember start of search pat
+ patlen = strlen(pat);
cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL);
if (cmd[0] == delimiter) { // end delimiter found
*cmd++ = NUL; // replace it with a NUL
@@ -3415,6 +3419,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
return 0;
}
pat = NULL; // search_regcomp() will use previous pattern
+ patlen = 0;
sub = xstrdup(old_sub.sub);
// Vi compatibility quirk: repeating with ":s" keeps the cursor in the
@@ -3422,7 +3427,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
endcolumn = (curwin->w_curswant == MAXCOL);
}
- if (sub != NULL && sub_joining_lines(eap, pat, sub, cmd, cmdpreview_ns <= 0)) {
+ if (sub != NULL && sub_joining_lines(eap, pat, patlen, sub, cmd, cmdpreview_ns <= 0)) {
xfree(sub);
return 0;
}
@@ -3477,7 +3482,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
return 0;
}
- if (search_regcomp(pat, NULL, RE_SUBST, which_pat,
+ if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat,
(cmdpreview_ns > 0 ? 0 : SEARCH_HIS), &regmatch) == FAIL) {
if (subflags.do_error) {
emsg(_(e_invcmd));
@@ -4390,6 +4395,7 @@ void ex_global(exarg_T *eap)
char delim; // delimiter, normally '/'
char *pat;
+ size_t patlen;
regmmatch_T regmatch;
// When nesting the command works on one line. This allows for
@@ -4425,6 +4431,7 @@ void ex_global(exarg_T *eap)
}
cmd++;
pat = "";
+ patlen = 0;
} else if (*cmd == NUL) {
emsg(_("E148: Regular expression missing from global"));
return;
@@ -4434,6 +4441,7 @@ void ex_global(exarg_T *eap)
delim = *cmd; // get the delimiter
cmd++; // skip delimiter if there is one
pat = cmd; // remember start of pattern
+ patlen = strlen(pat);
cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL);
if (cmd[0] == delim) { // end delimiter found
*cmd++ = NUL; // replace it with a NUL
@@ -4441,7 +4449,7 @@ void ex_global(exarg_T *eap)
}
char *used_pat;
- if (search_regcomp(pat, &used_pat, RE_BOTH, which_pat,
+ if (search_regcomp(pat, patlen, &used_pat, RE_BOTH, which_pat,
SEARCH_HIS, &regmatch) == FAIL) {
emsg(_(e_invcmd));
return;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index fb4acaec04..1fcfc505df 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -3506,7 +3506,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool
}
searchcmdlen = 0;
flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
- if (!do_search(NULL, c, c, cmd, 1, flags, NULL)) {
+ if (!do_search(NULL, c, c, cmd, strlen(cmd), 1, flags, NULL)) {
curwin->w_cursor = pos;
cmd = NULL;
goto error;
@@ -3543,7 +3543,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool
pos.coladd = 0;
if (searchit(curwin, curbuf, &pos, NULL,
*cmd == '?' ? BACKWARD : FORWARD,
- "", 1, SEARCH_MSG, i, NULL) != FAIL) {
+ "", 0, 1, SEARCH_MSG, i, NULL) != FAIL) {
lnum = pos.lnum;
} else {
cmd = NULL;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 8c9e6e454a..f18dc0f747 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -470,7 +470,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state
.sa_tm = &tm,
};
found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
- ccline.cmdbuff + skiplen, count,
+ ccline.cmdbuff + skiplen, (size_t)patlen, count,
search_flags, &sia);
ccline.cmdbuff[skiplen + patlen] = next_char;
emsg_off--;
@@ -884,11 +884,12 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
&& ccline.cmdlen
&& s->firstc != NUL
&& (s->some_key_typed || s->histype == HIST_SEARCH)) {
- add_to_history(s->histype, ccline.cmdbuff, true,
+ size_t cmdbufflen = strlen(ccline.cmdbuff);
+ add_to_history(s->histype, ccline.cmdbuff, cmdbufflen, true,
s->histype == HIST_SEARCH ? s->firstc : NUL);
if (s->firstc == ':') {
xfree(new_last_cmdline);
- new_last_cmdline = xstrdup(ccline.cmdbuff);
+ new_last_cmdline = xstrnsave(ccline.cmdbuff, cmdbufflen);
}
}
@@ -1451,7 +1452,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s
pat[patlen] = NUL;
int found = searchit(curwin, curbuf, &t, NULL,
next_match ? FORWARD : BACKWARD,
- pat, count, search_flags,
+ pat, (size_t)patlen, count, search_flags,
RE_SEARCH, NULL);
emsg_off--;
pat[patlen] = save;
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index c51b3b916d..cec1e4a9e3 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -253,6 +253,7 @@ static int ctrl_x_mode = CTRL_X_NORMAL;
static int compl_matches = 0; ///< number of completion matches
static char *compl_pattern = NULL;
+static size_t compl_patternlen = 0;
static Direction compl_direction = FORWARD;
static Direction compl_shows_dir = FORWARD;
static int compl_pending = 0; ///< > 1 for postponed CTRL-N
@@ -1583,6 +1584,7 @@ static char *find_line_end(char *ptr)
static void ins_compl_free(void)
{
XFREE_CLEAR(compl_pattern);
+ compl_patternlen = 0;
XFREE_CLEAR(compl_leader);
if (compl_first_match == NULL) {
@@ -1617,6 +1619,7 @@ void ins_compl_clear(void)
compl_started = false;
compl_matches = 0;
XFREE_CLEAR(compl_pattern);
+ compl_patternlen = 0;
XFREE_CLEAR(compl_leader);
edit_submode_extra = NULL;
kv_destroy(compl_orig_extmarks);
@@ -2991,7 +2994,7 @@ done:
static void get_next_include_file_completion(int compl_type)
{
find_pattern_in_path(compl_pattern, compl_direction,
- strlen(compl_pattern), false, false,
+ compl_patternlen, false, false,
((compl_type == CTRL_X_PATH_DEFINES
&& !(compl_cont_status & CONT_SOL))
? FIND_DEFINE : FIND_ANY),
@@ -3074,8 +3077,7 @@ static void get_next_cmdline_completion(void)
char **matches;
int num_matches;
if (expand_cmdline(&compl_xp, compl_pattern,
- (int)strlen(compl_pattern),
- &num_matches, &matches) == EXPAND_OK) {
+ (int)compl_patternlen, &num_matches, &matches) == EXPAND_OK) {
ins_compl_add_matches(num_matches, matches, false);
}
}
@@ -3217,8 +3219,8 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
compl_direction, compl_pattern);
} else {
found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
- NULL, compl_direction, compl_pattern, 1,
- SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
+ NULL, compl_direction, compl_pattern, compl_patternlen,
+ 1, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
}
msg_silent--;
if (!compl_started || st->set_match_pos) {
@@ -3902,7 +3904,8 @@ static bool ins_compl_use_match(int c)
/// Get the pattern, column and length for normal completion (CTRL-N CTRL-P
/// completion)
-/// Sets the global variables: compl_col, compl_length and compl_pattern.
+/// Sets the global variables: compl_col, compl_length, compl_pattern and
+/// compl_patternlen.
/// Uses the global variables: compl_cont_status and ctrl_x_mode
static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
{
@@ -3919,21 +3922,23 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
}
} else if (compl_status_adding()) {
char *prefix = "\\<";
+ size_t prefixlen = STRLEN_LITERAL("\\<");
// we need up to 2 extra chars for the prefix
- compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2);
+ compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
+ compl_length) + prefixlen);
if (!vim_iswordp(line + compl_col)
|| (compl_col > 0
&& (vim_iswordp(mb_prevptr(line, line + compl_col))))) {
prefix = "";
+ prefixlen = 0;
}
STRCPY(compl_pattern, prefix);
- quote_meta(compl_pattern + strlen(prefix),
- line + compl_col, compl_length);
+ quote_meta(compl_pattern + prefixlen, line + compl_col, compl_length);
} else if (--startcol < 0
|| !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
// Match any word of at least two chars
- compl_pattern = xstrdup("\\<\\k\\k");
+ compl_pattern = xstrnsave(S_LEN("\\<\\k\\k"));
compl_col += curs_col;
compl_length = 0;
} else {
@@ -3965,6 +3970,8 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
}
}
+ compl_patternlen = strlen(compl_pattern);
+
return OK;
}
@@ -3984,6 +3991,8 @@ static int get_wholeline_compl_info(char *line, colnr_T curs_col)
compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
}
+ compl_patternlen = strlen(compl_pattern);
+
return OK;
}
@@ -4009,6 +4018,7 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col)
compl_col += startcol;
compl_length = (int)curs_col - startcol;
compl_pattern = addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES);
+ compl_patternlen = strlen(compl_pattern);
return OK;
}
@@ -4018,7 +4028,8 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col)
static int get_cmdline_compl_info(char *line, colnr_T curs_col)
{
compl_pattern = xstrnsave(line, (size_t)curs_col);
- set_cmd_context(&compl_xp, compl_pattern, (int)strlen(compl_pattern), curs_col, false);
+ compl_patternlen = (size_t)curs_col;
+ set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false);
if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
|| compl_xp.xp_context == EXPAND_NOTHING) {
// No completion possible, use an empty pattern to get a
@@ -4104,6 +4115,7 @@ static int get_userdefined_compl_info(colnr_T curs_col)
char *line = ml_get(curwin->w_cursor.lnum);
compl_length = curs_col - compl_col;
compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
+ compl_patternlen = (size_t)compl_length;
return OK;
}
@@ -4129,6 +4141,7 @@ static int get_spell_compl_info(int startcol, colnr_T curs_col)
// Need to obtain "line" again, it may have become invalid.
char *line = ml_get(curwin->w_cursor.lnum);
compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
+ compl_patternlen = (size_t)compl_length;
return OK;
}
@@ -4324,6 +4337,7 @@ static int ins_compl_start(void)
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
flags, false) != OK) {
XFREE_CLEAR(compl_pattern);
+ compl_patternlen = 0;
XFREE_CLEAR(compl_orig_text);
kv_destroy(compl_orig_extmarks);
return FAIL;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 9646b83106..3b1f0bf73c 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2349,13 +2349,15 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar
bool incll;
int searchflags = flags_arg;
- size_t patlen = len + 7;
- char *pat = xmalloc(patlen);
+ size_t patsize = len + 7;
+ char *pat = xmalloc(patsize);
// Put "\V" before the pattern to avoid that the special meaning of "."
// and "~" causes trouble.
- assert(patlen <= INT_MAX);
- snprintf(pat, patlen, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", (int)len, ptr);
+ assert(patsize <= INT_MAX);
+ size_t patlen = (size_t)snprintf(pat, patsize,
+ vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s",
+ (int)len, ptr);
pos_T old_pos = curwin->w_cursor;
bool save_p_ws = p_ws;
bool save_p_scs = p_scs;
@@ -2382,7 +2384,7 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar
clearpos(&found_pos);
while (true) {
t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
- pat, 1, searchflags, RE_LAST, NULL);
+ pat, patlen, 1, searchflags, RE_LAST, NULL);
if (curwin->w_cursor.lnum >= old_pos.lnum) {
t = false; // match after start is failure too
}
@@ -3296,21 +3298,22 @@ void do_nv_ident(int c1, int c2)
/// 'K' normal-mode command. Get the command to lookup the keyword under the
/// cursor.
static size_t nv_K_getcmd(cmdarg_T *cap, char *kp, bool kp_help, bool kp_ex, char **ptr_arg,
- size_t n, char *buf, size_t buf_size)
+ size_t n, char *buf, size_t bufsize, size_t *buflen)
{
if (kp_help) {
// in the help buffer
STRCPY(buf, "he! ");
+ *buflen = STRLEN_LITERAL("he! ");
return n;
}
if (kp_ex) {
+ *buflen = 0;
// 'keywordprg' is an ex command
if (cap->count0 != 0) { // Send the count to the ex command.
- snprintf(buf, buf_size, "%" PRId64, (int64_t)(cap->count0));
+ *buflen = (size_t)snprintf(buf, bufsize, "%" PRId64, (int64_t)(cap->count0));
}
- STRCAT(buf, kp);
- STRCAT(buf, " ");
+ *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "%s ", kp);
return n;
}
@@ -3335,21 +3338,19 @@ static size_t nv_K_getcmd(cmdarg_T *cap, char *kp, bool kp_help, bool kp_ex, cha
bool isman = (strcmp(kp, "man") == 0);
bool isman_s = (strcmp(kp, "man -s") == 0);
if (cap->count0 != 0 && !(isman || isman_s)) {
- snprintf(buf, buf_size, ".,.+%" PRId64, (int64_t)(cap->count0 - 1));
+ *buflen = (size_t)snprintf(buf, bufsize, ".,.+%" PRId64, (int64_t)(cap->count0 - 1));
}
do_cmdline_cmd("tabnew");
- STRCAT(buf, "terminal ");
+ *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "terminal ");
if (cap->count0 == 0 && isman_s) {
- STRCAT(buf, "man");
+ *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "man ");
} else {
- STRCAT(buf, kp);
+ *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "%s ", kp);
}
- STRCAT(buf, " ");
if (cap->count0 != 0 && (isman || isman_s)) {
- snprintf(buf + strlen(buf), buf_size - strlen(buf), "%" PRId64,
- (int64_t)cap->count0);
- STRCAT(buf, " ");
+ *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen,
+ "%" PRId64 " ", (int64_t)cap->count0);
}
*ptr_arg = ptr;
@@ -3412,9 +3413,10 @@ static void nv_ident(cmdarg_T *cap)
return;
}
bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command
- size_t buf_size = n * 2 + 30 + strlen(kp);
- char *buf = xmalloc(buf_size);
+ size_t bufsize = n * 2 + 30 + strlen(kp);
+ char *buf = xmalloc(bufsize);
buf[0] = NUL;
+ size_t buflen = 0;
switch (cmdchar) {
case '*':
@@ -3428,12 +3430,13 @@ static void nv_ident(cmdarg_T *cap)
if (!g_cmd && vim_iswordp(ptr)) {
STRCPY(buf, "\\<");
+ buflen = STRLEN_LITERAL("\\<");
}
no_smartcase = true; // don't use 'smartcase' now
break;
case 'K':
- n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, buf_size);
+ n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, bufsize, &buflen);
if (n == 0) {
return;
}
@@ -3442,19 +3445,23 @@ static void nv_ident(cmdarg_T *cap)
case ']':
tag_cmd = true;
STRCPY(buf, "ts ");
+ buflen = STRLEN_LITERAL("ts ");
break;
default:
tag_cmd = true;
if (curbuf->b_help) {
STRCPY(buf, "he! ");
+ buflen = STRLEN_LITERAL("he! ");
} else {
if (g_cmd) {
STRCPY(buf, "tj ");
+ buflen = STRLEN_LITERAL("tj ");
} else if (cap->count0 == 0) {
STRCPY(buf, "ta ");
+ buflen = STRLEN_LITERAL("ta ");
} else {
- snprintf(buf, buf_size, ":%" PRId64 "ta ", (int64_t)cap->count0);
+ buflen = (size_t)snprintf(buf, bufsize, ":%" PRId64 "ta ", (int64_t)cap->count0);
}
}
}
@@ -3470,9 +3477,11 @@ static void nv_ident(cmdarg_T *cap)
p = vim_strsave_shellescape(ptr, true, true);
}
xfree(ptr);
- char *newbuf = xrealloc(buf, strlen(buf) + strlen(p) + 1);
+ size_t plen = strlen(p);
+ char *newbuf = xrealloc(buf, buflen + plen + 1);
buf = newbuf;
- STRCAT(buf, p);
+ STRCPY(buf + buflen, p);
+ buflen += plen;
xfree(p);
} else {
char *aux_ptr;
@@ -3491,12 +3500,13 @@ static void nv_ident(cmdarg_T *cap)
aux_ptr = "\\|\"\n*?[";
}
- p = buf + strlen(buf);
+ p = buf + buflen;
while (n-- > 0) {
// put a backslash before \ and some others
if (vim_strchr(aux_ptr, (uint8_t)(*ptr)) != NULL) {
*p++ = '\\';
}
+
// When current byte is a part of multibyte character, copy all
// bytes of that character.
const size_t len = (size_t)(utfc_ptr2len(ptr) - 1);
@@ -3506,20 +3516,21 @@ static void nv_ident(cmdarg_T *cap)
*p++ = *ptr++;
}
*p = NUL;
+ buflen = (size_t)(p - buf);
}
// Execute the command.
if (cmdchar == '*' || cmdchar == '#') {
- if (!g_cmd
- && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) {
- STRCAT(buf, "\\>");
+ if (!g_cmd && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) {
+ STRCPY(buf + buflen, "\\>");
+ buflen += STRLEN_LITERAL("\\>");
}
// put pattern in search history
init_history();
- add_to_history(HIST_SEARCH, buf, true, NUL);
+ add_to_history(HIST_SEARCH, buf, buflen, true, NUL);
- normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0, NULL);
+ normal_search(cap, cmdchar == '*' ? '/' : '?', buf, buflen, 0, NULL);
} else {
g_tag_at_cursor = true;
do_cmdline_cmd(buf);
@@ -3940,7 +3951,7 @@ static void nv_search(cmdarg_T *cap)
return;
}
- normal_search(cap, cap->cmdchar, cap->searchbuf,
+ normal_search(cap, cap->cmdchar, cap->searchbuf, strlen(cap->searchbuf),
(cap->arg || !equalpos(save_cursor, curwin->w_cursor))
? 0 : SEARCH_MARK, NULL);
}
@@ -3951,14 +3962,14 @@ static void nv_next(cmdarg_T *cap)
{
pos_T old = curwin->w_cursor;
int wrapped = false;
- int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, &wrapped);
+ int i = normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, &wrapped);
if (i == 1 && !wrapped && equalpos(old, curwin->w_cursor)) {
// Avoid getting stuck on the current cursor position, which can happen when
// an offset is given and the cursor is on the last char in the buffer:
// Repeat with count + 1.
cap->count1 += 1;
- normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, NULL);
+ normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, NULL);
cap->count1 -= 1;
}
}
@@ -3969,7 +3980,7 @@ static void nv_next(cmdarg_T *cap)
/// @param opt extra flags for do_search()
///
/// @return 0 for failure, 1 for found, 2 for found and line offset added.
-static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrapped)
+static int normal_search(cmdarg_T *cap, int dir, char *pat, size_t patlen, int opt, int *wrapped)
{
searchit_arg_T sia;
@@ -3979,7 +3990,7 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe
curwin->w_set_curswant = true;
CLEAR_FIELD(sia);
- int i = do_search(cap->oap, dir, dir, pat, cap->count1,
+ int i = do_search(cap->oap, dir, dir, pat, patlen, cap->count1,
opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia);
if (wrapped != NULL) {
*wrapped = sia.sa_wrapped;
@@ -3999,6 +4010,7 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe
// "/$" will put the cursor after the end of the line, may need to
// correct that here
check_cursor(curwin);
+
return i;
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2713dd2a45..e022184f2f 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2902,7 +2902,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char
// Move the cursor to the first line in the buffer
pos_T save_cursor = curwin->w_cursor;
curwin->w_cursor.lnum = 0;
- if (!do_search(NULL, '/', '/', qf_pattern, 1, SEARCH_KEEP, NULL)) {
+ if (!do_search(NULL, '/', '/', qf_pattern, strlen(qf_pattern), 1, SEARCH_KEEP, NULL)) {
curwin->w_cursor = save_cursor;
}
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index df0a9171d2..746c253708 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -99,9 +99,9 @@ static const char e_search_hit_bottom_without_match_for_str[]
static SearchPattern spats[2] = {
// Last used search pattern
- [0] = { NULL, true, false, 0, { '/', false, false, 0 }, NULL },
+ [0] = { NULL, 0, true, false, 0, { '/', false, false, 0 }, NULL },
// Last used substitute pattern
- [1] = { NULL, true, false, 0, { '/', false, false, 0 }, NULL }
+ [1] = { NULL, 0, true, false, 0, { '/', false, false, 0 }, NULL }
};
static int last_idx = 0; // index in spats[] for RE_LAST
@@ -113,13 +113,15 @@ static char lastc_bytes[MB_MAXBYTES + 1];
static int lastc_bytelen = 1; // >1 for multi-byte char
// copy of spats[], for keeping the search patterns while executing autocmds
-static SearchPattern saved_spats[2];
+static SearchPattern saved_spats[ARRAY_SIZE(spats)];
static char *saved_mr_pattern = NULL;
+static size_t saved_mr_patternlen = 0;
static int saved_spats_last_idx = 0;
static bool saved_spats_no_hlsearch = false;
// allocated copy of pattern used by search_regcomp()
static char *mr_pattern = NULL;
+static size_t mr_patternlen = 0;
// Type used by find_pattern_in_path() to remember which included files have
// been searched already.
@@ -144,8 +146,8 @@ typedef struct {
/// @param regmatch return: pattern and ignore-case flag
///
/// @return FAIL if failed, OK otherwise.
-int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int options,
- regmmatch_T *regmatch)
+int search_regcomp(char *pat, size_t patlen, char **used_pat, int pat_save, int pat_use,
+ int options, regmmatch_T *regmatch)
{
rc_did_emsg = false;
int magic = magic_isset();
@@ -168,10 +170,11 @@ int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int op
return FAIL;
}
pat = spats[i].pat;
+ patlen = spats[i].patlen;
magic = spats[i].magic;
no_smartcase = spats[i].no_scs;
} else if (options & SEARCH_HIS) { // put new pattern in history
- add_to_history(HIST_SEARCH, pat, true, NUL);
+ add_to_history(HIST_SEARCH, pat, patlen, true, NUL);
}
if (used_pat) {
@@ -182,19 +185,20 @@ int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int op
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
mr_pattern = reverse_text(pat);
} else {
- mr_pattern = xstrdup(pat);
+ mr_pattern = xstrnsave(pat, patlen);
}
+ mr_patternlen = patlen;
// Save the currently used pattern in the appropriate place,
// unless the pattern should not be remembered.
if (!(options & SEARCH_KEEP) && (cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) {
// search or global command
if (pat_save == RE_SEARCH || pat_save == RE_BOTH) {
- save_re_pat(RE_SEARCH, pat, magic);
+ save_re_pat(RE_SEARCH, pat, patlen, magic);
}
// substitute or global command
if (pat_save == RE_SUBST || pat_save == RE_BOTH) {
- save_re_pat(RE_SUBST, pat, magic);
+ save_re_pat(RE_SUBST, pat, patlen, magic);
}
}
@@ -213,14 +217,15 @@ char *get_search_pat(void)
return mr_pattern;
}
-void save_re_pat(int idx, char *pat, int magic)
+void save_re_pat(int idx, char *pat, size_t patlen, int magic)
{
if (spats[idx].pat == pat) {
return;
}
free_spat(&spats[idx]);
- spats[idx].pat = xstrdup(pat);
+ spats[idx].pat = xstrnsave(pat, patlen);
+ spats[idx].patlen = patlen;
spats[idx].magic = magic;
spats[idx].no_scs = no_smartcase;
spats[idx].timestamp = os_time();
@@ -243,18 +248,19 @@ void save_search_patterns(void)
return;
}
- saved_spats[0] = spats[0];
- if (spats[0].pat != NULL) {
- saved_spats[0].pat = xstrdup(spats[0].pat);
- }
- saved_spats[1] = spats[1];
- if (spats[1].pat != NULL) {
- saved_spats[1].pat = xstrdup(spats[1].pat);
+ for (size_t i = 0; i < ARRAY_SIZE(spats); i++) {
+ saved_spats[i] = spats[i];
+ if (spats[i].pat != NULL) {
+ saved_spats[i].pat = xstrnsave(spats[i].pat, spats[i].patlen);
+ saved_spats[i].patlen = spats[i].patlen;
+ }
}
if (mr_pattern == NULL) {
saved_mr_pattern = NULL;
+ saved_mr_patternlen = 0;
} else {
- saved_mr_pattern = xstrdup(mr_pattern);
+ saved_mr_pattern = xstrnsave(mr_pattern, mr_patternlen);
+ saved_mr_patternlen = mr_patternlen;
}
saved_spats_last_idx = last_idx;
saved_spats_no_hlsearch = no_hlsearch;
@@ -266,13 +272,14 @@ void restore_search_patterns(void)
return;
}
- free_spat(&spats[0]);
- spats[0] = saved_spats[0];
+ for (size_t i = 0; i < ARRAY_SIZE(spats); i++) {
+ free_spat(&spats[i]);
+ spats[i] = saved_spats[i];
+ }
set_vv_searchforward();
- free_spat(&spats[1]);
- spats[1] = saved_spats[1];
xfree(mr_pattern);
mr_pattern = saved_mr_pattern;
+ mr_patternlen = saved_mr_patternlen;
last_idx = saved_spats_last_idx;
set_no_hlsearch(saved_spats_no_hlsearch);
}
@@ -286,12 +293,13 @@ static inline void free_spat(SearchPattern *const spat)
#if defined(EXITFREE)
void free_search_patterns(void)
{
- free_spat(&spats[0]);
- free_spat(&spats[1]);
-
+ for (size_t i = 0