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) static arith_t ash_arith(const char *s) { - arith_eval_hooks_t math_hooks; + arith_state_t math_state; arith_t result; - int errcode = 0; - math_hooks.lookupvar = lookupvar; - math_hooks.setvar = setvar2; - //math_hooks.endofname = endofname; + math_state.lookupvar = lookupvar; + math_state.setvar = setvar2; + //math_state.endofname = endofname; INT_OFF; - result = arith(s, &errcode, &math_hooks); - if (errcode < 0) { - if (errcode == -3) + 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 (errcode == -2) + if (math_state.errcode == -2) ash_msg_and_raise_error("divide by zero"); - if (errcode == -5) + if (math_state.errcode == -5) ash_msg_and_raise_error("expression recursion loop detected"); raise_error_syntax(s); } 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 #if ENABLE_SH_MATH_SUPPORT static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) { - arith_eval_hooks_t hooks; + arith_state_t math_state; arith_t res; char *exp_str; - hooks.lookupvar = get_local_var_value; - hooks.setvar = set_local_var_from_halves; - //hooks.endofname = endofname; + math_state.lookupvar = get_local_var_value; + math_state.setvar = set_local_var_from_halves; + //math_state.endofname = endofname; exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); - res = arith(exp_str ? exp_str : arg, errcode_p, &hooks); + res = arith(&math_state, exp_str ? exp_str : arg); + *errcode_p = math_state.errcode; free(exp_str); return res; } 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 @@ #include "libbb.h" #include "math.h" -#define a_e_h_t arith_eval_hooks_t -#define lookupvar (math_hooks->lookupvar) -#define setvar (math_hooks->setvar ) -//#define endofname (math_hooks->endofname) +#define lookupvar (math_state->lookupvar) +#define setvar (math_state->setvar ) +//#define endofname (math_state->endofname) typedef unsigned char operator; @@ -249,13 +248,12 @@ typedef struct chk_var_recursive_looped_t { static chk_var_recursive_looped_t *prev_chk_var_recursive; static int -arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) +arith_lookup_val(arith_state_t *math_state, v_n_t *t) { if (t->var) { const char *p = lookupvar(t->var); if (p) { - int errcode; chk_var_recursive_looped_t *cur; chk_var_recursive_looped_t cur_save; @@ -273,10 +271,10 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) cur_save.next = cur; prev_chk_var_recursive = &cur_save; - t->val = arith(p, &errcode, math_hooks); + t->val = arith(math_state, p); /* restore previous ptr after recursion */ prev_chk_var_recursive = cur; - return errcode; + return math_state->errcode; } /* allow undefined var as 0 */ t->val = 0; @@ -288,13 +286,13 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) * 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 -arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks) +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 ret_arith_lookup_val; + int err; /* There is no operator that can work without arguments */ 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 numptr_m1 = NUMPTR - 1; /* Check operand is var with noninteger value */ - ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); - if (ret_arith_lookup_val) - return ret_arith_lookup_val; + err = arith_lookup_val(math_state, numptr_m1); + if (err) + return err; rez = numptr_m1->val; 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 numptr_m1 = NUMPTR - 1; if (op != TOK_ASSIGN) { /* check operand is var with noninteger value for not '=' */ - ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); - if (ret_arith_lookup_val) - return ret_arith_lookup_val; + err = arith_lookup_val(math_state, numptr_m1); + if (err) + return err; } if (op == TOK_CONDITIONAL) { numptr_m1->contidional_second_val = rez; @@ -490,7 +488,7 @@ endofname(const char *name) } arith_t -arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) +arith(arith_state_t *math_state, const char *expr) { operator lasttok; int errcode; @@ -543,7 +541,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) } if (numstack->var) { /* expression is $((var)) only, lookup now */ - errcode = arith_lookup_val(numstack, math_hooks); + errcode = arith_lookup_val(math_state, numstack); } goto ret; } @@ -658,7 +656,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) break; } } - errcode = arith_apply(prev_op, numstack, &numstackptr, math_hooks); + errcode = arith_apply(math_state, prev_op, numstack, &numstackptr); if (errcode) goto ret; } @@ -675,7 +673,7 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) err: numstack->val = errcode = -1; ret: - *perrcode = errcode; + math_state->errcode = errcode; return numstack->val; } 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 @@ /* The math library has just one function: * - * arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t *hooks); + * arith_t arith(arith_state_t *states, const char *expr); * - * The first argument is the math string to parse. All normal expansions must - * be done already. i.e. no dollar symbols should be present. + * The expr argument is the math string to parse. All normal expansions must + * be done already. i.e. no dollar symbols should be present. * - * The second argument is a semi-detailed error description in case something - * goes wrong in the parsing steps. Currently, those values are (for - * compatibility, you should assume all negative values are errors): - * 0 - no errors (yay!) - * -1 - unspecified problem - * -2 - divide by zero - * -3 - exponent less than 0 - * -5 - expression recursion loop detected + * The state argument is a pointer to a struct of hooks for your shell (see below), + * and a semi-detailed error code. Currently, those values are (for + * compatibility, you should assume all negative values are errors): + * 0 - no errors (yay!) + * -1 - unspecified problem + * -2 - divide by zero + * -3 - exponent less than 0 + * -5 - expression recursion loop detected * - * The third argument is a struct pointer of hooks for your shell (see below). - * - * The function returns the answer to the expression. So if you called it - * with the expression: - * "1 + 2 + 3" - * You would obviously get back 6. + * The function returns the answer to the expression. So if you called it + * with the expression: + * "1 + 2 + 3" + * you would obviously get back 6. */ /* To add support to a shell, you need to implement three functions: * - * lookupvar() - look up and return the value of a variable + * lookupvar() - look up and return the value of a variable * - * If the shell does: - * foo=123 - * Then the code: - * const char *val = lookupvar("foo"); - * Will result in val pointing to "123" + * If the shell does: + * foo=123 + * Then the code: + * const char *val = lookupvar("foo"); + * will result in val pointing to "123" * - * setvar() - set a variable to some value + * setvar() - set a variable to some value * - * If the arithmetic expansion does something like: - * $(( i = 1)) - * Then the math code will make a call like so: - * setvar("i", "1", 0); - * The storage for the first two parameters are not allocated, so your - * shell implementation will most likely need to strdup() them to save. + * If the arithmetic expansion does something like: + * $(( i = 1)) + * then the math code will make a call like so: + * setvar("i", "1", 0); + * The storage for the first two parameters are not allocated, so your + * shell implementation will most likely need to strdup() them to save. * - * endofname() - return the end of a variable name from input + * endofname() - return the end of a variable name from input * - * The arithmetic code does not know about variable naming conventions. - * So when it is given an experession, it knows something is not numeric, - * but it is up to the shell to dictate what is a valid identifiers. - * So when it encounters something like: - * $(( some_var + 123 )) - * It will make a call like so: - * end = endofname("some_var + 123"); - * So the shell needs to scan the input string and return a pointer to the - * first non-identifier string. In this case, it should return the input - * pointer with an offset pointing to the first space. The typical - * implementation will return the offset of first char that does not match - * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* + * The arithmetic code does not know about variable naming conventions. + * So when it is given an experession, it knows something is not numeric, + * but it is up to the shell to dictate what is a valid identifiers. + * So when it encounters something like: + * $(( some_var + 123 )) + * It will make a call like so: + * end = endofname("some_var + 123"); + * So the shell needs to scan the input string and return a pointer to the + * first non-identifier string. In this case, it should return the input + * pointer with an offset pointing to the first space. The typical + * implementation will return the offset of first char that does not match + * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* */ /* 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); typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); //typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); -typedef struct arith_eval_hooks { +typedef struct arith_state_t { arith_var_lookup_t lookupvar; arith_var_set_t setvar; // arith_var_endofname_t endofname; -} arith_eval_hooks_t; + int errcode; +} arith_state_t; -arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t*); +arith_t arith(arith_state_t *state, const char *expr); POP_SAVED_FUNCTION_VISIBILITY