diff options
| author | zeertzjq <zeertzjq@outlook.com> | 2024-05-21 06:22:23 +0800 |
|---|---|---|
| committer | zeertzjq <zeertzjq@outlook.com> | 2024-05-22 06:37:26 +0800 |
| commit | b86381f425223adf0ff91fa0746914a5774ddabb (patch) | |
| tree | 3a954980956a6ac250fc2e1a875802d5057bddde /src | |
| parent | 879d17ea8d62c199ea0c91c5f37a4f25495be7ce (diff) | |
| download | rneovim-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.c | 9 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 27 | ||||
| -rw-r--r-- | src/nvim/ex_cmds.c | 22 | ||||
| -rw-r--r-- | src/nvim/ex_docmd.c | 4 | ||||
| -rw-r--r-- | src/nvim/ex_getln.c | 9 | ||||
| -rw-r--r-- | src/nvim/insexpand.c | 36 | ||||
| -rw-r--r-- | src/nvim/normal.c | 80 | ||||
| -rw-r--r-- | src/nvim/quickfix.c | 2 | ||||
| -rw-r--r-- | src/nvim/search.c | 250 | ||||
| -rw-r--r-- | src/nvim/search.h | 1 | ||||
| -rw-r--r-- | src/nvim/spell.c | 8 | ||||
| -rw-r--r-- | src/nvim/tag.c | 18 |
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), ®match) == 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, ®match) == 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 |