From 82ea67fbfa98cfd6b8b422db764cb8c97fc3ea7b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Dec 2018 19:23:45 +0100 Subject: [PATCH] bc: change bc_read_line() and zbc_vm_stdin() to avoid double buffers function old new delta bc_read_line 129 124 -5 bc_vm_run 523 433 -90 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-95) Total: -95 bytes text data bss dec hex filename 980445 485 7296 988226 f1442 busybox_old 980350 485 7296 988131 f13e3 busybox_unstripped Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 61 ++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index bc2947161..7c4dfbb20 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -1226,6 +1226,7 @@ static void bc_vec_string(BcVec *v, size_t len, const char *str) bc_vec_pushZeroByte(v); } +#if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING static void bc_vec_concat(BcVec *v, const char *str) { size_t len, slen; @@ -1240,6 +1241,7 @@ static void bc_vec_concat(BcVec *v, const char *str) v->len = len; } +#endif static void *bc_vec_item(const BcVec *v, size_t idx) { @@ -1326,29 +1328,21 @@ static size_t bc_map_index(const BcVec *v, const void *ptr) } #endif -static int push_input_byte(BcVec *vec, char c) +static int bad_input_byte(char c) { if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'? || c > 0x7e ) { - // Bad chars on this line, ignore entire line bc_error_fmt("illegal character 0x%02x", c); return 1; } - bc_vec_pushByte(vec, (char)c); return 0; } +// Note: it _appends_ data from the stdin to vec. static void bc_read_line(BcVec *vec) { - bool bad_chars; - - do { - int c; - - bad_chars = 0; - bc_vec_pop_all(vec); - + again: fflush_and_check(); #if ENABLE_FEATURE_BC_SIGNALS @@ -1359,6 +1353,7 @@ static void bc_read_line(BcVec *vec) // GNU dc says "Interrupt!" fputs("\ninterrupted execution\n", stderr); } + # if ENABLE_FEATURE_EDITING if (G_ttyin) { int n, i; @@ -1371,15 +1366,20 @@ static void bc_read_line(BcVec *vec) } i = 0; for (;;) { - c = line_buf[i++]; + char c = line_buf[i++]; if (!c) break; - bad_chars |= push_input_byte(vec, c); + if (bad_input_byte(c)) goto again; } + bc_vec_concat(vec, line_buf); # undef line_buf } else # endif #endif { + int c; + bool bad_chars = 0; + size_t len = vec->len; + IF_FEATURE_BC_SIGNALS(errno = 0;) do { c = fgetc(stdin); @@ -1399,10 +1399,15 @@ static void bc_read_line(BcVec *vec) // printf 'print 123' | bc - fails (syntax error) break; } - bad_chars |= push_input_byte(vec, c); + bad_chars |= bad_input_byte(c); + bc_vec_pushByte(vec, (char)c); } while (c != '\n'); + if (bad_chars) { + // Bad chars on this line, ignore entire line + vec->len = len; + goto again; + } } - } while (bad_chars); bc_vec_pushZeroByte(vec); } @@ -5374,12 +5379,12 @@ static BC_STATUS zbc_program_read(void) f = bc_program_func(BC_PROG_READ); bc_vec_pop_all(&f->code); - bc_char_vec_init(&buf); sv_file = G.prog.file; G.prog.file = NULL; G.in_read = 1; + bc_char_vec_init(&buf); bc_read_line(&buf); bc_parse_create(&parse, BC_PROG_READ); @@ -7039,7 +7044,7 @@ err: static BC_STATUS zbc_vm_stdin(void) { BcStatus s; - BcVec buf, buffer; + BcVec buffer; size_t str; bool comment; @@ -7047,8 +7052,6 @@ static BC_STATUS zbc_vm_stdin(void) bc_lex_file(&G.prs.l); bc_char_vec_init(&buffer); - bc_char_vec_init(&buf); - bc_vec_pushZeroByte(&buffer); // This loop is complex because the vm tries not to send any lines that end // with a backslash to the parser. The reason for that is because the parser @@ -7058,16 +7061,18 @@ static BC_STATUS zbc_vm_stdin(void) comment = false; str = 0; for (;;) { + size_t prevlen = buffer.len; char *string; - bc_read_line(&buf); - if (buf.len <= 1) // "" buf means EOF + bc_read_line(&buffer); + // No more input means EOF + if (buffer.len <= prevlen + 1) // (we expect +1 for NUL byte) break; - string = buf.v; + string = buffer.v + prevlen; while (*string) { char c = *string; - if (string == buf.v || string[-1] != '\\') { + if (string == buffer.v || string[-1] != '\\') { // checking applet type is cheaper than accessing sbgn/send if (IS_BC) // bc: sbgn = send = '"' str ^= (c == '"'); @@ -7089,17 +7094,20 @@ static BC_STATUS zbc_vm_stdin(void) string++; } } - bc_vec_concat(&buffer, buf.v); - if (str || comment) + if (str || comment) { + buffer.len--; // backstep over the trailing NUL byte continue; + } // Check for backslash+newline. // we do not check that last char is '\n' - // if it is not, then it's EOF, and looping back // to bc_read_line() will detect it: string -= 2; - if (string >= buf.v && *string == '\\') + if (string >= buffer.v && *string == '\\') { + buffer.len--; continue; + } s = zbc_vm_process(buffer.v); if (s) { @@ -7121,7 +7129,6 @@ static BC_STATUS zbc_vm_stdin(void) s = bc_error("comment end could not be found"); } - bc_vec_free(&buf); bc_vec_free(&buffer); RETURN_STATUS(s); } -- 2.25.1