patch 9.1.0426: too many strlen() calls in search.c

Commit: 
https://github.com/vim/vim/commit/8c85a2a49acf80e4f53ec51e6ff2a5f3830eeddb
Author: John Marriott <basil...@internode.on.net>
Date:   Mon May 20 19:18:26 2024 +0200

    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 <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/cmdhist.c b/src/cmdhist.c
index 6342f02bd..7cdcee6b8 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 571ac0862..903205ad3 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 5c34e8645..8143c2406 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, &regmatch) 
== FAIL)
+    if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat, SEARCH_HIS, 
&regmatch) == 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,
                                                            &regmatch) == FAIL)
     {
        emsg(_(e_invalid_command));
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index a588f2665..c2aaca065 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 1731d2952..3ae4958f8 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 195369102..25662ef2c 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 1520d5760..c420c0ed9 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 580eb7229..38c6bad80 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 *)"\|\"
*?[";
 
-       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 9c9e56c07..5bf4b8da4 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 5b2b88931..d9cb16aa8 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 660622fc5..414fe650d 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 166ef4a58..43c40e03d 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)), &regmatch) == 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, &regmatch) == 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('
');     // 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('
');
     }
@@ -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 3ae484c14..909d426e2 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 36339c434..b5341e3ba 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 9117d0fd2..87ff802c7 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 * \<func  ("
-                       sprintf((char *)pbuf, "^\[#a-zA-Z_]\.\*\<%s\s\*(",
+                       pbuflen = vim_snprintf((char *)pbuf, LSIZE, 
"^\[#a-zA-Z_]\.\*\<%s\s\*(",
                                                                tagp.tagname);
-                       if (!do_search(NULL, '/', '/', pbuf, (long)1,
+                       if (!do_search(NULL, '/', '/', pbuf, len, (long)1,
                                                         search_options, NULL))
                            found = 0;
                    }
diff --git a/src/version.c b/src/version.c
index 7941f8af7..1ab889be6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    426,
 /**/
     425,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1s96pn-00Deob-Tb%40256bit.org.

Raspunde prin e-mail lui