Skip to content

Commit 95dacbb

Browse files
John Marriottchrisbra
authored andcommitted
patch 9.1.0727: too many strlen() calls in option.c
Problem: too many strlen() calls in option.c Solution: refactor the code to reduce the number of strlen() calls (John Marriott) closes: #15604 Signed-off-by: John Marriott <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 077d1d2 commit 95dacbb

2 files changed

Lines changed: 100 additions & 54 deletions

File tree

src/option.c

Lines changed: 98 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
static void set_options_default(int opt_flags);
4343
static void set_string_default_esc(char *name, char_u *val, int escape);
44-
static char_u *find_dup_item(char_u *origval, char_u *newval, long_u flags);
44+
static char_u *find_dup_item(char_u *origval, char_u *newval, size_t newvallen, long_u flags);
4545
static char_u *option_expand(int opt_idx, char_u *val);
4646
static void didset_options(void);
4747
static void didset_options2(void);
@@ -132,51 +132,72 @@ set_init_default_shell(void)
132132
set_init_default_backupskip(void)
133133
{
134134
int opt_idx;
135-
long_u n;
135+
int i;
136136
char_u *p;
137+
int plen;
137138
#ifdef UNIX
138139
static char *(names[4]) = {"", "TMPDIR", "TEMP", "TMP"};
139140
#else
140141
static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
141142
#endif
142-
int len;
143143
garray_T ga;
144-
char_u *item;
145144

146145
opt_idx = findoption((char_u *)"backupskip");
147146

148147
ga_init2(&ga, 1, 100);
149-
for (n = 0; n < (long)ARRAY_LENGTH(names); ++n)
148+
for (i = 0; i < (int)ARRAY_LENGTH(names); ++i)
150149
{
151150
int mustfree = FALSE;
152151
#ifdef UNIX
153-
if (*names[n] == NUL)
152+
if (*names[i] == NUL)
153+
{
154154
# ifdef MACOS_X
155155
p = (char_u *)"/private/tmp";
156+
plen = (int)STRLEN_LITERAL("/private/tmp");
156157
# else
157-
p = (char_u *)"/tmp";
158+
p = (char_u *)"/tmp";
159+
plen = (int)STRLEN_LITERAL("/tmp");
158160
# endif
161+
}
159162
else
160163
#endif
161-
p = vim_getenv((char_u *)names[n], &mustfree);
164+
{
165+
p = vim_getenv((char_u *)names[i], &mustfree);
166+
plen = 0; // will be calculated below
167+
}
162168
if (p != NULL && *p != NUL)
163169
{
164-
// First time count the NUL, otherwise count the ','.
165-
len = (int)STRLEN(p) + 3;
166-
item = alloc(len);
170+
char_u *item;
171+
size_t itemsize;
172+
int has_trailing_path_sep = FALSE;
173+
174+
if (plen == 0)
175+
{
176+
// the value was retrieved from the environment
177+
plen = (int)STRLEN(p);
178+
// does the value include a trailing path separator?
179+
if (after_pathsep(p, p + plen))
180+
has_trailing_path_sep = TRUE;
181+
}
182+
183+
// item size needs to be large enough to include "/*" and a trailing NUL
184+
// note: the value (and therefore plen) may already include a path separator
185+
itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
186+
item = alloc(itemsize);
167187
if (item != NULL)
168188
{
169-
STRCPY(item, p);
170-
add_pathsep(item);
171-
STRCAT(item, "*");
172-
if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
173-
== NULL
174-
&& ga_grow(&ga, len) == OK)
189+
// add a preceeding comma as a separator after the first item
190+
size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
191+
size_t itemlen;
192+
193+
itemlen = vim_snprintf((char *)item, itemsize, "%s%s*", p, (has_trailing_path_sep) ? "" : PATHSEPSTR);
194+
195+
if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL
196+
&& ga_grow(&ga, itemseplen + itemlen + 1) == OK)
175197
{
176-
if (ga.ga_len > 0)
177-
STRCAT(ga.ga_data, ",");
178-
STRCAT(ga.ga_data, item);
179-
ga.ga_len += len;
198+
ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
199+
itemseplen + itemlen + 1,
200+
"%s%s", (itemseplen > 0) ? "," : "", item);
180201
}
181202
vim_free(item);
182203
}
@@ -524,7 +545,7 @@ set_init_default_encoding(void)
524545
// MS-Windows has builtin support for conversion to and from Unicode, using
525546
// "utf-8" for 'encoding' should work best for most users.
526547
// z/OS built should default to UTF-8 mode as setlocale does not respect utf-8 environment variable locales
527-
p = vim_strsave((char_u *)ENC_DFLT);
548+
p = vim_strnsave((char_u *)ENC_DFLT, STRLEN_LITERAL(ENC_DFLT));
528549
# else
529550
// enc_locale() will try to find the encoding of the current locale.
530551
// This works best for properly configured systems, old and new.
@@ -542,7 +563,7 @@ set_init_default_encoding(void)
542563
// We don't support "gb18030", but "cp936" is a good substitute
543564
// for practical purposes, thus use that. It's not an alias to
544565
// still support conversion between gb18030 and utf-8.
545-
p_enc = vim_strsave((char_u *)"cp936");
566+
p_enc = vim_strnsave((char_u *)"cp936", STRLEN_LITERAL("cp936"));
546567
vim_free(p);
547568
}
548569
if (mb_init() == NULL)
@@ -584,14 +605,15 @@ set_init_default_encoding(void)
584605
GetACP() != GetConsoleCP())
585606
{
586607
char buf[50];
608+
size_t buflen;
587609

588610
// Win32 console: In ConPTY, GetConsoleCP() returns zero.
589611
// Use an alternative value.
590612
if (GetConsoleCP() == 0)
591-
sprintf(buf, "cp%ld", (long)GetACP());
613+
buflen = vim_snprintf(buf, sizeof(buf), "cp%ld", (long)GetACP());
592614
else
593-
sprintf(buf, "cp%ld", (long)GetConsoleCP());
594-
p_tenc = vim_strsave((char_u *)buf);
615+
buflen = vim_snprintf(buf, sizeof(buf), "cp%ld", (long)GetConsoleCP());
616+
p_tenc = vim_strnsave((char_u *)buf, buflen);
595617
if (p_tenc != NULL)
596618
{
597619
opt_idx = findoption((char_u *)"termencoding");
@@ -885,25 +907,23 @@ set_string_default(char *name, char_u *val)
885907
* "origval". Return NULL if not found.
886908
*/
887909
static char_u *
888-
find_dup_item(char_u *origval, char_u *newval, long_u flags)
910+
find_dup_item(char_u *origval, char_u *newval, size_t newvallen, long_u flags)
889911
{
890912
int bs = 0;
891-
size_t newlen;
892913
char_u *s;
893914

894915
if (origval == NULL)
895916
return NULL;
896917

897-
newlen = STRLEN(newval);
898918
for (s = origval; *s != NUL; ++s)
899919
{
900920
if ((!(flags & P_COMMA)
901921
|| s == origval
902922
|| (s[-1] == ',' && !(bs & 1)))
903-
&& STRNCMP(s, newval, newlen) == 0
923+
&& STRNCMP(s, newval, newvallen) == 0
904924
&& (!(flags & P_COMMA)
905-
|| s[newlen] == ','
906-
|| s[newlen] == NUL))
925+
|| s[newvallen] == ','
926+
|| s[newvallen] == NUL))
907927
return s;
908928
// Count backslashes. Only a comma with an even number of backslashes
909929
// or a single backslash preceded by a comma before it is recognized as
@@ -1289,28 +1309,34 @@ set_init_3(void)
12891309
set_helplang_default(char_u *lang)
12901310
{
12911311
int idx;
1312+
size_t langlen;
12921313

1293-
if (lang == NULL || STRLEN(lang) < 2) // safety check
1314+
if (lang == NULL) // safety check
12941315
return;
1316+
1317+
langlen = STRLEN(lang);
1318+
if (langlen < 2) // safety check
1319+
return;
1320+
12951321
idx = findoption((char_u *)"hlg");
12961322
if (idx < 0 || (options[idx].flags & P_WAS_SET))
12971323
return;
12981324

12991325
if (options[idx].flags & P_ALLOCED)
13001326
free_string_option(p_hlg);
1301-
p_hlg = vim_strsave(lang);
1327+
p_hlg = vim_strnsave(lang, langlen);
13021328
if (p_hlg == NULL)
13031329
p_hlg = empty_option;
13041330
else
13051331
{
13061332
// zh_CN becomes "cn", zh_TW becomes "tw"
1307-
if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5)
1333+
if (STRNICMP(p_hlg, "zh_", 3) == 0 && langlen >= 5)
13081334
{
13091335
p_hlg[0] = TOLOWER_ASC(p_hlg[3]);
13101336
p_hlg[1] = TOLOWER_ASC(p_hlg[4]);
13111337
}
13121338
// any C like setting, such as C.UTF-8, becomes "en"
1313-
else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C')
1339+
else if (langlen >= 1 && *p_hlg == 'C')
13141340
{
13151341
p_hlg[0] = 'e';
13161342
p_hlg[1] = 'n';
@@ -1625,13 +1651,13 @@ opt_backspace_nr2str(
16251651
*(char_u **)varp = empty_option;
16261652
break;
16271653
case 1:
1628-
*(char_u **)varp = vim_strsave((char_u *)"indent,eol");
1654+
*(char_u **)varp = vim_strnsave((char_u *)"indent,eol", STRLEN_LITERAL("indent,eol"));
16291655
break;
16301656
case 2:
1631-
*(char_u **)varp = vim_strsave((char_u *)"indent,eol,start");
1657+
*(char_u **)varp = vim_strnsave((char_u *)"indent,eol,start", STRLEN_LITERAL("indent,eol,start"));
16321658
break;
16331659
case 3:
1634-
*(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop");
1660+
*(char_u **)varp = vim_strnsave((char_u *)"indent,eol,nostop", STRLEN_LITERAL("indent,eol,nostop"));
16351661
break;
16361662
}
16371663
vim_free(*oldval_p);
@@ -1652,20 +1678,37 @@ opt_backspace_nr2str(
16521678
static char_u *
16531679
opt_whichwrap_nr2str(char_u **argp, char_u *whichwrap)
16541680
{
1681+
size_t len = 0;
1682+
16551683
*whichwrap = NUL;
16561684
int i = getdigits(argp);
16571685
if (i & 1)
1658-
STRCAT(whichwrap, "b,");
1686+
{
1687+
STRCPY(whichwrap, "b,");
1688+
len += 2;
1689+
}
16591690
if (i & 2)
1660-
STRCAT(whichwrap, "s,");
1691+
{
1692+
STRCPY(whichwrap + len, "s,");
1693+
len += 2;
1694+
}
16611695
if (i & 4)
1662-
STRCAT(whichwrap, "h,l,");
1696+
{
1697+
STRCPY(whichwrap + len, "h,l,");
1698+
len += 4;
1699+
}
16631700
if (i & 8)
1664-
STRCAT(whichwrap, "<,>,");
1701+
{
1702+
STRCPY(whichwrap + len, "<,>,");
1703+
len += 4;
1704+
}
16651705
if (i & 16)
1666-
STRCAT(whichwrap, "[,],");
1706+
{
1707+
STRCPY(whichwrap + len, "[,],");
1708+
len += 4;
1709+
}
16671710
if (*whichwrap != NUL) // remove trailing ,
1668-
whichwrap[STRLEN(whichwrap) - 1] = NUL;
1711+
whichwrap[len - 1] = NUL;
16691712

16701713
return whichwrap;
16711714
}
@@ -1952,7 +1995,7 @@ stropt_get_newval(
19521995
if (op == OP_REMOVING || (flags & P_NODUP))
19531996
{
19541997
len = (int)STRLEN(newval);
1955-
s = find_dup_item(origval, newval, flags);
1998+
s = find_dup_item(origval, newval, len, flags);
19561999

19572000
// do not add if already there
19582001
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL)
@@ -2680,12 +2723,11 @@ do_set(
26802723

26812724
if (errmsg != NULL)
26822725
{
2683-
vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
2684-
i = (int)STRLEN(IObuff) + 2;
2726+
i = vim_snprintf((char *)IObuff, IOSIZE, "%s", (char_u *)_(errmsg)) + 2;
26852727
if (i + (arg - startarg) < IOSIZE)
26862728
{
26872729
// append the argument with the error
2688-
STRCAT(IObuff, ": ");
2730+
STRCPY(IObuff + i - 2, ": ");
26892731
mch_memmove(IObuff + i, startarg, (arg - startarg));
26902732
IObuff[i + (arg - startarg)] = NUL;
26912733
}
@@ -5100,7 +5142,7 @@ get_option_value(
51005142
// never return the value of the crypt key
51015143
else if ((char_u **)varp == &curbuf->b_p_key
51025144
&& **(char_u **)(varp) != NUL)
5103-
*stringval = vim_strsave((char_u *)"*****");
5145+
*stringval = vim_strnsave((char_u *)"*****", STRLEN_LITERAL("*****"));
51045146
#endif
51055147
else
51065148
*stringval = vim_strsave(*(char_u **)(varp));
@@ -7334,6 +7376,7 @@ set_context_in_set_cmd(
73347376
char_u *s;
73357377
int is_term_option = FALSE;
73367378
int key;
7379+
char_u *argend;
73377380

73387381
expand_option_flags = opt_flags;
73397382

@@ -7343,7 +7386,8 @@ set_context_in_set_cmd(
73437386
xp->xp_pattern = arg;
73447387
return;
73457388
}
7346-
p = arg + STRLEN(arg) - 1;
7389+
argend = arg + STRLEN(arg);
7390+
p = argend - 1;
73477391
if (*p == ' ' && *(p - 1) != '\\')
73487392
{
73497393
xp->xp_pattern = p + 1;
@@ -7560,7 +7604,7 @@ set_context_in_set_cmd(
75607604
// delimited by space.
75617605
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON))
75627606
{
7563-
for (p = arg + STRLEN(arg) - 1; p >= xp->xp_pattern; --p)
7607+
for (p = argend - 1; p >= xp->xp_pattern; --p)
75647608
{
75657609
// count number of backslashes before ' ' or ',' or ':'
75667610
if (*p == ' ' || *p == ',' ||
@@ -7587,7 +7631,7 @@ set_context_in_set_cmd(
75877631
// An option that is a list of single-character flags should always start
75887632
// at the end as we don't complete words.
75897633
if (flags & P_FLAGLIST)
7590-
xp->xp_pattern = arg + STRLEN(arg);
7634+
xp->xp_pattern = argend;
75917635

75927636
// Some options can either be using file/dir expansions, or custom value
75937637
// expansion depending on what the user typed. Unfortunately we have to
@@ -8106,7 +8150,7 @@ ExpandSettingSubtract(
81068150
int count = 0;
81078151
char_u *p;
81088152

8109-
p = vim_strsave(option_val);
8153+
p = vim_strnsave(option_val, num_flags);
81108154
if (p == NULL)
81118155
{
81128156
VIM_CLEAR(*matches);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
727,
707709
/**/
708710
726,
709711
/**/

0 commit comments

Comments
 (0)