diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 00:34:26 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 00:34:26 +0200 |
commit | b771c654cab511b172484479cafd006d52588103 (patch) | |
tree | 54a5cd2fb09061217441afb00053a6e9c2e00284 | |
parent | 99862cbfad9c36b4f8f4378c3a7a9f077c239f20 (diff) | |
download | busybox-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.c | 8 | ||||
-rw-r--r-- | shell/math.c | 120 |
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 | |||
130 | typedef unsigned char operator; | 127 | typedef 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 | ||
482 | const char* FAST_FUNC | 479 | const char* FAST_FUNC |
483 | endofname(const char *name) | 480 | endofname(const char *name) |
@@ -494,32 +491,36 @@ endofname(const char *name) | |||
494 | arith_t | 491 | arith_t |
495 | arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | 492 | arith(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 | /* |