patch 9.2.0291: too many strlen() calls
Commit:
https://github.com/vim/vim/commit/cb51add7ae400a47407fb7fb7b7a54e238d4fdf4
Author: John Marriott <
basi...@internode.on.net>
Date: Fri Apr 3 15:08:48 2026 +0000
patch 9.2.0291: too many strlen() calls
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 <
c...@256bit.org>
Signed-off-by: John Marriott <
basi...@internode.on.net>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/filepath.c b/src/filepath.c
index 91423d9dc..721dbc05d 100644
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -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);
}
/*
diff --git a/src/if_cscope.c b/src/if_cscope.c
index 10437a532..796200077 100644
--- a/src/if_cscope.c
+++ b/src/if_cscope.c
@@ -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;
}
diff --git a/src/main.c b/src/main.c
index b5f542a49..d4019ff51 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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
diff --git a/src/memline.c b/src/memline.c
index 97396b0b1..35b1fae23 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -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;
}
/*
diff --git a/src/misc1.c b/src/misc1.c
index 3fa34c35e..1cf73a004 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -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;
}
diff --git a/src/option.c b/src/option.c
index c369fdbf0..ab1166098 100644
--- a/src/option.c
+++ b/src/option.c
@@ -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);
}
diff --git a/src/os_win32.c b/src/os_win32.c
index edbe895ec..e7216c122 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -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
diff --git a/src/proto/
filepath.pro b/src/proto/
filepath.pro
index d82652ce7..d00a66775 100644
--- a/src/proto/
filepath.pro
+++ b/src/proto/
filepath.pro
@@ -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);
diff --git a/src/quickfix.c b/src/quickfix.c
index 59579171c..527760d66 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -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)
diff --git a/src/scriptfile.c b/src/scriptfile.c
index c6d2b7370..6df5781a7 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -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;
}
diff --git a/src/undo.c b/src/undo.c
index 3b0a1524e..4bfdc659f 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -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;
}
diff --git a/src/version.c b/src/version.c
index caa45fe38..25442abc6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 291,
/**/
290,
/**/