From 8c85a2a49acf80e4f53ec51e6ff2a5f3830eeddb Mon Sep 17 00:00:00 2001 From: John Marriott Date: Mon, 20 May 2024 19:18:26 +0200 Subject: 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: #14796 Signed-off-by: John Marriott Signed-off-by: Christian Brabandt --- src/cmdhist.c | 9 +- src/evalfunc.c | 34 ++++-- src/ex_cmds.c | 15 ++- src/ex_docmd.c | 4 +- src/ex_getln.c | 10 +- src/gui.c | 4 +- src/insexpand.c | 67 ++++++++++-- src/normal.c | 95 ++++++++++------ src/proto/cmdhist.pro | 2 +- src/proto/search.pro | 8 +- src/quickfix.c | 2 +- src/search.c | 297 ++++++++++++++++++++++++++++++++++---------------- src/spell.c | 5 +- src/structs.h | 1 + src/tag.c | 14 ++- src/version.c | 2 + 16 files changed, 395 insertions(+), 174 deletions(-) (limited to 'src') diff --git a/src/cmdhist.c b/src/cmdhist.c index 6342f02bdd..7cdcee6b86 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -297,11 +297,11 @@ static int last_maptick = -1; // last seen maptick add_to_history( int histype, char_u *new_entry, + size_t new_entrylen, int in_map, // consider maptick when inside a mapping int sep) // separator character used (search hist) { histentry_T *hisptr; - int len; if (hislen == 0) // no history return; @@ -336,10 +336,9 @@ add_to_history( vim_free(hisptr->hisstr); // Store the separator after the NUL of the string. - len = (int)STRLEN(new_entry); - hisptr->hisstr = vim_strnsave(new_entry, len + 2); + hisptr->hisstr = vim_strnsave(new_entry, new_entrylen + 2); if (hisptr->hisstr != NULL) - hisptr->hisstr[len + 1] = sep; + hisptr->hisstr[new_entrylen + 1] = sep; hisptr->hisnum = ++hisnum[histype]; hisptr->viminfo = FALSE; @@ -566,7 +565,7 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv) return; 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/evalfunc.c b/src/evalfunc.c index 571ac08626..903205ad31 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -9712,6 +9712,7 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) { int flags; char_u *pat; + size_t patlen; pos_T pos; pos_T save_cursor; int save_p_ws = p_ws; @@ -9786,10 +9787,12 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) sia.sa_tm = time_limit; #endif + patlen = STRLEN(pat); + // Repeat until {skip} returns FALSE. for (;;) { - subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, + subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, patlen, 1L, options, RE_SEARCH, &sia); // finding the first match again means there is no match where {skip} // evaluates to zero. @@ -10202,6 +10205,13 @@ do_searchpair( { char_u *save_cpo; char_u *pat, *pat2 = NULL, *pat3 = NULL; + size_t patlen; + size_t spatlen; + size_t epatlen; + size_t pat2size; + size_t pat2len; + size_t pat3size; + size_t pat3len; long retval = 0; pos_T pos; pos_T firstpos; @@ -10221,15 +10231,24 @@ do_searchpair( // Make two search patterns: start/end (pat2, for in nested pairs) and // start/middle/end (pat3, for the top pair). - pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17); - pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25); - if (pat2 == NULL || pat3 == NULL) + spatlen = STRLEN(spat); + epatlen = STRLEN(epat); + pat2size = spatlen + epatlen + 17; + pat2 = alloc(pat2size); + if (pat2 == NULL) + goto theend; + pat3size = spatlen + STRLEN(mpat) + epatlen + 25; + pat3 = alloc(pat3size); + if (pat3 == NULL) goto theend; - sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); + pat2len = vim_snprintf((char *)pat2, pat2size, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); if (*mpat == NUL) + { STRCPY(pat3, pat2); + pat3len = pat2len; + } else - sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", + pat3len = vim_snprintf((char *)pat3, pat3size, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat); if (flags & SP_START) options |= SEARCH_START; @@ -10246,13 +10265,14 @@ do_searchpair( CLEAR_POS(&firstpos); CLEAR_POS(&foundpos); pat = pat3; + patlen = pat3len; for (;;) { searchit_arg_T sia; CLEAR_FIELD(sia); sia.sa_stop_lnum = lnum_stop; - n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, + n = searchit(curwin, curbuf, &pos, NULL, dir, pat, patlen, 1L, options, RE_SEARCH, &sia); if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))) // didn't find it or found the first match again: FAIL diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 5c34e8645d..8143c24060 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3750,6 +3750,7 @@ ex_substitute(exarg_T *eap) int save_do_all; // remember user specified 'g' flag int save_do_ask; // remember user specified 'c' flag char_u *pat = NULL, *sub = NULL; // init for GCC + size_t patlen = 0; int delimiter; int sublen; int got_quit = FALSE; @@ -3823,6 +3824,7 @@ ex_substitute(exarg_T *eap) if (*cmd != '&') which_pat = RE_SEARCH; // use last '/' pattern pat = (char_u *)""; // empty search pattern + patlen = 0; delimiter = *cmd++; // remember delimiter character } else // find the end of the regexp @@ -3830,6 +3832,7 @@ ex_substitute(exarg_T *eap) which_pat = RE_LAST; // use last used regexp delimiter = *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 @@ -3883,6 +3886,7 @@ ex_substitute(exarg_T *eap) return; } pat = NULL; // search_regcomp() will use previous pattern + patlen = 0; sub = vim_strsave(old_sub); // Vi compatibility quirk: repeating with ":s" keeps the cursor in the @@ -3929,9 +3933,9 @@ ex_substitute(exarg_T *eap) } 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); vim_free(sub); return; @@ -4066,7 +4070,7 @@ ex_substitute(exarg_T *eap) return; } - if (search_regcomp(pat, NULL, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL) + if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL) { if (subflags.do_error) emsg(_(e_invalid_command)); @@ -5104,6 +5108,7 @@ ex_global(exarg_T *eap) char_u delim; // delimiter, normally '/' char_u *pat; + size_t patlen; char_u *used_pat; regmmatch_T regmatch; int match; @@ -5150,6 +5155,7 @@ ex_global(exarg_T *eap) which_pat = RE_SEARCH; // use previous search pattern ++cmd; pat = (char_u *)""; + patlen = 0; } else if (*cmd == NUL) { @@ -5165,12 +5171,13 @@ 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 } - if (search_regcomp(pat, &used_pat, RE_BOTH, which_pat, SEARCH_HIS, + if (search_regcomp(pat, patlen, &used_pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) { emsg(_(e_invalid_command)); diff --git a/src/ex_docmd.c b/src/ex_docmd.c index a588f2665e..c2aaca0656 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -4567,7 +4567,7 @@ get_address( curwin->w_cursor.col = 0; searchcmdlen = 0; flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG; - if (!do_search(NULL, c, c, cmd, 1L, flags, NULL)) + if (!do_search(NULL, c, c, cmd, STRLEN(cmd), 1L, flags, NULL)) { curwin->w_cursor = pos; cmd = NULL; @@ -4621,7 +4621,7 @@ get_address( pos.coladd = 0; if (searchit(curwin, curbuf, &pos, NULL, *cmd == '?' ? BACKWARD : FORWARD, - (char_u *)"", 1L, SEARCH_MSG, i, NULL) != FAIL) + (char_u *)"", 0, 1L, SEARCH_MSG, i, NULL) != FAIL) lnum = pos.lnum; else { diff --git a/src/ex_getln.c b/src/ex_getln.c index 1731d2952c..3ae4958f8e 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -493,7 +493,7 @@ may_do_incsearch_highlighting( sia.sa_tm = 500; #endif found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, - ccline.cmdbuff + skiplen, count, search_flags, + ccline.cmdbuff + skiplen, patlen, count, search_flags, #ifdef FEAT_RELTIME &sia #else @@ -654,7 +654,7 @@ may_adjust_incsearch_highlighting( pat[patlen] = NUL; i = searchit(curwin, curbuf, &t, NULL, c == Ctrl_G ? FORWARD : BACKWARD, - pat, count, search_flags, RE_SEARCH, NULL); + pat, patlen, count, search_flags, RE_SEARCH, NULL); --emsg_off; pat[patlen] = save; if (i) @@ -2539,12 +2539,14 @@ returncmd: if (ccline.cmdlen && firstc != NUL && (some_key_typed || histype == HIST_SEARCH)) { - add_to_history(histype, ccline.cmdbuff, TRUE, + size_t cmdbufflen = STRLEN(ccline.cmdbuff); + + add_to_history(histype, ccline.cmdbuff, cmdbufflen, TRUE, histype == HIST_SEARCH ? firstc : NUL); if (firstc == ':') { vim_free(new_last_cmdline); - new_last_cmdline = vim_strsave(ccline.cmdbuff); + new_last_cmdline = vim_strnsave(ccline.cmdbuff, cmdbufflen); } } diff --git a/src/gui.c b/src/gui.c index 1953691021..25662ef2cb 100644 --- a/src/gui.c +++ b/src/gui.c @@ -5312,7 +5312,7 @@ gui_do_findrepl( i = msg_scroll; if (down) { - (void)do_search(NULL, '/', '/', ga.ga_data, 1L, searchflags, NULL); + (void)do_search(NULL, '/', '/', ga.ga_data, STRLEN(ga.ga_data), 1L, searchflags, NULL); } else { @@ -5320,7 +5320,7 @@ gui_do_findrepl( // direction p = vim_strsave_escaped(ga.ga_data, (char_u *)"?"); if (p != NULL) - (void)do_search(NULL, '?', '?', p, 1L, searchflags, NULL); + (void)do_search(NULL, '?', '?', p, STRLEN(p), 1L, searchflags, NULL); vim_free(p); } diff --git a/src/insexpand.c b/src/insexpand.c index 1520d57609..c420c0ed93 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -176,6 +176,7 @@ static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; // number of completion matches static char_u *compl_pattern = NULL; +static size_t compl_patternlen = 0; static int compl_direction = FORWARD; static int compl_shows_dir = FORWARD; static int compl_pending = 0; // > 1 for postponed CTRL-N @@ -1708,6 +1709,7 @@ ins_compl_free(void) int i; VIM_CLEAR(compl_pattern); + compl_patternlen = 0; VIM_CLEAR(compl_leader); if (compl_first_match == NULL) @@ -1747,6 +1749,7 @@ ins_compl_clear(void) compl_started = FALSE; compl_matches = 0; VIM_CLEAR(compl_pattern); + compl_patternlen = 0; VIM_CLEAR(compl_leader); edit_submode_extra = NULL; VIM_CLEAR(compl_orig_text); @@ -3374,7 +3377,7 @@ done: get_next_include_file_completion(int compl_type) { find_pattern_in_path(compl_pattern, compl_direction, - (int)STRLEN(compl_pattern), FALSE, FALSE, + compl_patternlen, FALSE, FALSE, (compl_type == CTRL_X_PATH_DEFINES && !(compl_cont_status & CONT_SOL)) ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND, @@ -3478,8 +3481,7 @@ get_next_cmdline_completion(void) int num_matches; if (expand_cmdline(&compl_xp, compl_pattern, - (int)STRLEN(compl_pattern), - &num_matches, &matches) == EXPAND_OK) + compl_patternlen, &num_matches, &matches) == EXPAND_OK) ins_compl_add_matches(num_matches, matches, FALSE); } @@ -3644,8 +3646,8 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos) st->cur_match_pos, compl_direction, compl_pattern); else found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, - NULL, compl_direction, compl_pattern, 1L, - SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); + NULL, compl_direction, compl_pattern, compl_patternlen, + 1L, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); --msg_silent; if (!compl_started || st->set_match_pos) { @@ -4383,7 +4385,8 @@ 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 @@ -4404,32 +4407,45 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) else compl_pattern = vim_strnsave(line + compl_col, compl_length); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } } else if (compl_status_adding()) { char_u *prefix = (char_u *)"\\<"; + size_t prefixlen = STRLEN_LITERAL("\\<"); // we need up to 2 extra chars for the prefix compl_pattern = alloc(quote_meta(NULL, line + compl_col, - compl_length) + 2); + compl_length) + prefixlen); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } if (!vim_iswordp(line + compl_col) || (compl_col > 0 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) + { prefix = (char_u *)""; + prefixlen = 0; + } STRCPY((char *)compl_pattern, prefix); - (void)quote_meta(compl_pattern + STRLEN(prefix), + (void)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 = vim_strsave((char_u *)"\\<\\k\\k"); + compl_pattern = vim_strnsave((char_u *)"\\<\\k\\k", STRLEN_LITERAL("\\<\\k\\k")); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } compl_col += curs_col; compl_length = 0; } @@ -4465,7 +4481,10 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) // alloc(7) is enough -- Acevedo compl_pattern = alloc(7); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } STRCPY((char *)compl_pattern, "\\<"); (void)quote_meta(compl_pattern + 2, line + compl_col, 1); STRCAT((char *)compl_pattern, "\\k"); @@ -4475,13 +4494,18 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) compl_pattern = alloc(quote_meta(NULL, line + compl_col, compl_length) + 2); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } STRCPY((char *)compl_pattern, "\\<"); (void)quote_meta(compl_pattern + 2, line + compl_col, compl_length); } } + compl_patternlen = STRLEN(compl_pattern); + return OK; } @@ -4503,7 +4527,12 @@ get_wholeline_compl_info(char_u *line, colnr_T curs_col) else compl_pattern = vim_strnsave(line + compl_col, compl_length); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } + + compl_patternlen = STRLEN(compl_pattern); return OK; } @@ -4533,7 +4562,12 @@ get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col) compl_length = (int)curs_col - startcol; compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } + + compl_patternlen = STRLEN(compl_pattern); return OK; } @@ -4547,9 +4581,13 @@ get_cmdline_compl_info(char_u *line, colnr_T curs_col) { compl_pattern = vim_strnsave(line, curs_col); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } + compl_patternlen = curs_col; set_cmd_context(&compl_xp, compl_pattern, - (int)STRLEN(compl_pattern), curs_col, FALSE); + 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 @@ -4647,8 +4685,12 @@ get_userdefined_compl_info(colnr_T curs_col UNUSED) compl_length = curs_col - compl_col; compl_pattern = vim_strnsave(line + compl_col, compl_length); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } + compl_patternlen = compl_length; ret = OK; #endif @@ -4685,8 +4727,12 @@ get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED) line = ml_get(curwin->w_cursor.lnum); compl_pattern = vim_strnsave(line + compl_col, compl_length); if (compl_pattern == NULL) + { + compl_patternlen = 0; return FAIL; + } + compl_patternlen = compl_length; ret = OK; #endif @@ -4907,6 +4953,7 @@ ins_compl_start(void) -1, NULL, NULL, NULL, 0, flags, FALSE) != OK) { VIM_CLEAR(compl_pattern); + compl_patternlen = 0; VIM_CLEAR(compl_orig_text); return FAIL; } diff --git a/src/normal.c b/src/normal.c index 580eb72298..38c6bad80f 100644 --- a/src/normal.c +++ b/src/normal.c @@ -61,7 +61,7 @@ static void nv_end(cmdarg_T *cap); static void nv_dollar(cmdarg_T *cap); static void nv_search(cmdarg_T *cap); static void nv_next(cmdarg_T *cap); -static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt, int *wrapped); +static int normal_search(cmdarg_T *cap, int dir, char_u *pat, size_t patlen, int opt, int *wrapped); static void nv_csearch(cmdarg_T *cap); static void nv_brackets(cmdarg_T *cap); static void nv_percent(cmdarg_T *cap); @@ -2169,6 +2169,7 @@ find_decl( int flags_arg) // flags passed to searchit() { char_u *pat; + size_t patlen; pos_T old_pos; pos_T par_pos; pos_T found_pos; @@ -2185,8 +2186,9 @@ find_decl( // Put "\V" before the pattern to avoid that the special meaning of "." // and "~" causes trouble. - sprintf((char *)pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", - len, ptr); + patlen = vim_snprintf((char *)pat, len + 7, + vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", len, ptr); + old_pos = curwin->w_cursor; save_p_ws = p_ws; save_p_scs = p_scs; @@ -2215,7 +2217,7 @@ find_decl( for (;;) { t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD, - pat, 1L, searchflags, RE_LAST, NULL); + pat, patlen, 1L, searchflags, RE_LAST, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) t = FAIL; // match after start is failure too @@ -3332,7 +3334,8 @@ nv_K_getcmd( char_u **ptr_arg, int n, char_u *buf, - unsigned buflen) + size_t bufsize, + size_t *buflen) { char_u *ptr = *ptr_arg; int isman; @@ -3342,6 +3345,7 @@ nv_K_getcmd( { // in the help buffer STRCPY(buf, "he! "); + *buflen = STRLEN_LITERAL("he! "); return n; } @@ -3349,10 +3353,9 @@ nv_K_getcmd( { // 'keywordprog' is an ex command if (cap->count0 != 0) - vim_snprintf((char *)buf, buflen, "%s %ld", kp, cap->count0); + *buflen = vim_snprintf((char *)buf, bufsize, "%s %ld ", kp, cap->count0); else - STRCPY(buf, kp); - STRCAT(buf, " "); + *buflen = vim_snprintf((char *)buf, bufsize, "%s ", kp); return n; } @@ -3377,19 +3380,16 @@ nv_K_getcmd( isman = (STRCMP(kp, "man") == 0); isman_s = (STRCMP(kp, "man -s") == 0); if (cap->count0 != 0 && !(isman || isman_s)) - sprintf((char *)buf, ".,.+%ld", cap->count0 - 1); + *buflen = vim_snprintf((char *)buf, bufsize, ".,.+%ld! ", cap->count0 - 1); + else + *buflen = vim_snprintf((char *)buf, bufsize, "! "); - STRCAT(buf, "! "); if (cap->count0 == 0 && isman_s) - STRCAT(buf, "man"); + *buflen += vim_snprintf((char *)buf + *buflen, bufsize - *buflen, "man "); else - STRCAT(buf, kp); - STRCAT(buf, " "); + *buflen += vim_snprintf((char *)buf + *buflen, bufsize - *buflen, "%s ", kp); if (cap->count0 != 0 && (isman || isman_s)) - { - sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0); - STRCAT(buf, " "); - } + *buflen += vim_snprintf((char *)buf + *buflen, bufsize - *buflen, "%ld ", cap->count0); *ptr_arg = ptr; return n; @@ -3408,7 +3408,8 @@ nv_ident(cmdarg_T *cap) { char_u *ptr = NULL; char_u *buf; - unsigned buflen; + size_t bufsize; + size_t buflen; char_u *newbuf; char_u *p; char_u *kp; // value of 'keywordprg' @@ -3463,11 +3464,12 @@ nv_ident(cmdarg_T *cap) return; } kp_ex = (*kp == ':'); - buflen = (unsigned)(n * 2 + 30 + STRLEN(kp)); - buf = alloc(buflen); + bufsize = (size_t)(n * 2 + 30 + STRLEN(kp)); + buf = alloc(bufsize); if (buf == NULL) return; buf[0] = NUL; + buflen = 0; switch (cmdchar) { @@ -3481,12 +3483,15 @@ nv_ident(cmdarg_T *cap) curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline()); 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, buflen); + n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, bufsize, &buflen); if (n == 0) return; break; @@ -3495,30 +3500,47 @@ nv_ident(cmdarg_T *cap) tag_cmd = TRUE; #ifdef FEAT_CSCOPE if (p_cst) + { STRCPY(buf, "cstag "); + buflen = STRLEN_LITERAL("cstag "); + } else #endif + { 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 - sprintf((char *)buf, ":%ldta ", cap->count0); + buflen = vim_snprintf((char *)buf, bufsize, ":%ldta ", cap->count0); } } // Now grab the chars in the identifier if (cmdchar == 'K' && !kp_help) { + size_t plen; + ptr = vim_strnsave(ptr, n); if (kp_ex) // Escape the argument properly for an Ex command @@ -3532,7 +3554,8 @@ nv_ident(cmdarg_T *cap) vim_free(buf); return; } - newbuf = vim_realloc(buf, STRLEN(buf) + STRLEN(p) + 1); + plen = STRLEN(p); + newbuf = vim_realloc(buf, buflen + plen + 1); if (newbuf == NULL) { vim_free(buf); @@ -3540,7 +3563,8 @@ nv_ident(cmdarg_T *cap) return; } buf = newbuf; - STRCAT(buf, p); + STRCPY(buf + buflen, p); + buflen += plen; vim_free(p); } else @@ -3560,12 +3584,13 @@ nv_ident(cmdarg_T *cap) else aux_ptr = (char_u *)"\\|\"\n*?["; - p = buf + STRLEN(buf); + p = buf + buflen; while (n-- > 0) { // put a backslash before \ and some others if (vim_strchr(aux_ptr, *ptr) != NULL) *p++ = '\\'; + // When current byte is a part of multibyte character, copy all // bytes of that character. if (has_mbyte) @@ -3579,6 +3604,7 @@ nv_ident(cmdarg_T *cap) *p++ = *ptr++; } *p = NUL; + buflen = p - buf; } // Execute the command. @@ -3587,13 +3613,16 @@ nv_ident(cmdarg_T *cap) if (!g_cmd && (has_mbyte ? vim_iswordp(mb_prevptr(ml_get_curline(), ptr)) : vim_iswordc(ptr[-1]))) - STRCAT(buf, "\\>"); + { + 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); - (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0, NULL); + (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, buflen, 0, NULL); } else { @@ -4117,7 +4146,7 @@ nv_search(cmdarg_T *cap) return; } - (void)normal_search(cap, cap->cmdchar, cap->searchbuf, + (void)normal_search(cap, cap->cmdchar, cap->searchbuf, STRLEN(cap->searchbuf), (cap->arg || !EQUAL_POS(save_cursor, curwin->w_cursor)) ? 0 : SEARCH_MARK, NULL); } @@ -4132,7 +4161,7 @@ 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 && EQUAL_POS(old, curwin->w_cursor)) { @@ -4140,7 +4169,7 @@ nv_next(cmdarg_T *cap) // happen when an offset is given and the cursor is on the last char // in the buffer: Repeat with count + 1. cap->count1 += 1; - (void)normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, NULL); + (void)normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, NULL); cap->count1 -= 1; } @@ -4161,6 +4190,7 @@ normal_search( cmdarg_T *cap, int dir, char_u *pat, + size_t patlen, int opt, // extra flags for do_search() int *wrapped) { @@ -4176,7 +4206,7 @@ normal_search( curwin->w_set_curswant = TRUE; CLEAR_FIELD(sia); - i = do_search(cap->oap, dir, dir, pat, cap->count1, + 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; @@ -4201,6 +4231,7 @@ normal_search( // "/$" will put the cursor after the end of the line, may need to // correct that here check_cursor(); + return i; } diff --git a/src/proto/cmdhist.pro b/src/proto/cmdhist.pro index 9c9e56c075..5bf4b8da44 100644 --- a/src/proto/cmdhist.pro +++ b/src/proto/cmdhist.pro @@ -9,7 +9,7 @@ char_u *get_history_arg(expand_T *xp, int idx); void init_history(void); void clear_hist_entry(histentry_T *hisptr); int in_history(int type, char_u *str, int move_to_front, int sep, int writing); -void add_to_history(int histype, char_u *new_entry, int in_map, int sep); +void add_to_history(int histype, char_u *new_entry, size_t new_entrylen, int in_map, int sep); void f_histadd(typval_T *argvars, typval_T *rettv); void f_histdel(typval_T *argvars, typval_T *rettv); void f_histget(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/search.pro b/src/proto/search.pro index 5b2b889317..d9cb16aa84 100644 --- a/src/proto/search.pro +++ b/src/proto/search.pro @@ -1,7 +1,7 @@ /* search.c */ -int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch); +int search_regcomp(char_u *pat, size_t patlen, char_u **used_pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch); char_u *get_search_pat(void); -void save_re_pat(int idx, char_u *pat, int magic); +void save_re_pat(int idx, char_u *pat, size_t patlen, int magic); void save_search_patterns(void); void restore_search_patterns(void); void free_search_patterns(void); @@ -21,9 +21,9 @@ char_u *last_search_pat(void); void reset_search_dir(void); void set_last_search_pat(char_u *s, int idx, int magic, int setlast); void last_pat_prog(regmmatch_T *regmatch); -int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, int dir, char_u *pat, long count, int options, int pat_use, searchit_arg_T *extra_arg); +int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, int dir, char_u *pat, size_t patlen, long count, int options, int pat_use, searchit_arg_T *extra_arg); void set_search_direction(int cdir); -int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, int options, searchit_arg_T *sia); +int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, size_t patlen, long count, int options, searchit_arg_T *sia); int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat); int searchc(cmdarg_T *cap, int t_cmd); pos_T *findmatch(oparg_T *oap, int initc); diff --git a/src/quickfix.c b/src/quickfix.c index 660622fc50..414fe650d7 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3388,7 +3388,7 @@ qf_jump_goto_line( // Move the cursor to the first line in the buffer save_cursor = curwin->w_cursor; curwin->w_cursor.lnum = 0; - if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL)) + if (!do_search(NULL, '/', '/', qf_pattern, STRLEN(qf_pattern), (long)1, SEARCH_KEEP, NULL)) curwin->w_cursor = save_cursor; } } diff --git a/src/search.c b/src/search.c index 166ef4a580..43c40e03d5 100644 --- a/src/search.c +++ b/src/search.c @@ -17,8 +17,8 @@ static void set_vv_searchforward(void); static int first_submatch(regmmatch_T *rp); #endif #ifdef FEAT_FIND_ID -static void show_pat_in_path(char_u *, int, - int, int, FILE *, linenr_T *, long); +static char_u *get_line_and_copy(linenr_T lnum, char_u *buf); +static void show_pat_in_path(char_u *, int, int, int, FILE *, linenr_T *, long); #endif typedef struct searchstat @@ -32,8 +32,27 @@ typedef struct searchstat int last_maxcount; // the max count of the last search } searchstat_T; -static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, int recompute, int maxcount, long timeout); +#ifdef FEAT_SEARCH_EXTRA +static void save_incsearch_state(void); +static void restore_incsearch_state(void); +#endif +static int check_prevcol(char_u *linep, int col, int ch, int *prevcol); +static int find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos); +static void find_mps_values(int *initc, int *findc, int *backwards, int switchit); +static int is_zero_width(char_u *pattern, size_t patternlen, int move, pos_T *cur, int direction); +static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, size_t msgbuflen, int recompute, int maxcount, long timeout); static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchstat_T *stat, int recompute, int maxcount, long timeout); +static int fuzzy_match_compute_score(char_u *str, int strSz, int_u *matches, int numMatches); +static int fuzzy_match_recursive(char_u *fuzpat, char_u *str, int_u strIdx, int *outScore, char_u *strBegin, int strLen, int_u *srcMatches, int_u *matches, int maxMatches, int nextMatch, int *recursionCount); +#if defined(FEAT_EVAL) || defined(FEAT_PROTO) +static int fuzzy_match_item_compare(const void *s1, const void *s2); +static void fuzzy_match_in_list(list_T *l, char_u *str, int matchseq, char_u *key, callback_T *item_cb, int retmatchpos, list_T *fmatchlist, long max_matches); +static void do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos); +#endif +static int fuzzy_match_str_compare(const void *s1, const void *s2); +static void fuzzy_match_str_sort(fuzmatch_str_T *fm, int sz); +static int fuzzy_match_func_compare(const void *s1, const void *s2); +static void fuzzy_match_func_sort(fuzmatch_str_T *fm, int sz); #define SEARCH_STAT_DEF_TIMEOUT 40L #define SEARCH_STAT_DEF_MAX_COUNT 99 @@ -69,8 +88,8 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst */ static spat_T spats[2] = { - {NULL, TRUE, FALSE, {'/', 0, 0, 0L}}, // last used search pat - {NULL, TRUE, FALSE, {'/', 0, 0, 0L}} // last used substitute pat + {NULL, 0, TRUE, FALSE, {'/', 0, 0, 0L}}, // last used search pat + {NULL, 0, TRUE, FALSE, {'/', 0, 0, 0L}} // last used substitute pat }; static int last_idx = 0; // index in spats[] for RE_LAST @@ -82,8 +101,9 @@ static char_u 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 spat_T saved_spats[2]; +static spat_T saved_spats[ARRAY_LENGTH(spats)]; static char_u *saved_mr_pattern = NULL; +static size_t saved_mr_patternlen = 0; # ifdef FEAT_SEARCH_EXTRA static int saved_spats_last_idx = 0; static int saved_spats_no_hlsearch = 0; @@ -91,6 +111,7 @@ static int saved_spats_no_hlsearch = 0; // allocated copy of pattern used by search_regcomp() static char_u *mr_pattern = NULL; +static size_t mr_patternlen = 0; #ifdef FEAT_FIND_ID /* @@ -123,6 +144,7 @@ typedef struct SearchedFile int search_regcomp( char_u *pat, + size_t patlen, char_u **used_pat, int pat_save, int pat_use, @@ -130,7 +152,6 @@ search_regcomp( regmmatch_T *regmatch) // return: pattern and ignore-case flag { int magic; - int i; rc_did_emsg = FALSE; magic = magic_isset(); @@ -140,6 +161,8 @@ search_regcomp( */ if (pat == NULL || *pat == NUL) { + int i; + if (pat_use == RE_LAST) i = last_idx; else @@ -154,11 +177,12 @@ search_regcomp( 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) *used_pat = pat; @@ -169,7 +193,11 @@ search_regcomp( mr_pattern = reverse_text(pat); else #endif - mr_pattern = vim_strsave(pat); + mr_pattern = vim_strnsave(pat, patlen); + if (mr_pattern == NULL) + mr_patternlen = 0; + else + mr_patternlen = patlen; /* * Save the currently used pattern in the appropriate place, @@ -180,10 +208,10 @@ search_regcomp( { // 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); } regmatch->rmm_ic = ignorecase(pat); @@ -204,13 +232,17 @@ get_search_pat(void) } void -save_re_pat(int idx, char_u *pat, int magic) +save_re_pat(int idx, char_u *pat, size_t patlen, int magic) { if (spats[idx].pat == pat) return; vim_free(spats[idx].pat); - spats[idx].pat = vim_strsave(pat); + spats[idx].pat = vim_strnsave(pat, patlen); + if (spats[idx].pat == NULL) + spats[idx].patlen = 0; + else + spats[idx].patlen = patlen; spats[idx].magic = magic; spats[idx].no_scs = no_smartcase; last_idx = idx; @@ -231,19 +263,31 @@ static int save_level = 0; void save_search_patterns(void) { + int i; + if (save_level++ != 0) return; - saved_spats[0] = spats[0]; - if (spats[0].pat != NULL) - saved_spats[0].pat = vim_strsave(spats[0].pat); - saved_spats[1] = spats[1]; - if (spats[1].pat != NULL) - saved_spats[1].pat = vim_strsave(spats[1].pat); + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + saved_spats[i] = spats[i]; + if (spats[i].pat != NULL) + { + saved_spats[i].pat = vim_strnsave(spats[i].pat, spats[i].patlen); + if (saved_spats[i].pat == NULL) + saved_spats[i].patlen = 0; + else + saved_spats[i].patlen = spats[i].patlen; + } + } if (mr_pattern == NULL) saved_mr_pattern = NULL; else - saved_mr_pattern = vim_strsave(mr_pattern); + saved_mr_pattern = vim_strnsave(mr_pattern, mr_patternlen); + if (saved_mr_pattern == NULL) + saved_mr_patternlen = 0; + else + saved_mr_patternlen = mr_patternlen; #ifdef FEAT_SEARCH_EXTRA saved_spats_last_idx = last_idx; saved_spats_no_hlsearch = no_hlsearch; @@ -253,18 +297,22 @@ save_search_patterns(void) void restore_search_patterns(void) { + int i; + if (--save_level != 0) return; - vim_free(spats[0].pat); - spats[0] = saved_spats[0]; + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + vim_free(spats[i].pat); + spats[i] = saved_spats[i]; + } #if defined(FEAT_EVAL) set_vv_searchforward(); #endif - vim_free(spats[1].pat); - spats[1] = saved_spats[1]; vim_free(mr_pattern); mr_pattern = saved_mr_pattern; + mr_patternlen = saved_mr_patternlen; #ifdef FEAT_SEARCH_EXTRA last_idx = saved_spats_last_idx; set_no_hlsearch(saved_spats_no_hlsearch); @@ -275,9 +323,15 @@ restore_search_patterns(void) void free_search_patterns(void) { - vim_free(spats[0].pat); - vim_free(spats[1].pat); + int i; + + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + VIM_CLEAR(spats[i].pat); + spats[i].patlen = 0; + } VIM_CLEAR(mr_pattern); + mr_patternlen = 0; } #endif @@ -308,7 +362,13 @@ save_last_search_pattern(void) saved_last_search_spat = spats[RE_SEARCH]; if (spats[RE_SEARCH].pat != NULL) - saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat); + { + saved_last_search_spat.pat = vim_strnsave(spats[RE_SEARCH].pat, spats[RE_SEARCH].patlen); + if (saved_last_search_spat.pat == NULL) + saved_last_search_spat.patlen = 0; + else + saved_last_search_spat.patlen = spats[RE_SEARCH].patlen; + } saved_last_idx = last_idx; saved_no_hlsearch = no_hlsearch; } @@ -328,6 +388,7 @@ restore_last_search_pattern(void) vim_free(spats[RE_SEARCH].pat); spats[RE_SEARCH] = saved_last_search_spat; saved_last_search_spat.pat = NULL; + saved_last_search_spat.patlen = 0; # if defined(FEAT_EVAL) set_vv_searchforward(); # endif @@ -513,7 +574,12 @@ set_last_search_pat( if (*s == NUL) spats[idx].pat = NULL; else - spats[idx].pat = vim_strsave(s); + { + spats[idx].patlen = STRLEN(s); + spats[idx].pat = vim_strnsave(s, spats[idx].patlen); + } + if (spats[idx].pat == NULL) + spats[idx].patlen = 0; spats[idx].magic = magic; spats[idx].no_scs = FALSE; spats[idx].off.dir = '/'; @@ -532,7 +598,11 @@ set_last_search_pat( if (spats[idx].pat == NULL) saved_spats[idx].pat = NULL; else - saved_spats[idx].pat = vim_strsave(spats[idx].pat); + saved_spats[idx].pat = vim_strnsave(spats[idx].pat, spats[idx].patlen); + if (saved_spats[idx].pat == NULL) + saved_spats[idx].patlen = 0; + else + saved_spats[idx].patlen = spats[idx].patlen; # ifdef FEAT_SEARCH_EXTRA saved_spats_last_idx = last_idx; # endif @@ -560,7 +630,7 @@ last_pat_prog(regmmatch_T *regmatch) return; } ++emsg_off; // So it doesn't beep if bad expr - (void)search_regcomp((char_u *)"", NULL, 0, last_idx, SEARCH_KEEP, regmatch); + (void)search_regcomp((char_u *)"", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch); --emsg_off; } #endif @@ -594,6 +664,7 @@ searchit( pos_T *end_pos, // set to end of the match, unless NULL int dir, char_u *pat, + size_t patlen, long count, int options, int pat_use, // which pattern to use when "pat" is empty @@ -623,8 +694,9 @@ searchit( linenr_T stop_lnum = 0; // stop after this line number when != 0 int unused_timeout_flag = FALSE; int *timed_out = &unused_timeout_flag; // set when timed out. + int search_from_match_end; // vi-compatible search? - 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) @@ -632,6 +704,8 @@ searchit( return FAIL; } + search_from_match_end = vim_strchr(p_cpo, CPO_SEARCH) != NULL; + if (extra_arg != NULL) { stop_lnum = extra_arg->sa_stop_lnum; @@ -778,7 +852,7 @@ searchit( * of the match, otherwise continue one position * forward. */ - if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) + if (search_from_match_end) { if (nmatched > 1) { @@ -890,7 +964,7 @@ searchit( * 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; @@ -1173,12 +1247,14 @@ do_search( int search_delim, // the delimiter for the search, e.g. '%' in // s%regex%replacement% char_u *pat, + size_t patlen, long count, int options, searchit_arg_T *sia) // optional arguments or NULL { pos_T pos; // position of the last match char_u *searchstr; + size_t searchstrlen; soffset_T old_off; int retval; // Return value char_u *p; @@ -1186,10 +1262,13 @@ do_search( char_u *dircp; char_u *strcopy = NULL; char_u *ps; + int show_search_stats; char_u *msgbuf = NULL; - size_t len; + size_t msgbuflen = 0; int has_offset = FALSE; + searchcmdlen = 0; + /* * A line offset is not remembered, this is vi compatible. */ @@ -1267,24 +1346,28 @@ do_search( int 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_no_previous_regular_expression)); 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 = (char_u *)""; + searchstrlen = 0; } } @@ -1299,13 +1382,17 @@ do_search( &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 = p - pat; dircp = p; // remember where we put the NUL *p++ = NUL; } @@ -1344,16 +1431,19 @@ do_search( // compute length of search command for get_address() searchcmdlen += (int)(p - pat); + patlen -= p - pat; pat = p; // put pat after search command } + show_search_stats = FALSE; if ((options & SEARCH_ECHO) && messaging() && !msg_silent && (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) { - char_u *trunc; char_u off_buf[40]; size_t off_len = 0; + size_t plen; + size_t msgbufsize; // Compute msg_row early. msg_start(); @@ -1362,24 +1452,28 @@ do_search( if (!cmd_silent && (spats[0].off.line || spats[0].off.end || spats[0].off.off)) { - p = off_buf; - *p++ = dirc; + off_buf[off_len++] = 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++ = '+'; - *p = NUL; + off_buf[off_len++] = '+'; + off_buf[off_len] = NUL; if (spats[0].off.off != 0 || spats[0].off.line) - sprintf((char *)p, "%ld", spats[0].off.off); - off_len = STRLEN(off_buf); + off_len += vim_snprintf((char *)off_buf + off_len, sizeof(off_buf) - off_len, "%ld", spats[0].off.off); } if (*searchstr == NUL) + { p = spats[0].pat; + plen = spats[0].patlen; + } else + { p = searchstr; + plen = searchstrlen; + } if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) { @@ -1389,45 +1483,53 @@ do_search( // msg_strtrunc() will shorten in the middle. if (msg_scrolled != 0 && !cmd_silent) // Use all the columns. - len = (int)(Rows - msg_row) * Columns - 1; + msgbufsize = (int)(Rows - msg_row) * Columns - 1; else // Use up to 'showcmd' column. - len = (int)(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; + msgbufsize = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; + 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; vim_free(msgbuf); - msgbuf = alloc(len); - if (msgbuf != NULL) + msgbuf = alloc(msgbufsize); + if (msgbuf == NULL) + { + msgbuflen = 0; + } + else { - vim_memset(msgbuf, ' ', len); - msgbuf[len - 1] = NUL; + vim_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. if (!cmd_silent) { + char_u *trunc; + msgbuf[0] = dirc; if (enc_utf8 && utf_iscomposing(utf_ptr2char(p))) { // Use a space to draw the composing char on. msgbuf[1] = ' '; - mch_memmove(msgbuf + 2, p, STRLEN(p)); + mch_memmove(msgbuf + 2, p, plen); } else - mch_memmove(msgbuf + 1, p, STRLEN(p)); + mch_memmove(msgbuf + 1, p, plen); if (off_len > 0) - mch_memmove(msgbuf + STRLEN(p) + 1, off_buf, off_len); + mch_memmove(msgbuf + plen + 1, off_buf, off_len); trunc = msg_strtrunc(msgbuf, TRUE); if (trunc != NULL) { vim_free(msgbuf); msgbuf = trunc; + msgbuflen = STRLEN(msgbuf); } #ifdef FEAT_RIGHTLEFT @@ -1448,7 +1550,7 @@ do_search( // move reversed text to beginning of buffer while (*r != NUL && *r == ' ') r++; - pat_len = msgbuf + STRLEN(msgbuf) - r; + pat_len = msgbuf + msgbuflen - r; mch_memmove(msgbuf, r, pat_len); // overwrite old text if ((size_t)(r - msgbuf) >= pat_len) @@ -1466,7 +1568,10 @@ do_search( out_flush(); msg_nowait = TRUE; // don't wait for this message } - } + + if (!shortmess(SHM_SEARCHCOUNT)) + show_search_stats = TRUE; + } // msgbuf != NULL } /* @@ -1507,7 +1612,7 @@ do_search( */ c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD, - searchstr, count, spats[0].off.end + (options & + searchstr, searchstrlen, count, spats[0].off.end + (options & (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG + SEARCH_START + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))), @@ -1574,14 +1679,9 @@ do_search( } // 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 #ifdef FEAT_FOLDING || (!(fdo_flags & FDO_SEARCH) @@ -1612,6 +1712,7 @@ do_search( goto end_do_search; } ++pat; + --patlen; } if (options & SEARCH_MARK) @@ -2825,7 +2926,7 @@ showmatch( * Returns TRUE, FALSE or -1 for failure. */ static int -is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) +is_zero_width(char_u *pattern, size_t patternlen, int move, pos_T *cur, int direction) { regmmatch_T regmatch; int nmatched = 0; @@ -2835,9 +2936,12 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) int flag = 0; 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; @@ -2855,7 +2959,7 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) 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) { // Zero-width pattern should match somewhere, then we can check if @@ -2925,8 +3029,8 @@ current_search( } // Is the pattern is zero-width?, this time, don't care about the direction - zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor, - FORWARD); + 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 @@ -2957,7 +3061,7 @@ current_search( result = searchit(curwin, curbuf, &pos, &end_pos, (dir ? FORWARD : BACKWARD), - spats[last_idx].pat, (long) (i ? count : 1), + spats[last_idx].pat, spats[last_idx].patlen, (long) (i ? count : 1), SEARCH_KEEP | flags, RE_SEARCH, NULL); p_ws = old_p_ws; @@ -3061,6 +3165,7 @@ cmdline_search_stat( pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, + size_t msgbuflen, int recompute, int maxcount, long timeout) @@ -3079,34 +3184,33 @@ cmdline_search_stat( if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { if (stat.incomplete == 1) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); else if (stat.cnt > maxcount && stat.cur > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + len = 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]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]", maxcount, stat.cur); else - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", stat.cnt, stat.cur); } else #endif { if (stat.incomplete == 1) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); else if (stat.cnt > maxcount && stat.cur > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + len = 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]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]", stat.cur, maxcount); else - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", stat.cur, stat.cnt); } - len = STRLEN(t); if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) { mch_memmove(t + 2, t, len); @@ -3115,10 +3219,9 @@ cmdline_search_stat( len += 2; } - size_t msgbuf_len = STRLEN(msgbuf); - if (len > msgbuf_len) - len = msgbuf_len; - mch_memmove(msgbuf + msgbuf_len - len, t, len); + if (len > msgbuflen) + len = msgbuflen; + mch_memmove(msgbuf + msgbuflen - len, t, len); if (dirc == '?' && stat.cur == maxcount + 1) stat.cur = -1; @@ -3214,7 +3317,7 @@ update_search_stat( profile_setlimit(timeout, &start); #endif while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos, - FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) + FORWARD, NULL, 0, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) { done_search = TRUE; #ifdef FEAT_RELTIME @@ -3342,7 +3445,7 @@ find_pattern_in_path( pat = alloc(len + 5); if (pat == NULL) goto fpip_end; - sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr); + vim_snprintf((char *)pat, len + 5, whole ? "\\<%.*s\\>" : "%.*s", 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); @@ -3361,8 +3464,7 @@ find_pattern_in_path( } 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; @@ -3879,7 +3981,7 @@ exit_matched: && action == ACTION_EXPAND && !compl_status_sol() && *startp != NUL - && *(p = startp + mb_ptr2len(startp)) != NUL) + && *(startp + mb_ptr2len(startp)) != NUL) goto search_line; } line_breakcheck(); @@ -3976,6 +4078,7 @@ show_pat_in_path( long count) { char_u *p; + size_t linelen; if (did_show) msg_putchar('\n'); // cursor below last one @@ -3983,9 +4086,10 @@ show_pat_in_path( gotocmdline(TRUE); // cursor at status line if (got_int) // 'q' typed at "--more--" message return; + linelen = STRLEN(line); for (;;) { - p = line + STRLEN(line) - 1; + p = line + linelen - 1; if (fp != NULL) { // We used fgets(), so get rid of newline at end @@ -4015,6 +4119,7 @@ show_pat_in_path( { if (vim_fgets(line, LSIZE, fp)) // end of file break; + linelen = STRLEN(line); ++*lnum; } else @@ -4022,6 +4127,7 @@ show_pat_in_path( if (++*lnum > curbuf->b_ml.ml_line_count) break; line = ml_get(*lnum); + linelen = ml_get_len(*lnum); } msg_putchar('\n'); } @@ -4149,7 +4255,10 @@ f_searchcount(typval_T *argvars, typval_T *rettv) if (*pattern == NUL) goto the_end; vim_free(spats[last_idx].pat); - spats[last_idx].pat = vim_strsave(pattern); + spats[last_idx].patlen = STRLEN(pattern); + spats[last_idx].pat = vim_strnsave(pattern, spats[last_idx].patlen); + if (spats[last_idx].pat == NULL) + spats[last_idx].patlen = 0; } if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) goto the_end; // the previous pattern was never defined diff --git a/src/spell.c b/src/spell.c index 3ae484c145..909d426e20 100644 --- a/src/spell.c +++ b/src/spell.c @@ -2955,6 +2955,7 @@ ex_spellrepall(exarg_T *eap UNUSED) { pos_T pos = curwin->w_cursor; char_u *frompat; + size_t frompatlen; char_u *line; char_u *p; int save_ws = p_ws; @@ -2972,7 +2973,7 @@ ex_spellrepall(exarg_T *eap UNUSED) frompat = alloc(repl_from_len + 7); if (frompat == NULL) return; - sprintf((char *)frompat, "\\V\\<%s\\>", repl_from); + frompatlen = vim_snprintf((char *)frompat, repl_from_len + 7, "\\V\\<%s\\>", repl_from); p_ws = FALSE; sub_nsubs = 0; @@ -2980,7 +2981,7 @@ ex_spellrepall(exarg_T *eap UNUSED) curwin->w_cursor.lnum = 0; while (!got_int) { - if (do_search(NULL, '/', '/', frompat, 1L, SEARCH_KEEP, NULL) == 0 + if (do_search(NULL, '/', '/', frompat, frompatlen, 1L, SEARCH_KEEP, NULL) == 0 || u_save_cursor() == FAIL) break; diff --git a/src/structs.h b/src/structs.h index 36339c4347..b5341e3bad 100644 --- a/src/structs.h +++ b/src/structs.h @@ -4795,6 +4795,7 @@ typedef struct soffset typedef struct spat { char_u *pat; // the pattern (in allocated memory) or NULL + size_t patlen; // the length of the patten (0 is pat is NULL) int magic; // magicness of the pattern int no_scs; // no smartcase for this pattern soffset_T off; diff --git a/src/tag.c b/src/tag.c index 9117d0fd27..87ff802c74 100644 --- a/src/tag.c +++ b/src/tag.c @@ -3901,6 +3901,8 @@ jumpto_tag( str = skip_regexp(pbuf + 1, pbuf[0], FALSE) + 1; if (str > pbuf_end - 1) // search command with nothing following { + size_t pbuflen = pbuf_end - pbuf; + save_p_ws = p_ws; save_p_ic = p_ic; save_p_scs = p_scs; @@ -3914,7 +3916,7 @@ jumpto_tag( else // start search before first line curwin->w_cursor.lnum = 0; - if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, (long)1, + if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, (long)1, search_options, NULL)) retval = OK; else @@ -3926,7 +3928,7 @@ jumpto_tag( * try again, ignore case now */ p_ic = TRUE; - if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, (long)1, + if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, (long)1, search_options, NULL)) { /* @@ -3936,14 +3938,14 @@ jumpto_tag( (void)test_for_static(&tagp); cc = *tagp.tagname_end; *tagp.tagname_end = NUL; - sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname); - if (!do_search(NULL, '/', '/', pbuf, (long)1, + pbuflen = vim_snprintf((char *)pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname); + if (!do_search(NULL, '/', '/', pbuf, pbuflen, (long)1, search_options, NULL)) { // Guess again: "^char * \