aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-26 18:46:03 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-26 18:46:03 +0100
commitb1b7996a2acd8a95ae13dad1f64f86e221167cb7 (patch)
tree09efc0d9d56d01caff85c2aa85fa74b8f1515045
parent7d32e25bf33c98af6878715907ebbf297ef3d64a (diff)
downloadbusybox-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.c144
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
2477static 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
2491static int bad_input_byte(char c) 2475static 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.
2503static void bc_read_line(BcVec *vec, FILE *fp) 2486static 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)
2743static bool bc_lex_more_input(void) 2725static 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"
2875static char peek_inbuf(void) 2770static 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)
3060static BC_STATUS zbc_lex_text_init(const char *text) 2955static 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);)