hush: do fewer strdups in % and hash expansions
function old new delta builtin_umask 133 132 -1 expand_one_var 1552 1543 -9 Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
parent
d98e5c65c3
commit
4f870496e7
29
shell/hush.c
29
shell/hush.c
@ -3800,8 +3800,8 @@ static int encode_string(o_string *as_string,
|
|||||||
ch = i_getch(input); /* eat next */
|
ch = i_getch(input); /* eat next */
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
goto again; /* skip \<newline> */
|
goto again; /* skip \<newline> */
|
||||||
} /* else: ch remains == '\\', and we double it */
|
} /* else: ch remains == '\\', and we double it below: */
|
||||||
o_addqchr(dest, ch); /* \c if c is s glob char, else just c */
|
o_addqchr(dest, ch); /* \c if c is a glob char, else just c */
|
||||||
nommu_addchr(as_string, ch);
|
nommu_addchr(as_string, ch);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@ -4618,26 +4618,29 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
|
|||||||
* Then var's value is matched to it and matching part removed.
|
* Then var's value is matched to it and matching part removed.
|
||||||
*/
|
*/
|
||||||
if (val && val[0]) {
|
if (val && val[0]) {
|
||||||
|
char *t;
|
||||||
char *exp_exp_word;
|
char *exp_exp_word;
|
||||||
char *loc;
|
char *loc;
|
||||||
unsigned scan_flags = pick_scan(exp_op, *exp_word);
|
unsigned scan_flags = pick_scan(exp_op, *exp_word);
|
||||||
if (exp_op == *exp_word) /* ## or %% */
|
if (exp_op == *exp_word) /* ## or %% */
|
||||||
exp_word++;
|
exp_word++;
|
||||||
//TODO: avoid xstrdup unless needed
|
|
||||||
// (see HACK ALERT below for an example)
|
|
||||||
val = to_be_freed = xstrdup(val);
|
|
||||||
exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
|
exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
|
||||||
if (exp_exp_word)
|
if (exp_exp_word)
|
||||||
exp_word = exp_exp_word;
|
exp_word = exp_exp_word;
|
||||||
loc = scan_and_match(to_be_freed, exp_word, scan_flags);
|
/* HACK ALERT. We depend here on the fact that
|
||||||
|
* G.global_argv and results of utoa and get_local_var_value
|
||||||
|
* are actually in writable memory:
|
||||||
|
* scan_and_match momentarily stores NULs there. */
|
||||||
|
t = (char*)val;
|
||||||
|
loc = scan_and_match(t, exp_word, scan_flags);
|
||||||
//bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'",
|
//bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'",
|
||||||
// exp_op, to_be_freed, exp_word, loc);
|
// exp_op, t, exp_word, loc);
|
||||||
free(exp_exp_word);
|
free(exp_exp_word);
|
||||||
if (loc) { /* match was found */
|
if (loc) { /* match was found */
|
||||||
if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
|
if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */
|
||||||
val = loc;
|
val = loc; /* take right part */
|
||||||
else /* %[%] */
|
else /* %[%] */
|
||||||
*loc = '\0';
|
val = to_be_freed = xstrndup(val, loc - val); /* left */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4646,13 +4649,13 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
|
|||||||
/* It's ${var/[/]pattern[/repl]} thing.
|
/* It's ${var/[/]pattern[/repl]} thing.
|
||||||
* Note that in encoded form it has TWO parts:
|
* Note that in encoded form it has TWO parts:
|
||||||
* var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
|
* var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
|
||||||
|
* and if // is used, it is encoded as \:
|
||||||
|
* var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
|
||||||
*/
|
*/
|
||||||
/* Empty variable always gives nothing: */
|
/* Empty variable always gives nothing: */
|
||||||
// "v=''; echo ${v/*/w}" prints "", not "w"
|
// "v=''; echo ${v/*/w}" prints "", not "w"
|
||||||
if (val && val[0]) {
|
if (val && val[0]) {
|
||||||
/* It's ${var/[/]pattern[/repl]} thing */
|
/* pattern uses non-standard expansion.
|
||||||
/*
|
|
||||||
* Pattern is taken literally, while
|
|
||||||
* repl should be unbackslashed and globbed
|
* repl should be unbackslashed and globbed
|
||||||
* by the usual expansion rules:
|
* by the usual expansion rules:
|
||||||
* >az; >bz;
|
* >az; >bz;
|
||||||
@ -7339,7 +7342,7 @@ int hush_main(int argc, char **argv)
|
|||||||
/* Deal with HUSH_VERSION */
|
/* Deal with HUSH_VERSION */
|
||||||
G.shell_ver.flg_export = 1;
|
G.shell_ver.flg_export = 1;
|
||||||
G.shell_ver.flg_read_only = 1;
|
G.shell_ver.flg_read_only = 1;
|
||||||
/* Code which handles ${var/P/R} needs writable values for all variables,
|
/* Code which handles ${var<op>...} needs writable values for all variables,
|
||||||
* therefore we xstrdup: */
|
* therefore we xstrdup: */
|
||||||
G.shell_ver.varstr = xstrdup(hush_version_str),
|
G.shell_ver.varstr = xstrdup(hush_version_str),
|
||||||
G.top_var = &G.shell_ver;
|
G.top_var = &G.shell_ver;
|
||||||
|
5
shell/hush_test/hush-vars/var_bash6.right
Normal file
5
shell/hush_test/hush-vars/var_bash6.right
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Expected Actual
|
||||||
|
a*z : a*z
|
||||||
|
\z : \z
|
||||||
|
a1z a2z: a1z a2z
|
||||||
|
z : z
|
9
shell/hush_test/hush-vars/var_bash6.tests
Executable file
9
shell/hush_test/hush-vars/var_bash6.tests
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
# This testcase checks globbing correctness in ${v/a/b}
|
||||||
|
|
||||||
|
>a1z; >a2z;
|
||||||
|
echo 'Expected' 'Actual'
|
||||||
|
v='a bz'; echo 'a*z :' "${v/a*z/a*z}"
|
||||||
|
v='a bz'; echo '\z :' "${v/a*z/\z}"
|
||||||
|
v='a bz'; echo 'a1z a2z:' ${v/a*z/a*z}
|
||||||
|
v='a bz'; echo 'z :' ${v/a*z/\z}
|
||||||
|
rm a1z a2z
|
Loading…
Reference in New Issue
Block a user