shell: shrink arith code; and prepare for returning text error codes

function                                             old     new   delta
arith                                                701     680     -21

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-13 00:34:26 +02:00
parent 99862cbfad
commit b771c654ca
2 changed files with 63 additions and 65 deletions

View 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 */ if (beg < 0) /* bash compat */
beg = 0; beg = 0;
debug_printf_varexp("from val:'%s'\n", val); debug_printf_varexp("from val:'%s'\n", val);
if (len == 0 || !val || beg >= strlen(val)) if (len == 0 || !val || beg >= strlen(val)) {
val = ""; val = NULL;
else { } else {
/* Paranoia. What if user entered 9999999999999 /* Paranoia. What if user entered 9999999999999
* which fits in arith_t but not int? */ * which fits in arith_t but not int? */
if (len >= INT_MAX) if (len >= INT_MAX)
@ -4742,7 +4742,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
#endif #endif
{ {
die_if_script("malformed ${%s:...}", var); die_if_script("malformed ${%s:...}", var);
val = ""; val = NULL;
} }
} else { /* one of "-=+?" */ } else { /* one of "-=+?" */
/* Standard-mandated substitution ops: /* Standard-mandated substitution ops:

View File

@ -124,9 +124,6 @@
#define setvar (math_hooks->setvar ) #define setvar (math_hooks->setvar )
//#define endofname (math_hooks->endofname) //#define endofname (math_hooks->endofname)
#define arith_isspace(arithval) \
(arithval == ' ' || arithval == '\n' || arithval == '\t')
typedef unsigned char operator; typedef unsigned char operator;
/* An operator's token id is a bit of a bitfield. The lower 5 bits are the /* 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) #define TOK_REM_ASSIGN tok_decl(3,2)
/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ /* 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 */ /* conditional is right associativity too */
#define TOK_CONDITIONAL tok_decl(4,0) #define TOK_CONDITIONAL tok_decl(4,0)
@ -223,7 +220,7 @@ tok_have_assign(operator op)
{ {
operator prec = PREC(op); operator prec = PREC(op);
convert_prec_is_assing(prec); convert_prec_is_assign(prec);
return (prec == PREC(TOK_ASSIGN) || return (prec == PREC(TOK_ASSIGN) ||
prec == PREC_PRE || prec == PREC_POST); prec == PREC_PRE || prec == PREC_POST);
} }
@ -477,7 +474,7 @@ static const char op_tokens[] ALIGN1 = {
0 0
}; };
/* ptr to ")" */ /* ptr to ")" */
#define endexpression (&op_tokens[sizeof(op_tokens)-7]) #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
const char* FAST_FUNC const char* FAST_FUNC
endofname(const char *name) endofname(const char *name)
@ -494,32 +491,36 @@ endofname(const char *name)
arith_t arith_t
arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
{ {
char arithval; /* Current character under analysis */ operator lasttok;
operator lasttok, op;
operator prec;
operator *stack, *stackptr;
const char *p = endexpression;
int errcode; int errcode;
v_n_t *numstack, *numstackptr; const char *start_expr = expr = skip_whitespace(expr);
unsigned datasizes = strlen(expr) + 2; unsigned expr_len = strlen(expr) + 2;
/* Stack of integers */ /* Stack of integers */
/* The proof that there can be no more than strlen(startbuf)/2+1 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 * in any given correct or incorrect expression is left as an exercise to
* the reader. */ * 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 */ /* 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 */ *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
*perrcode = errcode = 0; errcode = 0;
while (1) { while (1) {
const char *p;
operator op;
operator prec;
char arithval;
expr = skip_whitespace(expr);
arithval = *expr; arithval = *expr;
if (arithval == 0) { if (arithval == '\0') {
if (p == endexpression) { if (expr == start_expr) {
/* Null expression. */ /* Null expression. */
return 0; numstack->val = 0;
goto ret;
} }
/* This is only reached after all tokens have been extracted from the /* 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 * are to be applied in order. At the end, there should be a final
* result on the integer stack */ * result on the integer stack */
if (expr != endexpression + 1) { if (expr != ptr_to_rparen + 1) {
/* If we haven't done so already, */ /* If we haven't done so already, */
/* append a closing right paren */ /* append a closing right paren */
expr = endexpression; expr = ptr_to_rparen;
/* and let the loop process it. */ /* and let the loop process it. */
continue; continue;
} }
/* At this point, we're done with the expression. */ /* 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 */ /* ... but if there isn't, it's bad */
err: goto err;
*perrcode = -1;
return *perrcode;
} }
if (numstack->var) { if (numstack->var) {
/* expression is $((var)) only, lookup now */ /* expression is $((var)) only, lookup now */
errcode = arith_lookup_val(numstack, math_hooks); errcode = arith_lookup_val(numstack, math_hooks);
} }
ret: goto ret;
*perrcode = errcode;
return numstack->val;
} }
/* Continue processing the expression. */
if (arith_isspace(arithval)) {
/* Skip whitespace */
goto prologue;
}
p = endofname(expr); p = endofname(expr);
if (p != 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); numstackptr->var = alloca(var_name_size);
safe_strncpy(numstackptr->var, expr, var_name_size); safe_strncpy(numstackptr->var, expr, var_name_size);
expr = p; expr = p;
@ -568,36 +560,37 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
lasttok = TOK_NUM; lasttok = TOK_NUM;
continue; continue;
} }
if (isdigit(arithval)) { if (isdigit(arithval)) {
/* Number */
numstackptr->var = NULL; numstackptr->var = NULL;
errno = 0; 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) if (errno)
numstackptr->val = 0; /* bash compat */ numstackptr->val = 0; /* bash compat */
goto num; goto num;
} }
for (p = op_tokens; ; p++) {
const char *o;
if (*p == 0) { /* Should be an operator */
/* strange operator not found */ p = op_tokens;
goto err; while (1) {
} const char *e = expr;
for (o = expr; *p && *o == *p; p++) /* Compare expr to current op_tokens[] element */
o++; while (*p && *e == *p)
if (!*p) { p++, e++;
/* found */ if (*p == '\0') { /* match: operator is found */
expr = o - 1; expr = e;
break; break;
} }
/* skip tail uncompared token */ /* Go to next element of op_tokens[] */
while (*p) while (*p)
p++; p++;
/* skip zero delim */ p += 2; /* skip NUL and TOK_foo bytes */
p++; 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 */ /* post grammar: a++ reduce to num */
if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 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 */ /* Any operator directly after a */
lasttok = TOK_NUM; lasttok = TOK_NUM;
/* close paren should consider itself binary */ /* close paren should consider itself binary */
goto prologue; goto next;
} }
} else { } else {
operator prev_prec = PREC(stackptr[-1]); operator prev_prec = PREC(stackptr[-1]);
convert_prec_is_assign(prec);
convert_prec_is_assing(prec); convert_prec_is_assign(prev_prec);
convert_prec_is_assing(prev_prec);
if (prev_prec < prec) if (prev_prec < prec)
break; break;
/* check right assoc */ /* check right assoc */
@ -665,7 +657,8 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
break; break;
} }
errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks); errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks);
if (errcode) goto ret; if (errcode)
goto ret;
} }
if (op == TOK_RPAREN) { if (op == TOK_RPAREN) {
goto err; 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. */ /* Push this operator to the stack and remember it. */
*stackptr++ = lasttok = op; *stackptr++ = lasttok = op;
prologue: next: ;
++expr; } /* while (1) */
} /* while */
err:
numstack->val = errcode = -1;
ret:
*perrcode = errcode;
return numstack->val;
} }
/* /*