hush: fix more obscure ${var%...} cases
No binary (build failed)
—
(log yok)
| @@ -45,6 +45,8 @@ | |
| * follow IFS rules more precisely, including update semantics | |
| * builtins mandated by standards we don't support: | |
| * [un]alias, command, fc, getopts, newgrp, readonly, times | |
| + | * make complex ${var%...} constructs support optional |
| + | * make here documents optional |
| * | |
| * Bash compat TODO: | |
| * redirection of stdout+stderr: &> and >& | |
| @@ -5887,36 +5889,36 @@ static void add_till_backquote(o_string *dest, struct in_str *input) | |
| * echo $(echo 'TEST)' BEST) TEST) BEST | |
| * echo $(echo \(\(TEST\) BEST) ((TEST) BEST | |
| * | |
| - | * BUG: enter: echo $(( `printf '(\x28 1'` + `echo 2))` )) |
| - | * on the command line, press Enter. You get > prompt which is impossible |
| - | * to exit with ^C. |
| + | * Also adapted to eat ${var%...} constructs, since ... part |
| + | * can contain arbitrary constructs, just like $(cmd). |
| */ | |
| #define DOUBLE_CLOSE_CHAR_FLAG 0x80 | |
| static void add_till_closing_paren(o_string *dest, struct in_str *input, char end_ch) | |
| { | |
| - | int count = 0; |
| char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; | |
| end_ch &= (DOUBLE_CLOSE_CHAR_FLAG-1); | |
| while (1) { | |
| int ch = i_getch(input); | |
| if (ch == EOF) { | |
| - | syntax_error_unterm_ch(')'); |
| + | syntax_error_unterm_ch(end_ch); |
| /*xfunc_die(); - redundant */ | |
| } | |
| - | if (ch == '(' || ch == '{') |
| - | count++; |
| - | if (ch == ')' || ch == '}') { |
| - | count--; |
| - | if (count < 0 && ch == end_ch) { |
| - | if (!dbl) |
| - | break; |
| - | if (i_peek(input) == ')') { |
| - | i_getch(input); |
| - | break; |
| - | } |
| + | if (ch == end_ch) { |
| + | if (!dbl) |
| + | break; |
| + | /* we look for closing )) of $((EXPR)) */ |
| + | if (i_peek(input) == end_ch) { |
| + | i_getch(input); /* eat second ')' */ |
| + | break; |
| } | |
| } | |
| o_addchr(dest, ch); | |
| + | if (ch == '(' || ch == '{') { |
| + | ch = (ch == '(' ? ')' : '}'); |
| + | add_till_closing_paren(dest, input, ch); |
| + | o_addchr(dest, ch); |
| + | continue; |
| + | } |
| if (ch == '\'') { | |
| add_till_single_quote(dest, input); | |
| o_addchr(dest, ch); | |
| @@ -5927,6 +5929,11 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, char en | |
| o_addchr(dest, ch); | |
| continue; | |
| } | |
| + | if (ch == '`') { |
| + | add_till_backquote(dest, input); |
| + | o_addchr(dest, ch); |
| + | continue; |
| + | } |
| if (ch == '\\') { | |
| /* \x. Copy verbatim. Important for \(, \) */ | |
| ch = i_getch(input); | |
| @@ -43,21 +43,30 @@ Format: 'expected actual' | |
| 4 4 | |
| 29 29 | |
| 5 5 | |
| + | unary plus, minus |
| -4 -4 | |
| 4 4 | |
| + | conditional expressions |
| 1 1 | |
| 32 32 | |
| 32 32 | |
| 1 1 | |
| 1 1 | |
| 32 32 | |
| + | check that parentheses in `cmd` are interpreted correctly |
| + | 3 3 |
| + | check that the unevaluated part of the ternary operator does not do evaluation or assignment |
| 20 20 | |
| 30 30 | |
| 20 20 | |
| 30 30 | |
| + | check precedence of assignment vs. conditional operator |
| hush: error in arithmetic | |
| + | check precedence of assignment vs. conditional operator |
| + | associativity of assignment-operator operator |
| 6 6 | |
| 6,5,3 6,5,3 | |
| + | octal, hex |
| 263 263 | |
| 255 255 | |
| 40 40 | |
| @@ -75,11 +75,11 @@ echo 4 $(( iv &= 4 )) | |
| echo 29 $(( iv += (jv + 9))) | |
| echo 5 $(( (iv + 4) % 7 )) | |
| - | # unary plus, minus |
| + | echo unary plus, minus |
| echo -4 $(( +4 - 8 )) | |
| echo 4 $(( -4 + 8 )) | |
| - | # conditional expressions |
| + | echo conditional expressions |
| echo 1 $(( 4<5 ? 1 : 32)) | |
| echo 32 $(( 4>5 ? 1 : 32)) | |
| echo 32 $(( 4>(2+3) ? 1 : 32)) | |
| @@ -87,8 +87,11 @@ echo 1 $(( 4<(2+3) ? 1 : 32)) | |
| echo 1 $(( (2+2)<(2+3) ? 1 : 32)) | |
| echo 32 $(( (2+2)>(2+3) ? 1 : 32)) | |
| - | # check that the unevaluated part of the ternary operator does not do |
| - | # evaluation or assignment |
| + | echo 'check that parentheses in `cmd` are interpreted correctly' |
| + | # \x28 is '(' |
| + | echo 3 $(( ( `printf '(\x28 1'` + `echo 2\)\)` ) )) |
| + | |
| + | echo check that the unevaluated part of the ternary operator does not do evaluation or assignment |
| x=i+=2 | |
| y=j+=2 | |
| #ash# declare -i i=1 j=1 | |
| @@ -109,20 +112,20 @@ echo 20 $((1 ? 20 : (x+=2))) | |
| echo 30 $((0 ? (y+=2) : 30)) | |
| #ash# echo $i,$y # ash mishandles this | |
| - | # check precedence of assignment vs. conditional operator |
| + | echo check precedence of assignment vs. conditional operator |
| # should be an error | |
| #ash# declare -i x=2 | |
| x=2 | |
| #ashnote# bash reports error but continues, ash aborts - using subshell to 'emulate' bash: | |
| ( y=$((1 ? 20 : x+=2)) ) | |
| - | # check precedence of assignment vs. conditional operator |
| + | echo check precedence of assignment vs. conditional operator |
| #ash# declare -i x=2 | |
| x=2 | |
| # ash says "line NNN: syntax error: 0 ? x+=2 : 20" | |
| #ash# echo 20 $((0 ? x+=2 : 20)) | |
| - | # associativity of assignment-operator operator |
| + | echo associativity of assignment-operator operator |
| #ash# declare -i i=1 j=2 k=3 | |
| i=1 | |
| j=2 | |
| @@ -130,7 +133,7 @@ k=3 | |
| echo 6 $((i += j += k)) | |
| echo 6,5,3 $i,$j,$k | |
| - | # octal, hex |
| + | echo octal, hex |
| echo 263 $(( 0x100 | 007 )) | |
| echo 255 $(( 0xff )) | |
| #ash# echo 255 $(( 16#ff )) | |
| @@ -37,4 +37,5 @@ ababcdcd_tail | |
| ababcdcd | |
| ab | |
| ab | |
| + | ab |
| End | |
| @@ -47,5 +47,6 @@ echo ${var%\\*} | |
| a=ab}; echo ${a%\}}; | |
| a=abc; c=c; echo ${a%${c}} | |
| + | a=ab{{c; echo ${a%`echo {{c`} |
| echo End | |