bc: hook up line editing with history buffer
function old new delta push_input_byte - 65 +65 bc_vm_run 1875 1905 +30 bc_read_line 303 305 +2 bc_num_binary 148 150 +2 bc_num_ulong 103 92 -11 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/1 up/down: 99/-11) Total: 88 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
ed849351d1
commit
95f93bdc28
@ -167,6 +167,7 @@
|
|||||||
//usage: "64\n"
|
//usage: "64\n"
|
||||||
|
|
||||||
#include "libbb.h"
|
#include "libbb.h"
|
||||||
|
#include "common_bufsiz.h"
|
||||||
|
|
||||||
typedef enum BcStatus {
|
typedef enum BcStatus {
|
||||||
BC_STATUS_SUCCESS = 0,
|
BC_STATUS_SUCCESS = 0,
|
||||||
@ -750,6 +751,10 @@ struct globals {
|
|||||||
BcVec files;
|
BcVec files;
|
||||||
|
|
||||||
char *env_args;
|
char *env_args;
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_EDITING
|
||||||
|
line_input_t *line_input_state;
|
||||||
|
#endif
|
||||||
} FIX_ALIASING;
|
} FIX_ALIASING;
|
||||||
#define G (*ptr_to_globals)
|
#define G (*ptr_to_globals)
|
||||||
#define INIT_G() do { \
|
#define INIT_G() do { \
|
||||||
@ -974,9 +979,9 @@ static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
|
|||||||
|
|
||||||
// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
|
// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
|
||||||
// This idiom begs for tail-call optimization, but for it to work,
|
// This idiom begs for tail-call optimization, but for it to work,
|
||||||
// function must not have calller-cleaned parameters on stack.
|
// function must not have caller-cleaned parameters on stack.
|
||||||
// Unfortunately, vararg functions do exactly that on most arches.
|
// Unfortunately, vararg function API does exactly that on most arches.
|
||||||
// Thus, these shims for the cases when we have no PARAMS:
|
// Thus, use these shims for the cases when we have no vararg PARAMS:
|
||||||
static int bc_error(const char *msg)
|
static int bc_error(const char *msg)
|
||||||
{
|
{
|
||||||
return bc_error_fmt("%s", msg);
|
return bc_error_fmt("%s", msg);
|
||||||
@ -1195,17 +1200,33 @@ static size_t bc_map_index(const BcVec *v, const void *ptr)
|
|||||||
return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
|
return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int push_input_byte(BcVec *vec, 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;
|
||||||
|
}
|
||||||
|
|
||||||
static BcStatus bc_read_line(BcVec *vec, const char *prompt)
|
static BcStatus bc_read_line(BcVec *vec, const char *prompt)
|
||||||
{
|
{
|
||||||
bool bad_chars;
|
bool bad_chars;
|
||||||
|
|
||||||
|
if (G_posix) prompt = "";
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int i;
|
int c;
|
||||||
|
|
||||||
bad_chars = 0;
|
bad_chars = 0;
|
||||||
bc_vec_pop_all(vec);
|
bc_vec_pop_all(vec);
|
||||||
|
|
||||||
fflush_and_check();
|
fflush_and_check();
|
||||||
|
|
||||||
#if ENABLE_FEATURE_BC_SIGNALS
|
#if ENABLE_FEATURE_BC_SIGNALS
|
||||||
if (bb_got_signal) { // ^C was pressed
|
if (bb_got_signal) { // ^C was pressed
|
||||||
intr:
|
intr:
|
||||||
@ -1215,23 +1236,42 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
|
|||||||
: "\ninterrupt (type \"q\" to exit)\n"
|
: "\ninterrupt (type \"q\" to exit)\n"
|
||||||
, stderr);
|
, stderr);
|
||||||
}
|
}
|
||||||
|
# if ENABLE_FEATURE_EDITING
|
||||||
|
if (G_ttyin) {
|
||||||
|
int n, i;
|
||||||
|
# define line_buf bb_common_bufsiz1
|
||||||
|
n = read_line_input(G.line_input_state, prompt, line_buf, COMMON_BUFSIZE);
|
||||||
|
if (n <= 0) { // read errors or EOF, or ^D, or ^C
|
||||||
|
if (n == 0) // ^C
|
||||||
|
goto intr;
|
||||||
|
G.eof = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
for (;;) {
|
||||||
|
c = line_buf[i++];
|
||||||
|
if (!c) break;
|
||||||
|
bad_chars |= push_input_byte(vec, c);
|
||||||
|
}
|
||||||
|
# undef line_buf
|
||||||
|
} else
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (G_ttyin && !G_posix)
|
if (G_ttyin)
|
||||||
fputs(prompt, stderr);
|
fputs(prompt, stderr);
|
||||||
|
|
||||||
IF_FEATURE_BC_SIGNALS(errno = 0;)
|
IF_FEATURE_BC_SIGNALS(errno = 0;)
|
||||||
do {
|
do {
|
||||||
i = fgetc(stdin);
|
c = fgetc(stdin);
|
||||||
if (i == EOF) {
|
#if ENABLE_FEATURE_BC_SIGNALS && !ENABLE_FEATURE_EDITING
|
||||||
#if ENABLE_FEATURE_BC_SIGNALS
|
// Both conditions appear simultaneously, check both just in case
|
||||||
// Both conditions appear simultaneously, check both just in case
|
if (errno == EINTR || bb_got_signal) {
|
||||||
if (errno == EINTR || bb_got_signal) {
|
// ^C was pressed
|
||||||
// ^C was pressed
|
clearerr(stdin);
|
||||||
clearerr(stdin);
|
goto intr;
|
||||||
goto intr;
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
if (c == EOF) {
|
||||||
if (ferror(stdin))
|
if (ferror(stdin))
|
||||||
quit(); // this emits error message
|
quit(); // this emits error message
|
||||||
G.eof = 1;
|
G.eof = 1;
|
||||||
@ -1240,16 +1280,8 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
|
|||||||
// printf 'print 123' | bc - fails (syntax error)
|
// printf 'print 123' | bc - fails (syntax error)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
bad_chars |= push_input_byte(vec, c);
|
||||||
if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
|
} while (c != '\n');
|
||||||
|| i > 0x7e
|
|
||||||
) {
|
|
||||||
// Bad chars on this line, ignore entire line
|
|
||||||
bc_error_fmt("illegal character 0x%02x", i);
|
|
||||||
bad_chars = 1;
|
|
||||||
}
|
|
||||||
bc_vec_pushByte(vec, (char)i);
|
|
||||||
} while (i != '\n');
|
|
||||||
}
|
}
|
||||||
} while (bad_chars);
|
} while (bad_chars);
|
||||||
|
|
||||||
@ -7391,6 +7423,9 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
|
|||||||
{
|
{
|
||||||
BcStatus st;
|
BcStatus st;
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_EDITING
|
||||||
|
G.line_input_state = new_line_input_t(DO_HISTORY);
|
||||||
|
#endif
|
||||||
G.prog.len = bc_vm_envLen(env_len);
|
G.prog.len = bc_vm_envLen(env_len);
|
||||||
|
|
||||||
bc_vm_init();
|
bc_vm_init();
|
||||||
@ -7425,6 +7460,9 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
|
|||||||
|
|
||||||
#if ENABLE_FEATURE_CLEAN_UP
|
#if ENABLE_FEATURE_CLEAN_UP
|
||||||
bc_vm_free();
|
bc_vm_free();
|
||||||
|
# if ENABLE_FEATURE_EDITING
|
||||||
|
free_line_input_t(G.line_input_state);
|
||||||
|
# endif
|
||||||
FREE_G();
|
FREE_G();
|
||||||
#endif
|
#endif
|
||||||
return st;
|
return st;
|
||||||
|
Loading…
Reference in New Issue
Block a user