diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-26 13:25:49 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-26 13:29:25 +0200 |
commit | 1be73dd9ad6d2cf6747934374c1d58bd9bc211b4 (patch) | |
tree | a009dd15c30f36a991f945cca931c437479cd200 /shell | |
parent | 62e433131b289ea90e465cf0c5f78c8c226fc692 (diff) | |
download | busybox-w32-1be73dd9ad6d2cf6747934374c1d58bd9bc211b4.tar.gz busybox-w32-1be73dd9ad6d2cf6747934374c1d58bd9bc211b4.tar.bz2 busybox-w32-1be73dd9ad6d2cf6747934374c1d58bd9bc211b4.zip |
shell: fix parsing of $(( (v)++ + NUM ))
function old new delta
evaluate_string 988 1011 +23
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash_test/ash-arith/arith-postinc.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-arith/arith-postinc.tests | 4 | ||||
-rw-r--r-- | shell/hush_test/hush-arith/arith-postinc.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-arith/arith-postinc.tests | 4 | ||||
-rw-r--r-- | shell/math.c | 52 |
5 files changed, 44 insertions, 22 deletions
diff --git a/shell/ash_test/ash-arith/arith-postinc.right b/shell/ash_test/ash-arith/arith-postinc.right index c95ce02bf..5cd4ba6b4 100644 --- a/shell/ash_test/ash-arith/arith-postinc.right +++ b/shell/ash_test/ash-arith/arith-postinc.right | |||
@@ -2,4 +2,7 @@ | |||
2 | 1 1 | 2 | 1 1 |
3 | 1 1 | 3 | 1 1 |
4 | 1 1 | 4 | 1 1 |
5 | 6 6 | ||
6 | 7 7 | ||
7 | 7 7 | ||
5 | Ok:0 | 8 | Ok:0 |
diff --git a/shell/ash_test/ash-arith/arith-postinc.tests b/shell/ash_test/ash-arith/arith-postinc.tests index 3fd9bfed5..f2ae778df 100755 --- a/shell/ash_test/ash-arith/arith-postinc.tests +++ b/shell/ash_test/ash-arith/arith-postinc.tests | |||
@@ -2,4 +2,8 @@ echo 1 $((0++1)) | |||
2 | echo 1 $((0--1)) | 2 | echo 1 $((0--1)) |
3 | x=-1; echo 1 $((0-$x)) | 3 | x=-1; echo 1 $((0-$x)) |
4 | x=+1; echo 1 $((0+$x)) | 4 | x=+1; echo 1 $((0+$x)) |
5 | a=3 | ||
6 | echo 6 $((a+++3)) # a++ + 3 | ||
7 | echo 7 $(((a)+++3)) # a + + + 3 | ||
8 | echo 7 $(((a)+++3)) # a + + + 3 | ||
5 | echo Ok:$? | 9 | echo Ok:$? |
diff --git a/shell/hush_test/hush-arith/arith-postinc.right b/shell/hush_test/hush-arith/arith-postinc.right index c95ce02bf..5cd4ba6b4 100644 --- a/shell/hush_test/hush-arith/arith-postinc.right +++ b/shell/hush_test/hush-arith/arith-postinc.right | |||
@@ -2,4 +2,7 @@ | |||
2 | 1 1 | 2 | 1 1 |
3 | 1 1 | 3 | 1 1 |
4 | 1 1 | 4 | 1 1 |
5 | 6 6 | ||
6 | 7 7 | ||
7 | 7 7 | ||
5 | Ok:0 | 8 | Ok:0 |
diff --git a/shell/hush_test/hush-arith/arith-postinc.tests b/shell/hush_test/hush-arith/arith-postinc.tests index 3fd9bfed5..f2ae778df 100755 --- a/shell/hush_test/hush-arith/arith-postinc.tests +++ b/shell/hush_test/hush-arith/arith-postinc.tests | |||
@@ -2,4 +2,8 @@ echo 1 $((0++1)) | |||
2 | echo 1 $((0--1)) | 2 | echo 1 $((0--1)) |
3 | x=-1; echo 1 $((0-$x)) | 3 | x=-1; echo 1 $((0-$x)) |
4 | x=+1; echo 1 $((0+$x)) | 4 | x=+1; echo 1 $((0+$x)) |
5 | a=3 | ||
6 | echo 6 $((a+++3)) # a++ + 3 | ||
7 | echo 7 $(((a)+++3)) # a + + + 3 | ||
8 | echo 7 $(((a)+++3)) # a + + + 3 | ||
5 | echo Ok:$? | 9 | echo Ok:$? |
diff --git a/shell/math.c b/shell/math.c index 049d5703b..76d22c9bd 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -116,10 +116,6 @@ | |||
116 | #include "libbb.h" | 116 | #include "libbb.h" |
117 | #include "math.h" | 117 | #include "math.h" |
118 | 118 | ||
119 | #define lookupvar (math_state->lookupvar) | ||
120 | #define setvar (math_state->setvar ) | ||
121 | //#define endofname (math_state->endofname) | ||
122 | |||
123 | typedef unsigned char operator; | 119 | typedef unsigned char operator; |
124 | 120 | ||
125 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the | 121 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the |
@@ -258,7 +254,7 @@ static const char* | |||
258 | arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) | 254 | arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) |
259 | { | 255 | { |
260 | if (t->var) { | 256 | if (t->var) { |
261 | const char *p = lookupvar(t->var); | 257 | const char *p = math_state->lookupvar(t->var); |
262 | if (p) { | 258 | if (p) { |
263 | remembered_name *cur; | 259 | remembered_name *cur; |
264 | remembered_name cur_save; | 260 | remembered_name cur_save; |
@@ -445,16 +441,15 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ | |||
445 | 441 | ||
446 | if (top_of_stack->var == NULL) { | 442 | if (top_of_stack->var == NULL) { |
447 | /* Hmm, 1=2 ? */ | 443 | /* Hmm, 1=2 ? */ |
448 | //TODO: actually, bash allows ++7 but for some reason it evals to 7, not 8 | ||
449 | goto err; | 444 | goto err; |
450 | } | 445 | } |
451 | /* Save to shell variable */ | 446 | /* Save to shell variable */ |
452 | sprintf(buf, ARITH_FMT, rez); | 447 | sprintf(buf, ARITH_FMT, rez); |
453 | setvar(top_of_stack->var, buf); | 448 | math_state->setvar(top_of_stack->var, buf); |
454 | /* After saving, make previous value for v++ or v-- */ | 449 | /* After saving, make previous value for v++ or v-- */ |
455 | if (op == TOK_POST_INC) | 450 | if (op == TOK_POST_INC) |
456 | rez--; | 451 | rez--; |
457 | else if (op == TOK_POST_DEC) | 452 | if (op == TOK_POST_DEC) |
458 | rez++; | 453 | rez++; |
459 | } | 454 | } |
460 | 455 | ||
@@ -607,11 +602,9 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
607 | const char *p; | 602 | const char *p; |
608 | operator op; | 603 | operator op; |
609 | operator prec; | 604 | operator prec; |
610 | char arithval; | ||
611 | 605 | ||
612 | expr = skip_whitespace(expr); | 606 | expr = skip_whitespace(expr); |
613 | arithval = *expr; | 607 | if (*expr == '\0') { |
614 | if (arithval == '\0') { | ||
615 | if (expr == start_expr) { | 608 | if (expr == start_expr) { |
616 | /* Null expression */ | 609 | /* Null expression */ |
617 | numstack->val = 0; | 610 | numstack->val = 0; |
@@ -628,6 +621,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
628 | * append a closing right paren | 621 | * append a closing right paren |
629 | * and let the loop process it */ | 622 | * and let the loop process it */ |
630 | expr = ptr_to_rparen; | 623 | expr = ptr_to_rparen; |
624 | //bb_error_msg("expr=')'"); | ||
631 | continue; | 625 | continue; |
632 | } | 626 | } |
633 | /* At this point, we're done with the expression */ | 627 | /* At this point, we're done with the expression */ |
@@ -635,19 +629,16 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
635 | /* ...but if there isn't, it's bad */ | 629 | /* ...but if there isn't, it's bad */ |
636 | goto err; | 630 | goto err; |
637 | } | 631 | } |
638 | if (numstack->var) { | ||
639 | /* expression is $((var)) only, lookup now */ | ||
640 | errmsg = arith_lookup_val(math_state, numstack); | ||
641 | } | ||
642 | goto ret; | 632 | goto ret; |
643 | } | 633 | } |
644 | 634 | ||
645 | p = endofname(expr); | 635 | p = endofname(expr); |
646 | if (p != expr) { | 636 | if (p != expr) { |
647 | /* Name */ | 637 | /* Name */ |
648 | size_t var_name_size = (p-expr) + 1; /* +1 for NUL */ | 638 | size_t var_name_size = (p - expr) + 1; /* +1 for NUL */ |
649 | numstackptr->var = alloca(var_name_size); | 639 | numstackptr->var = alloca(var_name_size); |
650 | safe_strncpy(numstackptr->var, expr, var_name_size); | 640 | safe_strncpy(numstackptr->var, expr, var_name_size); |
641 | //bb_error_msg("var:'%s'", numstackptr->var); | ||
651 | expr = p; | 642 | expr = p; |
652 | num: | 643 | num: |
653 | numstackptr->second_val_present = 0; | 644 | numstackptr->second_val_present = 0; |
@@ -656,11 +647,12 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
656 | continue; | 647 | continue; |
657 | } | 648 | } |
658 | 649 | ||
659 | if (isdigit(arithval)) { | 650 | if (isdigit(*expr)) { |
660 | /* Number */ | 651 | /* Number */ |
661 | numstackptr->var = NULL; | 652 | numstackptr->var = NULL; |
662 | errno = 0; | 653 | errno = 0; |
663 | numstackptr->val = strto_arith_t(expr, (char**) &expr); | 654 | numstackptr->val = strto_arith_t(expr, (char**) &expr); |
655 | //bb_error_msg("val:%lld", numstackptr->val); | ||
664 | if (errno) | 656 | if (errno) |
665 | numstackptr->val = 0; /* bash compat */ | 657 | numstackptr->val = 0; /* bash compat */ |
666 | goto num; | 658 | goto num; |
@@ -671,10 +663,10 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
671 | /* Special case: XYZ--, XYZ++, --XYZ, ++XYZ are recognized | 663 | /* Special case: XYZ--, XYZ++, --XYZ, ++XYZ are recognized |
672 | * only if XYZ is a variable name, not a number or EXPR. IOW: | 664 | * only if XYZ is a variable name, not a number or EXPR. IOW: |
673 | * "a+++v" is a++ + v. | 665 | * "a+++v" is a++ + v. |
666 | * "(a)+++7" is ( a ) + + + 7. | ||
674 | * "7+++v" is 7 + ++v, not 7++ + v. | 667 | * "7+++v" is 7 + ++v, not 7++ + v. |
675 | * "--7" is - - 7, not --7. | 668 | * "--7" is - - 7, not --7. |
676 | * "++++a" is + + ++a, not ++ ++ a. | 669 | * "++++a" is + + ++a, not ++ ++a. |
677 | * (we still mishandle "(a)+++7", should be treated as (a) + + + 7, but we do increment a) | ||
678 | */ | 670 | */ |
679 | if ((expr[0] == '+' || expr[0] == '-') | 671 | if ((expr[0] == '+' || expr[0] == '-') |
680 | && (expr[1] == expr[0]) | 672 | && (expr[1] == expr[0]) |
@@ -756,26 +748,40 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
756 | * "applied" in this way. | 748 | * "applied" in this way. |
757 | */ | 749 | */ |
758 | prec = PREC(op); | 750 | prec = PREC(op); |
751 | //bb_error_msg("prec:%02x", prec); | ||
759 | if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { | 752 | if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { |
760 | /* not left paren or unary */ | 753 | /* not left paren or unary */ |
761 | if (lasttok != TOK_NUM) { | 754 | if (lasttok != TOK_NUM) { |
762 | /* binary op must be preceded by a num */ | 755 | /* binary op must be preceded by a num */ |
763 | goto err; | 756 | goto err; |
764 | } | 757 | } |
758 | /* The algorithm employed here is simple: while we don't | ||
759 | * hit an open paren nor the bottom of the stack, pop | ||
760 | * tokens and apply them */ | ||
765 | while (stackptr != stack) { | 761 | while (stackptr != stack) { |
766 | operator prev_op = *--stackptr; | 762 | operator prev_op = *--stackptr; |
767 | if (op == TOK_RPAREN) { | 763 | if (op == TOK_RPAREN) { |
768 | /* The algorithm employed here is simple: while we don't | 764 | //bb_error_msg("op == TOK_RPAREN"); |
769 | * hit an open paren nor the bottom of the stack, pop | ||
770 | * tokens and apply them */ | ||
771 | if (prev_op == TOK_LPAREN) { | 765 | if (prev_op == TOK_LPAREN) { |
766 | //bb_error_msg("prev_op == TOK_LPAREN"); | ||
767 | //bb_error_msg(" %p %p numstackptr[-1].var:'%s'", numstack, numstackptr-1, numstackptr[-1].var); | ||
768 | if (numstackptr[-1].var) { | ||
769 | /* Expression is (var), lookup now */ | ||
770 | errmsg = arith_lookup_val(math_state, &numstackptr[-1]); | ||
771 | if (errmsg) | ||
772 | goto err_with_custom_msg; | ||
773 | /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */ | ||
774 | numstackptr[-1].var = NULL; | ||
775 | } | ||
772 | /* Any operator directly after a | 776 | /* Any operator directly after a |
773 | * close paren should consider itself binary */ | 777 | * close paren should consider itself binary */ |
774 | lasttok = TOK_NUM; | 778 | lasttok = TOK_NUM; |
775 | goto next; | 779 | goto next; |
776 | } | 780 | } |
781 | //bb_error_msg("prev_op != TOK_LPAREN"); | ||
777 | } else { | 782 | } else { |
778 | operator prev_prec = PREC(prev_op); | 783 | operator prev_prec = PREC(prev_op); |
784 | //bb_error_msg("op != TOK_RPAREN"); | ||
779 | fix_assignment_prec(prec); | 785 | fix_assignment_prec(prec); |
780 | fix_assignment_prec(prev_prec); | 786 | fix_assignment_prec(prev_prec); |
781 | if (prev_prec < prec | 787 | if (prev_prec < prec |
@@ -785,6 +791,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
785 | break; | 791 | break; |
786 | } | 792 | } |
787 | } | 793 | } |
794 | //bb_error_msg("arith_apply(prev_op:%02x)", prev_op); | ||
788 | errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); | 795 | errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); |
789 | if (errmsg) | 796 | if (errmsg) |
790 | goto err_with_custom_msg; | 797 | goto err_with_custom_msg; |
@@ -794,6 +801,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
794 | } | 801 | } |
795 | 802 | ||
796 | /* Push this operator to the stack and remember it */ | 803 | /* Push this operator to the stack and remember it */ |
804 | //bb_error_msg("push op:%02x", op); | ||
797 | *stackptr++ = lasttok = op; | 805 | *stackptr++ = lasttok = op; |
798 | next: ; | 806 | next: ; |
799 | } /* while (1) */ | 807 | } /* while (1) */ |