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 | |
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>
-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);) |