From b7aaae9052025426b669a0edeec1da5997fea8be Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 2 Apr 2009 20:17:49 +0000 Subject: [PATCH] hush: rename ->o_quote to ->o_escape hush_test/hush-arith/*: new tests for arithmetic evaluation --- shell/hush.c | 56 ++--- shell/hush_test/hush-arith/arith.right | 138 +++++++++++ shell/hush_test/hush-arith/arith.tests | 302 +++++++++++++++++++++++++ shell/hush_test/hush-arith/arith1.sub | 40 ++++ shell/hush_test/hush-arith/arith2.sub | 57 +++++ 5 files changed, 565 insertions(+), 28 deletions(-) create mode 100644 shell/hush_test/hush-arith/arith.right create mode 100755 shell/hush_test/hush-arith/arith.tests create mode 100755 shell/hush_test/hush-arith/arith1.sub create mode 100755 shell/hush_test/hush-arith/arith2.sub diff --git a/shell/hush.c b/shell/hush.c index b46a1fd76..f0d372625 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -392,9 +392,9 @@ typedef struct o_string { char *data; int length; /* position where data is appended */ int maxlen; - /* Misnomer! it's not "quoting", it's "protection against globbing"! - * (by prepending \ to *, ?, [ and to \ too) */ - smallint o_quote; + /* Protect newly added chars against globbing + * (by prepending \ to *, ?, [, \) */ + smallint o_escape; smallint o_glob; smallint nonnull; smallint has_empty_slot; @@ -1440,7 +1440,7 @@ static void o_addqchr(o_string *o, int ch) static void o_addQchr(o_string *o, int ch) { int sz = 1; - if (o->o_quote && strchr("*?[\\", ch)) { + if (o->o_escape && strchr("*?[\\", ch)) { sz++; o->data[o->length] = '\\'; o->length++; @@ -1453,7 +1453,7 @@ static void o_addQchr(o_string *o, int ch) static void o_addQstr(o_string *o, const char *str, int len) { - if (!o->o_quote) { + if (!o->o_escape) { o_addstr(o, str, len); return; } @@ -1668,7 +1668,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str) while (1) { int word_len = strcspn(str, G.ifs); if (word_len) { - if (output->o_quote || !output->o_glob) + if (output->o_escape || !output->o_glob) o_addQstr(output, str, word_len); else /* protect backslashes against globbing up :) */ o_addstr_duplicate_backslash(output, str, word_len); @@ -1751,9 +1751,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) break; ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ - smallint sv = output->o_quote; - /* unquoted var's contents should be globbed, so don't quote */ - output->o_quote = 0; + smallint sv = output->o_escape; + /* unquoted var's contents should be globbed, so don't escape */ + output->o_escape = 0; while (G.global_argv[i]) { n = expand_on_ifs(output, n, G.global_argv[i]); debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); @@ -1766,7 +1766,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) debug_print_list("expand_vars_to_list[3]", output, n); } } - output->o_quote = sv; + output->o_escape = sv; } else /* If or_mask is nonzero, we handle assignment 'a=....$@.....' * and in this case should treat it like '$*' - see 'else...' below */ @@ -1945,17 +1945,17 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) store_val: #endif if (!(first_ch & 0x80)) { /* unquoted $VAR */ - debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote); + debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, output->o_escape); if (val) { - /* unquoted var's contents should be globbed, so don't quote */ - smallint sv = output->o_quote; - output->o_quote = 0; + /* unquoted var's contents should be globbed, so don't escape */ + smallint sv = output->o_escape; + output->o_escape = 0; n = expand_on_ifs(output, n, val); val = NULL; - output->o_quote = sv; + output->o_escape = sv; } } else { /* quoted $VAR, val will be appended below */ - debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); + debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, output->o_escape); } } /* default: */ } /* switch (char after ) */ @@ -1999,7 +1999,7 @@ static char **expand_variables(char **argv, int or_mask) o_string output = NULL_O_STRING; if (or_mask & 0x100) { - output.o_quote = 1; /* protect against globbing for "$var" */ + output.o_escape = 1; /* protect against globbing for "$var" */ /* (unquoted $var will temporarily switch it off) */ output.o_glob = 1; } @@ -3979,7 +3979,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) { int expansion; int ch = i_peek(input); /* first character after the $ */ - unsigned char quote_mask = dest->o_quote ? 0x80 : 0; + unsigned char quote_mask = dest->o_escape ? 0x80 : 0; debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); if (isalpha(ch)) { @@ -4143,7 +4143,7 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote if (ch == dquote_end) { /* may be only '"' or EOF */ dest->nonnull = 1; if (dest->o_assignment == NOT_ASSIGNMENT) - dest->o_quote ^= 1; + dest->o_escape ^= 1; debug_printf_parse("parse_stream_dquoted return 0\n"); return 0; } @@ -4157,8 +4157,8 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote if (ch != '\n') { next = i_peek(input); } - debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", - ch, ch, m, dest->o_quote); + debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", + ch, ch, m, dest->o_escape); /* Basically, checking every CHAR_SPECIAL char except '"' */ if (ch == '\\') { if (next == EOF) { @@ -4225,13 +4225,13 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, int is_in_dquote; int next; - /* Only double-quote state is handled in the state variable dest->o_quote. + /* Double-quote state is handled in the state variable is_in_dquote. * A single-quote triggers a bypass of the main loop until its mate is - * found. When recursing, quote state is passed in via dest->o_quote. */ + * found. When recursing, quote state is passed in via dest->o_escape. */ debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); - is_in_dquote = dest->o_quote; + is_in_dquote = dest->o_escape; while (1) { if (is_in_dquote) { if (parse_stream_dquoted(dest, input, '"')) @@ -4248,8 +4248,8 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, next = i_peek(input); } } - debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", - ch, ch, m, dest->o_quote); + debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", + ch, ch, m, dest->o_escape); if (m == CHAR_ORDINARY) { o_addQchr(dest, ch); if ((dest->o_assignment == MAYBE_ASSIGNMENT @@ -4365,7 +4365,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, dest->nonnull = 1; is_in_dquote ^= 1; /* invert */ if (dest->o_assignment == NOT_ASSIGNMENT) - dest->o_quote ^= 1; + dest->o_escape ^= 1; break; #if ENABLE_HUSH_TICK case '`': { @@ -4594,7 +4594,7 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag) } #endif /*temp.nonnull = 0; - o_free does it below */ - /*temp.o_quote = 0; - o_free does it below */ + /*temp.o_escape = 0; - o_free does it below */ free_pipe_list(ctx.list_head, /* indent: */ 0); /* Discard all unprocessed line input, force prompt on */ inp->p = NULL; diff --git a/shell/hush_test/hush-arith/arith.right b/shell/hush_test/hush-arith/arith.right new file mode 100644 index 000000000..a35fe893f --- /dev/null +++ b/shell/hush_test/hush-arith/arith.right @@ -0,0 +1,138 @@ +Format: 'expected actual' +163 163 +4 4 +16 16 +8 8 +2 2 +4 4 +2 2 +2 2 +1 1 +0 0 +0 0 +0 0 +1 1 +1 1 +2 2 +-3 -3 +-2 -2 +1 1 +0 0 +2 2 +131072 131072 +29 29 +33 33 +49 49 +1 1 +1 1 +0 0 +0 0 +1 1 +1 1 +1 1 +2 2 +3 3 +1 1 +58 58 +2 2 +60 60 +1 1 +256 256 +16 16 +62 62 +4 4 +29 29 +5 5 +-4 -4 +4 4 +1 1 +32 32 +32 32 +1 1 +1 1 +32 32 +20 20 +30 30 +20 20 +30 30 +hush: arith: syntax error +6 6 +6,5,3 6,5,3 +263 263 +255 255 +40 40 +hush: arith: syntax error +hush: arith: divide by zero +hush: can't exec 'let': No such file or directory +hush: arith: syntax error +hush: can't exec 'let': No such file or directory +abc +def +ghi +hush: arith: syntax error +16 16 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +9 9 +hush: arith: syntax error +hush: arith: syntax error +9 9 +9 9 +9 9 +7 7 +7 +4 4 +32767 32767 +32768 32768 +131072 131072 +2147483647 2147483647 +1 1 +4 4 +4 4 +5 5 +5 5 +4 4 +3 3 +3 3 +4 4 +4 4 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +4 4 +7 7 +-7 -7 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +6 6 +3 3 +7 7 +4 4 +0 0 +3 3 +7 7 +2 2 +-2 -2 +1 1 +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +hush: arith: syntax error +5 5 +1 1 +4 4 +0 0 +hush: arith: syntax error +hush: arith: syntax error +8 12 +hush: arith: syntax error +42 +42 +42 +hush: can't exec 'a[b[c]d]=e': No such file or directory diff --git a/shell/hush_test/hush-arith/arith.tests b/shell/hush_test/hush-arith/arith.tests new file mode 100755 index 000000000..57e66e888 --- /dev/null +++ b/shell/hush_test/hush-arith/arith.tests @@ -0,0 +1,302 @@ +#ash# set +o posix +#ash# declare -i iv jv + +echo "Format: 'expected actual'" + +iv=$(( 3 + 5 * 32 )) +echo 163 $iv +#ash# iv=iv+3 +#ash# echo 166 $iv +iv=2 +jv=iv + +: $((jv *= 2)) ##hush## let "jv *= 2" +echo 4 $jv +jv=$(( $jv << 2 )) +echo 16 $jv + +: $((jv=$jv / 2)) ##hush## let jv="$jv / 2" +echo 8 $jv +#ash# jv="jv >> 2" +: $((jv=jv >> 2)) ##hush## let jv="jv >> 2" +echo 2 $jv + +iv=$((iv+ $jv)) +echo 4 $iv +echo 2 $((iv -= jv)) +echo 2 $iv +echo 1 $(( iv == jv )) +echo 0 $(( iv != $jv )) +echo 0 $(( iv < jv )) +echo 0 $(( $iv > $jv )) +echo 1 $(( iv <= $jv )) +echo 1 $(( $iv >= jv )) + +echo 2 $jv +echo -3 $(( ~$jv )) +echo -2 $(( ~1 )) +echo 1 $(( ! 0 )) + +echo 0 $(( jv % 2 )) +echo 2 $(( $iv % 4 )) + +echo 131072 $(( iv <<= 16 )) +echo 29 $(( iv %= 33 )) + +echo 33 $(( 33 & 55 )) +echo 49 $(( 33 | 17 )) + +echo 1 $(( iv && $jv )) +echo 1 $(( $iv || jv )) + +echo 0 $(( iv && 0 )) +echo 0 $(( iv & 0 )) +echo 1 $(( iv && 1 )) +echo 1 $(( iv & 1 )) + +echo 1 $(( $jv || 0 )) +echo 2 $(( jv | 0 )) +echo 3 $(( jv | 1 )) +echo 1 $(( $jv || 1 )) + +: $((iv *= jv)) ##hush## let 'iv *= jv' +echo 58 $iv +echo 2 $jv +: $((jv += $iv)) ##hush## let "jv += $iv" +echo 60 $jv + +echo 1 $(( jv /= iv )) +echo 256 $(( jv <<= 8 )) +echo 16 $(( jv >>= 4 )) + +echo 62 $(( iv |= 4 )) +echo 4 $(( iv &= 4 )) + +echo 29 $(( iv += (jv + 9))) +echo 5 $(( (iv + 4) % 7 )) + +# unary plus, minus +echo -4 $(( +4 - 8 )) +echo 4 $(( -4 + 8 )) + +# conditional expressions +echo 1 $(( 4<5 ? 1 : 32)) +echo 32 $(( 4>5 ? 1 : 32)) +echo 32 $(( 4>(2+3) ? 1 : 32)) +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 +x=i+=2 +y=j+=2 +#ash# declare -i i=1 j=1 + i=1 + j=1 +echo 20 $((1 ? 20 : (x+=2))) +#ash# echo $i,$x # ash mishandles this +echo 30 $((0 ? (y+=2) : 30)) +#ash# echo $j,$y # ash mishandles this + +x=i+=2 +y=j+=2 +#ash# declare -i i=1 j=1 + i=1 + j=1 +echo 20 $((1 ? 20 : (x+=2))) +#ash# echo $i,$x # ash mishandles this +echo 30 $((0 ? (y+=2) : 30)) +#ash# echo $i,$y # ash mishandles this + +# 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 +#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 +#ash# declare -i i=1 j=2 k=3 +i=1 +j=2 +k=3 +echo 6 $((i += j += k)) +echo 6,5,3 $i,$j,$k + +# octal, hex +echo 263 $(( 0x100 | 007 )) +echo 255 $(( 0xff )) +#ash# echo 255 $(( 16#ff )) +#ash# echo 127 $(( 16#FF/2 )) +#ash# echo 36 $(( 8#44 )) + +echo 40 $(( 8 ^ 32 )) + +#ash# # other bases +#ash# echo 10 $(( 16#a )) +#ash# echo 10 $(( 32#a )) +#ash# echo 10 $(( 56#a )) +#ash# echo 10 $(( 64#a )) +#ash# +#ash# echo 10 $(( 16#A )) +#ash# echo 10 $(( 32#A )) +#ash# echo 36 $(( 56#A )) +#ash# echo 36 $(( 64#A )) +#ash# +#ash# echo 62 $(( 64#@ )) +#ash# echo 63 $(( 64#_ )) + +#ash# # weird bases (error) +#ash# echo $(( 3425#56 )) + +#ash# # missing number after base +#ash# echo 0 $(( 2# )) + +# these should generate errors +( echo $(( 7 = 43 )) ) +#ash# echo $(( 2#44 )) +( echo $(( 44 / 0 )) ) +( let 'jv += $iv' ) +( echo $(( jv += \$iv )) ) +( let 'rv = 7 + (43 * 6' ) + +#ash# # more errors +#ash# declare -i i +#ash# i=0#4 +#ash# i=2#110#11 + +((echo abc; echo def;); echo ghi) + +#ash# if (((4+4) + (4 + 7))); then +#ash# echo ok +#ash# fi + +#ash# (()) # make sure the null expression works OK + +#ash# a=(0 2 4 6) +#ash# echo 6 $(( a[1] + a[2] )) +#ash# echo 1 $(( (a[1] + a[2]) == a[3] )) +#ash# (( (a[1] + a[2]) == a[3] )) ; echo 0 $? + +# test pushing and popping the expression stack +unset A +A="4 + " +( echo A $(( ( 4 + A ) + 4 )) ) +A="3 + 5" +echo 16 $(( ( 4 + A ) + 4 )) + +# badly-formed conditional expressions +( echo $(( 4 ? : $A )) ) +( echo $(( 1 ? 20 )) ) +( echo $(( 4 ? 20 : )) ) + +# precedence and short-circuit evaluation +B=9 +echo 9 $B + +# error +( echo $(( 0 && B=42 )); echo 9 $B ) + +# error +( echo $(( 1 || B=88 )); echo 9 $B ) + +# ash mistakenly evaluates B=... below +#ash# echo 0 $(( 0 && (B=42) )) +echo 9 $B +#ash# echo 0 $(( (${$} - $$) && (B=42) )) +echo 9 $B +#ash# echo 1 $(( 1 || (B=88) )) +echo 9 $B + + +# until command with (( )) command +x=7 + +echo 7 $x +#ash# until (( x == 4 )) + until test "$x" = 4 +do + echo $x + x=4 +done + +echo 4 $x + +# exponentiation +echo 32767 $(( 2**15 - 1)) +echo 32768 $(( 2**(16-1))) +echo 131072 $(( 2**16*2 )) +echo 2147483647 $(( 2**31-1)) +echo 1 $(( 2**0 )) + +# {pre,post}-{inc,dec}rement and associated errors + +x=4 + +echo 4 $x +echo 4 $(( x++ )) +echo 5 $x +echo 5 $(( x-- )) +echo 4 $x + +echo 3 $(( --x )) +echo 3 $x + +echo 4 $(( ++x )) +echo 4 $x + +# bash 3.2 apparently thinks that ++7 is 7 +#ash# echo 7 $(( ++7 )) +( echo $(( 7-- )) ) + +( echo $(( --x=7 )) ) +( echo $(( ++x=7 )) ) + +( echo $(( x++=7 )) ) +( echo $(( x--=7 )) ) + +echo 4 $x + +echo 7 $(( +7 )) +echo -7 $(( -7 )) + +# bash 3.2 apparently thinks that ++7 is 7 +#ash# echo $(( ++7 )) +#ash# echo $(( --7 )) + +${THIS_SH} ./arith1.sub +${THIS_SH} ./arith2.sub + +x=4 +y=7 + +#ash# (( x=8 , y=12 )) + x=8 + y=12 +echo $x $y + +#ash# # should be an error +#ash# (( x=9 y=41 )) + +# These are errors +unset b +( echo $((a b)) ) +#ash# ((a b)) + +n=42 +printf "%d\n" $n +printf "%i\n" $n +#ash# echo $(( 8#$(printf "%o\n" $n) )) +printf "%u\n" $n +#ash# echo $(( 16#$(printf "%x\n" $n) )) +#ash# echo $(( 16#$(printf "%X\n" $n) )) + +# causes longjmp botches through bash-2.05b +a[b[c]d]=e diff --git a/shell/hush_test/hush-arith/arith1.sub b/shell/hush_test/hush-arith/arith1.sub new file mode 100755 index 000000000..80aa99922 --- /dev/null +++ b/shell/hush_test/hush-arith/arith1.sub @@ -0,0 +1,40 @@ +# test of redone post-increment and post-decrement code +( echo $(( 4-- )) ) +( echo $(( 4++ )) ) +( echo $(( 4 -- )) ) +( echo $(( 4 ++ )) ) + +#ash# (( array[0]++ )) +#ash# echo ${array} + +#ash# (( array[0] ++ )) +#ash# echo ${array} + +#ash# (( a++ )) +#ash# echo $a +#ash# (( a ++ )) +#ash# echo $a + a=2 + +echo 6 $(( a ++ + 4 )) +echo 3 $a + +echo 7 $(( a+++4 )) +echo 4 $a + +echo 0 $(( a---4 )) +echo 3 $a + +echo 7 $(( a -- + 4 )) +echo 2 $a + +echo -2 $(( a -- - 4 )) +echo 1 $a + +#ash# (( ++ + 7 )) + +#ash# (( ++ )) +( echo $(( +++7 )) ) +# bash 3.2 apparently thinks that ++ +7 is 7 +#ash# echo $(( ++ + 7 )) +#ash# (( -- )) diff --git a/shell/hush_test/hush-arith/arith2.sub b/shell/hush_test/hush-arith/arith2.sub new file mode 100755 index 000000000..f7e3c9235 --- /dev/null +++ b/shell/hush_test/hush-arith/arith2.sub @@ -0,0 +1,57 @@ +# bash 3.2 apparently thinks that ++7 is 7 etc +( echo $(( --7 )) ) +( echo $(( ++7 )) ) +( echo $(( -- 7 )) ) +( echo $(( ++ 7 )) ) + +#ash# ((++array[0] )) +#ash# echo 1 $array +#ash# (( ++ array[0] )) +#ash# echo 2 $array + +#ash# (( ++a )) +#ash# echo 1 $a +#ash# (( ++ a )) +#ash# echo 2 $a + +#ash# (( --a )) +#ash# echo 1 $a +#ash# (( -- a )) +#ash# echo 0 $a + a=0 + +echo 5 $(( 4 + ++a )) +echo 1 $a + +# ash doesn't handle it right... +#ash# echo 6 $(( 4+++a )) +#ash# echo 2 $a + a=2 + +# ash doesn't handle it right... +#ash# echo 3 $(( 4---a )) +#ash# echo 1 $a + a=1 + +echo 4 $(( 4 - -- a )) +echo 0 $a + +#ash# (( -- )) +# bash 3.2 apparently thinks that ---7 is -7 +#ash# echo $(( ---7 )) +( echo $(( -- - 7 )) ) + +#ash# (( ++ )) +# bash 3.2: 7 +#ash# echo 7 $(( ++7 )) +( echo $(( ++ + 7 )) ) + +# bash 3.2: -7 +#ash# echo -7 $(( ++-7 )) +# bash 3.2: -7 +#ash# echo -7 $(( ++ - 7 )) + +# bash 3.2: 7 +#ash# echo 7 $(( +--7 )) +# bash 3.2: 7 +#ash# echo 7 $(( -- + 7 )) -- 2.25.1