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 */
|
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:
|
||||||
|
120
shell/math.c
120
shell/math.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user