diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-06 10:29:12 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-06 10:29:12 +0100 |
commit | 95f93bdc280f93b6f1c30c64bf10a8be38669578 (patch) | |
tree | 881836791f890cb1a802da995562ca2898f7068e | |
parent | ed849351d11d9f5bb9519baa52e8c1e9d3615ca9 (diff) | |
download | busybox-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.c | 88 |
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 | ||
171 | typedef enum BcStatus { | 172 | typedef 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: |
980 | static int bc_error(const char *msg) | 985 | static 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 | ||
1203 | static 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 | |||
1198 | static BcStatus bc_read_line(BcVec *vec, const char *prompt) | 1216 | static 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; |