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:
parent
99862cbfad
commit
b771c654ca
@ -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:
|
||||
|
120
shell/math.c
120
shell/math.c
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user