]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0291: too many strlen() calls v9.2.0291
authorJohn Marriott <basilisk@internode.on.net>
Fri, 3 Apr 2026 15:08:48 +0000 (15:08 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 3 Apr 2026 15:14:24 +0000 (15:14 +0000)
Problem:  too many strlen() calls
Solution: refactor concat_fname() and remove calls to strlen()
          (John Marriott)

Function `concat_fnames()` can make up to 5 calls to `STRLEN()` (either
directly or indirectly via `STRCAT()`). In many cases the lengths of
arguments `fname1` and/or `fname2` are either known or can simply be
calculated.

This Commit refactors this function to accept the lengths of arguments
`fname1` and `fname2` as arguments. It also adds new argument `ret` to
return the resulting string as a `string_T`.

Additionally:
- function `add_pack_dir_to_rtp()` in `scriptfile.c`:
   Use a `string_T` to store local variables `new_rtp` and `afterdir`.
   Replace calls to `STRCAT()` with calls to `STRCPY()`.
   Change type of variable `keep` to `size_t` for consistency with
   other lengths.

- function `qf_get_fnum()` in `quickfix.c`:
  Use a `string_T` to store local variables `ptr` and `bufname`
- function `qf_push_dir()` in `quickfix.c`:
  Use a `string_T` to store local variable `dirname`.
  Replace call to `vim_strsave()` with `vim_strnsave()`.

- function `qf_guess_filepath()` in `quickfix.c`:
  Use a `string_T` to store local variable `fullname`.

- function `make_percent_swname()` in `memline.c`:
  Rename some variables to better reflect their use.
  Use a `string_T` to store local variables `d` and `fixed_name`.
  Slightly refactor to remove need to create an extra string.
- function `get_file_in_dir()` in `memline.c`:
  Use a `string_T` to store local variables `tail` and `retval`.
  Move some variables closer to where they are used.

- function `cs_resolve_file()` in `if_cscope.c`:
  Use a `string_T` to store local variable `csdir`.
  Remove one call to `STRLEN()`.

- function `add_pathsep()` in `filepath.c`:
  Refactor and remove 1 call to `STRLEN()`

- function `set_init_xdg_rtp()` in `option.c`:
  Use a `string_T` to store local variable `vimrc_xdg`.

closes: #19854

Co-authored-by: Christian Brabandt <cb@256bit.org>
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
12 files changed:
src/filepath.c
src/if_cscope.c
src/main.c
src/memline.c
src/misc1.c
src/option.c
src/os_win32.c
src/proto/filepath.pro
src/quickfix.c
src/scriptfile.c
src/undo.c
src/version.c

index 91423d9dccd1c2f8d04d428fcaa220405d997e00..721dbc05d73d7d5bb0d253d8f24839d1e882898d 100644 (file)
@@ -3178,19 +3178,25 @@ vim_fnamencmp(char_u *x, char_u *y, size_t len)
  * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary.
  */
     char_u  *
-concat_fnames(char_u *fname1, char_u *fname2, int sep)
+concat_fnames(char_u *fname1, size_t fname1len, char_u *fname2, size_t fname2len, int sep, string_T *ret)
 {
-    char_u  *dest;
-
-    dest = alloc(STRLEN(fname1) + STRLEN(fname2) + 3);
-    if (dest == NULL)
-       return NULL;
+    ret->string = alloc(fname1len + (sep ? STRLEN_LITERAL(PATHSEPSTR) : 0) + fname2len + 1);
+    if (ret->string == NULL)
+       ret->length = 0;
+    else
+    {
+       STRCPY(ret->string, fname1);
+       ret->length = fname1len;
+       if (sep && *ret->string != NUL && !after_pathsep(ret->string, ret->string + ret->length))
+       {
+           STRCPY(ret->string + ret->length, PATHSEPSTR);
+           ret->length += STRLEN_LITERAL(PATHSEPSTR);
+       }
+       STRCPY(ret->string + ret->length, fname2);
+       ret->length += fname2len;
+    }
 
-    STRCPY(dest, fname1);
-    if (sep)
-       add_pathsep(dest);
-    STRCAT(dest, fname2);
-    return dest;
+    return ret->string;
 }
 
 /*
@@ -3200,8 +3206,14 @@ concat_fnames(char_u *fname1, char_u *fname2, int sep)
     void
 add_pathsep(char_u *p)
 {
-    if (*p != NUL && !after_pathsep(p, p + STRLEN(p)))
-       STRCAT(p, PATHSEPSTR);
+    size_t  plen;
+
+    if (*p == NUL)
+       return;
+
+    plen = STRLEN(p);
+    if (!after_pathsep(p, p + plen))
+       STRCPY(p + plen, PATHSEPSTR);
 }
 
 /*
index 10437a532b6b9acd246b629d71babd3d80fe2f8b..796200077748bca71ca0dca4832505468a9ffda5 100644 (file)
@@ -2413,28 +2413,35 @@ cs_reset(exarg_T *eap UNUSED)
 cs_resolve_file(int i, char *name)
 {
     char       *fullname;
+    string_T   csdir = {NULL, 0};
+    size_t     namelen;
+    size_t     ppathlen = 0;
     int                len;
-    char_u     *csdir = NULL;
 
     /*
      * Ppath is freed when we destroy the cscope connection.
      * Fullname is freed after cs_make_vim_style_matches, after it's been
      * copied into the tag buffer used by Vim.
      */
-    len = (int)(strlen(name) + 2);
+    namelen = STRLEN(name);
+    len = (int)namelen + 2;
     if (csinfo[i].ppath != NULL)
-       len += (int)strlen(csinfo[i].ppath);
+    {
+       ppathlen = STRLEN(csinfo[i].ppath);
+       len += (int)ppathlen;
+    }
     else if (p_csre && csinfo[i].fname != NULL)
     {
        // If 'cscoperelative' is set and ppath is not set, use cscope.out
        // path in path resolution.
-       csdir = alloc(MAXPATHL);
-       if (csdir != NULL)
+       csdir.string = alloc(MAXPATHL);
+       if (csdir.string != NULL)
        {
-           vim_strncpy(csdir, (char_u *)csinfo[i].fname,
+           vim_strncpy(csdir.string, (char_u *)csinfo[i].fname,
                                          gettail((char_u *)csinfo[i].fname)
                                                 - (char_u *)csinfo[i].fname);
-           len += (int)STRLEN(csdir);
+           csdir.length = STRLEN(csdir.string);
+           len += (int)csdir.length;
        }
     }
 
@@ -2442,7 +2449,7 @@ cs_resolve_file(int i, char *name)
     // "../.." and the prefix path is also "../..".  if something like this
     // happens, you are screwed up and need to fix how you're using cscope.
     if (csinfo[i].ppath != NULL
-           && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0)
+           && (strncmp(name, csinfo[i].ppath, ppathlen) != 0)
            && (name[0] != '/')
 # ifdef MSWIN
            && name[0] != '\\' && name[1] != ':'
@@ -2452,18 +2459,20 @@ cs_resolve_file(int i, char *name)
        if ((fullname = alloc(len)) != NULL)
            (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
     }
-    else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL)
+    else if (csdir.string != NULL && csinfo[i].fname != NULL && *csdir.string != NUL)
     {
+       string_T    ret;
+
        // Check for csdir to be non empty to avoid empty path concatenated to
        // cscope output.
-       fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE);
+       fullname = (char *)concat_fnames(csdir.string, csdir.length, (char_u *)name, namelen, TRUE, &ret);
     }
     else
     {
-       fullname = (char *)vim_strsave((char_u *)name);
+       fullname = (char *)vim_strnsave((char_u *)name, namelen);
     }
 
-    vim_free(csdir);
+    vim_free(csdir.string);
     return fullname;
 }
 
index b5f542a496b4ea50ea8654ee3f347836a544795b..d4019ff51eaa088c2c6d4d8370eae7e05cf74e59 100644 (file)
@@ -2771,13 +2771,15 @@ scripterror:
            if (parmp->diff_mode && mch_isdir(p) && GARGCOUNT > 0
                                      && !mch_isdir(alist_name(&GARGLIST[0])))
            {
-               char_u      *r;
+               char_u      *tail;
+               string_T    ret;
 
-               r = concat_fnames(p, gettail(alist_name(&GARGLIST[0])), TRUE);
-               if (r != NULL)
+               tail = gettail(alist_name(&GARGLIST[0]));
+               concat_fnames(p, STRLEN(p), tail, STRLEN(tail), TRUE, &ret);
+               if (ret.string != NULL)
                {
                    vim_free(p);
-                   p = r;
+                   p = ret.string;
                }
            }
 # endif
index 97396b0b194feec59dea84ece606b67f50be9d94..35b1fae2301737a25b39fd8d5708557e17e7ec29 100644 (file)
@@ -1892,7 +1892,6 @@ recover_names(
 {
     int                num_names;
     char_u     *(names[6]);
-    char_u     *tail;
     char_u     *p;
     int                num_files;
     int                file_count = 0;
@@ -1969,20 +1968,27 @@ recover_names(
        {
            if (fname == NULL)
            {
+               string_T    ret;
+
 #ifdef VMS
-               names[0] = concat_fnames(dir_name.string, (char_u *)"*_sw%", TRUE);
+               names[0] = concat_fnames(dir_name.string, dir_name.length,
+                   (char_u *)"*_sw%", STRLEN_LITERAL("*_sw%"), TRUE, &ret);
 #else
-               names[0] = concat_fnames(dir_name.string, (char_u *)"*.sw?", TRUE);
+               names[0] = concat_fnames(dir_name.string, dir_name.length,
+                   (char_u *)"*.sw?", STRLEN_LITERAL("*.sw?"), TRUE, &ret);
 #endif
 #if defined(UNIX) || defined(MSWIN)
                // For Unix names starting with a dot are special.  MS-Windows
                // supports this too, on some file systems.
-               names[1] = concat_fnames(dir_name.string, (char_u *)".*.sw?", TRUE);
-               names[2] = concat_fnames(dir_name.string, (char_u *)".sw?", TRUE);
+               names[1] = concat_fnames(dir_name.string, dir_name.length,
+                   (char_u *)".*.sw?", STRLEN_LITERAL(".*.sw?"), TRUE, &ret);
+               names[2] = concat_fnames(dir_name.string, dir_name.length,
+                   (char_u *)".sw?", STRLEN_LITERAL(".sw?"), TRUE, &ret);
                num_names = 3;
 #else
 # ifdef VMS
-               names[1] = concat_fnames(dir_name.string, (char_u *)".*_sw%", TRUE);
+               names[1] = concat_fnames(dir_name.string, dir_name.length,
+                   (char_u *)".*_sw%", STRLEN_LITERAL(".*_sw%"), TRUE, &ret);
                num_names = 2;
 # else
                num_names = 1;
@@ -1991,6 +1997,8 @@ recover_names(
            }
            else
            {
+               char_u  *tail;
+
 #if defined(UNIX) || defined(MSWIN)
                p = dir_name.string + dir_name.length;
                if (after_pathsep(dir_name.string, p) && dir_name.length > 1 && p[-1] == p[-2])
@@ -2001,8 +2009,11 @@ recover_names(
                else
 #endif
                {
+                   string_T    ret;
+
                    tail = gettail(fname_res);
-                   tail = concat_fnames(dir_name.string, tail, TRUE);
+                   tail = concat_fnames(dir_name.string, dir_name.length,
+                       tail, STRLEN(tail), TRUE, &ret);
                }
                if (tail == NULL)
                    num_names = 0;
@@ -2132,13 +2143,16 @@ recover_names(
 #ifdef FEAT_EVAL
        else if (ret_list != NULL)
        {
+           string_T    name;
+
            for (int i = 0; i < num_files; ++i)
            {
-               char_u *name = concat_fnames(dir_name.string, files[i], TRUE);
-               if (name != NULL)
+               concat_fnames(dir_name.string, dir_name.length,
+                   files[i], STRLEN(files[i]), TRUE, &name);
+               if (name.string != NULL)
                {
-                   list_append_string(ret_list, name, -1);
-                   vim_free(name);
+                   list_append_string(ret_list, name.string, (int)name.length);
+                   vim_free(name.string);
                }
            }
        }
@@ -2166,26 +2180,26 @@ recover_names(
     char_u *
 make_percent_swname(char_u *dir, char_u *dir_end, char_u *name)
 {
-    char_u *d = NULL, *s, *f;
+    string_T   d = {NULL, 0};
+    string_T   fixed_fname;
+    char_u     *p;
 
-    f = fix_fname(name != NULL ? name : (char_u *)"");
-    if (f == NULL)
+    fixed_fname.string = fix_fname(name != NULL ? name : (char_u *)"");
+    if (fixed_fname.string == NULL)
        return NULL;
 
-    s = alloc(STRLEN(f) + 1);
-    if (s != NULL)
-    {
-       STRCPY(s, f);
-       for (d = s; *d != NUL; MB_PTR_ADV(d))
-           if (vim_ispathsep(*d))
-               *d = '%';
-
-       dir_end[-1] = NUL;  // remove one trailing slash
-       d = concat_fnames(dir, s, TRUE);
-       vim_free(s);
-    }
-    vim_free(f);
-    return d;
+    for (p = fixed_fname.string; *p != NUL; MB_PTR_ADV(p))
+       if (vim_ispathsep(*p))
+           *p = '%';
+    fixed_fname.length = (size_t)(p - fixed_fname.string);
+
+    // remove one trailing slash
+    p = &dir_end[-1];
+    *p = NUL;
+    concat_fnames(dir, (size_t)(p - dir), fixed_fname.string, fixed_fname.length, TRUE, &d);
+    vim_free(fixed_fname.string);
+
+    return d.string;
 }
 #endif
 
@@ -2432,6 +2446,7 @@ recov_file_names(char_u **names, char_u *path, int prepend_dot)
 
     curbuf->b_shortname = FALSE;
 #endif
+    string_T   ret;
 
     num_names = 0;
 
@@ -2451,9 +2466,11 @@ recov_file_names(char_u **names, char_u *path, int prepend_dot)
      * Form the normal swap file name pattern by appending ".sw?".
      */
 #ifdef VMS
-    names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
+    names[num_names] = concat_fnames(path, STRLEN(path),
+       (char_u *)"_sw%", STRLEN_LITERAL("_sw%"), FALSE, &ret);
 #else
-    names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
+    names[num_names] = concat_fnames(path, STRLEN(path),
+       (char_u *)".sw?", STRLEN_LITERAL(".sw?"), FALSE, &ret);
 #endif
     if (names[num_names] == NULL)
        goto end;
@@ -4746,45 +4763,61 @@ get_file_in_dir(
     char_u  *fname,
     char_u  *dname)    // don't use "dirname", it is a global for Alpha
 {
-    char_u     *t;
-    char_u     *tail;
-    char_u     *retval;
-    int                save_char;
+    string_T   tail;
+    string_T   retval;
 
-    tail = gettail(fname);
+    tail.string = gettail(fname);
+    tail.length = STRLEN(tail.string);
 
     if (dname[0] == '.' && dname[1] == NUL)
-       retval = vim_strsave(fname);
-    else if (dname[0] == '.' && vim_ispathsep(dname[1]))
+       retval.string =
+           vim_strnsave(fname, (size_t)(tail.string - fname) + tail.length);
+    else
     {
-       if (tail == fname)          // no path before file name
-           retval = concat_fnames(dname + 2, tail, TRUE);
-       else
+       size_t  dname_len = STRLEN(dname);
+
+       if (dname[0] == '.' && vim_ispathsep(dname[1]))
        {
-           save_char = *tail;
-           *tail = NUL;
-           t = concat_fnames(fname, dname + 2, TRUE);
-           *tail = save_char;
-           if (t == NULL)          // out of memory
-               retval = NULL;
+           if (tail.string == fname)       // no path before file name
+               concat_fnames(dname + 2, dname_len - 2,
+                   tail.string, tail.length, TRUE, &retval);
            else
            {
-               retval = concat_fnames(t, tail, TRUE);
-               vim_free(t);
+               int         save_char;
+               string_T    tmp;
+
+               save_char = *tail.string;
+               *tail.string = NUL;
+               concat_fnames(fname, (size_t)(tail.string - fname),
+                   dname + 2, dname_len - 2, TRUE, &tmp);
+               *tail.string = save_char;
+               if (tmp.string == NULL)     // out of memory
+                   retval.string = NULL;
+               else
+               {
+                   concat_fnames(tmp.string, tmp.length,
+                       tail.string, tail.length, TRUE, &retval);
+                   vim_free(tmp.string);
+               }
            }
        }
+       else
+           concat_fnames(dname, dname_len, tail.string, tail.length,
+               TRUE, &retval);
     }
-    else
-       retval = concat_fnames(dname, tail, TRUE);
 
 #ifdef MSWIN
-    if (retval != NULL)
-       for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t))
+    if (retval.string != NULL)
+    {
+       char_u  *t;
+
+       for (t = gettail(retval.string); *t != NUL; MB_PTR_ADV(t))
            if (*t == ':')
                *t = '%';
+    }
 #endif
 
-    return retval;
+    return retval.string;
 }
 
 /*
index 3fa34c35e7c18fccb09545f89e2320fa13b7002b..1cf73a004de806cf24ebdaca7a1c43f070956baa 100644 (file)
@@ -1752,32 +1752,39 @@ remove_tail(char_u *p, char_u *pend, char_u *name)
     static char_u *
 vim_version_dir(char_u *vimdir)
 {
-    char_u     *p;
+    string_T   p;
+    size_t     vimdir_len;
 
     if (vimdir == NULL || *vimdir == NUL)
        return NULL;
-    p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE);
-    if (p != NULL && mch_isdir(p))
-       return p;
-    vim_free(p);
-    p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE);
-    if (p != NULL && mch_isdir(p))
+    vimdir_len = STRLEN(vimdir);
+    concat_fnames(vimdir, vimdir_len,
+       (char_u *)VIM_VERSION_NODOT, STRLEN_LITERAL(VIM_VERSION_NODOT), TRUE, &p);
+    if (p.string != NULL && mch_isdir(p.string))
+       return p.string;
+    vim_free(p.string);
+    concat_fnames(vimdir, vimdir_len,
+       (char_u *)RUNTIME_DIRNAME, STRLEN_LITERAL(RUNTIME_DIRNAME), TRUE, &p);
+    if (p.string != NULL && mch_isdir(p.string))
     {
-       char_u *fname = concat_fnames(p, (char_u *)"defaults.vim", TRUE);
+       string_T    fname;
+
+       concat_fnames(p.string, p.length,
+           (char_u *)"defaults.vim", STRLEN_LITERAL("defaults.vim"), TRUE, &fname);
 
        // Check that "defaults.vim" exists in this directory, to avoid picking
        // up a stray "runtime" directory, it would make many tests fail in
        // mysterious ways.
-       if (fname != NULL)
+       if (fname.string != NULL)
        {
-           int exists = file_is_readable(fname);
+           int exists = file_is_readable(fname.string);
 
-           vim_free(fname);
+           vim_free(fname.string);
            if (exists)
-               return p;
+               return p.string;
        }
     }
-    vim_free(p);
+    vim_free(p.string);
     return NULL;
 }
 
index c369fdbf0eaaca8cd78ef21c4cd491c3b3a3ddea..ab1166098c92bc53f2677c2c2226c9e3db6b9d3f 100644 (file)
@@ -404,7 +404,7 @@ set_init_xdg_rtp(void)
     char_u     *vimrc2 = NULL;
     char_u     *xdg_dir = NULL;
     char_u     *xdg_rtp = NULL;
-    char_u     *vimrc_xdg = NULL;
+    string_T   vimrc_xdg = {NULL, 0};
 
     // initialize chartab, so we can expand $HOME
     (void)init_chartab();
@@ -418,10 +418,11 @@ set_init_xdg_rtp(void)
        should_free_xdg_dir = TRUE;
        has_xdg_env = FALSE;
     }
-    vimrc_xdg = concat_fnames(xdg_dir, (char_u *)"vim/vimrc", TRUE);
+    concat_fnames(xdg_dir, STRLEN(xdg_dir),
+       (char_u *)"vim/vimrc", STRLEN_LITERAL("vim/vimrc"), TRUE, &vimrc_xdg);
 
     if (file_is_readable(vimrc1) || file_is_readable(vimrc2) ||
-           !file_is_readable(vimrc_xdg))
+           !file_is_readable(vimrc_xdg.string))
        goto theend;
 
     xdg_rtp = has_xdg_env ? (char_u *)XDG_RUNTIMEPATH
@@ -450,7 +451,7 @@ set_init_xdg_rtp(void)
 theend:
     vim_free(vimrc1);
     vim_free(vimrc2);
-    vim_free(vimrc_xdg);
+    vim_free(vimrc_xdg.string);
     if (should_free_xdg_dir)
        vim_free(xdg_dir);
 }
index edbe895ecd22a13736f3e5539c45354871b46838..e7216c1220ccc3287a880d7554cec329633ccd9c 100644 (file)
@@ -8614,13 +8614,15 @@ fix_arg_enc(void)
            if (used_file_diff_mode && mch_isdir(str) && GARGCOUNT > 0
                                      && !mch_isdir(alist_name(&GARGLIST[0])))
            {
-               char_u      *r;
+               char_u      *tail;
+               string_T    ret;
 
-               r = concat_fnames(str, gettail(alist_name(&GARGLIST[0])), TRUE);
-               if (r != NULL)
+               tail = gettail(alist_name(&GARGLIST[0]));
+               concat_fnames(str, STRLEN(str), tail, STRLEN(tail), TRUE, &ret);
+               if (ret.string != NULL)
                {
                    vim_free(str);
-                   str = r;
+                   str = ret.string;
                }
            }
 #endif
index d82652ce71aab6a8a4eeeef7d2082fad66ebad35..d00a66775fe50d52350349f17531f2c5cc4be21a 100644 (file)
@@ -48,7 +48,7 @@ int vim_ispathsep_nocolon(int c);
 int dir_of_file_exists(char_u *fname);
 int vim_fnamecmp(char_u *x, char_u *y);
 int vim_fnamencmp(char_u *x, char_u *y, size_t len);
-char_u *concat_fnames(char_u *fname1, char_u *fname2, int sep);
+char_u *concat_fnames(char_u *fname1, size_t fname1len, char_u *fname2, size_t fname2len, int sep, string_T *ret);
 void add_pathsep(char_u *p);
 char_u *FullName_save(char_u *fname, int force);
 int vim_fexists(char_u *fname);
index 59579171c398fe562e8c396e414c52b410784308..527760d669f3d5e7ed9e1fc700b6db61e4f7833e 100644 (file)
@@ -2728,9 +2728,10 @@ copy_loclist_stack(win_T *from, win_T *to)
     static int
 qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname)
 {
-    char_u     *ptr = NULL;
+    string_T   ptr = {NULL, 0};
     buf_T      *buf;
-    char_u     *bufname;
+    string_T   bufname;
+    size_t     fname_len;
 
     if (fname == NULL || *fname == NUL)                // no file name
        return 0;
@@ -2743,44 +2744,52 @@ qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname)
        slash_adjust(directory);
     slash_adjust(fname);
 # endif
+    fname_len = STRLEN(fname);
     if (directory != NULL && !vim_isAbsName(fname)
-           && (ptr = concat_fnames(directory, fname, TRUE)) != NULL)
+           && concat_fnames(directory, STRLEN(directory), fname, fname_len, TRUE, &ptr) != NULL)
     {
        // Here we check if the file really exists.
        // This should normally be true, but if make works without
        // "leaving directory"-messages we might have missed a
        // directory change.
-       if (mch_getperm(ptr) < 0)
+       if (mch_getperm(ptr.string) < 0)
        {
-           vim_free(ptr);
+           vim_free(ptr.string);
            directory = qf_guess_filepath(qfl, fname);
            if (directory)
-               ptr = concat_fnames(directory, fname, TRUE);
+               concat_fnames(directory, STRLEN(directory), fname, fname_len, TRUE, &ptr);
            else
-               ptr = vim_strsave(fname);
-           if (ptr == NULL)
+           {
+               ptr.length = fname_len;
+               ptr.string = vim_strnsave(fname, fname_len);
+           }
+           if (ptr.string == NULL)
                return 0;
        }
        // Use concatenated directory name and file name
-       bufname = ptr;
+       bufname.string = ptr.string;
+       bufname.length = ptr.length;
     }
     else
-       bufname = fname;
+    {
+       bufname.string = fname;
+       bufname.length = fname_len;
+    }
 
-    if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
+    if (qf_last_bufname != NULL && STRCMP(bufname.string, qf_last_bufname) == 0
            && bufref_valid(&qf_last_bufref))
     {
        buf = qf_last_bufref.br_buf;
-       vim_free(ptr);
+       vim_free(ptr.string);
     }
     else
     {
        vim_free(qf_last_bufname);
-       buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
-       if (bufname == ptr)
-           qf_last_bufname = bufname;
+       buf = buflist_new(bufname.string, NULL, (linenr_T)0, BLN_NOOPT);
+       if (bufname.string == ptr.string)
+           qf_last_bufname = bufname.string;
        else
-           qf_last_bufname = vim_strsave(bufname);
+           qf_last_bufname = vim_strnsave(bufname.string, bufname.length);
        set_bufref(&qf_last_bufref, buf);
     }
     if (buf == NULL)
@@ -2817,17 +2826,21 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
        (*stackptr)->dirname = vim_strsave(dirbuf);
     else
     {
+       size_t  dirbuf_len;
+
        // Okay we don't have an absolute path.
        // dirbuf must be a subdir of one of the directories on the stack.
        // Let's search...
+       dirbuf_len = STRLEN(dirbuf);
        ds_new = (*stackptr)->next;
        (*stackptr)->dirname = NULL;
        while (ds_new)
        {
-           char_u  *dirname;
+           string_T    dirname;
 
-           dirname = concat_fnames(ds_new->dirname, dirbuf, TRUE);
-           if (dirname == NULL)
+           concat_fnames(ds_new->dirname, STRLEN(ds_new->dirname),
+               dirbuf, dirbuf_len, TRUE, &dirname);
+           if (dirname.string == NULL)
            {
                // pop the new element from the stack and free it
                ds_ptr = *stackptr;
@@ -2836,13 +2849,13 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
 
                return NULL;
            }
-           if (mch_isdir(dirname) == TRUE)
+           if (mch_isdir(dirname.string) == TRUE)
            {
                vim_free((*stackptr)->dirname);
-               (*stackptr)->dirname = dirname;
+               (*stackptr)->dirname = dirname.string;
                break;
            }
-           vim_free(dirname);
+           vim_free(dirname.string);
            ds_new = ds_new->next;
        }
 
@@ -2859,7 +2872,7 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
        if (ds_new == NULL)
        {
            vim_free((*stackptr)->dirname);
-           (*stackptr)->dirname = vim_strsave(dirbuf);
+           (*stackptr)->dirname = vim_strnsave(dirbuf, dirbuf_len);
        }
     }
 
@@ -2940,28 +2953,32 @@ qf_guess_filepath(qf_list_T *qfl, char_u *filename)
 {
     struct dir_stack_T     *ds_ptr;
     struct dir_stack_T     *ds_tmp;
-    char_u                *fullname;
+    string_T              fullname;
+    size_t                filename_len;
 
     // no dirs on the stack - there's nothing we can do
     if (qfl->qf_dir_stack == NULL)
        return NULL;
 
     ds_ptr = qfl->qf_dir_stack->next;
-    fullname = NULL;
+    fullname.string = NULL;
+    fullname.length = 0;
+    filename_len = STRLEN(filename);
     while (ds_ptr)
     {
-       vim_free(fullname);
-       fullname = concat_fnames(ds_ptr->dirname, filename, TRUE);
+       vim_free(fullname.string);
+       concat_fnames(ds_ptr->dirname, STRLEN(ds_ptr->dirname),
+           filename, filename_len, TRUE, &fullname);
 
        // If concat_fnames failed, just go on. The worst thing that can happen
        // is that we delete the entire stack.
-       if ((fullname != NULL) && (mch_getperm(fullname) >= 0))
+       if ((fullname.string != NULL) && (mch_getperm(fullname.string) >= 0))
            break;
 
        ds_ptr = ds_ptr->next;
     }
 
-    vim_free(fullname);
+    vim_free(fullname.string);
 
     // clean up all dirs we already left
     while (qfl->qf_dir_stack->next != ds_ptr)
index c6d2b737090fe5a6da5624acd9e5d3b2c4e79357..6df5781a7305a411a2299c3abe3045ff6b69c0d7 100644 (file)
@@ -841,19 +841,14 @@ add_pack_dir_to_rtp(char_u *fname)
     char_u  *entry;
     char_u  *insp = NULL;
     int            c;
-    char_u  *new_rtp;
-    int            keep;
-    size_t  oldlen;
-    size_t  addlen;
-    size_t  new_rtp_len;
-    char_u  *afterdir = NULL;
-    size_t  afterlen = 0;
+    string_T  new_rtp;
+    size_t  keep;
+    size_t  p_rtp_len;
+    string_T  afterdir = {NULL, 0};
     char_u  *after_insp = NULL;
     char_u  *ffname = NULL;
     size_t  fname_len;
     string_T   buf = {NULL, 0};
-    char_u  *rtp_ffname;
-    int            match;
     int            retval = FAIL;
 
     p4 = p3 = p2 = p1 = get_past_head(fname);
@@ -881,12 +876,17 @@ add_pack_dir_to_rtp(char_u *fname)
     buf.string = alloc(MAXPATHL);
     if (buf.string == NULL)
        goto theend;
+
+    p_rtp_len = 0;
     for (entry = p_rtp; *entry != NUL; )
     {
        char_u *cur_entry = entry;
 
        buf.length = (size_t)copy_option_part(&entry, buf.string, MAXPATHL, ",");
 
+       // keep track of p_rtp length as we go to make the STRLEN() below have less work to do
+       p_rtp_len += (*(p_rtp + buf.length) == ',') ? buf.length + 1 : buf.length;
+
        if ((p = (char_u *)strstr((char *)buf.string, "after")) != NULL
                && p > buf.string
                && vim_ispathsep(p[-1])
@@ -902,6 +902,9 @@ add_pack_dir_to_rtp(char_u *fname)
 
        if (insp == NULL)
        {
+           char_u  *rtp_ffname;
+           int     match;
+
            if (*buf.string != NUL && !after_pathsep(buf.string, buf.string + buf.length))
                STRCPY(buf.string + buf.length, PATHSEPSTR);
            rtp_ffname = fix_fname(buf.string);
@@ -915,69 +918,76 @@ add_pack_dir_to_rtp(char_u *fname)
        }
     }
 
+    // finish measuring the length of p_rtp
+    p_rtp_len += STRLEN(p_rtp + p_rtp_len);
     if (insp == NULL)
        // Both "fname" and "after" not found, append at the end.
-       insp = p_rtp + STRLEN(p_rtp);
+       insp = p_rtp + p_rtp_len;
 
     // check if rtp/pack/name/start/name/after exists
-    afterdir = concat_fnames(fname, (char_u *)"after", TRUE);
-    if (afterdir != NULL && mch_isdir(afterdir))
-       afterlen = STRLEN(afterdir) + 1; // add one for comma
-
-    oldlen = STRLEN(p_rtp);
-    addlen = STRLEN(fname) + 1; // add one for comma
-    new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL
-    if (new_rtp == NULL)
+    fname_len = STRLEN(fname);
+    concat_fnames(fname, fname_len, (char_u *)"after", STRLEN_LITERAL("after"), TRUE, &afterdir);
+    if (afterdir.string == NULL || !mch_isdir(afterdir.string))
+       afterdir.length = 0;
+
+    new_rtp.string = alloc(p_rtp_len + fname_len + afterdir.length + 3); // add two for commas and one for NUL
+    if (new_rtp.string == NULL)
        goto theend;
 
     // We now have 'rtp' parts: {keep}{keep_after}{rest}.
     // Create new_rtp, first: {keep},{fname}
-    keep = (int)(insp - p_rtp);
-    mch_memmove(new_rtp, p_rtp, keep);
-    new_rtp_len = keep;
+    keep = (size_t)(insp - p_rtp);
+    mch_memmove(new_rtp.string, p_rtp, keep);
+    new_rtp.length = keep;
     if (*insp == NUL)
-       new_rtp[new_rtp_len++] = ',';  // add comma before
-    mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1);
-    new_rtp_len += addlen - 1;
+       new_rtp.string[new_rtp.length++] = ',';  // add comma before
+    mch_memmove(new_rtp.string + new_rtp.length, fname, fname_len);
+    new_rtp.length += fname_len;
     if (*insp != NUL)
-       new_rtp[new_rtp_len++] = ',';  // add comma after
+       new_rtp.string[new_rtp.length++] = ',';  // add comma after
 
-    if (afterlen > 0 && after_insp != NULL)
+    if (afterdir.length > 0 && after_insp != NULL)
     {
-       int keep_after = (int)(after_insp - p_rtp);
+       size_t keep_after = (size_t)(after_insp - p_rtp);
+       size_t append_len = keep_after - keep;
 
        // Add to new_rtp: {keep},{fname}{keep_after},{afterdir}
-       mch_memmove(new_rtp + new_rtp_len, p_rtp + keep,
-                                                       keep_after - keep);
-       new_rtp_len += keep_after - keep;
-       mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1);
-       new_rtp_len += afterlen - 1;
-       new_rtp[new_rtp_len++] = ',';
+       mch_memmove(new_rtp.string + new_rtp.length, p_rtp + keep,
+                                                       append_len);
+       new_rtp.length += append_len;
+       mch_memmove(new_rtp.string + new_rtp.length, afterdir.string, afterdir.length);
+       new_rtp.length += afterdir.length;
+       new_rtp.string[new_rtp.length++] = ',';
        keep = keep_after;
     }
 
     if (p_rtp[keep] != NUL)
+    {
+       size_t  append_len = p_rtp_len - keep;
+
        // Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
-       mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
+       mch_memmove(new_rtp.string + new_rtp.length, p_rtp + keep, append_len + 1);     // add one for NUL
+       new_rtp.length += append_len;
+    }
     else
-       new_rtp[new_rtp_len] = NUL;
+       new_rtp.string[new_rtp.length] = NUL;
 
-    if (afterlen > 0 && after_insp == NULL)
+    if (afterdir.length > 0 && after_insp == NULL)
     {
        // Append afterdir when "after" was not found:
        // {keep},{fname}{rest},{afterdir}
-       STRCAT(new_rtp, ",");
-       STRCAT(new_rtp, afterdir);
+       new_rtp.string[new_rtp.length++] = ',';
+       STRCPY(new_rtp.string + new_rtp.length, afterdir.string);
     }
 
-    set_option_value_give_err((char_u *)"rtp", 0L, new_rtp, 0);
-    vim_free(new_rtp);
+    set_option_value_give_err((char_u *)"rtp", 0L, new_rtp.string, 0);
+    vim_free(new_rtp.string);
     retval = OK;
 
 theend:
     vim_free(buf.string);
     vim_free(ffname);
-    vim_free(afterdir);
+    vim_free(afterdir.string);
     return retval;
 }
 
index 3b0a1524e5a5c6e661922127dc49c76cdc7ef218..4bfdc659f9224d21a90d8e0c62cd1abd1f6d672f 100644 (file)
@@ -804,7 +804,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading)
 {
     char_u     *dirp;
     char_u     dir_name[IOSIZE + 1];
-    char_u     *munged_name = NULL;
+    string_T   munged_name = {NULL, 0};
     char_u     *undo_file_name = NULL;
     int                dir_len;
     char_u     *p;
@@ -862,16 +862,20 @@ u_get_undo_file_name(char_u *buf_ffname, int reading)
            dir_name[dir_len] = NUL;
            if (mch_isdir(dir_name))
            {
-               if (munged_name == NULL)
+               string_T    ret;
+
+               if (munged_name.string == NULL)
                {
-                   munged_name = vim_strnsave(ffname, ffnamelen);
-                   if (munged_name == NULL)
+                   munged_name.string = vim_strnsave(ffname, ffnamelen);
+                   if (munged_name.string == NULL)
                        return NULL;
-                   for (p = munged_name; *p != NUL; MB_PTR_ADV(p))
+                   munged_name.length = ffnamelen;
+                   for (p = munged_name.string; *p != NUL; MB_PTR_ADV(p))
                        if (vim_ispathsep(*p))
                            *p = '%';
                }
-               undo_file_name = concat_fnames(dir_name, munged_name, TRUE);
+               undo_file_name = concat_fnames(dir_name, (size_t)dir_len,
+                   munged_name.string, munged_name.length, TRUE, &ret);
            }
        }
 
@@ -882,7 +886,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading)
        VIM_CLEAR(undo_file_name);
     }
 
-    vim_free(munged_name);
+    vim_free(munged_name.string);
     return undo_file_name;
 }
 
index caa45fe38eff46ecda59a0a13ca9e87e7a607d29..25442abc6166fada5a5fbbf1944e492c572f6f87 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    291,
 /**/
     290,
 /**/