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