aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-06 10:29:12 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-06 10:29:12 +0100
commit95f93bdc280f93b6f1c30c64bf10a8be38669578 (patch)
tree881836791f890cb1a802da995562ca2898f7068e
parented849351d11d9f5bb9519baa52e8c1e9d3615ca9 (diff)
downloadbusybox-w32-95f93bdc280f93b6f1c30c64bf10a8be38669578.tar.gz
busybox-w32-95f93bdc280f93b6f1c30c64bf10a8be38669578.tar.bz2
busybox-w32-95f93bdc280f93b6f1c30c64bf10a8be38669578.zip
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>
-rw-r--r--miscutils/bc.c88
1 files changed, 63 insertions, 25 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 90c3bf5d6..dc4fa37a4 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -167,6 +167,7 @@
167//usage: "64\n" 167//usage: "64\n"
168 168
169#include "libbb.h" 169#include "libbb.h"
170#include "common_bufsiz.h"
170 171
171typedef enum BcStatus { 172typedef enum BcStatus {
172 BC_STATUS_SUCCESS = 0, 173 BC_STATUS_SUCCESS = 0,
@@ -750,6 +751,10 @@ struct globals {
750 BcVec files; 751 BcVec files;
751 752
752 char *env_args; 753 char *env_args;
754
755#if ENABLE_FEATURE_EDITING
756 line_input_t *line_input_state;
757#endif
753} FIX_ALIASING; 758} FIX_ALIASING;
754#define G (*ptr_to_globals) 759#define G (*ptr_to_globals)
755#define INIT_G() do { \ 760#define INIT_G() do { \
@@ -974,9 +979,9 @@ static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
974 979
975// We use error functions with "return bc_error(FMT[, PARAMS])" idiom. 980// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
976// This idiom begs for tail-call optimization, but for it to work, 981// This idiom begs for tail-call optimization, but for it to work,
977// function must not have calller-cleaned parameters on stack. 982// function must not have caller-cleaned parameters on stack.
978// Unfortunately, vararg functions do exactly that on most arches. 983// Unfortunately, vararg function API does exactly that on most arches.
979// Thus, these shims for the cases when we have no PARAMS: 984// Thus, use these shims for the cases when we have no vararg PARAMS:
980static int bc_error(const char *msg) 985static int bc_error(const char *msg)
981{ 986{
982 return bc_error_fmt("%s", msg); 987 return bc_error_fmt("%s", msg);
@@ -1195,17 +1200,33 @@ static size_t bc_map_index(const BcVec *v, const void *ptr)
1195 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i; 1200 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1196} 1201}
1197 1202
1203static int push_input_byte(BcVec *vec, char c)
1204{
1205 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1206 || c > 0x7e
1207 ) {
1208 // Bad chars on this line, ignore entire line
1209 bc_error_fmt("illegal character 0x%02x", c);
1210 return 1;
1211 }
1212 bc_vec_pushByte(vec, (char)c);
1213 return 0;
1214}
1215
1198static BcStatus bc_read_line(BcVec *vec, const char *prompt) 1216static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1199{ 1217{
1200 bool bad_chars; 1218 bool bad_chars;
1201 1219
1220 if (G_posix) prompt = "";
1221
1202 do { 1222 do {
1203 int i; 1223 int c;
1204 1224
1205 bad_chars = 0; 1225 bad_chars = 0;
1206 bc_vec_pop_all(vec); 1226 bc_vec_pop_all(vec);
1207 1227
1208 fflush_and_check(); 1228 fflush_and_check();
1229
1209#if ENABLE_FEATURE_BC_SIGNALS 1230#if ENABLE_FEATURE_BC_SIGNALS
1210 if (bb_got_signal) { // ^C was pressed 1231 if (bb_got_signal) { // ^C was pressed
1211 intr: 1232 intr:
@@ -1215,23 +1236,42 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1215 : "\ninterrupt (type \"q\" to exit)\n" 1236 : "\ninterrupt (type \"q\" to exit)\n"
1216 , stderr); 1237 , stderr);
1217 } 1238 }
1239# if ENABLE_FEATURE_EDITING
1240 if (G_ttyin) {
1241 int n, i;
1242# define line_buf bb_common_bufsiz1
1243 n = read_line_input(G.line_input_state, prompt, line_buf, COMMON_BUFSIZE);
1244 if (n <= 0) { // read errors or EOF, or ^D, or ^C
1245 if (n == 0) // ^C
1246 goto intr;
1247 G.eof = 1;
1248 break;
1249 }
1250 i = 0;
1251 for (;;) {
1252 c = line_buf[i++];
1253 if (!c) break;
1254 bad_chars |= push_input_byte(vec, c);
1255 }
1256# undef line_buf
1257 } else
1258# endif
1218#endif 1259#endif
1219 { 1260 {
1220 if (G_ttyin && !G_posix) 1261 if (G_ttyin)
1221 fputs(prompt, stderr); 1262 fputs(prompt, stderr);
1222
1223 IF_FEATURE_BC_SIGNALS(errno = 0;) 1263 IF_FEATURE_BC_SIGNALS(errno = 0;)
1224 do { 1264 do {
1225 i = fgetc(stdin); 1265 c = fgetc(stdin);
1226 if (i == EOF) { 1266#if ENABLE_FEATURE_BC_SIGNALS && !ENABLE_FEATURE_EDITING
1227#if ENABLE_FEATURE_BC_SIGNALS 1267 // Both conditions appear simultaneously, check both just in case
1228 // Both conditions appear simultaneously, check both just in case 1268 if (errno == EINTR || bb_got_signal) {
1229 if (errno == EINTR || bb_got_signal) { 1269 // ^C was pressed
1230 // ^C was pressed 1270 clearerr(stdin);
1231 clearerr(stdin); 1271 goto intr;
1232 goto intr; 1272 }
1233 }
1234#endif 1273#endif
1274 if (c == EOF) {
1235 if (ferror(stdin)) 1275 if (ferror(stdin))
1236 quit(); // this emits error message 1276 quit(); // this emits error message
1237 G.eof = 1; 1277 G.eof = 1;
@@ -1240,16 +1280,8 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1240 // printf 'print 123' | bc - fails (syntax error) 1280 // printf 'print 123' | bc - fails (syntax error)
1241 break; 1281 break;
1242 } 1282 }
1243 1283 bad_chars |= push_input_byte(vec, c);
1244 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'? 1284 } while (c != '\n');
1245 || i > 0x7e
1246 ) {
1247 // Bad chars on this line, ignore entire line
1248 bc_error_fmt("illegal character 0x%02x", i);
1249 bad_chars = 1;
1250 }
1251 bc_vec_pushByte(vec, (char)i);
1252 } while (i != '\n');
1253 } 1285 }
1254 } while (bad_chars); 1286 } while (bad_chars);
1255 1287
@@ -7391,6 +7423,9 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
7391{ 7423{
7392 BcStatus st; 7424 BcStatus st;
7393 7425
7426#if ENABLE_FEATURE_EDITING
7427 G.line_input_state = new_line_input_t(DO_HISTORY);
7428#endif
7394 G.prog.len = bc_vm_envLen(env_len); 7429 G.prog.len = bc_vm_envLen(env_len);
7395 7430
7396 bc_vm_init(); 7431 bc_vm_init();
@@ -7425,6 +7460,9 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
7425 7460
7426#if ENABLE_FEATURE_CLEAN_UP 7461#if ENABLE_FEATURE_CLEAN_UP
7427 bc_vm_free(); 7462 bc_vm_free();
7463# if ENABLE_FEATURE_EDITING
7464 free_line_input_t(G.line_input_state);
7465# endif
7428 FREE_G(); 7466 FREE_G();
7429#endif 7467#endif
7430 return st; 7468 return st;