hush: remove code to track PS1/2 values dynamically - it's too much work
[oweals/busybox.git] / shell / math.c
index 9d3b912a730de6217cb5b2fd95429c71d28ba3ba..611b3beabd0199dbc77f89a1c1c41cde915ec5eb 100644 (file)
@@ -410,15 +410,34 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
                                return "exponent less than 0";
                        c = 1;
                        while (--right_side_val >= 0)
-                           c *= rez;
+                               c *= rez;
                        rez = c;
                }
                else if (right_side_val == 0)
                        return "divide by zero";
-               else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
-                       rez /= right_side_val;
-               else if (op == TOK_REM || op == TOK_REM_ASSIGN)
-                       rez %= right_side_val;
+               else if (op == TOK_DIV || op == TOK_DIV_ASSIGN
+                     || op == TOK_REM || op == TOK_REM_ASSIGN) {
+                       /*
+                        * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))'
+                        *
+                        * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1
+                        * and thus is not representable.
+                        * Some CPUs segfault trying such op.
+                        * Others overflow MAX_POSITIVE_INT+1 to
+                        * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000).
+                        * Make sure to at least not SEGV here:
+                        */
+                       if (right_side_val == -1
+                        && rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */
+                       ) {
+                               right_side_val = 1;
+                       }
+                       if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
+                               rez /= right_side_val;
+                       else {
+                               rez %= right_side_val;
+                       }
+               }
        }
 
        if (is_assign_op(op)) {
@@ -494,18 +513,6 @@ static const char op_tokens[] ALIGN1 = {
 };
 #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
 
-const char* FAST_FUNC
-endofname(const char *name)
-{
-       if (!is_name(*name))
-               return name;
-       while (*++name) {
-               if (!is_in_name(*name))
-                       break;
-       }
-       return name;
-}
-
 static arith_t FAST_FUNC
 evaluate_string(arith_state_t *math_state, const char *expr)
 {
@@ -591,10 +598,24 @@ evaluate_string(arith_state_t *math_state, const char *expr)
                }
 
                /* Should be an operator */
+
+               /* Special case: NUM-- and NUM++ are not recognized if NUM
+                * is a literal number, not a variable. IOW:
+                * "a+++v" is a++ + v.
+                * "7+++v" is 7 + ++v, not 7++ + v.
+                */
+               if (lasttok == TOK_NUM && !numstackptr[-1].var /* number literal */
+                && (expr[0] == '+' || expr[0] == '-')
+                && (expr[1] == expr[0])
+               ) {
+                       //bb_error_msg("special %c%c", expr[0], expr[0]);
+                       op = (expr[0] == '+' ? TOK_ADD : TOK_SUB);
+                       expr += 1;
+                       goto tok_found1;
+               }
+
                p = op_tokens;
                while (1) {
-// TODO: bash allows 7+++v, treats it as 7 + ++v
-// we treat it as 7++ + v and reject
                        /* Compare expr to current op_tokens[] element */
                        const char *e = expr;
                        while (1) {
@@ -620,6 +641,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
                }
  tok_found:
                op = p[1]; /* fetch TOK_foo value */
+ tok_found1:
                /* NB: expr now points past the operator */
 
                /* post grammar: a++ reduce to num */
@@ -652,10 +674,10 @@ evaluate_string(arith_state_t *math_state, const char *expr)
                 * integer stack.
                 * But for binary operators, "apply" everything on the operator
                 * stack until we find an operator with a lesser priority than the
-                * one we have just extracted.
+                * one we have just extracted. If op is right-associative,
+                * then stop "applying" on the equal priority too.
                 * Left paren is given the lowest priority so it will never be
                 * "applied" in this way.
-                * if associativity is right and priority eq, applied also skip
                 */
                prec = PREC(op);
                if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
@@ -736,7 +758,7 @@ arith(arith_state_t *math_state, const char *expr)
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE