diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-15 13:33:02 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-15 13:33:02 +0200 |
commit | 063847d6bd23e184c409f37645ba90fa4d039ada (patch) | |
tree | 63e360e3e0a2f46d187ef2e21487753a52697efa /shell/math.c | |
parent | 197a6b3c14a8be7101903118516e0e16ec843eb5 (diff) | |
download | busybox-w32-063847d6bd23e184c409f37645ba90fa4d039ada.tar.gz busybox-w32-063847d6bd23e184c409f37645ba90fa4d039ada.tar.bz2 busybox-w32-063847d6bd23e184c409f37645ba90fa4d039ada.zip |
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>
Diffstat (limited to 'shell/math.c')
-rw-r--r-- | shell/math.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/shell/math.c b/shell/math.c index 839715776..871c06c3e 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -26,26 +26,26 @@ | |||
26 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 26 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
27 | */ | 27 | */ |
28 | /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | 28 | /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> |
29 | 29 | * | |
30 | Permission is hereby granted, free of charge, to any person obtaining | 30 | * Permission is hereby granted, free of charge, to any person obtaining |
31 | a copy of this software and associated documentation files (the | 31 | * a copy of this software and associated documentation files (the |
32 | "Software"), to deal in the Software without restriction, including | 32 | * "Software"), to deal in the Software without restriction, including |
33 | without limitation the rights to use, copy, modify, merge, publish, | 33 | * without limitation the rights to use, copy, modify, merge, publish, |
34 | distribute, sublicense, and/or sell copies of the Software, and to | 34 | * distribute, sublicense, and/or sell copies of the Software, and to |
35 | permit persons to whom the Software is furnished to do so, subject to | 35 | * permit persons to whom the Software is furnished to do so, subject to |
36 | the following conditions: | 36 | * the following conditions: |
37 | 37 | * | |
38 | The above copyright notice and this permission notice shall be | 38 | * The above copyright notice and this permission notice shall be |
39 | included in all copies or substantial portions of the Software. | 39 | * included in all copies or substantial portions of the Software. |
40 | 40 | * | |
41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 41 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
42 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 42 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
43 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | 43 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
44 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | 44 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
45 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | 45 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
46 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | 46 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 47 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | /* This is my infix parser/evaluator. It is optimized for size, intended | 50 | /* This is my infix parser/evaluator. It is optimized for size, intended |
51 | * as a replacement for yacc-based parsers. However, it may well be faster | 51 | * as a replacement for yacc-based parsers. However, it may well be faster |
@@ -60,9 +60,6 @@ | |||
60 | * this is based (this code differs in that it applies operators immediately | 60 | * this is based (this code differs in that it applies operators immediately |
61 | * to the stack instead of adding them to a queue to end up with an | 61 | * to the stack instead of adding them to a queue to end up with an |
62 | * expression). | 62 | * expression). |
63 | * | ||
64 | * To use the routine, call it with an expression string and error return | ||
65 | * pointer | ||
66 | */ | 63 | */ |
67 | 64 | ||
68 | /* | 65 | /* |
@@ -250,7 +247,7 @@ typedef struct remembered_name { | |||
250 | static arith_t FAST_FUNC | 247 | static arith_t FAST_FUNC |
251 | evaluate_string(arith_state_t *math_state, const char *expr); | 248 | evaluate_string(arith_state_t *math_state, const char *expr); |
252 | 249 | ||
253 | static int | 250 | static const char* |
254 | arith_lookup_val(arith_state_t *math_state, v_n_t *t) | 251 | arith_lookup_val(arith_state_t *math_state, v_n_t *t) |
255 | { | 252 | { |
256 | if (t->var) { | 253 | if (t->var) { |
@@ -264,8 +261,8 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t) | |||
264 | */ | 261 | */ |
265 | for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { | 262 | for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { |
266 | if (strcmp(cur->var, t->var) == 0) { | 263 | if (strcmp(cur->var, t->var) == 0) { |
267 | /* Yes. Expression recursion loop detected */ | 264 | /* Yes */ |
268 | return -5; | 265 | return "expression recursion loop detected"; |
269 | } | 266 | } |
270 | } | 267 | } |
271 | 268 | ||
@@ -281,7 +278,7 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t) | |||
281 | /* pop current var name */ | 278 | /* pop current var name */ |
282 | math_state->list_of_recursed_names = cur; | 279 | math_state->list_of_recursed_names = cur; |
283 | 280 | ||
284 | return math_state->errcode; | 281 | return math_state->errmsg; |
285 | } | 282 | } |
286 | /* treat undefined var as 0 */ | 283 | /* treat undefined var as 0 */ |
287 | t->val = 0; | 284 | t->val = 0; |
@@ -292,14 +289,14 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t) | |||
292 | /* "Applying" a token means performing it on the top elements on the integer | 289 | /* "Applying" a token means performing it on the top elements on the integer |
293 | * stack. For an unary operator it will only change the top element, but a | 290 | * stack. For an unary operator it will only change the top element, but a |
294 | * binary operator will pop two arguments and push the result */ | 291 | * binary operator will pop two arguments and push the result */ |
295 | static NOINLINE int | 292 | static NOINLINE const char* |
296 | arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr) | 293 | arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr) |
297 | { | 294 | { |
298 | #define NUMPTR (*numstackptr) | 295 | #define NUMPTR (*numstackptr) |
299 | 296 | ||
300 | v_n_t *numptr_m1; | 297 | v_n_t *numptr_m1; |
301 | arith_t numptr_val, rez; | 298 | arith_t numptr_val, rez; |
302 | int err; | 299 | const char *err; |
303 | 300 | ||
304 | /* There is no operator that can work without arguments */ | 301 | /* There is no operator that can work without arguments */ |
305 | if (NUMPTR == numstack) | 302 | if (NUMPTR == numstack) |
@@ -399,13 +396,13 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num | |||
399 | } else if (op == TOK_EXPONENT) { | 396 | } else if (op == TOK_EXPONENT) { |
400 | arith_t c; | 397 | arith_t c; |
401 | if (numptr_val < 0) | 398 | if (numptr_val < 0) |
402 | return -3; /* exponent less than 0 */ | 399 | return "exponent less than 0"; |
403 | c = 1; | 400 | c = 1; |
404 | while (--numptr_val >= 0) | 401 | while (--numptr_val >= 0) |
405 | c *= rez; | 402 | c *= rez; |
406 | rez = c; | 403 | rez = c; |
407 | } else if (numptr_val==0) /* zero divisor check */ | 404 | } else if (numptr_val == 0) |
408 | return -2; | 405 | return "divide by zero"; |
409 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | 406 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) |
410 | rez /= numptr_val; | 407 | rez /= numptr_val; |
411 | else if (op == TOK_REM || op == TOK_REM_ASSIGN) | 408 | 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 | |||
430 | numptr_m1->val = rez; | 427 | numptr_m1->val = rez; |
431 | /* erase var name, it is just a number now */ | 428 | /* erase var name, it is just a number now */ |
432 | numptr_m1->var = NULL; | 429 | numptr_m1->var = NULL; |
433 | return 0; | 430 | return NULL; |
434 | err: | 431 | err: |
435 | return -1; | 432 | return "arithmetic syntax error"; |
436 | #undef NUMPTR | 433 | #undef NUMPTR |
437 | } | 434 | } |
438 | 435 | ||
@@ -498,7 +495,7 @@ static arith_t FAST_FUNC | |||
498 | evaluate_string(arith_state_t *math_state, const char *expr) | 495 | evaluate_string(arith_state_t *math_state, const char *expr) |
499 | { | 496 | { |
500 | operator lasttok; | 497 | operator lasttok; |
501 | int errcode; | 498 | const char *errmsg; |
502 | const char *start_expr = expr = skip_whitespace(expr); | 499 | const char *start_expr = expr = skip_whitespace(expr); |
503 | unsigned expr_len = strlen(expr) + 2; | 500 | unsigned expr_len = strlen(expr) + 2; |
504 | /* Stack of integers */ | 501 | /* Stack of integers */ |
@@ -512,7 +509,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
512 | operator *stackptr = stack; | 509 | operator *stackptr = stack; |
513 | 510 | ||
514 | *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ | 511 | *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ |
515 | errcode = 0; | 512 | errmsg = NULL; |
516 | 513 | ||
517 | while (1) { | 514 | while (1) { |
518 | const char *p; | 515 | const char *p; |
@@ -548,7 +545,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
548 | } | 545 | } |
549 | if (numstack->var) { | 546 | if (numstack->var) { |
550 | /* expression is $((var)) only, lookup now */ | 547 | /* expression is $((var)) only, lookup now */ |
551 | errcode = arith_lookup_val(math_state, numstack); | 548 | errmsg = arith_lookup_val(math_state, numstack); |
552 | } | 549 | } |
553 | goto ret; | 550 | goto ret; |
554 | } | 551 | } |
@@ -663,8 +660,8 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
663 | break; | 660 | break; |
664 | } | 661 | } |
665 | } | 662 | } |
666 | errcode = arith_apply(math_state, prev_op, numstack, &numstackptr); | 663 | errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); |
667 | if (errcode) | 664 | if (errmsg) |
668 | goto ret; | 665 | goto ret; |
669 | } | 666 | } |
670 | if (op == TOK_RPAREN) { | 667 | if (op == TOK_RPAREN) { |
@@ -678,15 +675,17 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
678 | } /* while (1) */ | 675 | } /* while (1) */ |
679 | 676 | ||
680 | err: | 677 | err: |
681 | numstack->val = errcode = -1; | 678 | numstack->val = -1; |
679 | errmsg = "arithmetic syntax error"; | ||
682 | ret: | 680 | ret: |
683 | math_state->errcode = errcode; | 681 | math_state->errmsg = errmsg; |
684 | return numstack->val; | 682 | return numstack->val; |
685 | } | 683 | } |
686 | 684 | ||
687 | arith_t FAST_FUNC | 685 | arith_t FAST_FUNC |
688 | arith(arith_state_t *math_state, const char *expr) | 686 | arith(arith_state_t *math_state, const char *expr) |
689 | { | 687 | { |
688 | math_state->errmsg = NULL; | ||
690 | math_state->list_of_recursed_names = NULL; | 689 | math_state->list_of_recursed_names = NULL; |
691 | return evaluate_string(math_state, expr); | 690 | return evaluate_string(math_state, expr); |
692 | } | 691 | } |