shell/math: return string error indicator, not integer
authorDenys Vlasenko <dvlasenk@redhat.com>
Wed, 15 Sep 2010 11:33:02 +0000 (13:33 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Wed, 15 Sep 2010 11:33:02 +0000 (13:33 +0200)
function                                             old     new   delta
expand_and_evaluate_arith                             87     106     +19
expand_one_var                                      1563    1570      +7
arith                                                 12      18      +6
evaluate_string                                      678     680      +2
arith_apply                                         1269    1271      +2
builtin_umask                                        133     132      -1
ash_arith                                            118      75     -43
expand_vars_to_list                                 1094    1038     -56
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/3 up/down: 36/-100)           Total: -64 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
shell/ash.c
shell/ash_test/ash-arith/arith.right
shell/hush.c
shell/hush_test/hush-arith/arith.right
shell/math.c
shell/math.h

index c27ab7de2301309c8f0b54aaa5e70d6746ab5f61..ec887e088f1f1e22b866eb0b0d0626ea27e6ee80 100644 (file)
@@ -5451,15 +5451,8 @@ ash_arith(const char *s)
 
        INT_OFF;
        result = arith(&math_state, s);
-       if (math_state.errcode < 0) {
-               if (math_state.errcode == -3)
-                       ash_msg_and_raise_error("exponent less than 0");
-               if (math_state.errcode == -2)
-                       ash_msg_and_raise_error("divide by zero");
-               if (math_state.errcode == -5)
-                       ash_msg_and_raise_error("expression recursion loop detected");
-               raise_error_syntax(s);
-       }
+       if (math_state.errmsg)
+               ash_msg_and_raise_error(math_state.errmsg);
        INT_ON;
 
        return result;
index 3ea7ce680d3613a76e426136d0cddb500ac99837..7257cc566b6bd88438a603d58f587593cb9353d3 100644 (file)
@@ -55,28 +55,28 @@ Format: 'expected actual'
 30 30
 20 20
 30 30
-./arith.tests: line 117: syntax error: 1 ? 20 : x+=2
+./arith.tests: line 117: arithmetic syntax error
 6 6
 6,5,3 6,5,3
 263 263
 255 255
 40 40
-./arith.tests: line 163: syntax error:  7 = 43 
+./arith.tests: line 163: arithmetic syntax error
 ./arith.tests: line 165: divide by zero
-./arith.tests: let: line 166: syntax error: jv += $iv
-./arith.tests: line 167: syntax error:  jv += $iv 
-./arith.tests: let: line 168: syntax error: rv = 7 + (43 * 6
+./arith.tests: let: line 166: arithmetic syntax error
+./arith.tests: line 167: arithmetic syntax error
+./arith.tests: let: line 168: arithmetic syntax error
 abc
 def
 ghi
-./arith.tests: line 191: syntax error:  ( 4 + A ) + 4 
+./arith.tests: line 191: arithmetic syntax error
 16 16
-./arith.tests: line 196: syntax error:  4 ? : 3 + 5 
-./arith.tests: line 197: syntax error:  1 ? 20 
-./arith.tests: line 198: syntax error:  4 ? 20 : 
+./arith.tests: line 196: arithmetic syntax error
+./arith.tests: line 197: arithmetic syntax error
+./arith.tests: line 198: arithmetic syntax error
 9 9
-./arith.tests: line 205: syntax error:  0 && B=42 
-./arith.tests: line 208: syntax error:  1 || B=88 
+./arith.tests: line 205: arithmetic syntax error
+./arith.tests: line 208: arithmetic syntax error
 9 9
 9 9
 9 9
@@ -97,18 +97,18 @@ ghi
 3 3
 4 4
 4 4
-./arith.tests: line 257: syntax error:  7-- 
-./arith.tests: line 259: syntax error:  --x=7 
-./arith.tests: line 260: syntax error:  ++x=7 
-./arith.tests: line 262: syntax error:  x++=7 
-./arith.tests: line 263: syntax error:  x--=7 
+./arith.tests: line 257: arithmetic syntax error
+./arith.tests: line 259: arithmetic syntax error
+./arith.tests: line 260: arithmetic syntax error
+./arith.tests: line 262: arithmetic syntax error
+./arith.tests: line 263: arithmetic syntax error
 4 4
 7 7
 -7 -7
-./arith1.sub: line 2: syntax error:  4-- 
-./arith1.sub: line 3: syntax error:  4++ 
-./arith1.sub: line 4: syntax error:  4 -- 
-./arith1.sub: line 5: syntax error:  4 ++ 
+./arith1.sub: line 2: arithmetic syntax error
+./arith1.sub: line 3: arithmetic syntax error
+./arith1.sub: line 4: arithmetic syntax error
+./arith1.sub: line 5: arithmetic syntax error
 6 6
 3 3
 7 7
@@ -119,19 +119,19 @@ ghi
 2 2
 -2 -2
 1 1
-./arith1.sub: line 37: syntax error:  +++7 
-./arith2.sub: line 2: syntax error:  --7 
-./arith2.sub: line 3: syntax error:  ++7 
-./arith2.sub: line 4: syntax error:  -- 7 
-./arith2.sub: line 5: syntax error:  ++ 7 
+./arith1.sub: line 37: arithmetic syntax error
+./arith2.sub: line 2: arithmetic syntax error
+./arith2.sub: line 3: arithmetic syntax error
+./arith2.sub: line 4: arithmetic syntax error
+./arith2.sub: line 5: arithmetic syntax error
 5 5
 1 1
 4 4
 0 0
-./arith2.sub: line 42: syntax error:  -- - 7 
-./arith2.sub: line 47: syntax error:  ++ + 7 
+./arith2.sub: line 42: arithmetic syntax error
+./arith2.sub: line 47: arithmetic syntax error
 8 12
-./arith.tests: line 290: syntax error: a b
+./arith.tests: line 290: arithmetic syntax error
 42
 42
 42
index 4ca5403dee406b793fe11dbcca26bda2d3a696bb..ad30ac1eaa79d028eb64c03876b7e2fc9ccf53fd 100644 (file)
@@ -4461,7 +4461,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
 }
 
 #if ENABLE_SH_MATH_SUPPORT
-static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p)
+static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
 {
        arith_state_t math_state;
        arith_t res;
@@ -4472,8 +4472,11 @@ static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p)
        //math_state.endofname = endofname;
        exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
        res = arith(&math_state, exp_str ? exp_str : arg);
-       *errcode_p = math_state.errcode;
        free(exp_str);
+       if (errmsg_p)
+               *errmsg_p = math_state.errmsg;
+       if (math_state.errmsg)
+               die_if_script(math_state.errmsg);
        return res;
 }
 #endif
@@ -4714,22 +4717,26 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
                         * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
                         */
                        arith_t beg, len;
-                       int errcode = 0;
+                       const char *errmsg;
 
-                       beg = expand_and_evaluate_arith(exp_word, &errcode);
+                       beg = expand_and_evaluate_arith(exp_word, &errmsg);
+                       if (errmsg)
+                               goto arith_err;
                        debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
                        *p++ = SPECIAL_VAR_SYMBOL;
                        exp_word = p;
                        p = strchr(p, SPECIAL_VAR_SYMBOL);
                        *p = '\0';
-                       len = expand_and_evaluate_arith(exp_word, &errcode);
+                       len = expand_and_evaluate_arith(exp_word, &errmsg);
+                       if (errmsg)
+                               goto arith_err;
                        debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
-
-                       if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
+                       if (len >= 0) { /* bash compat: len < 0 is illegal */
                                if (beg < 0) /* bash compat */
                                        beg = 0;
                                debug_printf_varexp("from val:'%s'\n", val);
                                if (len == 0 || !val || beg >= strlen(val)) {
+ arith_err:
                                        val = NULL;
                                } else {
                                        /* Paranoia. What if user entered 9999999999999
@@ -4926,28 +4933,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
 #if ENABLE_SH_MATH_SUPPORT
                case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
                        arith_t res;
-                       int errcode;
 
                        arg++; /* skip '+' */
                        *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
                        debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
-                       res = expand_and_evaluate_arith(arg, &errcode);
-
-                       if (errcode < 0) {
-                               const char *msg = "error in arithmetic";
-                               switch (errcode) {
-                               case -3:
-                                       msg = "exponent less than 0";
-                                       break;
-                               case -2:
-                                       msg = "divide by 0";
-                                       break;
-                               case -5:
-                                       msg = "expression recursion loop detected";
-                                       break;
-                               }
-                               die_if_script(msg);
-                       }
+                       res = expand_and_evaluate_arith(arg, NULL);
                        debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
                        sprintf(arith_buf, arith_t_fmt, res);
                        val = arith_buf;
index 718c26ad0b8f47312076ef711675c33c24e26fcb..fd4ea8e01aa0be6038ac37cd5f1650c8cd0d6204 100644 (file)
@@ -61,7 +61,7 @@ check that the unevaluated part of the ternary operator does not do evaluation o
 20 20
 30 30
 check precedence of assignment vs. conditional operator
-hush: error in arithmetic
+hush: arithmetic syntax error
 check precedence of assignment vs. conditional operator
 associativity of assignment-operator operator
 6 6
@@ -70,22 +70,22 @@ octal, hex
 263 263
 255 255
 40 40
-hush: error in arithmetic
-hush: divide by 0
+hush: arithmetic syntax error
+hush: divide by zero
 hush: can't execute 'let': No such file or directory
-hush: error in arithmetic
+hush: arithmetic syntax error
 hush: can't execute 'let': No such file or directory
 abc
 def
 ghi
-hush: error in arithmetic
+hush: arithmetic syntax error
 16 16
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 9 9
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 9 9
 9 9
 9 9
@@ -106,18 +106,18 @@ hush: error in arithmetic
 3 3
 4 4
 4 4
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 4 4
 7 7
 -7 -7
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 6 6
 3 3
 7 7
@@ -128,19 +128,19 @@ hush: error in arithmetic
 2 2
 -2 -2
 1 1
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 5 5
 1 1
 4 4
 0 0
-hush: error in arithmetic
-hush: error in arithmetic
+hush: arithmetic syntax error
+hush: arithmetic syntax error
 8 12
-hush: error in arithmetic
+hush: arithmetic syntax error
 42
 42
 42
index 839715776ad69dd0566aa7bc299b8f2b32a01cf3..871c06c3ee19a73be530e19640918a9063df1d26 100644 (file)
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
-
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
-
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
-
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
+ *
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
+ *
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
 
 /* This is my infix parser/evaluator. It is optimized for size, intended
  * as a replacement for yacc-based parsers. However, it may well be faster
@@ -60,9 +60,6 @@
  * this is based (this code differs in that it applies operators immediately
  * to the stack instead of adding them to a queue to end up with an
  * expression).
- *
- * To use the routine, call it with an expression string and error return
- * pointer
  */
 
 /*
@@ -250,7 +247,7 @@ typedef struct remembered_name {
 static arith_t FAST_FUNC
 evaluate_string(arith_state_t *math_state, const char *expr);
 
-static int
+static const char*
 arith_lookup_val(arith_state_t *math_state, v_n_t *t)
 {
        if (t->var) {
@@ -264,8 +261,8 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
                         */
                        for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
                                if (strcmp(cur->var, t->var) == 0) {
-                                       /* Yes. Expression recursion loop detected */
-                                       return -5;
+                                       /* Yes */
+                                       return "expression recursion loop detected";
                                }
                        }
 
@@ -281,7 +278,7 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
                        /* pop current var name */
                        math_state->list_of_recursed_names = cur;
 
-                       return math_state->errcode;
+                       return math_state->errmsg;
                }
                /* treat undefined var as 0 */
                t->val = 0;
@@ -292,14 +289,14 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
 /* "Applying" a token means performing it on the top elements on the integer
  * stack. For an unary operator it will only change the top element, but a
  * binary operator will pop two arguments and push the result */
-static NOINLINE int
+static NOINLINE const char*
 arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr)
 {
 #define NUMPTR (*numstackptr)
 
        v_n_t *numptr_m1;
        arith_t numptr_val, rez;
-       int err;
+       const char *err;
 
        /* There is no operator that can work without arguments */
        if (NUMPTR == numstack)
@@ -399,13 +396,13 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num
                } else if (op == TOK_EXPONENT) {
                        arith_t c;
                        if (numptr_val < 0)
-                               return -3;      /* exponent less than 0 */
+                               return "exponent less than 0";
                        c = 1;
                        while (--numptr_val >= 0)
                            c *= rez;
                        rez = c;
-               } else if (numptr_val==0)          /* zero divisor check */
-                       return -2;
+               } else if (numptr_val == 0)
+                       return "divide by zero";
                else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
                        rez /= numptr_val;
                else if (op == TOK_REM || op == TOK_REM_ASSIGN)
@@ -430,9 +427,9 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num
        numptr_m1->val = rez;
        /* erase var name, it is just a number now */
        numptr_m1->var = NULL;
-       return 0;
+       return NULL;
  err:
-       return -1;
+       return "arithmetic syntax error";
 #undef NUMPTR
 }
 
@@ -498,7 +495,7 @@ static arith_t FAST_FUNC
 evaluate_string(arith_state_t *math_state, const char *expr)
 {
        operator lasttok;
-       int errcode;
+       const char *errmsg;
        const char *start_expr = expr = skip_whitespace(expr);
        unsigned expr_len = strlen(expr) + 2;
        /* Stack of integers */
@@ -512,7 +509,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
        operator *stackptr = stack;
 
        *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
-       errcode = 0;
+       errmsg = NULL;
 
        while (1) {
                const char *p;
@@ -548,7 +545,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
                        }
                        if (numstack->var) {
                                /* expression is $((var)) only, lookup now */
-                               errcode = arith_lookup_val(math_state, numstack);
+                               errmsg = arith_lookup_val(math_state, numstack);
                        }
                        goto ret;
                }
@@ -663,8 +660,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
                                                break;
                                        }
                                }
-                               errcode = arith_apply(math_state, prev_op, numstack, &numstackptr);
-                               if (errcode)
+                               errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
+                               if (errmsg)
                                        goto ret;
                        }
                        if (op == TOK_RPAREN) {
@@ -678,15 +675,17 @@ evaluate_string(arith_state_t *math_state, const char *expr)
        } /* while (1) */
 
  err:
-       numstack->val = errcode = -1;
+       numstack->val = -1;
+       errmsg = "arithmetic syntax error";
  ret:
-       math_state->errcode = errcode;
+       math_state->errmsg = errmsg;
        return numstack->val;
 }
 
 arith_t FAST_FUNC
 arith(arith_state_t *math_state, const char *expr)
 {
+       math_state->errmsg = NULL;
        math_state->list_of_recursed_names = NULL;
        return evaluate_string(math_state, expr);
 }
index e34b65d5d70cd6b0b5393919506cd0f0abfa863f..2dcab130d8ea1a2cd3d4286818ddad2a238d1312 100644 (file)
@@ -95,7 +95,7 @@ typedef void        FAST_FUNC (*arith_var_set_t)(const char *name, const char *v
 //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name);
 
 typedef struct arith_state_t {
-       int                   errcode;
+       const char           *errmsg;
        arith_var_lookup_t    lookupvar;
        arith_var_set_t       setvar;
 //     arith_var_endofname_t endofname;