aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-09-26 13:25:49 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-09-26 13:29:25 +0200
commit1be73dd9ad6d2cf6747934374c1d58bd9bc211b4 (patch)
treea009dd15c30f36a991f945cca931c437479cd200 /shell
parent62e433131b289ea90e465cf0c5f78c8c226fc692 (diff)
downloadbusybox-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.right3
-rwxr-xr-xshell/ash_test/ash-arith/arith-postinc.tests4
-rw-r--r--shell/hush_test/hush-arith/arith-postinc.right3
-rwxr-xr-xshell/hush_test/hush-arith/arith-postinc.tests4
-rw-r--r--shell/math.c52
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 @@
21 1 21 1
31 1 31 1
41 1 41 1
56 6
67 7
77 7
5Ok:0 8Ok: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))
2echo 1 $((0--1)) 2echo 1 $((0--1))
3x=-1; echo 1 $((0-$x)) 3x=-1; echo 1 $((0-$x))
4x=+1; echo 1 $((0+$x)) 4x=+1; echo 1 $((0+$x))
5a=3
6echo 6 $((a+++3)) # a++ + 3
7echo 7 $(((a)+++3)) # a + + + 3
8echo 7 $(((a)+++3)) # a + + + 3
5echo Ok:$? 9echo 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 @@
21 1 21 1
31 1 31 1
41 1 41 1
56 6
67 7
77 7
5Ok:0 8Ok: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))
2echo 1 $((0--1)) 2echo 1 $((0--1))
3x=-1; echo 1 $((0-$x)) 3x=-1; echo 1 $((0-$x))
4x=+1; echo 1 $((0+$x)) 4x=+1; echo 1 $((0+$x))
5a=3
6echo 6 $((a+++3)) # a++ + 3
7echo 7 $(((a)+++3)) # a + + + 3
8echo 7 $(((a)+++3)) # a + + + 3
5echo Ok:$? 9echo 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
123typedef unsigned char operator; 119typedef 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*
258arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) 254arith_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) */