diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-10 11:06:01 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-10 11:06:01 +0200 |
commit | 4f870496e7d934fcbe092478f1da8ec7a3ea4466 (patch) | |
tree | 931344dd0d6d1d8cfaf358b1cd6f6e8982101b74 | |
parent | d98e5c65c3c69373dab56a7f9af8780c1a8123b2 (diff) | |
download | busybox-w32-4f870496e7d934fcbe092478f1da8ec7a3ea4466.tar.gz busybox-w32-4f870496e7d934fcbe092478f1da8ec7a3ea4466.tar.bz2 busybox-w32-4f870496e7d934fcbe092478f1da8ec7a3ea4466.zip |
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>
-rw-r--r-- | shell/hush.c | 29 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_bash6.right | 5 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_bash6.tests | 9 |
3 files changed, 30 insertions, 13 deletions
diff --git a/shell/hush.c b/shell/hush.c index 920d9638c..3faf2b326 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -3800,8 +3800,8 @@ static int encode_string(o_string *as_string, | |||
3800 | ch = i_getch(input); /* eat next */ | 3800 | ch = i_getch(input); /* eat next */ |
3801 | if (ch == '\n') | 3801 | if (ch == '\n') |
3802 | goto again; /* skip \<newline> */ | 3802 | goto again; /* skip \<newline> */ |
3803 | } /* else: ch remains == '\\', and we double it */ | 3803 | } /* else: ch remains == '\\', and we double it below: */ |
3804 | o_addqchr(dest, ch); /* \c if c is s glob char, else just c */ | 3804 | o_addqchr(dest, ch); /* \c if c is a glob char, else just c */ |
3805 | nommu_addchr(as_string, ch); | 3805 | nommu_addchr(as_string, ch); |
3806 | goto again; | 3806 | goto again; |
3807 | } | 3807 | } |
@@ -4618,26 +4618,29 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4618 | * Then var's value is matched to it and matching part removed. | 4618 | * Then var's value is matched to it and matching part removed. |
4619 | */ | 4619 | */ |
4620 | if (val && val[0]) { | 4620 | if (val && val[0]) { |
4621 | char *t; | ||
4621 | char *exp_exp_word; | 4622 | char *exp_exp_word; |
4622 | char *loc; | 4623 | char *loc; |
4623 | unsigned scan_flags = pick_scan(exp_op, *exp_word); | 4624 | unsigned scan_flags = pick_scan(exp_op, *exp_word); |
4624 | if (exp_op == *exp_word) /* ## or %% */ | 4625 | if (exp_op == *exp_word) /* ## or %% */ |
4625 | exp_word++; | 4626 | exp_word++; |
4626 | //TODO: avoid xstrdup unless needed | ||
4627 | // (see HACK ALERT below for an example) | ||
4628 | val = to_be_freed = xstrdup(val); | ||
4629 | exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); | 4627 | exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); |
4630 | if (exp_exp_word) | 4628 | if (exp_exp_word) |
4631 | exp_word = exp_exp_word; | 4629 | exp_word = exp_exp_word; |
4632 | loc = scan_and_match(to_be_freed, exp_word, scan_flags); | 4630 | /* HACK ALERT. We depend here on the fact that |
4631 | * G.global_argv and results of utoa and get_local_var_value | ||
4632 | * are actually in writable memory: | ||
4633 | * scan_and_match momentarily stores NULs there. */ | ||
4634 | t = (char*)val; | ||
4635 | loc = scan_and_match(t, exp_word, scan_flags); | ||
4633 | //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", | 4636 | //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", |
4634 | // exp_op, to_be_freed, exp_word, loc); | 4637 | // exp_op, t, exp_word, loc); |
4635 | free(exp_exp_word); | 4638 | free(exp_exp_word); |
4636 | if (loc) { /* match was found */ | 4639 | if (loc) { /* match was found */ |
4637 | if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */ | 4640 | if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */ |
4638 | val = loc; | 4641 | val = loc; /* take right part */ |
4639 | else /* %[%] */ | 4642 | else /* %[%] */ |
4640 | *loc = '\0'; | 4643 | val = to_be_freed = xstrndup(val, loc - val); /* left */ |
4641 | } | 4644 | } |
4642 | } | 4645 | } |
4643 | } | 4646 | } |
@@ -4646,13 +4649,13 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
4646 | /* It's ${var/[/]pattern[/repl]} thing. | 4649 | /* It's ${var/[/]pattern[/repl]} thing. |
4647 | * Note that in encoded form it has TWO parts: | 4650 | * Note that in encoded form it has TWO parts: |
4648 | * var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> | 4651 | * var/pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> |
4652 | * and if // is used, it is encoded as \: | ||
4653 | * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> | ||
4649 | */ | 4654 | */ |
4650 | /* Empty variable always gives nothing: */ | 4655 | /* Empty variable always gives nothing: */ |
4651 | // "v=''; echo ${v/*/w}" prints "", not "w" | 4656 | // "v=''; echo ${v/*/w}" prints "", not "w" |
4652 | if (val && val[0]) { | 4657 | if (val && val[0]) { |
4653 | /* It's ${var/[/]pattern[/repl]} thing */ | 4658 | /* pattern uses non-standard expansion. |
4654 | /* | ||
4655 | * Pattern is taken literally, while | ||
4656 | * repl should be unbackslashed and globbed | 4659 | * repl should be unbackslashed and globbed |
4657 | * by the usual expansion rules: | 4660 | * by the usual expansion rules: |
4658 | * >az; >bz; | 4661 | * >az; >bz; |
@@ -7339,7 +7342,7 @@ int hush_main(int argc, char **argv) | |||
7339 | /* Deal with HUSH_VERSION */ | 7342 | /* Deal with HUSH_VERSION */ |
7340 | G.shell_ver.flg_export = 1; | 7343 | G.shell_ver.flg_export = 1; |
7341 | G.shell_ver.flg_read_only = 1; | 7344 | G.shell_ver.flg_read_only = 1; |
7342 | /* Code which handles ${var/P/R} needs writable values for all variables, | 7345 | /* Code which handles ${var<op>...} needs writable values for all variables, |
7343 | * therefore we xstrdup: */ | 7346 | * therefore we xstrdup: */ |
7344 | G.shell_ver.varstr = xstrdup(hush_version_str), | 7347 | G.shell_ver.varstr = xstrdup(hush_version_str), |
7345 | G.top_var = &G.shell_ver; | 7348 | G.top_var = &G.shell_ver; |
diff --git a/shell/hush_test/hush-vars/var_bash6.right b/shell/hush_test/hush-vars/var_bash6.right new file mode 100644 index 000000000..63fc23df8 --- /dev/null +++ b/shell/hush_test/hush-vars/var_bash6.right | |||
@@ -0,0 +1,5 @@ | |||
1 | Expected Actual | ||
2 | a*z : a*z | ||
3 | \z : \z | ||
4 | a1z a2z: a1z a2z | ||
5 | z : z | ||
diff --git a/shell/hush_test/hush-vars/var_bash6.tests b/shell/hush_test/hush-vars/var_bash6.tests new file mode 100755 index 000000000..cf2e4f020 --- /dev/null +++ b/shell/hush_test/hush-vars/var_bash6.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | # This testcase checks globbing correctness in ${v/a/b} | ||
2 | |||
3 | >a1z; >a2z; | ||
4 | echo 'Expected' 'Actual' | ||
5 | v='a bz'; echo 'a*z :' "${v/a*z/a*z}" | ||
6 | v='a bz'; echo '\z :' "${v/a*z/\z}" | ||
7 | v='a bz'; echo 'a1z a2z:' ${v/a*z/a*z} | ||
8 | v='a bz'; echo 'z :' ${v/a*z/\z} | ||
9 | rm a1z a2z | ||