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

8c85a2a49a

Co-authored-by: John Marriott <basilisk@internode.on.net>
This commit is contained in:
zeertzjq 2024-05-21 06:22:23 +08:00
parent 879d17ea8d
commit b86381f425
13 changed files with 279 additions and 194 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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; i < ARRAY_SIZE(spats); i++) {
free_spat(&spats[i]);
}
CLEAR_FIELD(spats);
XFREE_CLEAR(mr_pattern);
mr_patternlen = 0;
}
#endif
@ -320,7 +328,8 @@ void save_last_search_pattern(void)
saved_last_search_spat = spats[RE_SEARCH];
if (spats[RE_SEARCH].pat != NULL) {
saved_last_search_spat.pat = xstrdup(spats[RE_SEARCH].pat);
saved_last_search_spat.pat = xstrnsave(spats[RE_SEARCH].pat, spats[RE_SEARCH].patlen);
saved_last_search_spat.patlen = spats[RE_SEARCH].patlen;
}
saved_last_idx = last_idx;
saved_no_hlsearch = no_hlsearch;
@ -341,6 +350,7 @@ void restore_last_search_pattern(void)
xfree(spats[RE_SEARCH].pat);
spats[RE_SEARCH] = saved_last_search_spat;
saved_last_search_spat.pat = NULL;
saved_last_search_spat.patlen = 0;
set_vv_searchforward();
last_idx = saved_last_idx;
set_no_hlsearch(saved_no_hlsearch);
@ -487,8 +497,10 @@ void set_last_search_pat(const char *s, int idx, int magic, bool setlast)
// An empty string means that nothing should be matched.
if (*s == NUL) {
spats[idx].pat = NULL;
spats[idx].patlen = 0;
} else {
spats[idx].pat = xstrdup(s);
spats[idx].patlen = strlen(s);
spats[idx].pat = xstrnsave(s, spats[idx].patlen);
}
spats[idx].timestamp = os_time();
spats[idx].additional_data = NULL;
@ -507,8 +519,10 @@ void set_last_search_pat(const char *s, int idx, int magic, bool setlast)
saved_spats[idx] = spats[0];
if (spats[idx].pat == NULL) {
saved_spats[idx].pat = NULL;
saved_spats[idx].patlen = 0;
} else {
saved_spats[idx].pat = xstrdup(spats[idx].pat);
saved_spats[idx].pat = xstrnsave(spats[idx].pat, spats[idx].patlen);
saved_spats[idx].patlen = spats[idx].patlen;
}
saved_spats_last_idx = last_idx;
}
@ -528,7 +542,7 @@ void last_pat_prog(regmmatch_T *regmatch)
return;
}
emsg_off++; // So it doesn't beep if bad expr
search_regcomp("", NULL, 0, last_idx, SEARCH_KEEP, regmatch);
search_regcomp("", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch);
emsg_off--;
}
@ -556,7 +570,7 @@ void last_pat_prog(regmmatch_T *regmatch)
/// the index of the first matching
/// subpattern plus one; one if there was none.
int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char *pat,
int count, int options, int pat_use, searchit_arg_T *extra_arg)
size_t patlen, int count, int options, int pat_use, searchit_arg_T *extra_arg)
{
int found;
linenr_T lnum; // no init to shut up Apollo cc
@ -584,7 +598,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
timed_out = &extra_arg->sa_timed_out;
}
if (search_regcomp(pat, NULL, RE_SEARCH, pat_use,
if (search_regcomp(pat, patlen, NULL, RE_SEARCH, pat_use,
(options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL) {
if ((options & SEARCH_MSG) && !rc_did_emsg) {
semsg(_("E383: Invalid search string: %s"), mr_pattern);
@ -592,6 +606,8 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
return FAIL;
}
const bool search_from_match_end = vim_strchr(p_cpo, CPO_SEARCH) != NULL;
// find the string
do { // loop for count
// When not accepting a match at the start position set "extra_col" to a
@ -699,7 +715,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
// If vi-compatible searching, continue at the end
// of the match, otherwise continue one position
// forward.
if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) {
if (search_from_match_end) {
if (nmatched > 1) {
// end is in next line, thus no match in
// this line
@ -791,7 +807,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
// If vi-compatible searching, continue at the end
// of the match, otherwise continue one position
// forward.
if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) {
if (search_from_match_end) {
if (nmatched > 1) {
break;
}
@ -1031,11 +1047,12 @@ static int first_submatch(regmmatch_T *rp)
/// @param sia optional arguments or NULL
///
/// @return 0 for failure, 1 for found, 2 for found and line offset added.
int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, int options,
searchit_arg_T *sia)
int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen, int count,
int options, searchit_arg_T *sia)
{
pos_T pos; // position of the last match
char *searchstr;
size_t searchstrlen;
int retval; // Return value
char *p;
int64_t c;
@ -1043,9 +1060,11 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
char *strcopy = NULL;
char *ps;
char *msgbuf = NULL;
size_t len;
size_t msgbuflen = 0;
bool has_offset = false;
searchcmdlen = 0;
// A line offset is not remembered, this is vi compatible.
if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL) {
spats[0].off.line = false;
@ -1096,19 +1115,23 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
bool show_top_bot_msg = false;
searchstr = pat;
searchstrlen = patlen;
dircp = NULL;
// use previous pattern
if (pat == NULL || *pat == NUL || *pat == search_delim) {
if (spats[RE_SEARCH].pat == NULL) { // no previous pattern
searchstr = spats[RE_SUBST].pat;
if (searchstr == NULL) {
if (spats[RE_SUBST].pat == NULL) {
emsg(_(e_noprevre));
retval = 0;
goto end_do_search;
}
searchstr = spats[RE_SUBST].pat;
searchstrlen = spats[RE_SUBST].patlen;
} else {
// make search_regcomp() use spats[RE_SEARCH].pat
searchstr = "";
searchstrlen = 0;
}
}
@ -1118,12 +1141,16 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
ps = strcopy;
p = skip_regexp_ex(pat, search_delim, magic_isset(), &strcopy, NULL, NULL);
if (strcopy != ps) {
size_t len = strlen(strcopy);
// made a copy of "pat" to change "\?" to "?"
searchcmdlen += (int)(strlen(pat) - strlen(strcopy));
searchcmdlen += (int)(patlen - len);
pat = strcopy;
patlen = len;
searchstr = strcopy;
searchstrlen = len;
}
if (*p == search_delim) {
searchstrlen = (size_t)(p - pat);
dircp = p; // remember where we put the NUL
*p++ = NUL;
}
@ -1161,12 +1188,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
// compute length of search command for get_address()
searchcmdlen += (int)(p - pat);
patlen -= (size_t)(p - pat);
pat = p; // put pat after search command
}
bool show_search_stats = false;
if ((options & SEARCH_ECHO) && messaging() && !msg_silent
&& (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) {
char *trunc;
char off_buf[40];
size_t off_len = 0;
@ -1176,56 +1204,59 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
// Get the offset, so we know how long it is.
if (!cmd_silent
&& (spats[0].off.line || spats[0].off.end || spats[0].off.off)) {
p = off_buf;
*p++ = (char)dirc;
off_buf[off_len++] = (char)dirc;
if (spats[0].off.end) {
*p++ = 'e';
off_buf[off_len++] = 'e';
} else if (!spats[0].off.line) {
*p++ = 's';
off_buf[off_len++] = 's';
}
if (spats[0].off.off > 0 || spats[0].off.line) {
*p++ = '+';
off_buf[off_len++] = '+';
}
*p = NUL;
off_buf[off_len] = NUL;
if (spats[0].off.off != 0 || spats[0].off.line) {
snprintf(p, sizeof(off_buf) - 1 - (size_t)(p - off_buf),
"%" PRId64, spats[0].off.off);
off_len += (size_t)snprintf(off_buf + off_len, sizeof(off_buf) - off_len,
"%" PRId64, spats[0].off.off);
}
off_len = strlen(off_buf);
}
size_t plen;
if (*searchstr == NUL) {
p = spats[0].pat;
plen = spats[0].patlen;
} else {
p = searchstr;
plen = searchstrlen;
}
size_t msgbufsize;
if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) {
// Reserve enough space for the search pattern + offset +
// search stat. Use all the space available, so that the
// search state is right aligned. If there is not enough space
// msg_strtrunc() will shorten in the middle.
if (ui_has(kUIMessages)) {
len = 0; // adjusted below
msgbufsize = 0; // adjusted below
} else if (msg_scrolled != 0 && !cmd_silent) {
// Use all the columns.
len = (size_t)((Rows - msg_row) * Columns - 1);
msgbufsize = (size_t)((Rows - msg_row) * Columns - 1);
} else {
// Use up to 'showcmd' column.
len = (size_t)((Rows - msg_row - 1) * Columns + sc_col - 1);
msgbufsize = (size_t)((Rows - msg_row - 1) * Columns + sc_col - 1);
}
if (len < strlen(p) + off_len + SEARCH_STAT_BUF_LEN + 3) {
len = strlen(p) + off_len + SEARCH_STAT_BUF_LEN + 3;
if (msgbufsize < plen + off_len + SEARCH_STAT_BUF_LEN + 3) {
msgbufsize = plen + off_len + SEARCH_STAT_BUF_LEN + 3;
}
} else {
// Reserve enough space for the search pattern + offset.
len = strlen(p) + off_len + 3;
msgbufsize = plen + off_len + 3;
}
xfree(msgbuf);
msgbuf = xmalloc(len);
memset(msgbuf, ' ', len);
msgbuf[len - 1] = NUL;
msgbuf = xmalloc(msgbufsize);
memset(msgbuf, ' ', msgbufsize);
msgbuflen = msgbufsize - 1;
msgbuf[msgbuflen] = NUL;
// do not fill the msgbuf buffer, if cmd_silent is set, leave it
// empty for the search_stat feature.
@ -1234,18 +1265,19 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
if (utf_iscomposing(utf_ptr2char(p))) {
// Use a space to draw the composing char on.
msgbuf[1] = ' ';
memmove(msgbuf + 2, p, strlen(p));
memmove(msgbuf + 2, p, plen);
} else {
memmove(msgbuf + 1, p, strlen(p));
memmove(msgbuf + 1, p, plen);
}
if (off_len > 0) {
memmove(msgbuf + strlen(p) + 1, off_buf, off_len);
memmove(msgbuf + plen + 1, off_buf, off_len);
}
trunc = msg_strtrunc(msgbuf, true);
char *trunc = msg_strtrunc(msgbuf, true);
if (trunc != NULL) {
xfree(msgbuf);
msgbuf = trunc;
msgbuflen = strlen(msgbuf);
}
// The search pattern could be shown on the right in rightleft
@ -1260,7 +1292,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
while (*r == ' ') {
r++;
}
size_t pat_len = (size_t)(msgbuf + strlen(msgbuf) - r);
size_t pat_len = (size_t)(msgbuf + msgbuflen - r);
memmove(msgbuf, r, pat_len);
// overwrite old text
if ((size_t)(r - msgbuf) >= pat_len) {
@ -1277,6 +1309,10 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
ui_flush();
msg_nowait = true; // don't wait for this message
}
if (!shortmess(SHM_SEARCHCOUNT)) {
show_search_stats = true;
}
}
// If there is a character offset, subtract it from the current
@ -1309,7 +1345,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
}
c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD,
searchstr, count,
searchstr, searchstrlen, count,
(spats[0].off.end * SEARCH_END
+ (options
& (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG
@ -1379,14 +1415,9 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
}
// Show [1/15] if 'S' is not in 'shortmess'.
if ((options & SEARCH_ECHO)
&& messaging()
&& !msg_silent
&& c != FAIL
&& !shortmess(SHM_SEARCHCOUNT)
&& msgbuf != NULL) {
if (show_search_stats) {
cmdline_search_stat(dirc, &pos, &curwin->w_cursor,
show_top_bot_msg, msgbuf,
show_top_bot_msg, msgbuf, msgbuflen,
(count != 1 || has_offset
|| (!(fdo_flags & FDO_SEARCH)
&& hasFolding(curwin, curwin->w_cursor.lnum, NULL,
@ -1413,6 +1444,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in
goto end_do_search;
}
pat++;
patlen--;
}
if (options & SEARCH_MARK) {
@ -2418,7 +2450,8 @@ int current_search(int count, bool forward)
}
// Is the pattern is zero-width?, this time, don't care about the direction
int zero_width = is_zero_width(spats[last_idx].pat, true, &curwin->w_cursor, FORWARD);
int zero_width = is_zero_width(spats[last_idx].pat, spats[last_idx].patlen,
true, &curwin->w_cursor, FORWARD);
if (zero_width == -1) {
return FAIL; // pattern not found
}
@ -2451,7 +2484,7 @@ int current_search(int count, bool forward)
result = searchit(curwin, curbuf, &pos, &end_pos,
(dir ? FORWARD : BACKWARD),
spats[last_idx].pat, i ? count : 1,
spats[last_idx].pat, spats[last_idx].patlen, i ? count : 1,
SEARCH_KEEP | flags, RE_SEARCH, NULL);
p_ws = old_p_ws;
@ -2525,7 +2558,8 @@ int current_search(int count, bool forward)
/// else from position "cur".
/// "direction" is FORWARD or BACKWARD.
/// Returns true, false or -1 for failure.
static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction direction)
static int is_zero_width(char *pattern, size_t patternlen, bool move, pos_T *cur,
Direction direction)
{
regmmatch_T regmatch;
int result = -1;
@ -2535,9 +2569,10 @@ static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction directi
if (pattern == NULL) {
pattern = spats[last_idx].pat;
patternlen = spats[last_idx].patlen;
}
if (search_regcomp(pattern, NULL, RE_SEARCH, RE_SEARCH,
if (search_regcomp(pattern, patternlen, NULL, RE_SEARCH, RE_SEARCH,
SEARCH_KEEP, &regmatch) == FAIL) {
return -1;
}
@ -2552,7 +2587,7 @@ static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction directi
// accept a match at the cursor position
flag = SEARCH_START;
}
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, patternlen, 1,
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) {
int nmatched = 0;
// Zero-width pattern should match somewhere, then we can check if
@ -2591,7 +2626,8 @@ bool linewhite(linenr_T lnum)
/// Add the search count "[3/19]" to "msgbuf".
/// See update_search_stat() for other arguments.
static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool show_top_bot_msg,
char *msgbuf, bool recompute, int maxcount, int timeout)
char *msgbuf, size_t msgbuflen, bool recompute, int maxcount,
int timeout)
{
searchstat_T stat;
@ -2602,36 +2638,36 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
}
char t[SEARCH_STAT_BUF_LEN];
size_t len;
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
if (stat.incomplete == 1) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
} else if (stat.cnt > maxcount && stat.cur > maxcount) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
maxcount, maxcount);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
maxcount, maxcount);
} else if (stat.cnt > maxcount) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]",
maxcount, stat.cur);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]",
maxcount, stat.cur);
} else {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
stat.cnt, stat.cur);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
stat.cnt, stat.cur);
}
} else {
if (stat.incomplete == 1) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
} else if (stat.cnt > maxcount && stat.cur > maxcount) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
maxcount, maxcount);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
maxcount, maxcount);
} else if (stat.cnt > maxcount) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]",
stat.cur, maxcount);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]",
stat.cur, maxcount);
} else {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
stat.cur, stat.cnt);
len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
stat.cur, stat.cnt);
}
}
size_t len = strlen(t);
if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
memmove(t + 2, t, len);
t[0] = 'W';
@ -2639,11 +2675,10 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
len += 2;
}
size_t msgbuf_len = strlen(msgbuf);
if (len > msgbuf_len) {
len = msgbuf_len;
if (len > msgbuflen) {
len = msgbuflen;
}
memmove(msgbuf + msgbuf_len - len, t, len);
memmove(msgbuf + msgbuflen - len, t, len);
if (dirc == '?' && stat.cur == maxcount + 1) {
stat.cur = -1;
@ -2726,7 +2761,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst
start = profile_setlimit(timeout);
}
while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos,
FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST,
FORWARD, NULL, 0, 1, SEARCH_KEEP, RE_LAST,
NULL) != FAIL) {
done_search = true;
// Stop after passing the time limit.
@ -2860,7 +2895,8 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
goto the_end;
}
xfree(spats[last_idx].pat);
spats[last_idx].pat = xstrdup(pattern);
spats[last_idx].patlen = strlen(pattern);
spats[last_idx].pat = xstrnsave(pattern, spats[last_idx].patlen);
}
if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) {
goto the_end; // the previous pattern was never defined
@ -3602,10 +3638,10 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
// when CONT_SOL is set compare "ptr" with the beginning of the
// line is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo
&& !compl_status_sol()) {
size_t patlen = len + 5;
char *pat = xmalloc(patlen);
size_t patsize = len + 5;
char *pat = xmalloc(patsize);
assert(len <= INT_MAX);
snprintf(pat, patlen, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr);
snprintf(pat, patsize, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr);
// ignore case according to p_ic, p_scs and pat
regmatch.rm_ic = ignorecase(pat);
regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0);
@ -3623,8 +3659,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
incl_regmatch.rm_ic = false; // don't ignore case in incl. pat.
}
if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) {
def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL
? p_def : curbuf->b_p_def,
def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL ? p_def : curbuf->b_p_def,
magic_isset() ? RE_MAGIC : 0);
if (def_regmatch.regprog == NULL) {
goto fpip_end;
@ -4066,7 +4101,7 @@ exit_matched:
&& action == ACTION_EXPAND
&& !compl_status_sol()
&& *startp != NUL
&& *(p = startp + utfc_ptr2len(startp)) != NUL) {
&& *(startp + utfc_ptr2len(startp)) != NUL) {
goto search_line;
}
}
@ -4165,8 +4200,9 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI
if (got_int) { // 'q' typed at "--more--" message
return;
}
size_t linelen = strlen(line);
while (true) {
char *p = line + strlen(line) - 1;
char *p = line + linelen - 1;
if (fp != NULL) {
// We used fgets(), so get rid of newline at end
if (p >= line && *p == '\n') {
@ -4196,12 +4232,14 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI
if (vim_fgets(line, LSIZE, fp)) { // end of file
break;
}
linelen = strlen(line);
(*lnum)++;
} else {
if (++*lnum > curbuf->b_ml.ml_line_count) {
break;
}
line = ml_get(*lnum);
linelen = (size_t)ml_get_len(*lnum);
}
msg_putchar('\n');
}

View File

@ -84,6 +84,7 @@ typedef struct {
/// Structure containing last search pattern and its attributes.
typedef struct {
char *pat; ///< The pattern (in allocated memory) or NULL.
size_t patlen; ///< The length of the patten (0 is pat is NULL).
bool magic; ///< Magicness of the pattern.
bool no_scs; ///< No smartcase for this pattern.
Timestamp timestamp; ///< Time of the last change.

View File

@ -2665,16 +2665,16 @@ void ex_spellrepall(exarg_T *eap)
const size_t repl_to_len = strlen(repl_to);
const int addlen = (int)(repl_to_len - repl_from_len);
const size_t frompatlen = repl_from_len + 7;
char *frompat = xmalloc(frompatlen);
snprintf(frompat, frompatlen, "\\V\\<%s\\>", repl_from);
const size_t frompatsize = repl_from_len + 7;
char *frompat = xmalloc(frompatsize);
size_t frompatlen = (size_t)snprintf(frompat, frompatsize, "\\V\\<%s\\>", repl_from);
p_ws = false;
sub_nsubs = 0;
sub_nlines = 0;
curwin->w_cursor.lnum = 0;
while (!got_int) {
if (do_search(NULL, '/', '/', frompat, 1, SEARCH_KEEP, NULL) == 0
if (do_search(NULL, '/', '/', frompat, frompatlen, 1, SEARCH_KEEP, NULL) == 0
|| u_save_cursor() == FAIL) {
break;
}

View File

@ -2942,6 +2942,8 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help)
str = skip_regexp(pbuf + 1, pbuf[0], false) + 1;
}
if (str > pbuf_end - 1) { // search command with nothing following
size_t pbuflen = (size_t)(pbuf_end - pbuf);
bool save_p_ws = p_ws;
int save_p_ic = p_ic;
int save_p_scs = p_scs;
@ -2956,25 +2958,27 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help)
// start search before first line
curwin->w_cursor.lnum = 0;
}
if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, 1, search_options, NULL)) {
if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, 1,
search_options, NULL)) {
retval = OK;
} else {
int found = 1;
// try again, ignore case now
p_ic = true;
if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, 1, search_options, NULL)) {
if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, 1,
search_options, NULL)) {
// Failed to find pattern, take a guess: "^func ("
found = 2;
test_for_static(&tagp);
char cc = *tagp.tagname_end;
*tagp.tagname_end = NUL;
snprintf(pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname);
if (!do_search(NULL, '/', '/', pbuf, 1, search_options, NULL)) {
pbuflen = (size_t)snprintf(pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname);
if (!do_search(NULL, '/', '/', pbuf, pbuflen, 1, search_options, NULL)) {
// Guess again: "^char * \<func ("
snprintf(pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
tagp.tagname);
if (!do_search(NULL, '/', '/', pbuf, 1, search_options, NULL)) {
pbuflen = (size_t)snprintf(pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
tagp.tagname);
if (!do_search(NULL, '/', '/', pbuf, len, 1, search_options, NULL)) {
found = 0;
}
}

View File

@ -35,9 +35,10 @@ itp('pat_has_uppercase', function()
end)
describe('search_regcomp', function()
local search_regcomp = function(pat, pat_save, pat_use, options)
local search_regcomp = function(pat, patlen, pat_save, pat_use, options)
local regmatch = ffi.new('regmmatch_T')
local fail = search.search_regcomp(to_cstr(pat), nil, pat_save, pat_use, options, regmatch)
local fail =
search.search_regcomp(to_cstr(pat), patlen, nil, pat_save, pat_use, options, regmatch)
return fail, regmatch
end
@ -50,7 +51,7 @@ describe('search_regcomp', function()
globals.curwin.w_onebuf_opt.wo_rl = 1
globals.curwin.w_onebuf_opt.wo_rlc = to_cstr('s')
globals.cmdmod.cmod_flags = globals.CMOD_KEEPPATTERNS
local fail = search_regcomp('a\192', 0, 0, 0)
local fail = search_regcomp('a\192', 2, 0, 0, 0)
eq(1, fail)
eq('\192a', get_search_pat())
end)