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; 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)), ®match) == 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, ®match) == 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'); } diff --git a/src/nvim/search.h b/src/nvim/search.h index 09af34d87e..783756b781 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -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. diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 6f0c7bab8e..d7a6adef58 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -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; } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 1c03731048..f322438485 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -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 * \