diff options
-rw-r--r-- | shell/math.c | 54 | ||||
-rw-r--r-- | shell/math.h | 5 |
2 files changed, 37 insertions, 22 deletions
diff --git a/shell/math.c b/shell/math.c index 555559a26..839715776 100644 --- a/shell/math.c +++ b/shell/math.c @@ -232,6 +232,7 @@ is_right_associative(operator prec) || prec == PREC(TOK_CONDITIONAL)); } + typedef struct { arith_t val; arith_t contidional_second_val; @@ -240,43 +241,49 @@ typedef struct { else is variable name */ } v_n_t; -typedef struct chk_var_recursive_looped_t { +typedef struct remembered_name { + struct remembered_name *next; const char *var; - struct chk_var_recursive_looped_t *next; -} chk_var_recursive_looped_t; +} remembered_name; + -static chk_var_recursive_looped_t *prev_chk_var_recursive; +static arith_t FAST_FUNC +evaluate_string(arith_state_t *math_state, const char *expr); static int arith_lookup_val(arith_state_t *math_state, v_n_t *t) { if (t->var) { const char *p = lookupvar(t->var); - if (p) { - chk_var_recursive_looped_t *cur; - chk_var_recursive_looped_t cur_save; + remembered_name *cur; + remembered_name cur_save; - /* recursively try p as expression */ - - for (cur = prev_chk_var_recursive; cur; cur = cur->next) { + /* did we already see this name? + * testcase: a=b; b=a; echo $((a)) + */ + for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { if (strcmp(cur->var, t->var) == 0) { - /* expression recursion loop detected */ + /* Yes. Expression recursion loop detected */ return -5; } } - /* save current var name */ - cur = prev_chk_var_recursive; + + /* push current var name */ + cur = math_state->list_of_recursed_names; cur_save.var = t->var; cur_save.next = cur; - prev_chk_var_recursive = &cur_save; + math_state->list_of_recursed_names = &cur_save; + + /* recursively evaluate p as expression */ + t->val = evaluate_string(math_state, p); + + /* pop current var name */ + math_state->list_of_recursed_names = cur; - t->val = arith(math_state, p); - /* restore previous ptr after recursion */ - prev_chk_var_recursive = cur; return math_state->errcode; } - /* allow undefined var as 0 */ + /* treat undefined var as 0 */ t->val = 0; } return 0; @@ -487,8 +494,8 @@ endofname(const char *name) return name; } -arith_t -arith(arith_state_t *math_state, const char *expr) +static arith_t FAST_FUNC +evaluate_string(arith_state_t *math_state, const char *expr) { operator lasttok; int errcode; @@ -677,6 +684,13 @@ arith(arith_state_t *math_state, const char *expr) return numstack->val; } +arith_t FAST_FUNC +arith(arith_state_t *math_state, const char *expr) +{ + math_state->list_of_recursed_names = NULL; + return evaluate_string(math_state, expr); +} + /* * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. diff --git a/shell/math.h b/shell/math.h index 9f3da7f59..e34b65d5d 100644 --- a/shell/math.h +++ b/shell/math.h @@ -95,13 +95,14 @@ 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; arith_var_lookup_t lookupvar; arith_var_set_t setvar; // arith_var_endofname_t endofname; - int errcode; + void *list_of_recursed_names; } arith_state_t; -arith_t arith(arith_state_t *state, const char *expr); +arith_t FAST_FUNC arith(arith_state_t *state, const char *expr); POP_SAVED_FUNCTION_VISIBILITY |