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 */
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:

View File

@ -124,9 +124,6 @@
#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) {
/* ... 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);
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;
}
/*