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>
This commit is contained in:
parent
1e3e2ccd5d
commit
2093ad296f
@ -6,7 +6,7 @@
|
|||||||
# now some funky ones.
|
# now some funky ones.
|
||||||
# ${V+word} "if V unset, then substitute nothing, else substitute word"
|
# ${V+word} "if V unset, then substitute nothing, else substitute word"
|
||||||
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
|
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
|
||||||
# bash doesn't accept ${#+}. ash prints 0 (not $#).
|
# bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+"
|
||||||
echo _${#+}_ _${#:+}_
|
echo _${#+}_ _${#:+}_
|
||||||
# Forms with non-empty word work as expected in both ash and bash.
|
# Forms with non-empty word work as expected in both ash and bash.
|
||||||
echo _${#+z}_ _${#:+z}_
|
echo _${#+z}_ _${#:+z}_
|
||||||
|
11
shell/ash_test/ash-vars/param_expand_len1.right
Normal file
11
shell/ash_test/ash-vars/param_expand_len1.right
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
One:1
|
||||||
|
Two:2
|
||||||
|
Three:3
|
||||||
|
|
||||||
|
One:1
|
||||||
|
Two:2
|
||||||
|
Three:3
|
||||||
|
|
||||||
|
Ok ${#$}: 0
|
||||||
|
|
||||||
|
Ok ${#!}: 0
|
31
shell/ash_test/ash-vars/param_expand_len1.tests
Executable file
31
shell/ash_test/ash-vars/param_expand_len1.tests
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
# ${#c} for any single char c means "length of $c", including all special vars
|
||||||
|
|
||||||
|
false
|
||||||
|
echo One:${#?}
|
||||||
|
(exit 10)
|
||||||
|
echo Two:${#?}
|
||||||
|
(exit 100)
|
||||||
|
echo Three:${#?}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo One:${##}
|
||||||
|
set -- 1 2 3 4 5 6 7 8 9 0
|
||||||
|
echo Two:${##}
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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
|
||||||
|
echo Three:${##}
|
||||||
|
|
||||||
|
echo
|
||||||
|
v=$$
|
||||||
|
test "${#v}" = "${#$}"
|
||||||
|
echo 'Ok ${#$}:' $?
|
||||||
|
|
||||||
|
echo
|
||||||
|
sleep 0 &
|
||||||
|
v=$!
|
||||||
|
test "${#v}" = "${#!}"
|
||||||
|
echo 'Ok ${#!}:' $?
|
||||||
|
|
||||||
|
# TODO: ${#-} ${#_}
|
25
shell/hush.c
25
shell/hush.c
@ -4466,6 +4466,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
case '@': /* args */
|
case '@': /* args */
|
||||||
goto make_one_char_var;
|
goto make_one_char_var;
|
||||||
case '{': {
|
case '{': {
|
||||||
|
char len_single_ch;
|
||||||
|
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
|
|
||||||
ch = i_getch(input); /* eat '{' */
|
ch = i_getch(input); /* eat '{' */
|
||||||
@ -4485,6 +4487,7 @@ static int parse_dollar(o_string *as_string,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
nommu_addchr(as_string, ch);
|
nommu_addchr(as_string, ch);
|
||||||
|
len_single_ch = ch;
|
||||||
ch |= quote_mask;
|
ch |= quote_mask;
|
||||||
|
|
||||||
/* It's possible to just call add_till_closing_bracket() at this point.
|
/* 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,
|
|||||||
/* handle parameter expansions
|
/* handle parameter expansions
|
||||||
* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
|
* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
|
||||||
*/
|
*/
|
||||||
if (!strchr(VAR_SUBST_OPS, ch)) /* ${var<bad_char>... */
|
if (!strchr(VAR_SUBST_OPS, ch)) { /* ${var<bad_char>... */
|
||||||
|
if (len_single_ch != '#'
|
||||||
|
/*|| !strchr(SPECIAL_VARS_STR, ch) - disallow errors like ${#+} ? */
|
||||||
|
|| i_peek(input) != '}'
|
||||||
|
) {
|
||||||
goto bad_dollar_syntax;
|
goto bad_dollar_syntax;
|
||||||
|
}
|
||||||
|
/* else: it's "length of C" ${#C} op,
|
||||||
|
* where C is a single char
|
||||||
|
* special var name, e.g. ${#!}.
|
||||||
|
*/
|
||||||
|
}
|
||||||
/* Eat everything until closing '}' (or ':') */
|
/* Eat everything until closing '}' (or ':') */
|
||||||
end_ch = '}';
|
end_ch = '}';
|
||||||
if (BASH_SUBSTR
|
if (BASH_SUBSTR
|
||||||
@ -4568,6 +4580,7 @@ static int parse_dollar(o_string *as_string,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
len_single_ch = 0; /* it can't be ${#C} op */
|
||||||
}
|
}
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
break;
|
break;
|
||||||
@ -5559,10 +5572,10 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
|
|||||||
first_char = arg[0] = arg0 & 0x7f;
|
first_char = arg[0] = arg0 & 0x7f;
|
||||||
exp_op = 0;
|
exp_op = 0;
|
||||||
|
|
||||||
if (first_char == '#' && arg[1] /* ${#... but not ${#} */
|
if (first_char == '#' && arg[1] /* ${#...} but not ${#} */
|
||||||
&& (!exp_saveptr /* and (not ${#<op_char>...} */
|
&& (!exp_saveptr /* and ( not(${#<op_char>...}) */
|
||||||
|| (arg[1] == '?' && arg[2] == '\0') /* or ${#?} - "len of $?") */
|
|| (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */
|
||||||
)
|
) /* NB: skipping ^^^specvar check mishandles ${#::2} */
|
||||||
) {
|
) {
|
||||||
/* It must be length operator: ${#var} */
|
/* It must be length operator: ${#var} */
|
||||||
var++;
|
var++;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# now some funky ones.
|
# now some funky ones.
|
||||||
# ${V+word} "if V unset, then substitute nothing, else substitute word"
|
# ${V+word} "if V unset, then substitute nothing, else substitute word"
|
||||||
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
|
# ${V:+word} "if V unset or '', then substitute nothing, else substitute word"
|
||||||
# bash doesn't accept ${#+}. ash prints 0 (not $#).
|
# bash doesn't accept ${#+}. ash prints 0 (not $#): "len of $+"
|
||||||
echo _${#+}_ _${#:+}_
|
echo _${#+}_ _${#:+}_
|
||||||
# Forms with non-empty word work as expected in both ash and bash.
|
# Forms with non-empty word work as expected in both ash and bash.
|
||||||
echo _${#+z}_ _${#:+z}_
|
echo _${#+z}_ _${#:+z}_
|
||||||
|
11
shell/hush_test/hush-vars/param_expand_len1.right
Normal file
11
shell/hush_test/hush-vars/param_expand_len1.right
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
One:1
|
||||||
|
Two:2
|
||||||
|
Three:3
|
||||||
|
|
||||||
|
One:1
|
||||||
|
Two:2
|
||||||
|
Three:3
|
||||||
|
|
||||||
|
Ok ${#$}: 0
|
||||||
|
|
||||||
|
Ok ${#!}: 0
|
31
shell/hush_test/hush-vars/param_expand_len1.tests
Executable file
31
shell/hush_test/hush-vars/param_expand_len1.tests
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
# ${#c} for any single char c means "length of $c", including all special vars
|
||||||
|
|
||||||
|
false
|
||||||
|
echo One:${#?}
|
||||||
|
(exit 10)
|
||||||
|
echo Two:${#?}
|
||||||
|
(exit 100)
|
||||||
|
echo Three:${#?}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo One:${##}
|
||||||
|
set -- 1 2 3 4 5 6 7 8 9 0
|
||||||
|
echo Two:${##}
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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
|
||||||
|
echo Three:${##}
|
||||||
|
|
||||||
|
echo
|
||||||
|
v=$$
|
||||||
|
test "${#v}" = "${#$}"
|
||||||
|
echo 'Ok ${#$}:' $?
|
||||||
|
|
||||||
|
echo
|
||||||
|
sleep 0 &
|
||||||
|
v=$!
|
||||||
|
test "${#v}" = "${#!}"
|
||||||
|
echo 'Ok ${#!}:' $?
|
||||||
|
|
||||||
|
# TODO: ${#-} ${#_}
|
Loading…
Reference in New Issue
Block a user