shell/math: return string error indicator, not integer

function                                             old     new   delta
expand_and_evaluate_arith                             87     106     +19
expand_one_var                                      1563    1570      +7
arith                                                 12      18      +6
evaluate_string                                      678     680      +2
arith_apply                                         1269    1271      +2
builtin_umask                                        133     132      -1
ash_arith                                            118      75     -43
expand_vars_to_list                                 1094    1038     -56
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/3 up/down: 36/-100)           Total: -64 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-15 13:33:02 +02:00
parent 197a6b3c14
commit 063847d6bd
6 changed files with 113 additions and 131 deletions

View File

@ -5451,15 +5451,8 @@ ash_arith(const char *s)
INT_OFF;
result = arith(&math_state, s);
if (math_state.errcode < 0) {
if (math_state.errcode == -3)
ash_msg_and_raise_error("exponent less than 0");
if (math_state.errcode == -2)
ash_msg_and_raise_error("divide by zero");
if (math_state.errcode == -5)
ash_msg_and_raise_error("expression recursion loop detected");
raise_error_syntax(s);
}
if (math_state.errmsg)
ash_msg_and_raise_error(math_state.errmsg);
INT_ON;
return result;

View File

@ -55,28 +55,28 @@ Format: 'expected actual'
30 30
20 20
30 30
./arith.tests: line 117: syntax error: 1 ? 20 : x+=2
./arith.tests: line 117: arithmetic syntax error
6 6
6,5,3 6,5,3
263 263
255 255
40 40
./arith.tests: line 163: syntax error: 7 = 43
./arith.tests: line 163: arithmetic syntax error
./arith.tests: line 165: divide by zero
./arith.tests: let: line 166: syntax error: jv += $iv
./arith.tests: line 167: syntax error: jv += $iv
./arith.tests: let: line 168: syntax error: rv = 7 + (43 * 6
./arith.tests: let: line 166: arithmetic syntax error
./arith.tests: line 167: arithmetic syntax error
./arith.tests: let: line 168: arithmetic syntax error
abc
def
ghi
./arith.tests: line 191: syntax error: ( 4 + A ) + 4
./arith.tests: line 191: arithmetic syntax error
16 16
./arith.tests: line 196: syntax error: 4 ? : 3 + 5
./arith.tests: line 197: syntax error: 1 ? 20
./arith.tests: line 198: syntax error: 4 ? 20 :
./arith.tests: line 196: arithmetic syntax error
./arith.tests: line 197: arithmetic syntax error
./arith.tests: line 198: arithmetic syntax error
9 9
./arith.tests: line 205: syntax error: 0 && B=42
./arith.tests: line 208: syntax error: 1 || B=88
./arith.tests: line 205: arithmetic syntax error
./arith.tests: line 208: arithmetic syntax error
9 9
9 9
9 9
@ -97,18 +97,18 @@ ghi
3 3
4 4
4 4
./arith.tests: line 257: syntax error: 7--
./arith.tests: line 259: syntax error: --x=7
./arith.tests: line 260: syntax error: ++x=7
./arith.tests: line 262: syntax error: x++=7
./arith.tests: line 263: syntax error: x--=7
./arith.tests: line 257: arithmetic syntax error
./arith.tests: line 259: arithmetic syntax error
./arith.tests: line 260: arithmetic syntax error
./arith.tests: line 262: arithmetic syntax error
./arith.tests: line 263: arithmetic syntax error
4 4
7 7
-7 -7
./arith1.sub: line 2: syntax error: 4--
./arith1.sub: line 3: syntax error: 4++
./arith1.sub: line 4: syntax error: 4 --
./arith1.sub: line 5: syntax error: 4 ++
./arith1.sub: line 2: arithmetic syntax error
./arith1.sub: line 3: arithmetic syntax error
./arith1.sub: line 4: arithmetic syntax error
./arith1.sub: line 5: arithmetic syntax error
6 6
3 3
7 7
@ -119,19 +119,19 @@ ghi
2 2
-2 -2
1 1
./arith1.sub: line 37: syntax error: +++7
./arith2.sub: line 2: syntax error: --7
./arith2.sub: line 3: syntax error: ++7
./arith2.sub: line 4: syntax error: -- 7
./arith2.sub: line 5: syntax error: ++ 7
./arith1.sub: line 37: arithmetic syntax error
./arith2.sub: line 2: arithmetic syntax error
./arith2.sub: line 3: arithmetic syntax error
./arith2.sub: line 4: arithmetic syntax error
./arith2.sub: line 5: arithmetic syntax error
5 5
1 1
4 4
0 0
./arith2.sub: line 42: syntax error: -- - 7
./arith2.sub: line 47: syntax error: ++ + 7
./arith2.sub: line 42: arithmetic syntax error
./arith2.sub: line 47: arithmetic syntax error
8 12
./arith.tests: line 290: syntax error: a b
./arith.tests: line 290: arithmetic syntax error
42
42
42

View File

@ -4461,7 +4461,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
}
#if ENABLE_SH_MATH_SUPPORT
static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p)
static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
{
arith_state_t math_state;
arith_t res;
@ -4472,8 +4472,11 @@ static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p)
//math_state.endofname = endofname;
exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
res = arith(&math_state, exp_str ? exp_str : arg);
*errcode_p = math_state.errcode;
free(exp_str);
if (errmsg_p)
*errmsg_p = math_state.errmsg;
if (math_state.errmsg)
die_if_script(math_state.errmsg);
return res;
}
#endif
@ -4714,22 +4717,26 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
* var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
*/
arith_t beg, len;
int errcode = 0;
const char *errmsg;
beg = expand_and_evaluate_arith(exp_word, &errcode);
beg = expand_and_evaluate_arith(exp_word, &errmsg);
if (errmsg)
goto arith_err;
debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
*p++ = SPECIAL_VAR_SYMBOL;
exp_word = p;
p = strchr(p, SPECIAL_VAR_SYMBOL);
*p = '\0';
len = expand_and_evaluate_arith(exp_word, &errcode);
len = expand_and_evaluate_arith(exp_word, &errmsg);
if (errmsg)
goto arith_err;
debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
if (len >= 0) { /* bash compat: len < 0 is illegal */
if (beg < 0) /* bash compat */
beg = 0;
debug_printf_varexp("from val:'%s'\n", val);
if (len == 0 || !val || beg >= strlen(val)) {
arith_err:
val = NULL;
} else {
/* Paranoia. What if user entered 9999999999999
@ -4926,28 +4933,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
#if ENABLE_SH_MATH_SUPPORT
case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
arith_t res;
int errcode;
arg++; /* skip '+' */
*p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
res = expand_and_evaluate_arith(arg, &errcode);
if (errcode < 0) {
const char *msg = "error in arithmetic";
switch (errcode) {
case -3:
msg = "exponent less than 0";
break;
case -2:
msg = "divide by 0";
break;
case -5:
msg = "expression recursion loop detected";
break;
}
die_if_script(msg);
}
res = expand_and_evaluate_arith(arg, NULL);
debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
sprintf(arith_buf, arith_t_fmt, res);
val = arith_buf;

View File

@ -61,7 +61,7 @@ check that the unevaluated part of the ternary operator does not do evaluation o
20 20
30 30
check precedence of assignment vs. conditional operator
hush: error in arithmetic
hush: arithmetic syntax error
check precedence of assignment vs. conditional operator
associativity of assignment-operator operator
6 6
@ -70,22 +70,22 @@ octal, hex
263 263
255 255
40 40
hush: error in arithmetic
hush: divide by 0
hush: arithmetic syntax error
hush: divide by zero
hush: can't execute 'let': No such file or directory
hush: error in arithmetic
hush: arithmetic syntax error
hush: can't execute 'let': No such file or directory
abc
def
ghi
hush: error in arithmetic
hush: arithmetic syntax error
16 16
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
9 9
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
9 9
9 9
9 9
@ -106,18 +106,18 @@ hush: error in arithmetic
3 3
4 4
4 4
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
4 4
7 7
-7 -7
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
6 6
3 3
7 7
@ -128,19 +128,19 @@ hush: error in arithmetic
2 2
-2 -2
1 1
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
hush: arithmetic syntax error
5 5
1 1
4 4
0 0
hush: error in arithmetic
hush: error in arithmetic
hush: arithmetic syntax error
hush: arithmetic syntax error
8 12
hush: error in arithmetic
hush: arithmetic syntax error
42
42
42

View File

@ -26,26 +26,26 @@
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* This is my infix parser/evaluator. It is optimized for size, intended
* as a replacement for yacc-based parsers. However, it may well be faster
@ -60,9 +60,6 @@
* this is based (this code differs in that it applies operators immediately
* to the stack instead of adding them to a queue to end up with an
* expression).
*
* To use the routine, call it with an expression string and error return
* pointer
*/
/*
@ -250,7 +247,7 @@ typedef struct remembered_name {
static arith_t FAST_FUNC
evaluate_string(arith_state_t *math_state, const char *expr);
static int
static const char*
arith_lookup_val(arith_state_t *math_state, v_n_t *t)
{
if (t->var) {
@ -264,8 +261,8 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
*/
for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
if (strcmp(cur->var, t->var) == 0) {
/* Yes. Expression recursion loop detected */
return -5;
/* Yes */
return "expression recursion loop detected";
}
}
@ -281,7 +278,7 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
/* pop current var name */
math_state->list_of_recursed_names = cur;
return math_state->errcode;
return math_state->errmsg;
}
/* treat undefined var as 0 */
t->val = 0;
@ -292,14 +289,14 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
/* "Applying" a token means performing it on the top elements on the integer
* stack. For an unary operator it will only change the top element, but a
* binary operator will pop two arguments and push the result */
static NOINLINE int
static NOINLINE const char*
arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr)
{
#define NUMPTR (*numstackptr)
v_n_t *numptr_m1;
arith_t numptr_val, rez;
int err;
const char *err;
/* There is no operator that can work without arguments */
if (NUMPTR == numstack)
@ -399,13 +396,13 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num
} else if (op == TOK_EXPONENT) {
arith_t c;
if (numptr_val < 0)
return -3; /* exponent less than 0 */
return "exponent less than 0";
c = 1;
while (--numptr_val >= 0)
c *= rez;
rez = c;
} else if (numptr_val==0) /* zero divisor check */
return -2;
} else if (numptr_val == 0)
return "divide by zero";
else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
rez /= numptr_val;
else if (op == TOK_REM || op == TOK_REM_ASSIGN)
@ -430,9 +427,9 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num
numptr_m1->val = rez;
/* erase var name, it is just a number now */
numptr_m1->var = NULL;
return 0;
return NULL;
err:
return -1;
return "arithmetic syntax error";
#undef NUMPTR
}
@ -498,7 +495,7 @@ static arith_t FAST_FUNC
evaluate_string(arith_state_t *math_state, const char *expr)
{
operator lasttok;
int errcode;
const char *errmsg;
const char *start_expr = expr = skip_whitespace(expr);
unsigned expr_len = strlen(expr) + 2;
/* Stack of integers */
@ -512,7 +509,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
operator *stackptr = stack;
*stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
errcode = 0;
errmsg = NULL;
while (1) {
const char *p;
@ -548,7 +545,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
}
if (numstack->var) {
/* expression is $((var)) only, lookup now */
errcode = arith_lookup_val(math_state, numstack);
errmsg = arith_lookup_val(math_state, numstack);
}
goto ret;
}
@ -663,8 +660,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
break;
}
}
errcode = arith_apply(math_state, prev_op, numstack, &numstackptr);
if (errcode)
errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
if (errmsg)
goto ret;
}
if (op == TOK_RPAREN) {
@ -678,15 +675,17 @@ evaluate_string(arith_state_t *math_state, const char *expr)
} /* while (1) */
err:
numstack->val = errcode = -1;
numstack->val = -1;
errmsg = "arithmetic syntax error";
ret:
math_state->errcode = errcode;
math_state->errmsg = errmsg;
return numstack->val;
}
arith_t FAST_FUNC
arith(arith_state_t *math_state, const char *expr)
{
math_state->errmsg = NULL;
math_state->list_of_recursed_names = NULL;
return evaluate_string(math_state, expr);
}

View File

@ -95,7 +95,7 @@ typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *v
//typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name);
typedef struct arith_state_t {
int errcode;
const char *errmsg;
arith_var_lookup_t lookupvar;
arith_var_set_t setvar;
// arith_var_endofname_t endofname;