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 <cb@256bit.org>
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
John Marriott
2026-04-03 15:08:48 +00:00
committed by Christian Brabandt
parent b7205b6426
commit cb51add7ae
12 changed files with 280 additions and 181 deletions
+52 -42
View 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
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;
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)
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)
// Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1);
else
new_rtp[new_rtp_len] = NUL;
{
size_t append_len = p_rtp_len - keep;
if (afterlen > 0 && after_insp == NULL)
// Append rest: {keep},{fname}{keep_after},{afterdir}{rest}
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.string[new_rtp.length] = NUL;
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;
}