diff options
| author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 12:49:03 +0200 |
|---|---|---|
| committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 12:49:03 +0200 |
| commit | 06d44d7dfb709bfe02e74d187cceb8591bbda3b4 (patch) | |
| tree | 9a2a8e8381cecae29a5c02ed10995d0a0ad9d412 /shell | |
| parent | bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3 (diff) | |
| download | busybox-w32-06d44d7dfb709bfe02e74d187cceb8591bbda3b4.tar.gz busybox-w32-06d44d7dfb709bfe02e74d187cceb8591bbda3b4.tar.bz2 busybox-w32-06d44d7dfb709bfe02e74d187cceb8591bbda3b4.zip | |
shell/math.c: rename arith_eval_hooks to arith_state, put error code into it
function old new delta
expand_and_evaluate_arith 79 89 +10
arith 675 674 -1
arith_lookup_val 151 142 -9
ash_arith 135 122 -13
arith_apply 1304 1269 -35
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/4 up/down: 10/-58) Total: -48 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 19 | ||||
| -rw-r--r-- | shell/hush.c | 11 | ||||
| -rw-r--r-- | shell/math.c | 38 | ||||
| -rw-r--r-- | shell/math.h | 91 |
4 files changed, 78 insertions, 81 deletions
diff --git a/shell/ash.c b/shell/ash.c index f631e3d25..c27ab7de2 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -5442,22 +5442,21 @@ redirectsafe(union node *redir, int flags) | |||
| 5442 | static arith_t | 5442 | static arith_t |
| 5443 | ash_arith(const char *s) | 5443 | ash_arith(const char *s) |
| 5444 | { | 5444 | { |
| 5445 | arith_eval_hooks_t math_hooks; | 5445 | arith_state_t math_state; |
| 5446 | arith_t result; | 5446 | arith_t result; |
| 5447 | int errcode = 0; | ||
| 5448 | 5447 | ||
| 5449 | math_hooks.lookupvar = lookupvar; | 5448 | math_state.lookupvar = lookupvar; |
| 5450 | math_hooks.setvar = setvar2; | 5449 | math_state.setvar = setvar2; |
| 5451 | //math_hooks.endofname = endofname; | 5450 | //math_state.endofname = endofname; |
| 5452 | 5451 | ||
| 5453 | INT_OFF; | 5452 | INT_OFF; |
| 5454 | result = arith(s, &errcode, &math_hooks); | 5453 | result = arith(&math_state, s); |
| 5455 | if (errcode < 0) { | 5454 | if (math_state.errcode < 0) { |
| 5456 | if (errcode == -3) | 5455 | if (math_state.errcode == -3) |
| 5457 | ash_msg_and_raise_error("exponent less than 0"); | 5456 | ash_msg_and_raise_error("exponent less than 0"); |
| 5458 | if (errcode == -2) | 5457 | if (math_state.errcode == -2) |
| 5459 | ash_msg_and_raise_error("divide by zero"); | 5458 | ash_msg_and_raise_error("divide by zero"); |
| 5460 | if (errcode == -5) | 5459 | if (math_state.errcode == -5) |
| 5461 | ash_msg_and_raise_error("expression recursion loop detected"); | 5460 | ash_msg_and_raise_error("expression recursion loop detected"); |
| 5462 | raise_error_syntax(s); | 5461 | raise_error_syntax(s); |
| 5463 | } | 5462 | } |
diff --git a/shell/hush.c b/shell/hush.c index ef0c454ec..4ca5403de 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -4463,15 +4463,16 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int | |||
| 4463 | #if ENABLE_SH_MATH_SUPPORT | 4463 | #if ENABLE_SH_MATH_SUPPORT |
| 4464 | static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) | 4464 | static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) |
| 4465 | { | 4465 | { |
| 4466 | arith_eval_hooks_t hooks; | 4466 | arith_state_t math_state; |
| 4467 | arith_t res; | 4467 | arith_t res; |
| 4468 | char *exp_str; | 4468 | char *exp_str; |
| 4469 | 4469 | ||
| 4470 | hooks.lookupvar = get_local_var_value; | 4470 | math_state.lookupvar = get_local_var_value; |
| 4471 | hooks.setvar = set_local_var_from_halves; | 4471 | math_state.setvar = set_local_var_from_halves; |
| 4472 | //hooks.endofname = endofname; | 4472 | //math_state.endofname = endofname; |
| 4473 | exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); | 4473 | exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); |
| 4474 | res = arith(exp_str ? exp_str : arg, errcode_p, &hooks); | 4474 | res = arith(&math_state, exp_str ? exp_str : arg); |
| 4475 | *errcode_p = math_state.errcode; | ||
| 4475 | free(exp_str); | 4476 | free(exp_str); |
| 4476 | return res; | 4477 | return res; |
| 4477 | } | 4478 | } |
diff --git a/shell/math.c b/shell/math.c index a9fbc8910..555559a26 100644 --- a/shell/math.c +++ b/shell/math.c | |||
| @@ -119,10 +119,9 @@ | |||
| 119 | #include "libbb.h" | 119 | #include "libbb.h" |
| 120 | #include "math.h" | 120 | #include "math.h" |
| 121 | 121 | ||
| 122 | #define a_e_h_t arith_eval_hooks_t | 122 | #define lookupvar (math_state->lookupvar) |
| 123 | #define lookupvar (math_hooks->lookupvar) | 123 | #define setvar (math_state->setvar ) |
| 124 | #define setvar (math_hooks->setvar ) | 124 | //#define endofname (math_state->endofname) |
| 125 | //#define endofname (math_hooks->endofname) | ||
| 126 | 125 | ||
| 127 | typedef unsigned char operator; | 126 | typedef unsigned char operator; |
| 128 | 127 | ||
| @@ -249,13 +248,12 @@ typedef struct chk_var_recursive_looped_t { | |||
| 249 | static chk_var_recursive_looped_t *prev_chk_var_recursive; | 248 | static chk_var_recursive_looped_t *prev_chk_var_recursive; |
| 250 | 249 | ||
| 251 | static int | 250 | static int |
| 252 | arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) | 251 | arith_lookup_val(arith_state_t *math_state, v_n_t *t) |
| 253 | { | 252 | { |
| 254 | if (t->var) { | 253 | if (t->var) { |
| 255 | const char *p = lookupvar(t->var); | 254 | const char *p = lookupvar(t->var); |
| 256 | 255 | ||
| 257 | if (p) { | 256 | if (p) { |
| 258 | int errcode; | ||
| 259 | chk_var_recursive_looped_t *cur; | 257 | chk_var_recursive_looped_t *cur; |
| 260 | chk_var_recursive_looped_t cur_save; | 258 | chk_var_recursive_looped_t cur_save; |
| 261 | 259 | ||
| @@ -273,10 +271,10 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) | |||
| 273 | cur_save.next = cur; | 271 | cur_save.next = cur; |
| 274 | prev_chk_var_recursive = &cur_save; | 272 | prev_chk_var_recursive = &cur_save; |
| 275 | 273 | ||
| 276 | t->val = arith(p, &errcode, math_hooks); | 274 | t->val = arith(math_state, p); |
| 277 | /* restore previous ptr after recursion */ | 275 | /* restore previous ptr after recursion */ |
| 278 | prev_chk_var_recursive = cur; | 276 | prev_chk_var_recursive = cur; |
| 279 | return errcode; | 277 | return math_state->errcode; |
| 280 | } | 278 | } |
| 281 | /* allow undefined var as 0 */ | 279 | /* allow undefined var as 0 */ |
| 282 | t->val = 0; | 280 | t->val = 0; |
| @@ -288,13 +286,13 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) | |||
| 288 | * stack. For an unary operator it will only change the top element, but a | 286 | * stack. For an unary operator it will only change the top element, but a |
| 289 | * binary operator will pop two arguments and push the result */ | 287 | * binary operator will pop two arguments and push the result */ |
| 290 | static NOINLINE int | 288 | static NOINLINE int |
| 291 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks) | 289 | arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr) |
| 292 | { | 290 | { |
| 293 | #define NUMPTR (*numstackptr) | 291 | #define NUMPTR (*numstackptr) |
| 294 | 292 | ||
| 295 | v_n_t *numptr_m1; | 293 | v_n_t *numptr_m1; |
| 296 | arith_t numptr_val, rez; | 294 | arith_t numptr_val, rez; |
| 297 | int ret_arith_lookup_val; | 295 | int err; |
| 298 | 296 | ||
| 299 | /* There is no operator that can work without arguments */ | 297 | /* There is no operator that can work without arguments */ |
| 300 | if (NUMPTR == numstack) | 298 | if (NUMPTR == numstack) |
| @@ -302,9 +300,9 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo | |||
| 302 | numptr_m1 = NUMPTR - 1; | 300 | numptr_m1 = NUMPTR - 1; |
| 303 | 301 | ||
| 304 | /* Check operand is var with noninteger value */ | 302 | /* Check operand is var with noninteger value */ |
| 305 | ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); | 303 | err = arith_lookup_val(math_state, numptr_m1); |
| 306 | if (ret_arith_lookup_val) | 304 | if (err) |
| 307 | return ret_arith_lookup_val; | 305 | return err; |
| 308 | 306 | ||
| 309 | rez = numptr_m1->val; | 307 | rez = numptr_m1->val; |
| 310 | if (op == TOK_UMINUS) | 308 | if (op == TOK_UMINUS) |
| @@ -339,9 +337,9 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo | |||
| 339 | numptr_m1 = NUMPTR - 1; | 337 | numptr_m1 = NUMPTR - 1; |
| 340 | if (op != TOK_ASSIGN) { | 338 | if (op != TOK_ASSIGN) { |
| 341 | /* check operand is var with noninteger value for not '=' */ | 339 | /* check operand is var with noninteger value for not '=' */ |
| 342 | ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); | 340 | err = arith_lookup_val(math_state, numptr_m1); |
| 343 | if (ret_arith_lookup_val) | 341 | if (err) |
| 344 | return ret_arith_lookup_val; | 342 | return err; |
| 345 | } | 343 | } |
| 346 | if (op == TOK_CONDITIONAL) { | 344 | if (op == TOK_CONDITIONAL) { |
| 347 | numptr_m1->contidional_second_val = rez; | 345 | numptr_m1->contidional_second_val = rez; |
| @@ -490,7 +488,7 @@ endofname(const char *name) | |||
| 490 | } | 488 | } |
| 491 | 489 | ||
| 492 | arith_t | 490 | arith_t |
| 493 | arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | 491 | arith(arith_state_t *math_state, const char *expr) |
| 494 | { | 492 | { |
| 495 | operator lasttok; | 493 | operator lasttok; |
| 496 | int errcode; | 494 | int errcode; |
| @@ -543,7 +541,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
| 543 | } | 541 | } |
| 544 | if (numstack->var) { | 542 | if (numstack->var) { |
| 545 | /* expression is $((var)) only, lookup now */ | 543 | /* expression is $((var)) only, lookup now */ |
| 546 | errcode = arith_lookup_val(numstack, math_hooks); | 544 | errcode = arith_lookup_val(math_state, numstack); |
| 547 | } | 545 | } |
| 548 | goto ret; | 546 | goto ret; |
| 549 | } | 547 | } |
| @@ -658,7 +656,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
| 658 | break; | 656 | break; |
| 659 | } | 657 | } |
| 660 | } | 658 | } |
| 661 | errcode = arith_apply(prev_op, numstack, &numstackptr, math_hooks); | 659 | errcode = arith_apply(math_state, prev_op, numstack, &numstackptr); |
| 662 | if (errcode) | 660 | if (errcode) |
| 663 | goto ret; | 661 | goto ret; |
| 664 | } | 662 | } |
| @@ -675,7 +673,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
| 675 | err: | 673 | err: |
| 676 | numstack->val = errcode = -1; | 674 | numstack->val = errcode = -1; |
| 677 | ret: | 675 | ret: |
| 678 | *perrcode = errcode; | 676 | math_state->errcode = errcode; |
| 679 | return numstack->val; | 677 | return numstack->val; |
| 680 | } | 678 | } |
| 681 | 679 | ||
diff --git a/shell/math.h b/shell/math.h index 96088b4d2..9f3da7f59 100644 --- a/shell/math.h +++ b/shell/math.h | |||
| @@ -9,61 +9,59 @@ | |||
| 9 | 9 | ||
| 10 | /* The math library has just one function: | 10 | /* The math library has just one function: |
| 11 | * | 11 | * |
| 12 | * arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t *hooks); | 12 | * arith_t arith(arith_state_t *states, const char *expr); |
| 13 | * | 13 | * |
| 14 | * The first argument is the math string to parse. All normal expansions must | 14 | * The expr argument is the math string to parse. All normal expansions must |
| 15 | * be done already. i.e. no dollar symbols should be present. | 15 | * be done already. i.e. no dollar symbols should be present. |
| 16 | * | 16 | * |
| 17 | * The second argument is a semi-detailed error description in case something | 17 | * The state argument is a pointer to a struct of hooks for your shell (see below), |
| 18 | * goes wrong in the parsing steps. Currently, those values are (for | 18 | * and a semi-detailed error code. Currently, those values are (for |
| 19 | * compatibility, you should assume all negative values are errors): | 19 | * compatibility, you should assume all negative values are errors): |
| 20 | * 0 - no errors (yay!) | 20 | * 0 - no errors (yay!) |
| 21 | * -1 - unspecified problem | 21 | * -1 - unspecified problem |
| 22 | * -2 - divide by zero | 22 | * -2 - divide by zero |
| 23 | * -3 - exponent less than 0 | 23 | * -3 - exponent less than 0 |
| 24 | * -5 - expression recursion loop detected | 24 | * -5 - expression recursion loop detected |
| 25 | * | 25 | * |
| 26 | * The third argument is a struct pointer of hooks for your shell (see below). | 26 | * The function returns the answer to the expression. So if you called it |
| 27 | * | 27 | * with the expression: |
| 28 | * The function returns the answer to the expression. So if you called it | 28 | * "1 + 2 + 3" |
| 29 | * with the expression: | 29 | * you would obviously get back 6. |
| 30 | * "1 + 2 + 3" | ||
| 31 | * You would obviously get back 6. | ||
| 32 | */ | 30 | */ |
| 33 | 31 | ||
| 34 | /* To add support to a shell, you need to implement three functions: | 32 | /* To add support to a shell, you need to implement three functions: |
| 35 | * | 33 | * |
| 36 | * lookupvar() - look up and return the value of a variable | 34 | * lookupvar() - look up and return the value of a variable |
| 37 | * | 35 | * |
| 38 | * If the shell does: | 36 | * If the shell does: |
| 39 | * foo=123 | 37 | * foo=123 |
| 40 | * Then the code: | 38 | * Then the code: |
| 41 | * const char *val = lookupvar("foo"); | 39 | * const char *val = lookupvar("foo"); |
| 42 | * Will result in val pointing to "123" | 40 | * will result in val pointing to "123" |
| 43 | * | 41 | * |
| 44 | * setvar() - set a variable to some value | 42 | * setvar() - set a variable to some value |
| 45 | * | 43 | * |
| 46 | * If the arithmetic expansion does something like: | 44 | * If the arithmetic expansion does something like: |
| 47 | * $(( i = 1)) | 45 | * $(( i = 1)) |
| 48 | * Then the math code will make a call like so: | 46 | * then the math code will make a call like so: |
| 49 | * setvar("i", "1", 0); | 47 | * setvar("i", "1", 0); |
| 50 | * The storage for the first two parameters are not allocated, so your | 48 | * The storage for the first two parameters are not allocated, so your |
| 51 | * shell implementation will most likely need to strdup() them to save. | 49 | * shell implementation will most likely need to strdup() them to save. |
| 52 | * | 50 | * |
| 53 | * endofname() - return the end of a variable name from input | 51 | * endofname() - return the end of a variable name from input |
| 54 | * | 52 | * |
| 55 | * The arithmetic code does not know about variable naming conventions. | 53 | * The arithmetic code does not know about variable naming conventions. |
| 56 | * So when it is given an experession, it knows something is not numeric, | 54 | * So when it is given an experession, it knows something is not numeric, |
| 57 | * but it is up to the shell to dictate what is a valid identifiers. | 55 | * but it is up to the shell to dictate what is a valid identifiers. |
| 58 | * So when it encounters something like: | 56 | * So when it encounters something like: |
| 59 | * $(( some_var + 123 )) | 57 | * $(( some_var + 123 )) |
| 60 | * It will make a call like so: | 58 | * It will make a call like so: |
| 61 | * end = endofname("some_var + 123"); | 59 | * end = endofname("some_var + 123"); |
| 62 | * So the shell needs to scan the input string and return a pointer to the | 60 | * So the shell needs to scan the input string and return a pointer to the |
| 63 | * first non-identifier string. In this case, it should return the input | 61 | * first non-identifier string. In this case, it should return the input |
| 64 | * pointer with an offset pointing to the first space. The typical | 62 | * pointer with an offset pointing to the first space. The typical |
| 65 | * implementation will return the offset of first char that does not match | 63 | * implementation will return the offset of first char that does not match |
| 66 | * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* | 64 | * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* |
| 67 | */ | 65 | */ |
| 68 | 66 | ||
| 69 | /* To make your life easier when dealing with optional 64bit math support, | 67 | /* To make your life easier when dealing with optional 64bit math support, |
| @@ -96,13 +94,14 @@ typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); | |||
| 96 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); | 94 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); |
| 97 | //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); | 95 | //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); |
| 98 | 96 | ||
| 99 | typedef struct arith_eval_hooks { | 97 | typedef struct arith_state_t { |
| 100 | arith_var_lookup_t lookupvar; | 98 | arith_var_lookup_t lookupvar; |
| 101 | arith_var_set_t setvar; | 99 | arith_var_set_t setvar; |
| 102 | // arith_var_endofname_t endofname; | 100 | // arith_var_endofname_t endofname; |
| 103 | } arith_eval_hooks_t; | 101 | int errcode; |
| 102 | } arith_state_t; | ||
| 104 | 103 | ||
| 105 | arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t*); | 104 | arith_t arith(arith_state_t *state, const char *expr); |
| 106 | 105 | ||
| 107 | POP_SAVED_FUNCTION_VISIBILITY | 106 | POP_SAVED_FUNCTION_VISIBILITY |
| 108 | 107 | ||
