vim-patch:9.1.0727: too many strlen() calls in option.c (#30338)

Problem:  too many strlen() calls in option.c
Solution: refactor the code to reduce the number of strlen() calls
          (John Marriott)

closes: vim/vim#15604

95dacbb5fd

Co-authored-by: John Marriott <basilisk@internode.on.net>
This commit is contained in:
zeertzjq 2024-09-11 07:31:07 +08:00 committed by GitHub
parent f289161c3c
commit 15bfdf73ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -210,39 +210,53 @@ static void set_init_default_backupskip(void)
OptIndex opt_idx = kOptBackupskip; OptIndex opt_idx = kOptBackupskip;
ga_init(&ga, 1, 100); ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) { for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
bool mustfree = true; bool mustfree = true;
char *p; char *p;
size_t plen;
#ifdef UNIX #ifdef UNIX
if (*names[n] == NUL) { if (*names[i] == NUL) {
# ifdef __APPLE__ # ifdef __APPLE__
p = "/private/tmp"; p = "/private/tmp";
plen = STRLEN_LITERAL("/private/tmp");
# else # else
p = "/tmp"; p = "/tmp";
plen = STRLEN_LITERAL("/tmp");
# endif # endif
mustfree = false; mustfree = false;
} else } else
#endif #endif
{ {
p = vim_getenv(names[n]); p = vim_getenv(names[i]);
plen = 0; // will be calcuated below
} }
if (p != NULL && *p != NUL) { if (p != NULL && *p != NUL) {
// First time count the NUL, otherwise count the ','. bool has_trailing_path_sep = false;
const size_t len = strlen(p) + 3;
char *item = xmalloc(len); if (plen == 0) {
xstrlcpy(item, p, len); // the value was retrieved from the environment
add_pathsep(item); plen = strlen(p);
xstrlcat(item, "*", len); // does the value include a trailing path separator?
if (find_dup_item(ga.ga_data, item, options[opt_idx].flags) if (after_pathsep(p, p + plen)) {
== NULL) { has_trailing_path_sep = true;
ga_grow(&ga, (int)len);
if (!GA_EMPTY(&ga)) {
strcat(ga.ga_data, ",");
} }
strcat(ga.ga_data, p); }
add_pathsep(ga.ga_data);
strcat(ga.ga_data, "*"); // item size needs to be large enough to include "/*" and a trailing NUL
ga.ga_len += (int)len; // note: the value (and therefore plen) may already include a path separator
size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
char *item = xmalloc(itemsize);
// add a preceeding comma as a separator after the first item
size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p,
has_trailing_path_sep ? "" : PATHSEPSTR);
if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) {
ga_grow(&ga, (int)(itemseplen + itemlen + 1));
ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
itemseplen + itemlen + 1,
"%s%s", (itemseplen > 0) ? "," : "", item);
} }
xfree(item); xfree(item);
} }
@ -526,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
/// For an option value that contains comma separated items, find "newval" in /// For an option value that contains comma separated items, find "newval" in
/// "origval". Return NULL if not found. /// "origval". Return NULL if not found.
static char *find_dup_item(char *origval, const char *newval, uint32_t flags) static char *find_dup_item(char *origval, const char *newval, const size_t newvallen,
uint32_t flags)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(2)
{ {
if (origval == NULL) { if (origval == NULL) {
@ -535,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
int bs = 0; int bs = 0;
const size_t newlen = strlen(newval);
for (char *s = origval; *s != NUL; s++) { for (char *s = origval; *s != NUL; s++) {
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1))) if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
&& strncmp(s, newval, newlen) == 0 && strncmp(s, newval, newvallen) == 0
&& (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) { && (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
return s; return s;
} }
// Count backslashes. Only a comma with an even number of backslashes // Count backslashes. Only a comma with an even number of backslashes
@ -697,10 +711,10 @@ void set_helplang_default(const char *lang)
} }
p_hlg = xmemdupz(lang, lang_len); p_hlg = xmemdupz(lang, lang_len);
// zh_CN becomes "cn", zh_TW becomes "tw". // zh_CN becomes "cn", zh_TW becomes "tw".
if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) { if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
} else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') { } else if (lang_len && *p_hlg == 'C') {
// any C like setting, such as C.UTF-8, becomes "en" // any C like setting, such as C.UTF-8, becomes "en"
p_hlg[0] = 'e'; p_hlg[0] = 'e';
p_hlg[1] = 'n'; p_hlg[1] = 'n';
@ -950,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
int len = 0; int len = 0;
if (op == OP_REMOVING || (flags & P_NODUP)) { if (op == OP_REMOVING || (flags & P_NODUP)) {
len = (int)strlen(newval); len = (int)strlen(newval);
s = find_dup_item(origval, newval, flags); s = find_dup_item(origval, newval, (size_t)len, flags);
// do not add if already there // do not add if already there
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
@ -1464,11 +1478,10 @@ int do_set(char *arg, int opt_flags)
} }
if (errmsg != NULL) { if (errmsg != NULL) {
xstrlcpy(IObuff, _(errmsg), IOSIZE); int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2;
int i = (int)strlen(IObuff) + 2;
if (i + (arg - startarg) < IOSIZE) { if (i + (arg - startarg) < IOSIZE) {
// append the argument with the error // append the argument with the error
xstrlcat(IObuff, ": ", IOSIZE); xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2));
assert(arg >= startarg); assert(arg >= startarg);
memmove(IObuff + i, startarg, (size_t)(arg - startarg)); memmove(IObuff + i, startarg, (size_t)(arg - startarg));
IObuff[i + (arg - startarg)] = NUL; IObuff[i + (arg - startarg)] = NUL;
@ -5431,7 +5444,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
xp->xp_pattern = arg; xp->xp_pattern = arg;
return; return;
} }
char *p = arg + strlen(arg) - 1; char *const argend = arg + strlen(arg);
char *p = argend - 1;
if (*p == ' ' && *(p - 1) != '\\') { if (*p == ' ' && *(p - 1) != '\\') {
xp->xp_pattern = p + 1; xp->xp_pattern = p + 1;
return; return;
@ -5618,7 +5632,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// Triple-backslashed escaped file names (e.g. 'path') can also be // Triple-backslashed escaped file names (e.g. 'path') can also be
// delimited by space. // delimited by space.
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) { if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) { for (p = argend - 1; p > xp->xp_pattern; p--) {
// count number of backslashes before ' ' or ',' // count number of backslashes before ' ' or ','
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) { if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
char *s = p; char *s = p;
@ -5642,7 +5656,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// An option that is a list of single-character flags should always start // An option that is a list of single-character flags should always start
// at the end as we don't complete words. // at the end as we don't complete words.
if (flags & P_FLAGLIST) { if (flags & P_FLAGLIST) {
xp->xp_pattern = arg + strlen(arg); xp->xp_pattern = argend;
} }
// Some options can either be using file/dir expansions, or custom value // Some options can either be using file/dir expansions, or custom value
@ -5952,7 +5966,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
int count = 0; int count = 0;
(*matches)[count++] = xstrdup(option_val); (*matches)[count++] = xmemdupz(option_val, num_flags);
if (num_flags > 1) { if (num_flags > 1) {
// If more than one flags, split the flags up and expose each // If more than one flags, split the flags up and expose each