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 <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-12-13 19:23:45 +01:00
parent b7e61e3e4a
commit 82ea67fbfa

View File

@ -1226,6 +1226,7 @@ static void bc_vec_string(BcVec *v, size_t len, const char *str)
bc_vec_pushZeroByte(v); bc_vec_pushZeroByte(v);
} }
#if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING
static void bc_vec_concat(BcVec *v, const char *str) static void bc_vec_concat(BcVec *v, const char *str)
{ {
size_t len, slen; size_t len, slen;
@ -1240,6 +1241,7 @@ static void bc_vec_concat(BcVec *v, const char *str)
v->len = len; v->len = len;
} }
#endif
static void *bc_vec_item(const BcVec *v, size_t idx) 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 #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'? if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
|| c > 0x7e || c > 0x7e
) { ) {
// Bad chars on this line, ignore entire line
bc_error_fmt("illegal character 0x%02x", c); bc_error_fmt("illegal character 0x%02x", c);
return 1; return 1;
} }
bc_vec_pushByte(vec, (char)c);
return 0; return 0;
} }
// Note: it _appends_ data from the stdin to vec.
static void bc_read_line(BcVec *vec) static void bc_read_line(BcVec *vec)
{ {
bool bad_chars; again:
do {
int c;
bad_chars = 0;
bc_vec_pop_all(vec);
fflush_and_check(); fflush_and_check();
#if ENABLE_FEATURE_BC_SIGNALS #if ENABLE_FEATURE_BC_SIGNALS
@ -1359,6 +1353,7 @@ static void bc_read_line(BcVec *vec)
// GNU dc says "Interrupt!" // GNU dc says "Interrupt!"
fputs("\ninterrupted execution\n", stderr); fputs("\ninterrupted execution\n", stderr);
} }
# if ENABLE_FEATURE_EDITING # if ENABLE_FEATURE_EDITING
if (G_ttyin) { if (G_ttyin) {
int n, i; int n, i;
@ -1371,15 +1366,20 @@ static void bc_read_line(BcVec *vec)
} }
i = 0; i = 0;
for (;;) { for (;;) {
c = line_buf[i++]; char c = line_buf[i++];
if (!c) break; 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 # undef line_buf
} else } else
# endif # endif
#endif #endif
{ {
int c;
bool bad_chars = 0;
size_t len = vec->len;
IF_FEATURE_BC_SIGNALS(errno = 0;) IF_FEATURE_BC_SIGNALS(errno = 0;)
do { do {
c = fgetc(stdin); c = fgetc(stdin);
@ -1399,10 +1399,15 @@ static void bc_read_line(BcVec *vec)
// printf 'print 123' | bc - fails (syntax error) // printf 'print 123' | bc - fails (syntax error)
break; break;
} }
bad_chars |= push_input_byte(vec, c); bad_chars |= bad_input_byte(c);
bc_vec_pushByte(vec, (char)c);
} while (c != '\n'); } 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); bc_vec_pushZeroByte(vec);
} }
@ -5374,12 +5379,12 @@ static BC_STATUS zbc_program_read(void)
f = bc_program_func(BC_PROG_READ); f = bc_program_func(BC_PROG_READ);
bc_vec_pop_all(&f->code); bc_vec_pop_all(&f->code);
bc_char_vec_init(&buf);
sv_file = G.prog.file; sv_file = G.prog.file;
G.prog.file = NULL; G.prog.file = NULL;
G.in_read = 1; G.in_read = 1;
bc_char_vec_init(&buf);
bc_read_line(&buf); bc_read_line(&buf);
bc_parse_create(&parse, BC_PROG_READ); bc_parse_create(&parse, BC_PROG_READ);
@ -7039,7 +7044,7 @@ err:
static BC_STATUS zbc_vm_stdin(void) static BC_STATUS zbc_vm_stdin(void)
{ {
BcStatus s; BcStatus s;
BcVec buf, buffer; BcVec buffer;
size_t str; size_t str;
bool comment; bool comment;
@ -7047,8 +7052,6 @@ static BC_STATUS zbc_vm_stdin(void)
bc_lex_file(&G.prs.l); bc_lex_file(&G.prs.l);
bc_char_vec_init(&buffer); 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 // 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 // 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; comment = false;
str = 0; str = 0;
for (;;) { for (;;) {
size_t prevlen = buffer.len;
char *string; char *string;
bc_read_line(&buf); bc_read_line(&buffer);
if (buf.len <= 1) // "" buf means EOF // No more input means EOF
if (buffer.len <= prevlen + 1) // (we expect +1 for NUL byte)
break; break;
string = buf.v; string = buffer.v + prevlen;
while (*string) { while (*string) {
char c = *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 // checking applet type is cheaper than accessing sbgn/send
if (IS_BC) // bc: sbgn = send = '"' if (IS_BC) // bc: sbgn = send = '"'
str ^= (c == '"'); str ^= (c == '"');
@ -7089,17 +7094,20 @@ static BC_STATUS zbc_vm_stdin(void)
string++; string++;
} }
} }
bc_vec_concat(&buffer, buf.v); if (str || comment) {
if (str || comment) buffer.len--; // backstep over the trailing NUL byte
continue; continue;
}
// Check for backslash+newline. // Check for backslash+newline.
// we do not check that last char is '\n' - // we do not check that last char is '\n' -
// if it is not, then it's EOF, and looping back // if it is not, then it's EOF, and looping back
// to bc_read_line() will detect it: // to bc_read_line() will detect it:
string -= 2; string -= 2;
if (string >= buf.v && *string == '\\') if (string >= buffer.v && *string == '\\') {
buffer.len--;
continue; continue;
}
s = zbc_vm_process(buffer.v); s = zbc_vm_process(buffer.v);
if (s) { if (s) {
@ -7121,7 +7129,6 @@ static BC_STATUS zbc_vm_stdin(void)
s = bc_error("comment end could not be found"); s = bc_error("comment end could not be found");
} }
bc_vec_free(&buf);
bc_vec_free(&buffer); bc_vec_free(&buffer);
RETURN_STATUS(s); RETURN_STATUS(s);
} }