diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 18:46:03 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 18:46:03 +0100 |
| commit | b1b7996a2acd8a95ae13dad1f64f86e221167cb7 (patch) | |
| tree | 09efc0d9d56d01caff85c2aa85fa74b8f1515045 /miscutils | |
| parent | 7d32e25bf33c98af6878715907ebbf297ef3d64a (diff) | |
| download | busybox-w32-b1b7996a2acd8a95ae13dad1f64f86e221167cb7.tar.gz busybox-w32-b1b7996a2acd8a95ae13dad1f64f86e221167cb7.tar.bz2 busybox-w32-b1b7996a2acd8a95ae13dad1f64f86e221167cb7.zip | |
bc: remove all logic for multi-line buffering
function old new delta
zbc_vm_process 865 874 +9
zbc_parse_text_init 51 38 -13
bc_read_line 394 345 -49
peek_inbuf 292 69 -223
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/3 up/down: 9/-285) Total: -276 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils')
| -rw-r--r-- | miscutils/bc.c | 144 |
1 files changed, 19 insertions, 125 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 5789869a7..632158b7f 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
| @@ -715,7 +715,6 @@ typedef struct BcParse { | |||
| 715 | smallint lex_last; // was BcLexType | 715 | smallint lex_last; // was BcLexType |
| 716 | size_t lex_line; | 716 | size_t lex_line; |
| 717 | const char *lex_inbuf; | 717 | const char *lex_inbuf; |
| 718 | const char *lex_end; | ||
| 719 | const char *lex_next_at; // last lex_next() was called at this string | 718 | const char *lex_next_at; // last lex_next() was called at this string |
| 720 | const char *lex_filename; | 719 | const char *lex_filename; |
| 721 | FILE *lex_input_fp; | 720 | FILE *lex_input_fp; |
| @@ -2473,21 +2472,6 @@ static FAST_FUNC void bc_result_free(void *result) | |||
| 2473 | } | 2472 | } |
| 2474 | } | 2473 | } |
| 2475 | 2474 | ||
| 2476 | #if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING | ||
| 2477 | static void bc_vec_concat(BcVec *v, const char *str) | ||
| 2478 | { | ||
| 2479 | size_t len, slen; | ||
| 2480 | |||
| 2481 | slen = strlen(str); | ||
| 2482 | len = v->len + slen + 1; | ||
| 2483 | |||
| 2484 | if (v->cap < len) bc_vec_grow(v, slen); | ||
| 2485 | strcpy(v->v + v->len, str); | ||
| 2486 | |||
| 2487 | v->len = len; | ||
| 2488 | } | ||
| 2489 | #endif | ||
| 2490 | |||
| 2491 | static int bad_input_byte(char c) | 2475 | static int bad_input_byte(char c) |
| 2492 | { | 2476 | { |
| 2493 | if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'? | 2477 | if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'? |
| @@ -2499,10 +2483,10 @@ static int bad_input_byte(char c) | |||
| 2499 | return 0; | 2483 | return 0; |
| 2500 | } | 2484 | } |
| 2501 | 2485 | ||
| 2502 | // Note: it _appends_ data from fp to vec. | ||
| 2503 | static void bc_read_line(BcVec *vec, FILE *fp) | 2486 | static void bc_read_line(BcVec *vec, FILE *fp) |
| 2504 | { | 2487 | { |
| 2505 | again: | 2488 | again: |
| 2489 | bc_vec_pop_all(vec); | ||
| 2506 | fflush_and_check(); | 2490 | fflush_and_check(); |
| 2507 | 2491 | ||
| 2508 | #if ENABLE_FEATURE_BC_SIGNALS | 2492 | #if ENABLE_FEATURE_BC_SIGNALS |
| @@ -2542,7 +2526,7 @@ static void bc_read_line(BcVec *vec, FILE *fp) | |||
| 2542 | if (!c) break; | 2526 | if (!c) break; |
| 2543 | if (bad_input_byte(c)) goto again; | 2527 | if (bad_input_byte(c)) goto again; |
| 2544 | } | 2528 | } |
| 2545 | bc_vec_concat(vec, line_buf); | 2529 | bc_vec_string(vec, n, line_buf); |
| 2546 | # undef line_buf | 2530 | # undef line_buf |
| 2547 | } else | 2531 | } else |
| 2548 | # endif | 2532 | # endif |
| @@ -2550,13 +2534,12 @@ static void bc_read_line(BcVec *vec, FILE *fp) | |||
| 2550 | { | 2534 | { |
| 2551 | int c; | 2535 | int c; |
| 2552 | bool bad_chars = 0; | 2536 | bool bad_chars = 0; |
| 2553 | size_t len = vec->len; | ||
| 2554 | 2537 | ||
| 2555 | do { | 2538 | do { |
| 2556 | #if ENABLE_FEATURE_BC_SIGNALS | 2539 | #if ENABLE_FEATURE_BC_SIGNALS |
| 2557 | if (G_interrupt) { | 2540 | if (G_interrupt) { |
| 2558 | // ^C was pressed: ignore entire line, get another one | 2541 | // ^C was pressed: ignore entire line, get another one |
| 2559 | vec->len = len; | 2542 | bc_vec_pop_all(vec); |
| 2560 | goto intr; | 2543 | goto intr; |
| 2561 | } | 2544 | } |
| 2562 | #endif | 2545 | #endif |
| @@ -2575,7 +2558,6 @@ static void bc_read_line(BcVec *vec, FILE *fp) | |||
| 2575 | // Bad chars on this line | 2558 | // Bad chars on this line |
| 2576 | if (!G.prs.lex_filename) { // stdin | 2559 | if (!G.prs.lex_filename) { // stdin |
| 2577 | // ignore entire line, get another one | 2560 | // ignore entire line, get another one |
| 2578 | vec->len = len; | ||
| 2579 | goto again; | 2561 | goto again; |
| 2580 | } | 2562 | } |
| 2581 | bb_perror_msg_and_die("file '%s' is not text", G.prs.lex_filename); | 2563 | bb_perror_msg_and_die("file '%s' is not text", G.prs.lex_filename); |
| @@ -2743,113 +2725,13 @@ static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t) | |||
| 2743 | static bool bc_lex_more_input(void) | 2725 | static bool bc_lex_more_input(void) |
| 2744 | { | 2726 | { |
| 2745 | BcParse *p = &G.prs; | 2727 | BcParse *p = &G.prs; |
| 2746 | unsigned str; // bool for bc, string nest count for dc | ||
| 2747 | bool comment; | ||
| 2748 | 2728 | ||
| 2749 | bc_vec_pop_all(&G.input_buffer); | 2729 | bc_vec_pop_all(&G.input_buffer); |
| 2750 | 2730 | ||
| 2751 | // This loop is complex because the vm tries not to send any lines that end | 2731 | bc_read_line(&G.input_buffer, G.prs.lex_input_fp); |
| 2752 | // with a backslash to the parser. The reason for that is because the parser | ||
| 2753 | // treats a backslash+newline combo as whitespace, per the bc spec. In that | ||
| 2754 | // case, and for strings and comments, the parser will expect more stuff. | ||
| 2755 | // | ||
| 2756 | // bc cases to test interactively: | ||
| 2757 | // 1 #comment\ - prints "1<newline>" at once (comment is not continued) | ||
| 2758 | // 1 #comment/* - prints "1<newline>" at once | ||
| 2759 | // 1 #comment" - prints "1<newline>" at once | ||
| 2760 | // 1\#comment - error at once (\ is not a line continuation) | ||
| 2761 | // 1 + /*"*/2 - prints "3<newline>" at once | ||
| 2762 | // 1 + /*#*/2 - prints "3<newline>" at once | ||
| 2763 | // "str\" - prints "str\" at once | ||
| 2764 | // "str#" - prints "str#" at once | ||
| 2765 | // "str/*" - prints "str/*" at once | ||
| 2766 | // "str#\ - waits for second line | ||
| 2767 | // end" - ...prints "str#\<newline>end" | ||
| 2768 | //This is way too complex, we duplicate comment/string logic of lexer | ||
| 2769 | //TODO: switch to char-by-char input like hush does it | ||
| 2770 | str = 0; | ||
| 2771 | comment = false; // stays always false for dc | ||
| 2772 | for (;;) { | ||
| 2773 | size_t prevlen = G.input_buffer.len; | ||
| 2774 | char *string; | ||
| 2775 | |||
| 2776 | bc_read_line(&G.input_buffer, G.prs.lex_input_fp); | ||
| 2777 | // No more input means EOF | ||
| 2778 | if (G.input_buffer.len <= prevlen + 1) // (we expect +1 for NUL byte) | ||
| 2779 | break; | ||
| 2780 | |||
| 2781 | string = G.input_buffer.v + prevlen; | ||
| 2782 | while (*string) { | ||
| 2783 | char c = *string++; | ||
| 2784 | #if ENABLE_BC | ||
| 2785 | if (comment) { | ||
| 2786 | // We are in /**/ comment, exit only on "*/" | ||
| 2787 | if (c == '*' && *string == '/') { | ||
| 2788 | comment = false; | ||
| 2789 | string++; | ||
| 2790 | } | ||
| 2791 | continue; | ||
| 2792 | } | ||
| 2793 | #endif | ||
| 2794 | // We are not in /**/ comment | ||
| 2795 | if (str) { | ||
| 2796 | // We are in "string" (bc) or [string] (dc) | ||
| 2797 | if (IS_BC) { | ||
| 2798 | // bc strings have no escapes: \\ is not special, | ||
| 2799 | // \n is not, \" is not, \<newline> is not. | ||
| 2800 | str = (c != '"'); // clear flag when " is seen | ||
| 2801 | } else { | ||
| 2802 | // dc strings have no escapes as well, can nest | ||
| 2803 | if (c == ']') | ||
| 2804 | str--; | ||
| 2805 | if (c == '[') | ||
| 2806 | str++; | ||
| 2807 | } | ||
| 2808 | continue; | ||
| 2809 | } | ||
| 2810 | // We are not in a string or /**/ comment | ||
| 2811 | |||
| 2812 | // Is it a #comment? Return the string (can't have continuation) | ||
| 2813 | if (c == '#') | ||
| 2814 | goto return_string; | ||
| 2815 | #if ENABLE_BC | ||
| 2816 | if (IS_BC) { | ||
| 2817 | // bc: is it a start of /**/ comment or string? | ||
| 2818 | if (c == '/' && *string == '*') { | ||
| 2819 | comment = true; | ||
| 2820 | string++; | ||
| 2821 | continue; | ||
| 2822 | } | ||
| 2823 | str = (c == '"'); // set flag if " is seen | ||
| 2824 | continue; | ||
| 2825 | } | ||
| 2826 | #endif | ||
| 2827 | // dc: is it a start of string? | ||
| 2828 | str = (c == '['); | ||
| 2829 | } // end of "check all chars in string" loop | ||
| 2830 | |||
| 2831 | if (str != 0 || comment) { | ||
| 2832 | G.input_buffer.len--; // backstep over the trailing NUL byte | ||
| 2833 | continue; | ||
| 2834 | } | ||
| 2835 | |||
| 2836 | // Check for backslash+newline. | ||
| 2837 | // We do not check that last char is '\n' - | ||
| 2838 | // if it is not, then it's EOF, and looping back | ||
| 2839 | // to bc_read_line() will detect it: | ||
| 2840 | string -= 2; | ||
| 2841 | if (string >= G.input_buffer.v && *string == '\\') { | ||
| 2842 | G.input_buffer.len--; | ||
| 2843 | continue; | ||
| 2844 | } | ||
| 2845 | |||
| 2846 | break; | ||
| 2847 | } | ||
| 2848 | return_string: | ||
| 2849 | 2732 | ||
| 2850 | p->lex_inbuf = G.input_buffer.v; | 2733 | p->lex_inbuf = G.input_buffer.v; |
| 2851 | // bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v); | 2734 | // bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v); |
| 2852 | p->lex_end = p->lex_inbuf + G.input_buffer.len - 1; // do not include NUL | ||
| 2853 | 2735 | ||
| 2854 | return G.input_buffer.len > 1; | 2736 | return G.input_buffer.len > 1; |
| 2855 | } | 2737 | } |
| @@ -2872,9 +2754,22 @@ static bool bc_lex_more_input(void) | |||
| 2872 | // In many cases, you can use fast *p->lex_inbuf instead of peek_inbuf(): | 2754 | // In many cases, you can use fast *p->lex_inbuf instead of peek_inbuf(): |
| 2873 | // unless prev char might have been '\n', *p->lex_inbuf is '\0' ONLY | 2755 | // unless prev char might have been '\n', *p->lex_inbuf is '\0' ONLY |
| 2874 | // on real EOF, not end-of-buffer. | 2756 | // on real EOF, not end-of-buffer. |
| 2757 | // | ||
| 2758 | // bc cases to test interactively: | ||
| 2759 | // 1 #comment\ - prints "1<newline>" at once (comment is not continued) | ||
| 2760 | // 1 #comment/* - prints "1<newline>" at once | ||
| 2761 | // 1 #comment" - prints "1<newline>" at once | ||
| 2762 | // 1\#comment - error at once (\ is not a line continuation) | ||
| 2763 | // 1 + /*"*/2 - prints "3<newline>" at once | ||
| 2764 | // 1 + /*#*/2 - prints "3<newline>" at once | ||
| 2765 | // "str\" - prints "str\" at once | ||
| 2766 | // "str#" - prints "str#" at once | ||
| 2767 | // "str/*" - prints "str/*" at once | ||
| 2768 | // "str#\ - waits for second line | ||
| 2769 | // end" - ...prints "str#\<newline>end" | ||
| 2875 | static char peek_inbuf(void) | 2770 | static char peek_inbuf(void) |
| 2876 | { | 2771 | { |
| 2877 | if (G.prs.lex_inbuf == G.prs.lex_end) { | 2772 | if (*G.prs.lex_inbuf == '\0') { |
| 2878 | if (G.prs.lex_input_fp) | 2773 | if (G.prs.lex_input_fp) |
| 2879 | if (!bc_lex_more_input()) | 2774 | if (!bc_lex_more_input()) |
| 2880 | G.prs.lex_input_fp = NULL; | 2775 | G.prs.lex_input_fp = NULL; |
| @@ -3060,7 +2955,6 @@ static BC_STATUS zbc_lex_next_and_skip_NLINE(void) | |||
| 3060 | static BC_STATUS zbc_lex_text_init(const char *text) | 2955 | static BC_STATUS zbc_lex_text_init(const char *text) |
| 3061 | { | 2956 | { |
| 3062 | G.prs.lex_inbuf = text; | 2957 | G.prs.lex_inbuf = text; |
| 3063 | G.prs.lex_end = text + strlen(text); | ||
| 3064 | G.prs.lex = G.prs.lex_last = XC_LEX_INVALID; | 2958 | G.prs.lex = G.prs.lex_last = XC_LEX_INVALID; |
| 3065 | RETURN_STATUS(zbc_lex_next()); | 2959 | RETURN_STATUS(zbc_lex_next()); |
| 3066 | } | 2960 | } |
| @@ -3652,7 +3546,7 @@ static void bc_parse_reset(void) | |||
| 3652 | p->func = bc_program_func_BC_PROG_MAIN(); | 3546 | p->func = bc_program_func_BC_PROG_MAIN(); |
| 3653 | } | 3547 | } |
| 3654 | 3548 | ||
| 3655 | p->lex_inbuf = p->lex_end; | 3549 | p->lex_inbuf += strlen(p->lex_inbuf); |
| 3656 | p->lex = XC_LEX_EOF; | 3550 | p->lex = XC_LEX_EOF; |
| 3657 | 3551 | ||
| 3658 | IF_BC(bc_vec_pop_all(&p->exits);) | 3552 | IF_BC(bc_vec_pop_all(&p->exits);) |
