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 | |
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>
-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 | ||