summaryrefslogtreecommitdiff
path: root/shell/math.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/math.c')
-rw-r--r--shell/math.c85
1 files changed, 63 insertions, 22 deletions
diff --git a/shell/math.c b/shell/math.c
index a398bcb..b1aabef 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -356,6 +356,11 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
NUMPTR = top_of_stack; /* this decrements NUMPTR */
top_of_stack--; /* now points to left side */
+ if (math_state->evaluation_disabled) {
+ dbg("binary op %02x skipped", op);
+ goto ret_NULL;
+ }
+
right_side_val = rez;
rez = top_of_stack->val;
if (op == TOK_BOR || op == TOK_OR_ASSIGN)
@@ -428,6 +433,11 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
}
}
+ if (math_state->evaluation_disabled) {
+ dbg("unary op %02x skipped", op);
+ goto ret_NULL;
+ }
+
if (is_assign_op(op)) {
char buf[sizeof(arith_t)*3 + 2];
@@ -446,6 +456,7 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
}
top_of_stack->val = rez;
+ ret_NULL:
/* Erase var name, it is just a number now */
top_of_stack->var_name = NULL;
return NULL;
@@ -594,8 +605,10 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
static arith_t
evaluate_string(arith_state_t *math_state, const char *expr)
{
+#define EVAL_DISABLED ((unsigned long long)math_state->evaluation_disabled)
+#define TOP_BIT_ULL ((unsigned long long)LLONG_MAX + 1)
operator lasttok;
- const char *errmsg;
+ const char *errmsg = NULL;
const char *start_expr = expr = skip_whitespace(expr);
unsigned expr_len = strlen(expr) + 2;
/* Stack of integers/names */
@@ -614,7 +627,6 @@ evaluate_string(arith_state_t *math_state, const char *expr)
/* Start with a left paren */
dbg("(%d) op:TOK_LPAREN", (int)(opstackptr - opstack));
*opstackptr++ = lasttok = TOK_LPAREN;
- errmsg = NULL;
while (1) {
const char *p;
@@ -653,19 +665,26 @@ evaluate_string(arith_state_t *math_state, const char *expr)
p = endofname(expr);
if (p != expr) {
/* Name */
- size_t var_name_size = (p - expr) + 1; /* +1 for NUL */
- numstackptr->var_name = alloca(var_name_size);
- safe_strncpy(numstackptr->var_name, expr, var_name_size);
- dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
- expr = skip_whitespace(p);
- /* If it is not followed by "=" operator... */
- if (expr[0] != '=' /* not "=..." */
- || expr[1] == '=' /* or "==..." */
- ) {
- /* Evaluate variable to value */
- errmsg = arith_lookup_val(math_state, numstackptr);
- if (errmsg)
- goto err_with_custom_msg;
+ if (!math_state->evaluation_disabled) {
+ size_t var_name_size = (p - expr) + 1; /* +1 for NUL */
+ numstackptr->var_name = alloca(var_name_size);
+ safe_strncpy(numstackptr->var_name, expr, var_name_size);
+ dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
+ expr = skip_whitespace(p);
+ /* If it is not followed by "=" operator... */
+ if (expr[0] != '=' /* not "=..." */
+ || expr[1] == '=' /* or "==..." */
+ ) {
+ /* Evaluate variable to value */
+ errmsg = arith_lookup_val(math_state, numstackptr);
+ if (errmsg)
+ goto err_with_custom_msg;
+ }
+ } else {
+ dbg("[%d] var:IGNORED", (int)(numstackptr - numstack));
+ numstackptr->var_name = NULL;
+ numstackptr->val = 0; //paranoia, probably not needed
+ expr = p;
}
push_num:
numstackptr++;
@@ -814,10 +833,11 @@ evaluate_string(arith_state_t *math_state, const char *expr)
* pop prev_op
* if can't evaluate prev_op (it is lower precedence than op):
* push prev_op back
- * goto P
+ * goto C
* evaluate prev_op on top of numstack
- * P: push op
- * N: loop to parse the rest of string
+ * C:if op is "?": check result, set disable flag if needed
+ * push op
+ * N:loop to parse the rest of string
*/
while (opstackptr != opstack) {
operator prev_op = *--opstackptr;
@@ -840,7 +860,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
) {
/* ...x~y@. push @ on opstack */
opstackptr++; /* undo removal of ~ op */
- goto push_op;
+ goto check_cond;
}
/* else: ...x~y@. Evaluate x~y, replace it on stack with result. Then repeat */
}
@@ -863,21 +883,41 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[
errmsg = "malformed ?: operator";
goto err_with_custom_msg;
}
+ /* Example: a=1?2:3,a. We just executed ":".
+ * Prevent assignment from being still disabled.
+ */
+ math_state->evaluation_disabled >>= 1;
+ dbg("':' executed: evaluation_disabled=%llx (restored)", EVAL_DISABLED);
}
} /* while (opstack not empty) */
if (op == TOK_RPAREN) /* unpaired RPAREN? */
goto err;
- }
+ check_cond:
+ if (op == TOK_CONDITIONAL) {
+ /* We know the value of EXPR in "EXPR ? ..."
+ * Should we stop evaluating now? */
+ if (math_state->evaluation_disabled & TOP_BIT_ULL)
+ goto err; /* >63 levels of ?: nesting not supported */
+ math_state->evaluation_disabled <<= 1;
+ if (numstackptr[-1].val == 0)
+ math_state->evaluation_disabled |= 1;
+ dbg("'?' entered: evaluation_disabled=%llx", EVAL_DISABLED);
+ }
+ } /* if */
/* else: LPAREN or UNARY: push it on opstack */
- push_op:
+
/* Push this operator to opstack */
dbg("(%d) op:%02x insert_op:%02x", (int)(opstackptr - opstack), op, insert_op);
*opstackptr++ = lasttok = op;
- next: ;
+ next:
if (insert_op != 0xff) {
op = insert_op;
insert_op = 0xff;
dbg("inserting %02x", op);
+ if (op == TOK_CONDITIONAL_SEP) {
+ math_state->evaluation_disabled ^= 1;
+ dbg("':' entered: evaluation_disabled=%llx (negated)", EVAL_DISABLED);
+ }
goto tok_found1;
}
} /* while (1) */
@@ -896,6 +936,7 @@ arith(arith_state_t *math_state, const char *expr)
{
math_state->errmsg = NULL;
math_state->list_of_recursed_names = NULL;
+ math_state->evaluation_disabled = 0;
return evaluate_string(math_state, expr);
}