shell: shrink arith code; and prepare for returning text error codes
authorDenys Vlasenko <dvlasenk@redhat.com>
Sun, 12 Sep 2010 22:34:26 +0000 (00:34 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Sun, 12 Sep 2010 22:34:26 +0000 (00:34 +0200)
function                                             old     new   delta
arith                                                701     680     -21

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
shell/hush.c
shell/math.c

index 752efd0c8b985d0b1872a49bc26317471a20c479..ef0c454ec2f9994f15af1e99ee05f55696ea6539 100644 (file)
@@ -4728,9 +4728,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
                                if (beg < 0) /* bash compat */
                                        beg = 0;
                                debug_printf_varexp("from val:'%s'\n", val);
-                               if (len == 0 || !val || beg >= strlen(val))
-                                       val = "";
-                               else {
+                               if (len == 0 || !val || beg >= strlen(val)) {
+                                       val = NULL;
+                               else {
                                        /* Paranoia. What if user entered 9999999999999
                                         * which fits in arith_t but not int? */
                                        if (len >= INT_MAX)
@@ -4742,7 +4742,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
 #endif
                        {
                                die_if_script("malformed ${%s:...}", var);
-                               val = "";
+                               val = NULL;
                        }
                } else { /* one of "-=+?" */
                        /* Standard-mandated substitution ops:
index a4c55a4d078ad3a6649f0b5f47485b6c8f41f8d4..2f093391fd3dd8adc1f301231876c7ad0431f5f7 100644 (file)
 #define setvar    (math_hooks->setvar   )
 //#define endofname (math_hooks->endofname)
 
-#define arith_isspace(arithval) \
-       (arithval == ' ' || arithval == '\n' || arithval == '\t')
-
 typedef unsigned char operator;
 
 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
@@ -156,7 +153,7 @@ typedef unsigned char operator;
 #define TOK_REM_ASSIGN tok_decl(3,2)
 
 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
-#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
+#define convert_prec_is_assign(prec) do { if (prec == 3) prec = 2; } while (0)
 
 /* conditional is right associativity too */
 #define TOK_CONDITIONAL tok_decl(4,0)
@@ -223,7 +220,7 @@ tok_have_assign(operator op)
 {
        operator prec = PREC(op);
 
-       convert_prec_is_assing(prec);
+       convert_prec_is_assign(prec);
        return (prec == PREC(TOK_ASSIGN) ||
                        prec == PREC_PRE || prec == PREC_POST);
 }
@@ -477,7 +474,7 @@ static const char op_tokens[] ALIGN1 = {
        0
 };
 /* ptr to ")" */
-#define endexpression (&op_tokens[sizeof(op_tokens)-7])
+#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
 
 const char* FAST_FUNC
 endofname(const char *name)
@@ -494,32 +491,36 @@ endofname(const char *name)
 arith_t
 arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
 {
-       char arithval; /* Current character under analysis */
-       operator lasttok, op;
-       operator prec;
-       operator *stack, *stackptr;
-       const char *p = endexpression;
+       operator lasttok;
        int errcode;
-       v_n_t *numstack, *numstackptr;
-       unsigned datasizes = strlen(expr) + 2;
-
+       const char *start_expr = expr = skip_whitespace(expr);
+       unsigned expr_len = strlen(expr) + 2;
        /* Stack of integers */
        /* The proof that there can be no more than strlen(startbuf)/2+1 integers
         * in any given correct or incorrect expression is left as an exercise to
         * the reader. */
-       numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
+       v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
+       v_n_t *numstackptr = numstack;
        /* Stack of operator tokens */
-       stackptr = stack = alloca(datasizes * sizeof(stack[0]));
+       operator *const stack = alloca(expr_len * sizeof(stack[0]));
+       operator *stackptr = stack;
 
        *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
-       *perrcode = errcode = 0;
+       errcode = 0;
 
        while (1) {
+               const char *p;
+               operator op;
+               operator prec;
+               char arithval;
+
+               expr = skip_whitespace(expr);
                arithval = *expr;
-               if (arithval == 0) {
-                       if (p == endexpression) {
+               if (arithval == '\0') {
+                       if (expr == start_expr) {
                                /* Null expression. */
-                               return 0;
+                               numstack->val = 0;
+                               goto ret;
                        }
 
                        /* This is only reached after all tokens have been extracted from the
@@ -527,38 +528,29 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
                         * are to be applied in order. At the end, there should be a final
                         * result on the integer stack */
 
-                       if (expr != endexpression + 1) {
+                       if (expr != ptr_to_rparen + 1) {
                                /* If we haven't done so already, */
                                /* append a closing right paren */
-                               expr = endexpression;
+                               expr = ptr_to_rparen;
                                /* and let the loop process it. */
                                continue;
                        }
                        /* At this point, we're done with the expression. */
-                       if (numstackptr != numstack+1) {
+                       if (numstackptr != numstack + 1) {
                                /* ... but if there isn't, it's bad */
- err:
-                               *perrcode = -1;
-                               return *perrcode;
+                               goto err;
                        }
                        if (numstack->var) {
                                /* expression is $((var)) only, lookup now */
                                errcode = arith_lookup_val(numstack, math_hooks);
                        }
- ret:
-                       *perrcode = errcode;
-                       return numstack->val;
+                       goto ret;
                }
 
-               /* Continue processing the expression. */
-               if (arith_isspace(arithval)) {
-                       /* Skip whitespace */
-                       goto prologue;
-               }
                p = endofname(expr);
                if (p != expr) {
-                       size_t var_name_size = (p-expr) + 1;  /* trailing zero */
-
+                       /* Name */
+                       size_t var_name_size = (p-expr) + 1;  /* +1 for NUL */
                        numstackptr->var = alloca(var_name_size);
                        safe_strncpy(numstackptr->var, expr, var_name_size);
                        expr = p;
@@ -568,36 +560,37 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
                        lasttok = TOK_NUM;
                        continue;
                }
+
                if (isdigit(arithval)) {
+                       /* Number */
                        numstackptr->var = NULL;
                        errno = 0;
-                       /* call strtoul[l]: */
-                       numstackptr->val = strto_arith_t(expr, (char **) &expr, 0);
+                       numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
                        if (errno)
                                numstackptr->val = 0; /* bash compat */
                        goto num;
                }
-               for (p = op_tokens; ; p++) {
-                       const char *o;
 
-                       if (*p == 0) {
-                               /* strange operator not found */
-                               goto err;
-                       }
-                       for (o = expr; *p && *o == *p; p++)
-                               o++;
-                       if (!*p) {
-                               /* found */
-                               expr = o - 1;
+               /* Should be an operator */
+               p = op_tokens;
+               while (1) {
+                       const char *e = expr;
+                       /* Compare expr to current op_tokens[] element */
+                       while (*p && *e == *p)
+                               p++, e++;
+                       if (*p == '\0') { /* match: operator is found */
+                               expr = e;
                                break;
                        }
-                       /* skip tail uncompared token */
+                       /* Go to next element of op_tokens[] */
                        while (*p)
                                p++;
-                       /* skip zero delim */
-                       p++;
+                       p += 2; /* skip NUL and TOK_foo bytes */
+                       if (*p == '\0') /* no next element, operator not found */
+                               goto err;
                }
-               op = p[1];
+               op = p[1]; /* fetch TOK_foo value */
+               /* NB: expr now points past the operator */
 
                /* post grammar: a++ reduce to num */
                if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
@@ -651,13 +644,12 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
                                                /* Any operator directly after a */
                                                lasttok = TOK_NUM;
                                                /* close paren should consider itself binary */
-                                               goto prologue;
+                                               goto next;
                                        }
                                } else {
                                        operator prev_prec = PREC(stackptr[-1]);
-
-                                       convert_prec_is_assing(prec);
-                                       convert_prec_is_assing(prev_prec);
+                                       convert_prec_is_assign(prec);
+                                       convert_prec_is_assign(prev_prec);
                                        if (prev_prec < prec)
                                                break;
                                        /* check right assoc */
@@ -665,7 +657,8 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
                                                break;
                                }
                                errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks);
-                               if (errcode) goto ret;
+                               if (errcode)
+                                       goto ret;
                        }
                        if (op == TOK_RPAREN) {
                                goto err;
@@ -674,9 +667,14 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
 
                /* Push this operator to the stack and remember it. */
                *stackptr++ = lasttok = op;
- prologue:
-               ++expr;
-       } /* while */
+ next: ;
+       } /* while (1) */
+
+ err:
+       numstack->val = errcode = -1;
+ ret:
+       *perrcode = errcode;
+       return numstack->val;
 }
 
 /*