aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-13 00:34:26 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-13 00:34:26 +0200
commitb771c654cab511b172484479cafd006d52588103 (patch)
tree54a5cd2fb09061217441afb00053a6e9c2e00284
parent99862cbfad9c36b4f8f4378c3a7a9f077c239f20 (diff)
downloadbusybox-w32-b771c654cab511b172484479cafd006d52588103.tar.gz
busybox-w32-b771c654cab511b172484479cafd006d52588103.tar.bz2
busybox-w32-b771c654cab511b172484479cafd006d52588103.zip
shell: shrink arith code; and prepare for returning text error codes
function old new delta arith 701 680 -21 Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r--shell/hush.c8
-rw-r--r--shell/math.c120
2 files changed, 63 insertions, 65 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 752efd0c8..ef0c454ec 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -4728,9 +4728,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4728 if (beg < 0) /* bash compat */ 4728 if (beg < 0) /* bash compat */
4729 beg = 0; 4729 beg = 0;
4730 debug_printf_varexp("from val:'%s'\n", val); 4730 debug_printf_varexp("from val:'%s'\n", val);
4731 if (len == 0 || !val || beg >= strlen(val)) 4731 if (len == 0 || !val || beg >= strlen(val)) {
4732 val = ""; 4732 val = NULL;
4733 else { 4733 } else {
4734 /* Paranoia. What if user entered 9999999999999 4734 /* Paranoia. What if user entered 9999999999999
4735 * which fits in arith_t but not int? */ 4735 * which fits in arith_t but not int? */
4736 if (len >= INT_MAX) 4736 if (len >= INT_MAX)
@@ -4742,7 +4742,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4742#endif 4742#endif
4743 { 4743 {
4744 die_if_script("malformed ${%s:...}", var); 4744 die_if_script("malformed ${%s:...}", var);
4745 val = ""; 4745 val = NULL;
4746 } 4746 }
4747 } else { /* one of "-=+?" */ 4747 } else { /* one of "-=+?" */
4748 /* Standard-mandated substitution ops: 4748 /* Standard-mandated substitution ops:
diff --git a/shell/math.c b/shell/math.c
index a4c55a4d0..2f093391f 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -124,9 +124,6 @@
124#define setvar (math_hooks->setvar ) 124#define setvar (math_hooks->setvar )
125//#define endofname (math_hooks->endofname) 125//#define endofname (math_hooks->endofname)
126 126
127#define arith_isspace(arithval) \
128 (arithval == ' ' || arithval == '\n' || arithval == '\t')
129
130typedef unsigned char operator; 127typedef unsigned char operator;
131 128
132/* An operator's token id is a bit of a bitfield. The lower 5 bits are the 129/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
@@ -156,7 +153,7 @@ typedef unsigned char operator;
156#define TOK_REM_ASSIGN tok_decl(3,2) 153#define TOK_REM_ASSIGN tok_decl(3,2)
157 154
158/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 155/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
159#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 156#define convert_prec_is_assign(prec) do { if (prec == 3) prec = 2; } while (0)
160 157
161/* conditional is right associativity too */ 158/* conditional is right associativity too */
162#define TOK_CONDITIONAL tok_decl(4,0) 159#define TOK_CONDITIONAL tok_decl(4,0)
@@ -223,7 +220,7 @@ tok_have_assign(operator op)
223{ 220{
224 operator prec = PREC(op); 221 operator prec = PREC(op);
225 222
226 convert_prec_is_assing(prec); 223 convert_prec_is_assign(prec);
227 return (prec == PREC(TOK_ASSIGN) || 224 return (prec == PREC(TOK_ASSIGN) ||
228 prec == PREC_PRE || prec == PREC_POST); 225 prec == PREC_PRE || prec == PREC_POST);
229} 226}
@@ -477,7 +474,7 @@ static const char op_tokens[] ALIGN1 = {
477 0 474 0
478}; 475};
479/* ptr to ")" */ 476/* ptr to ")" */
480#define endexpression (&op_tokens[sizeof(op_tokens)-7]) 477#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
481 478
482const char* FAST_FUNC 479const char* FAST_FUNC
483endofname(const char *name) 480endofname(const char *name)
@@ -494,32 +491,36 @@ endofname(const char *name)
494arith_t 491arith_t
495arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) 492arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
496{ 493{
497 char arithval; /* Current character under analysis */ 494 operator lasttok;
498 operator lasttok, op;
499 operator prec;
500 operator *stack, *stackptr;
501 const char *p = endexpression;
502 int errcode; 495 int errcode;
503 v_n_t *numstack, *numstackptr; 496 const char *start_expr = expr = skip_whitespace(expr);
504 unsigned datasizes = strlen(expr) + 2; 497 unsigned expr_len = strlen(expr) + 2;
505
506 /* Stack of integers */ 498 /* Stack of integers */
507 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 499 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
508 * in any given correct or incorrect expression is left as an exercise to 500 * in any given correct or incorrect expression is left as an exercise to
509 * the reader. */ 501 * the reader. */
510 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0])); 502 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
503 v_n_t *numstackptr = numstack;
511 /* Stack of operator tokens */ 504 /* Stack of operator tokens */
512 stackptr = stack = alloca(datasizes * sizeof(stack[0])); 505 operator *const stack = alloca(expr_len * sizeof(stack[0]));
506 operator *stackptr = stack;
513 507
514 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 508 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
515 *perrcode = errcode = 0; 509 errcode = 0;
516 510
517 while (1) { 511 while (1) {
512 const char *p;
513 operator op;
514 operator prec;
515 char arithval;
516
517 expr = skip_whitespace(expr);
518 arithval = *expr; 518 arithval = *expr;
519 if (arithval == 0) { 519 if (arithval == '\0') {
520 if (p == endexpression) { 520 if (expr == start_expr) {
521 /* Null expression. */ 521 /* Null expression. */
522 return 0; 522 numstack->val = 0;
523 goto ret;
523 } 524 }
524 525
525 /* This is only reached after all tokens have been extracted from the 526 /* This is only reached after all tokens have been extracted from the
@@ -527,38 +528,29 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
527 * are to be applied in order. At the end, there should be a final 528 * are to be applied in order. At the end, there should be a final
528 * result on the integer stack */ 529 * result on the integer stack */
529 530
530 if (expr != endexpression + 1) { 531 if (expr != ptr_to_rparen + 1) {
531 /* If we haven't done so already, */ 532 /* If we haven't done so already, */
532 /* append a closing right paren */ 533 /* append a closing right paren */
533 expr = endexpression; 534 expr = ptr_to_rparen;
534 /* and let the loop process it. */ 535 /* and let the loop process it. */
535 continue; 536 continue;
536 } 537 }
537 /* At this point, we're done with the expression. */ 538 /* At this point, we're done with the expression. */
538 if (numstackptr != numstack+1) { 539 if (numstackptr != numstack + 1) {
539 /* ... but if there isn't, it's bad */ 540 /* ... but if there isn't, it's bad */
540 err: 541 goto err;
541 *perrcode = -1;
542 return *perrcode;
543 } 542 }
544 if (numstack->var) { 543 if (numstack->var) {
545 /* expression is $((var)) only, lookup now */ 544 /* expression is $((var)) only, lookup now */
546 errcode = arith_lookup_val(numstack, math_hooks); 545 errcode = arith_lookup_val(numstack, math_hooks);
547 } 546 }
548 ret: 547 goto ret;
549 *perrcode = errcode;
550 return numstack->val;
551 } 548 }
552 549
553 /* Continue processing the expression. */
554 if (arith_isspace(arithval)) {
555 /* Skip whitespace */
556 goto prologue;
557 }
558 p = endofname(expr); 550 p = endofname(expr);
559 if (p != expr) { 551 if (p != expr) {
560 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 552 /* Name */
561 553 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
562 numstackptr->var = alloca(var_name_size); 554 numstackptr->var = alloca(var_name_size);
563 safe_strncpy(numstackptr->var, expr, var_name_size); 555 safe_strncpy(numstackptr->var, expr, var_name_size);
564 expr = p; 556 expr = p;
@@ -568,36 +560,37 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
568 lasttok = TOK_NUM; 560 lasttok = TOK_NUM;
569 continue; 561 continue;
570 } 562 }
563
571 if (isdigit(arithval)) { 564 if (isdigit(arithval)) {
565 /* Number */
572 numstackptr->var = NULL; 566 numstackptr->var = NULL;
573 errno = 0; 567 errno = 0;
574 /* call strtoul[l]: */ 568 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
575 numstackptr->val = strto_arith_t(expr, (char **) &expr, 0);
576 if (errno) 569 if (errno)
577 numstackptr->val = 0; /* bash compat */ 570 numstackptr->val = 0; /* bash compat */
578 goto num; 571 goto num;
579 } 572 }
580 for (p = op_tokens; ; p++) {
581 const char *o;
582 573
583 if (*p == 0) { 574 /* Should be an operator */
584 /* strange operator not found */ 575 p = op_tokens;
585 goto err; 576 while (1) {
586 } 577 const char *e = expr;
587 for (o = expr; *p && *o == *p; p++) 578 /* Compare expr to current op_tokens[] element */
588 o++; 579 while (*p && *e == *p)
589 if (!*p) { 580 p++, e++;
590 /* found */ 581 if (*p == '\0') { /* match: operator is found */
591 expr = o - 1; 582 expr = e;
592 break; 583 break;
593 } 584 }
594 /* skip tail uncompared token */ 585 /* Go to next element of op_tokens[] */
595 while (*p) 586 while (*p)
596 p++; 587 p++;
597 /* skip zero delim */ 588 p += 2; /* skip NUL and TOK_foo bytes */
598 p++; 589 if (*p == '\0') /* no next element, operator not found */
590 goto err;
599 } 591 }
600 op = p[1]; 592 op = p[1]; /* fetch TOK_foo value */
593 /* NB: expr now points past the operator */
601 594
602 /* post grammar: a++ reduce to num */ 595 /* post grammar: a++ reduce to num */
603 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 596 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
@@ -651,13 +644,12 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
651 /* Any operator directly after a */ 644 /* Any operator directly after a */
652 lasttok = TOK_NUM; 645 lasttok = TOK_NUM;
653 /* close paren should consider itself binary */ 646 /* close paren should consider itself binary */
654 goto prologue; 647 goto next;
655 } 648 }
656 } else { 649 } else {
657 operator prev_prec = PREC(stackptr[-1]); 650 operator prev_prec = PREC(stackptr[-1]);
658 651 convert_prec_is_assign(prec);
659 convert_prec_is_assing(prec); 652 convert_prec_is_assign(prev_prec);
660 convert_prec_is_assing(prev_prec);
661 if (prev_prec < prec) 653 if (prev_prec < prec)
662 break; 654 break;
663 /* check right assoc */ 655 /* check right assoc */
@@ -665,7 +657,8 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
665 break; 657 break;
666 } 658 }
667 errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks); 659 errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks);
668 if (errcode) goto ret; 660 if (errcode)
661 goto ret;
669 } 662 }
670 if (op == TOK_RPAREN) { 663 if (op == TOK_RPAREN) {
671 goto err; 664 goto err;
@@ -674,9 +667,14 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
674 667
675 /* Push this operator to the stack and remember it. */ 668 /* Push this operator to the stack and remember it. */
676 *stackptr++ = lasttok = op; 669 *stackptr++ = lasttok = op;
677 prologue: 670 next: ;
678 ++expr; 671 } /* while (1) */
679 } /* while */ 672
673 err:
674 numstack->val = errcode = -1;
675 ret:
676 *perrcode = errcode;
677 return numstack->val;
680} 678}
681 679
682/* 680/*