diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-26 00:07:27 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-26 00:07:27 +0200 |
commit | 2093ad296f8a4528ad0e106b52074871a2bf070e (patch) | |
tree | d94c965340ab56f3394b4c3fba675df29ed43f80 | |
parent | 1e3e2ccd5dd280371c9ca29c0e0304a0d40592af (diff) | |
download | busybox-w32-2093ad296f8a4528ad0e106b52074871a2bf070e.tar.gz busybox-w32-2093ad296f8a4528ad0e106b52074871a2bf070e.tar.bz2 busybox-w32-2093ad296f8a4528ad0e106b52074871a2bf070e.zip |
hush: fix ${##}, ${#?}, ${#!} handling
function old new delta
parse_dollar 786 820 +34
expand_one_var 1579 1592 +13
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 47/0) Total: 47 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rwxr-xr-x | shell/ash_test/ash-vars/param_expand_alt.tests | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/param_expand_len1.right | 11 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/param_expand_len1.tests | 31 | ||||
-rw-r--r-- | shell/hush.c | 27 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/param_expand_alt.tests | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/param_expand_len1.right | 11 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/param_expand_len1.tests | 31 |
7 files changed, 106 insertions, 9 deletions
diff --git a/shell/ash_test/ash-vars/param_expand_alt.tests b/shell/ash_test/ash-vars/param_expand_alt.tests index c9c4249af..d80452434 100755 --- a/shell/ash_test/ash-vars/param_expand_alt.tests +++ b/shell/ash_test/ash-vars/param_expand_alt.tests | |||
@@ -6,7 +6,7 @@ | |||
6 | # now some funky ones. | 6 | # now some funky ones. |
7 | # ${V+word} "if V unset, then substitute nothing, else substitute word" | 7 | # ${V+word} "if V unset, then substitute nothing, else substitute word" |
8 | # ${V:+word} "if V unset or '', then substitute nothing, else substitute word" | 8 | # ${V:+word} "if V unset or '', then substitute nothing, else substitute word" |
9 | # bash doesn't accept ${#+}. ash prints 0 (not $#). | 9 | # bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+" |
10 | echo _${#+}_ _${#:+}_ | 10 | echo _${#+}_ _${#:+}_ |
11 | # Forms with non-empty word work as expected in both ash and bash. | 11 | # Forms with non-empty word work as expected in both ash and bash. |
12 | echo _${#+z}_ _${#:+z}_ | 12 | echo _${#+z}_ _${#:+z}_ |
diff --git a/shell/ash_test/ash-vars/param_expand_len1.right b/shell/ash_test/ash-vars/param_expand_len1.right new file mode 100644 index 000000000..dff3c7bb1 --- /dev/null +++ b/shell/ash_test/ash-vars/param_expand_len1.right | |||
@@ -0,0 +1,11 @@ | |||
1 | One:1 | ||
2 | Two:2 | ||
3 | Three:3 | ||
4 | |||
5 | One:1 | ||
6 | Two:2 | ||
7 | Three:3 | ||
8 | |||
9 | Ok ${#$}: 0 | ||
10 | |||
11 | Ok ${#!}: 0 | ||
diff --git a/shell/ash_test/ash-vars/param_expand_len1.tests b/shell/ash_test/ash-vars/param_expand_len1.tests new file mode 100755 index 000000000..e1beab320 --- /dev/null +++ b/shell/ash_test/ash-vars/param_expand_len1.tests | |||
@@ -0,0 +1,31 @@ | |||
1 | # ${#c} for any single char c means "length of $c", including all special vars | ||
2 | |||
3 | false | ||
4 | echo One:${#?} | ||
5 | (exit 10) | ||
6 | echo Two:${#?} | ||
7 | (exit 100) | ||
8 | echo Three:${#?} | ||
9 | |||
10 | echo | ||
11 | echo One:${##} | ||
12 | set -- 1 2 3 4 5 6 7 8 9 0 | ||
13 | echo Two:${##} | ||
14 | set -- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
15 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
16 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
17 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 | ||
18 | echo Three:${##} | ||
19 | |||
20 | echo | ||
21 | v=$$ | ||
22 | test "${#v}" = "${#$}" | ||
23 | echo 'Ok ${#$}:' $? | ||
24 | |||
25 | echo | ||
26 | sleep 0 & | ||
27 | v=$! | ||
28 | test "${#v}" = "${#!}" | ||
29 | echo 'Ok ${#!}:' $? | ||
30 | |||
31 | # TODO: ${#-} ${#_} | ||
diff --git a/shell/hush.c b/shell/hush.c index 11b33f40a..d0225edb9 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -4466,6 +4466,8 @@ static int parse_dollar(o_string *as_string, | |||
4466 | case '@': /* args */ | 4466 | case '@': /* args */ |
4467 | goto make_one_char_var; | 4467 | goto make_one_char_var; |
4468 | case '{': { | 4468 | case '{': { |
4469 | char len_single_ch; | ||
4470 | |||
4469 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4471 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4470 | 4472 | ||
4471 | ch = i_getch(input); /* eat '{' */ | 4473 | ch = i_getch(input); /* eat '{' */ |
@@ -4485,6 +4487,7 @@ static int parse_dollar(o_string *as_string, | |||
4485 | return 0; | 4487 | return 0; |
4486 | } | 4488 | } |
4487 | nommu_addchr(as_string, ch); | 4489 | nommu_addchr(as_string, ch); |
4490 | len_single_ch = ch; | ||
4488 | ch |= quote_mask; | 4491 | ch |= quote_mask; |
4489 | 4492 | ||
4490 | /* It's possible to just call add_till_closing_bracket() at this point. | 4493 | /* It's possible to just call add_till_closing_bracket() at this point. |
@@ -4509,9 +4512,18 @@ static int parse_dollar(o_string *as_string, | |||
4509 | /* handle parameter expansions | 4512 | /* handle parameter expansions |
4510 | * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 | 4513 | * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 |
4511 | */ | 4514 | */ |
4512 | if (!strchr(VAR_SUBST_OPS, ch)) /* ${var<bad_char>... */ | 4515 | if (!strchr(VAR_SUBST_OPS, ch)) { /* ${var<bad_char>... */ |
4513 | goto bad_dollar_syntax; | 4516 | if (len_single_ch != '#' |
4514 | 4517 | /*|| !strchr(SPECIAL_VARS_STR, ch) - disallow errors like ${#+} ? */ | |
4518 | || i_peek(input) != '}' | ||
4519 | ) { | ||
4520 | goto bad_dollar_syntax; | ||
4521 | } | ||
4522 | /* else: it's "length of C" ${#C} op, | ||
4523 | * where C is a single char | ||
4524 | * special var name, e.g. ${#!}. | ||
4525 | */ | ||
4526 | } | ||
4515 | /* Eat everything until closing '}' (or ':') */ | 4527 | /* Eat everything until closing '}' (or ':') */ |
4516 | end_ch = '}'; | 4528 | end_ch = '}'; |
4517 | if (BASH_SUBSTR | 4529 | if (BASH_SUBSTR |
@@ -4568,6 +4580,7 @@ static int parse_dollar(o_string *as_string, | |||
4568 | } | 4580 | } |
4569 | break; | 4581 | break; |
4570 | } | 4582 | } |
4583 | len_single_ch = 0; /* it can't be ${#C} op */ | ||
4571 | } | 4584 | } |
4572 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4585 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4573 | break; | 4586 | break; |
@@ -5559,10 +5572,10 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5559 | first_char = arg[0] = arg0 & 0x7f; | 5572 | first_char = arg[0] = arg0 & 0x7f; |
5560 | exp_op = 0; | 5573 | exp_op = 0; |
5561 | 5574 | ||
5562 | if (first_char == '#' && arg[1] /* ${#... but not ${#} */ | 5575 | if (first_char == '#' && arg[1] /* ${#...} but not ${#} */ |
5563 | && (!exp_saveptr /* and (not ${#<op_char>...} */ | 5576 | && (!exp_saveptr /* and ( not(${#<op_char>...}) */ |
5564 | || (arg[1] == '?' && arg[2] == '\0') /* or ${#?} - "len of $?") */ | 5577 | || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */ |
5565 | ) | 5578 | ) /* NB: skipping ^^^specvar check mishandles ${#::2} */ |
5566 | ) { | 5579 | ) { |
5567 | /* It must be length operator: ${#var} */ | 5580 | /* It must be length operator: ${#var} */ |
5568 | var++; | 5581 | var++; |
diff --git a/shell/hush_test/hush-vars/param_expand_alt.tests b/shell/hush_test/hush-vars/param_expand_alt.tests index c9c4249af..d80452434 100755 --- a/shell/hush_test/hush-vars/param_expand_alt.tests +++ b/shell/hush_test/hush-vars/param_expand_alt.tests | |||
@@ -6,7 +6,7 @@ | |||
6 | # now some funky ones. | 6 | # now some funky ones. |
7 | # ${V+word} "if V unset, then substitute nothing, else substitute word" | 7 | # ${V+word} "if V unset, then substitute nothing, else substitute word" |
8 | # ${V:+word} "if V unset or '', then substitute nothing, else substitute word" | 8 | # ${V:+word} "if V unset or '', then substitute nothing, else substitute word" |
9 | # bash doesn't accept ${#+}. ash prints 0 (not $#). | 9 | # bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+" |
10 | echo _${#+}_ _${#:+}_ | 10 | echo _${#+}_ _${#:+}_ |
11 | # Forms with non-empty word work as expected in both ash and bash. | 11 | # Forms with non-empty word work as expected in both ash and bash. |
12 | echo _${#+z}_ _${#:+z}_ | 12 | echo _${#+z}_ _${#:+z}_ |
diff --git a/shell/hush_test/hush-vars/param_expand_len1.right b/shell/hush_test/hush-vars/param_expand_len1.right new file mode 100644 index 000000000..dff3c7bb1 --- /dev/null +++ b/shell/hush_test/hush-vars/param_expand_len1.right | |||
@@ -0,0 +1,11 @@ | |||
1 | One:1 | ||
2 | Two:2 | ||
3 | Three:3 | ||
4 | |||
5 | One:1 | ||
6 | Two:2 | ||
7 | Three:3 | ||
8 | |||
9 | Ok ${#$}: 0 | ||
10 | |||
11 | Ok ${#!}: 0 | ||
diff --git a/shell/hush_test/hush-vars/param_expand_len1.tests b/shell/hush_test/hush-vars/param_expand_len1.tests new file mode 100755 index 000000000..e1beab320 --- /dev/null +++ b/shell/hush_test/hush-vars/param_expand_len1.tests | |||
@@ -0,0 +1,31 @@ | |||
1 | # ${#c} for any single char c means "length of $c", including all special vars | ||
2 | |||
3 | false | ||
4 | echo One:${#?} | ||
5 | (exit 10) | ||
6 | echo Two:${#?} | ||
7 | (exit 100) | ||
8 | echo Three:${#?} | ||
9 | |||
10 | echo | ||
11 | echo One:${##} | ||
12 | set -- 1 2 3 4 5 6 7 8 9 0 | ||
13 | echo Two:${##} | ||
14 | set -- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
15 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
16 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 \ | ||
17 | 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 | ||
18 | echo Three:${##} | ||
19 | |||
20 | echo | ||
21 | v=$$ | ||
22 | test "${#v}" = "${#$}" | ||
23 | echo 'Ok ${#$}:' $? | ||
24 | |||
25 | echo | ||
26 | sleep 0 & | ||
27 | v=$! | ||
28 | test "${#v}" = "${#!}" | ||
29 | echo 'Ok ${#!}:' $? | ||
30 | |||
31 | # TODO: ${#-} ${#_} | ||