aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-16 11:50:46 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-16 11:50:46 +0200
commitbed7c81ea24e9e9ba2a897e233de2abefe611e8b (patch)
treeb18a4559e60300fecd7275c0088f8942441072a2
parent063847d6bd23e184c409f37645ba90fa4d039ada (diff)
downloadbusybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.tar.gz
busybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.tar.bz2
busybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.zip
shell/math: deconvolute and explain ?: handling. Give better error message
function old new delta arith_apply 1271 1283 +12 Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r--shell/ash.c2
-rw-r--r--shell/ash_test/ash-arith/arith.right2
-rw-r--r--shell/hush.c4
-rw-r--r--shell/hush_test/hush-arith/arith.right2
-rw-r--r--shell/math.c243
-rw-r--r--shell/math.h20
6 files changed, 144 insertions, 129 deletions
diff --git a/shell/ash.c b/shell/ash.c
index ec887e088..9089adc63 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5516,7 +5516,7 @@ cvtnum(arith_t num)
5516 int len; 5516 int len;
5517 5517
5518 expdest = makestrspace(32, expdest); 5518 expdest = makestrspace(32, expdest);
5519 len = fmtstr(expdest, 32, arith_t_fmt, num); 5519 len = fmtstr(expdest, 32, ARITH_FMT, num);
5520 STADJUST(len, expdest); 5520 STADJUST(len, expdest);
5521 return len; 5521 return len;
5522} 5522}
diff --git a/shell/ash_test/ash-arith/arith.right b/shell/ash_test/ash-arith/arith.right
index 7257cc566..9b9ca8e2f 100644
--- a/shell/ash_test/ash-arith/arith.right
+++ b/shell/ash_test/ash-arith/arith.right
@@ -72,7 +72,7 @@ ghi
72./arith.tests: line 191: arithmetic syntax error 72./arith.tests: line 191: arithmetic syntax error
7316 16 7316 16
74./arith.tests: line 196: arithmetic syntax error 74./arith.tests: line 196: arithmetic syntax error
75./arith.tests: line 197: arithmetic syntax error 75./arith.tests: line 197: malformed ?: operator
76./arith.tests: line 198: arithmetic syntax error 76./arith.tests: line 198: arithmetic syntax error
779 9 779 9
78./arith.tests: line 205: arithmetic syntax error 78./arith.tests: line 205: arithmetic syntax error
diff --git a/shell/hush.c b/shell/hush.c
index ad30ac1ea..a888332bc 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4938,8 +4938,8 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
4938 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 4938 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
4939 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); 4939 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
4940 res = expand_and_evaluate_arith(arg, NULL); 4940 res = expand_and_evaluate_arith(arg, NULL);
4941 debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); 4941 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
4942 sprintf(arith_buf, arith_t_fmt, res); 4942 sprintf(arith_buf, ARITH_FMT, res);
4943 val = arith_buf; 4943 val = arith_buf;
4944 break; 4944 break;
4945 } 4945 }
diff --git a/shell/hush_test/hush-arith/arith.right b/shell/hush_test/hush-arith/arith.right
index fd4ea8e01..8a201fb3b 100644
--- a/shell/hush_test/hush-arith/arith.right
+++ b/shell/hush_test/hush-arith/arith.right
@@ -81,7 +81,7 @@ ghi
81hush: arithmetic syntax error 81hush: arithmetic syntax error
8216 16 8216 16
83hush: arithmetic syntax error 83hush: arithmetic syntax error
84hush: arithmetic syntax error 84hush: malformed ?: operator
85hush: arithmetic syntax error 85hush: arithmetic syntax error
869 9 869 9
87hush: arithmetic syntax error 87hush: arithmetic syntax error
diff --git a/shell/math.c b/shell/math.c
index 871c06c3e..9d3b912a7 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * arithmetic code ripped out of ash shell for code sharing 2 * Arithmetic code ripped out of ash shell for code sharing.
3 * 3 *
4 * This code is derived from software contributed to Berkeley by 4 * This code is derived from software contributed to Berkeley by
5 * Kenneth Almquist. 5 * Kenneth Almquist.
@@ -154,7 +154,7 @@ typedef unsigned char operator;
154 154
155#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0) 155#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
156 156
157/* ternary conditional operator is right associative too */ 157/* Ternary conditional operator is right associative too */
158#define TOK_CONDITIONAL tok_decl(4,0) 158#define TOK_CONDITIONAL tok_decl(4,0)
159#define TOK_CONDITIONAL_SEP tok_decl(4,1) 159#define TOK_CONDITIONAL_SEP tok_decl(4,1)
160 160
@@ -186,10 +186,10 @@ typedef unsigned char operator;
186#define TOK_DIV tok_decl(14,1) 186#define TOK_DIV tok_decl(14,1)
187#define TOK_REM tok_decl(14,2) 187#define TOK_REM tok_decl(14,2)
188 188
189/* exponent is right associative */ 189/* Exponent is right associative */
190#define TOK_EXPONENT tok_decl(15,1) 190#define TOK_EXPONENT tok_decl(15,1)
191 191
192/* unary operators */ 192/* Unary operators */
193#define UNARYPREC 16 193#define UNARYPREC 16
194#define TOK_BNOT tok_decl(UNARYPREC,0) 194#define TOK_BNOT tok_decl(UNARYPREC,0)
195#define TOK_NOT tok_decl(UNARYPREC,1) 195#define TOK_NOT tok_decl(UNARYPREC,1)
@@ -213,30 +213,37 @@ typedef unsigned char operator;
213#define TOK_RPAREN tok_decl(SPEC_PREC, 1) 213#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
214 214
215static int 215static int
216tok_have_assign(operator op) 216is_assign_op(operator op)
217{ 217{
218 operator prec = PREC(op); 218 operator prec = PREC(op);
219
220 fix_assignment_prec(prec); 219 fix_assignment_prec(prec);
221 return (prec == PREC(TOK_ASSIGN) || 220 return prec == PREC(TOK_ASSIGN)
222 prec == PREC_PRE || prec == PREC_POST); 221 || prec == PREC_PRE
222 || prec == PREC_POST;
223} 223}
224 224
225static int 225static int
226is_right_associative(operator prec) 226is_right_associative(operator prec)
227{ 227{
228 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 228 return prec == PREC(TOK_ASSIGN)
229 || prec == PREC(TOK_CONDITIONAL)); 229 || prec == PREC(TOK_EXPONENT)
230 || prec == PREC(TOK_CONDITIONAL);
230} 231}
231 232
232 233
233typedef struct { 234typedef struct {
234 arith_t val; 235 arith_t val;
235 arith_t contidional_second_val; 236 /* We acquire second_val only when "expr1 : expr2" part
236 char contidional_second_val_initialized; 237 * of ternary ?: op is evaluated.
237 char *var; /* if NULL then is regular number, 238 * We treat ?: as two binary ops: (expr ? (expr1 : expr2)).
238 else is variable name */ 239 * ':' produces a new value which has two parts, val and second_val;
239} v_n_t; 240 * then '?' selects one of them based on its left side.
241 */
242 arith_t second_val;
243 char second_val_present;
244 /* If NULL then it's just a number, else it's a named variable */
245 char *var;
246} var_or_num_t;
240 247
241typedef struct remembered_name { 248typedef struct remembered_name {
242 struct remembered_name *next; 249 struct remembered_name *next;
@@ -248,7 +255,7 @@ static arith_t FAST_FUNC
248evaluate_string(arith_state_t *math_state, const char *expr); 255evaluate_string(arith_state_t *math_state, const char *expr);
249 256
250static const char* 257static const char*
251arith_lookup_val(arith_state_t *math_state, v_n_t *t) 258arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
252{ 259{
253 if (t->var) { 260 if (t->var) {
254 const char *p = lookupvar(t->var); 261 const char *p = lookupvar(t->var);
@@ -290,27 +297,28 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t)
290 * stack. For an unary operator it will only change the top element, but a 297 * stack. For an unary operator it will only change the top element, but a
291 * binary operator will pop two arguments and push the result */ 298 * binary operator will pop two arguments and push the result */
292static NOINLINE const char* 299static NOINLINE const char*
293arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr) 300arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_or_num_t **numstackptr)
294{ 301{
295#define NUMPTR (*numstackptr) 302#define NUMPTR (*numstackptr)
296 303
297 v_n_t *numptr_m1; 304 var_or_num_t *top_of_stack;
298 arith_t numptr_val, rez; 305 arith_t rez;
299 const char *err; 306 const char *err;
300 307
301 /* There is no operator that can work without arguments */ 308 /* There is no operator that can work without arguments */
302 if (NUMPTR == numstack) 309 if (NUMPTR == numstack)
303 goto err; 310 goto err;
304 numptr_m1 = NUMPTR - 1;
305 311
306 /* Check operand is var with noninteger value */ 312 top_of_stack = NUMPTR - 1;
307 err = arith_lookup_val(math_state, numptr_m1); 313
314 /* Resolve name to value, if needed */
315 err = arith_lookup_val(math_state, top_of_stack);
308 if (err) 316 if (err)
309 return err; 317 return err;
310 318
311 rez = numptr_m1->val; 319 rez = top_of_stack->val;
312 if (op == TOK_UMINUS) 320 if (op == TOK_UMINUS)
313 rez *= -1; 321 rez = -rez;
314 else if (op == TOK_NOT) 322 else if (op == TOK_NOT)
315 rez = !rez; 323 rez = !rez;
316 else if (op == TOK_BNOT) 324 else if (op == TOK_BNOT)
@@ -321,112 +329,119 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num
321 rez--; 329 rez--;
322 else if (op != TOK_UPLUS) { 330 else if (op != TOK_UPLUS) {
323 /* Binary operators */ 331 /* Binary operators */
332 arith_t right_side_val;
333 char bad_second_val;
324 334
325 /* check and binary operators need two arguments */ 335 /* Binary operators need two arguments */
326 if (numptr_m1 == numstack) goto err; 336 if (top_of_stack == numstack)
327
328 /* ... and they pop one */
329 --NUMPTR;
330 numptr_val = rez;
331 if (op == TOK_CONDITIONAL) {
332 if (!numptr_m1->contidional_second_val_initialized) {
333 /* protect $((expr1 ? expr2)) without ": expr" */
334 goto err;
335 }
336 rez = numptr_m1->contidional_second_val;
337 } else if (numptr_m1->contidional_second_val_initialized) {
338 /* protect $((expr1 : expr2)) without "expr ? " */
339 goto err; 337 goto err;
338 /* ...and they pop one */
339 NUMPTR = top_of_stack; /* this decrements NUMPTR */
340
341 bad_second_val = top_of_stack->second_val_present;
342 if (op == TOK_CONDITIONAL) { /* ? operation */
343 /* Make next if (...) protect against
344 * $((expr1 ? expr2)) - that is, missing ": expr" */
345 bad_second_val = !bad_second_val;
346 }
347 if (bad_second_val) {
348 /* Protect against $((expr <not_?_op> expr1 : expr2)) */
349 return "malformed ?: operator";
340 } 350 }
341 numptr_m1 = NUMPTR - 1; 351
352 top_of_stack--; /* now points to left side */
353
342 if (op != TOK_ASSIGN) { 354 if (op != TOK_ASSIGN) {
343 /* check operand is var with noninteger value for not '=' */ 355 /* Resolve left side value (unless the op is '=') */
344 err = arith_lookup_val(math_state, numptr_m1); 356 err = arith_lookup_val(math_state, top_of_stack);
345 if (err) 357 if (err)
346 return err; 358 return err;
347 } 359 }
348 if (op == TOK_CONDITIONAL) { 360
349 numptr_m1->contidional_second_val = rez; 361 right_side_val = rez;
362 rez = top_of_stack->val;
363 if (op == TOK_CONDITIONAL) /* ? operation */
364 rez = (rez ? right_side_val : top_of_stack[1].second_val);
365 else if (op == TOK_CONDITIONAL_SEP) { /* : operation */
366 if (top_of_stack == numstack) {
367 /* Protect against $((expr : expr)) */
368 return "malformed ?: operator";
369 }
370 top_of_stack->second_val_present = op;
371 top_of_stack->second_val = right_side_val;
350 } 372 }
351 rez = numptr_m1->val; 373 else if (op == TOK_BOR || op == TOK_OR_ASSIGN)
352 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 374 rez |= right_side_val;
353 rez |= numptr_val;
354 else if (op == TOK_OR) 375 else if (op == TOK_OR)
355 rez = numptr_val || rez; 376 rez = right_side_val || rez;
356 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 377 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
357 rez &= numptr_val; 378 rez &= right_side_val;
358 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 379 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
359 rez ^= numptr_val; 380 rez ^= right_side_val;
360 else if (op == TOK_AND) 381 else if (op == TOK_AND)
361 rez = rez && numptr_val; 382 rez = rez && right_side_val;
362 else if (op == TOK_EQ) 383 else if (op == TOK_EQ)
363 rez = (rez == numptr_val); 384 rez = (rez == right_side_val);
364 else if (op == TOK_NE) 385 else if (op == TOK_NE)
365 rez = (rez != numptr_val); 386 rez = (rez != right_side_val);
366 else if (op == TOK_GE) 387 else if (op == TOK_GE)
367 rez = (rez >= numptr_val); 388 rez = (rez >= right_side_val);
368 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 389 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
369 rez >>= numptr_val; 390 rez >>= right_side_val;
370 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 391 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
371 rez <<= numptr_val; 392 rez <<= right_side_val;
372 else if (op == TOK_GT) 393 else if (op == TOK_GT)
373 rez = (rez > numptr_val); 394 rez = (rez > right_side_val);
374 else if (op == TOK_LT) 395 else if (op == TOK_LT)
375 rez = (rez < numptr_val); 396 rez = (rez < right_side_val);
376 else if (op == TOK_LE) 397 else if (op == TOK_LE)
377 rez = (rez <= numptr_val); 398 rez = (rez <= right_side_val);
378 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 399 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
379 rez *= numptr_val; 400 rez *= right_side_val;
380 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 401 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
381 rez += numptr_val; 402 rez += right_side_val;
382 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 403 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
383 rez -= numptr_val; 404 rez -= right_side_val;
384 else if (op == TOK_ASSIGN || op == TOK_COMMA) 405 else if (op == TOK_ASSIGN || op == TOK_COMMA)
385 rez = numptr_val; 406 rez = right_side_val;
386 else if (op == TOK_CONDITIONAL_SEP) { 407 else if (op == TOK_EXPONENT) {
387 if (numptr_m1 == numstack) {
388 /* protect $((expr : expr)) without "expr ? " */
389 goto err;
390 }
391 numptr_m1->contidional_second_val_initialized = op;
392 numptr_m1->contidional_second_val = numptr_val;
393 } else if (op == TOK_CONDITIONAL) {
394 rez = rez ?
395 numptr_val : numptr_m1->contidional_second_val;
396 } else if (op == TOK_EXPONENT) {
397 arith_t c; 408 arith_t c;
398 if (numptr_val < 0) 409 if (right_side_val < 0)
399 return "exponent less than 0"; 410 return "exponent less than 0";
400 c = 1; 411 c = 1;
401 while (--numptr_val >= 0) 412 while (--right_side_val >= 0)
402 c *= rez; 413 c *= rez;
403 rez = c; 414 rez = c;
404 } else if (numptr_val == 0) 415 }
416 else if (right_side_val == 0)
405 return "divide by zero"; 417 return "divide by zero";
406 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 418 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
407 rez /= numptr_val; 419 rez /= right_side_val;
408 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 420 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
409 rez %= numptr_val; 421 rez %= right_side_val;
410 } 422 }
411 if (tok_have_assign(op)) { 423
424 if (is_assign_op(op)) {
412 char buf[sizeof(arith_t)*3 + 2]; 425 char buf[sizeof(arith_t)*3 + 2];
413 426
414 if (numptr_m1->var == NULL) { 427 if (top_of_stack->var == NULL) {
415 /* Hmm, 1=2 ? */ 428 /* Hmm, 1=2 ? */
429//TODO: actually, bash allows ++7 but for some reason it evals to 7, not 8
416 goto err; 430 goto err;
417 } 431 }
418 /* save to shell variable */ 432 /* Save to shell variable */
419 sprintf(buf, arith_t_fmt, rez); 433 sprintf(buf, ARITH_FMT, rez);
420 setvar(numptr_m1->var, buf); 434 setvar(top_of_stack->var, buf);
421 /* after saving, make previous value for v++ or v-- */ 435 /* After saving, make previous value for v++ or v-- */
422 if (op == TOK_POST_INC) 436 if (op == TOK_POST_INC)
423 rez--; 437 rez--;
424 else if (op == TOK_POST_DEC) 438 else if (op == TOK_POST_DEC)
425 rez++; 439 rez++;
426 } 440 }
427 numptr_m1->val = rez; 441
428 /* erase var name, it is just a number now */ 442 top_of_stack->val = rez;
429 numptr_m1->var = NULL; 443 /* Erase var name, it is just a number now */
444 top_of_stack->var = NULL;
430 return NULL; 445 return NULL;
431 err: 446 err:
432 return "arithmetic syntax error"; 447 return "arithmetic syntax error";
@@ -499,16 +514,17 @@ evaluate_string(arith_state_t *math_state, const char *expr)
499 const char *start_expr = expr = skip_whitespace(expr); 514 const char *start_expr = expr = skip_whitespace(expr);
500 unsigned expr_len = strlen(expr) + 2; 515 unsigned expr_len = strlen(expr) + 2;
501 /* Stack of integers */ 516 /* Stack of integers */
502 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 517 /* The proof that there can be no more than strlen(startbuf)/2+1
503 * in any given correct or incorrect expression is left as an exercise to 518 * integers in any given correct or incorrect expression
504 * the reader. */ 519 * is left as an exercise to the reader. */
505 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0])); 520 var_or_num_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
506 v_n_t *numstackptr = numstack; 521 var_or_num_t *numstackptr = numstack;
507 /* Stack of operator tokens */ 522 /* Stack of operator tokens */
508 operator *const stack = alloca(expr_len * sizeof(stack[0])); 523 operator *const stack = alloca(expr_len * sizeof(stack[0]));
509 operator *stackptr = stack; 524 operator *stackptr = stack;
510 525
511 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 526 /* Start with a left paren */
527 *stackptr++ = lasttok = TOK_LPAREN;
512 errmsg = NULL; 528 errmsg = NULL;
513 529
514 while (1) { 530 while (1) {
@@ -521,7 +537,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
521 arithval = *expr; 537 arithval = *expr;
522 if (arithval == '\0') { 538 if (arithval == '\0') {
523 if (expr == start_expr) { 539 if (expr == start_expr) {
524 /* Null expression. */ 540 /* Null expression */
525 numstack->val = 0; 541 numstack->val = 0;
526 goto ret; 542 goto ret;
527 } 543 }
@@ -558,7 +574,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
558 safe_strncpy(numstackptr->var, expr, var_name_size); 574 safe_strncpy(numstackptr->var, expr, var_name_size);
559 expr = p; 575 expr = p;
560 num: 576 num:
561 numstackptr->contidional_second_val_initialized = 0; 577 numstackptr->second_val_present = 0;
562 numstackptr++; 578 numstackptr++;
563 lasttok = TOK_NUM; 579 lasttok = TOK_NUM;
564 continue; 580 continue;
@@ -577,21 +593,32 @@ evaluate_string(arith_state_t *math_state, const char *expr)
577 /* Should be an operator */ 593 /* Should be an operator */
578 p = op_tokens; 594 p = op_tokens;
579 while (1) { 595 while (1) {
580 const char *e = expr; 596// TODO: bash allows 7+++v, treats it as 7 + ++v
597// we treat it as 7++ + v and reject
581 /* Compare expr to current op_tokens[] element */ 598 /* Compare expr to current op_tokens[] element */
582 while (*p && *e == *p) 599 const char *e = expr;
583 p++, e++; 600 while (1) {
584 if (*p == '\0') { /* match: operator is found */ 601 if (*p == '\0') {
585 expr = e; 602 /* Match: operator is found */
586 break; 603 expr = e;
604 goto tok_found;
605 }
606 if (*p != *e)
607 break;
608 p++;
609 e++;
587 } 610 }
588 /* Go to next element of op_tokens[] */ 611 /* No match, go to next element of op_tokens[] */
589 while (*p) 612 while (*p)
590 p++; 613 p++;
591 p += 2; /* skip NUL and TOK_foo bytes */ 614 p += 2; /* skip NUL and TOK_foo bytes */
592 if (*p == '\0') /* no next element, operator not found */ 615 if (*p == '\0') {
616 /* No next element, operator not found */
617 //math_state->syntax_error_at = expr;
593 goto err; 618 goto err;
619 }
594 } 620 }
621 tok_found:
595 op = p[1]; /* fetch TOK_foo value */ 622 op = p[1]; /* fetch TOK_foo value */
596 /* NB: expr now points past the operator */ 623 /* NB: expr now points past the operator */
597 624
@@ -662,21 +689,21 @@ evaluate_string(arith_state_t *math_state, const char *expr)
662 } 689 }
663 errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); 690 errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
664 if (errmsg) 691 if (errmsg)
665 goto ret; 692 goto err_with_custom_msg;
666 } 693 }
667 if (op == TOK_RPAREN) { 694 if (op == TOK_RPAREN)
668 goto err; 695 goto err;
669 }
670 } 696 }
671 697
672 /* Push this operator to the stack and remember it. */ 698 /* Push this operator to the stack and remember it */
673 *stackptr++ = lasttok = op; 699 *stackptr++ = lasttok = op;
674 next: ; 700 next: ;
675 } /* while (1) */ 701 } /* while (1) */
676 702
677 err: 703 err:
678 numstack->val = -1;
679 errmsg = "arithmetic syntax error"; 704 errmsg = "arithmetic syntax error";
705 err_with_custom_msg:
706 numstack->val = -1;
680 ret: 707 ret:
681 math_state->errmsg = errmsg; 708 math_state->errmsg = errmsg;
682 return numstack->val; 709 return numstack->val;
diff --git a/shell/math.h b/shell/math.h
index 2dcab130d..2d305eb12 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -9,19 +9,13 @@
9 9
10/* The math library has just one function: 10/* The math library has just one function:
11 * 11 *
12 * arith_t arith(arith_state_t *states, const char *expr); 12 * arith_t arith(arith_state_t *state, const char *expr);
13 * 13 *
14 * The expr 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 state argument is a pointer to a struct of hooks for your shell (see below), 17 * The state argument is a pointer to a struct of hooks for your shell (see below),
18 * and a semi-detailed error code. Currently, those values are (for 18 * and an error message string (NULL if no error).
19 * compatibility, you should assume all negative values are errors):
20 * 0 - no errors (yay!)
21 * -1 - unspecified problem
22 * -2 - divide by zero
23 * -3 - exponent less than 0
24 * -5 - expression recursion loop detected
25 * 19 *
26 * The function returns the answer to the expression. So if you called it 20 * The function returns the answer to the expression. So if you called it
27 * with the expression: 21 * with the expression:
@@ -64,12 +58,6 @@
64 * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* 58 * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]*
65 */ 59 */
66 60
67/* To make your life easier when dealing with optional 64bit math support,
68 * rather than assume that the type is "signed long" and you can always
69 * use "%ld" to scan/print the value, use the arith_t helper defines. See
70 * below for the exact things that are available.
71 */
72
73#ifndef SHELL_MATH_H 61#ifndef SHELL_MATH_H
74#define SHELL_MATH_H 1 62#define SHELL_MATH_H 1
75 63
@@ -77,11 +65,11 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
77 65
78#if ENABLE_SH_MATH_SUPPORT_64 66#if ENABLE_SH_MATH_SUPPORT_64
79typedef long long arith_t; 67typedef long long arith_t;
80#define arith_t_fmt "%lld" 68#define ARITH_FMT "%lld"
81#define strto_arith_t strtoull 69#define strto_arith_t strtoull
82#else 70#else
83typedef long arith_t; 71typedef long arith_t;
84#define arith_t_fmt "%ld" 72#define ARITH_FMT "%ld"
85#define strto_arith_t strtoul 73#define strto_arith_t strtoul
86#endif 74#endif
87 75