aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-03 16:06:02 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-05 15:43:35 +0100
commitc1c2470f843c0b8218dd3611330a941b00d0cc34 (patch)
tree59dd8c0a1b3c31954bb699513e098b28f7e90798
parentd4744adf35c678554e609a74eeebc7b7603ee25d (diff)
downloadbusybox-w32-c1c2470f843c0b8218dd3611330a941b00d0cc34.tar.gz
busybox-w32-c1c2470f843c0b8218dd3611330a941b00d0cc34.tar.bz2
busybox-w32-c1c2470f843c0b8218dd3611330a941b00d0cc34.zip
bc: handle BIN_FILE and LEX_BAD_CHAR errors at the site of detection
The most informative message can be generated at the location where error is detected. The "error codes" are stupid: print error meesage immediately, then just return "there was an error" indicator. All error codes will be converted. For now, converting these two. For now, this and following changes will degrade error messages quality. For example, file name and line number printouts may be lost. This will be re-added later. This change anlso fixes handling of invalid stdin input: this used to cause interactive bc to exit: .... >>> ς bc: illegal character 0xcf bc: illegal character 0x82 >>> _ function old new delta bc_error - 42 +42 bc_lex_token 1333 1369 +36 dc_lex_token 675 695 +20 bc_read_line 311 325 +14 bc_num_a 456 454 -2 bc_err_msgs 188 184 -4 bc_num_ulong 95 85 -10 bc_vm_run 1984 1955 -29 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/4 up/down: 112/-45) Total: 67 bytes text data bss dec hex filename 987828 485 7296 995609 f3119 busybox_old 987929 485 7296 995710 f317e busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--miscutils/bc.c130
1 files changed, 76 insertions, 54 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index c819decff..dd01f5409 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -169,13 +169,14 @@
169 169
170typedef enum BcStatus { 170typedef enum BcStatus {
171 BC_STATUS_SUCCESS, 171 BC_STATUS_SUCCESS,
172 BC_STATUS_FAILURE,
172 173
173// BC_STATUS_ALLOC_ERR, 174// BC_STATUS_ALLOC_ERR,
174// BC_STATUS_INPUT_EOF, 175// BC_STATUS_INPUT_EOF,
175 BC_STATUS_BIN_FILE, 176// BC_STATUS_BIN_FILE,
176// BC_STATUS_PATH_IS_DIR, 177// BC_STATUS_PATH_IS_DIR,
177 178
178 BC_STATUS_LEX_BAD_CHAR, 179// BC_STATUS_LEX_BAD_CHAR,
179 BC_STATUS_LEX_NO_STRING_END, 180 BC_STATUS_LEX_NO_STRING_END,
180 BC_STATUS_LEX_NO_COMMENT_END, 181 BC_STATUS_LEX_NO_COMMENT_END,
181 BC_STATUS_LEX_EOF, 182 BC_STATUS_LEX_EOF,
@@ -239,12 +240,13 @@ typedef enum BcStatus {
239// Keep enum above and messages below in sync! 240// Keep enum above and messages below in sync!
240static const char *const bc_err_msgs[] = { 241static const char *const bc_err_msgs[] = {
241 NULL, 242 NULL,
243 "",
242// "memory allocation error", 244// "memory allocation error",
243// "I/O error", 245// "I/O error",
244 "file is not text:", 246// "file is not text:",
245// "path is a directory:", 247// "path is a directory:",
246 248
247 "bad character", 249// "bad character",
248 "string end could not be found", 250 "string end could not be found",
249 "comment end could not be found", 251 "comment end could not be found",
250 "end of file", 252 "end of file",
@@ -321,8 +323,6 @@ typedef struct BcVec {
321 323
322#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free)) 324#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
323 325
324#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
325
326typedef signed char BcDig; 326typedef signed char BcDig;
327 327
328typedef struct BcNum { 328typedef struct BcNum {
@@ -1138,6 +1138,18 @@ static void quit(void)
1138 exit(0); 1138 exit(0);
1139} 1139}
1140 1140
1141static int bc_error(const char *fmt, ...)
1142{
1143 va_list p;
1144
1145 va_start(p, fmt);
1146 bb_verror_msg(fmt, p, NULL);
1147 va_end(p);
1148 if (!G.ttyin)
1149 exit(1);
1150 return BC_STATUS_FAILURE;
1151}
1152
1141static void bc_vec_grow(BcVec *v, size_t n) 1153static void bc_vec_grow(BcVec *v, size_t n)
1142{ 1154{
1143 size_t cap = v->cap * 2; 1155 size_t cap = v->cap * 2;
@@ -1289,54 +1301,63 @@ static size_t bc_map_index(const BcVec *v, const void *ptr)
1289 1301
1290static BcStatus bc_read_line(BcVec *vec, const char *prompt) 1302static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1291{ 1303{
1292 int i; 1304 bool bad_chars;
1293 signed char c;
1294 1305
1295 bc_vec_npop(vec, vec->len); 1306 do {
1307 int i;
1308 char c;
1296 1309
1297 fflush_and_check(); 1310 bad_chars = 0;
1311 bc_vec_npop(vec, vec->len);
1312
1313 fflush_and_check();
1298#if ENABLE_FEATURE_BC_SIGNALS 1314#if ENABLE_FEATURE_BC_SIGNALS
1299 if (bb_got_signal) { // ^C was pressed 1315 if (bb_got_signal) { // ^C was pressed
1300 intr: 1316 intr:
1301 bb_got_signal = 0; // resets G_interrupt to zero 1317 bb_got_signal = 0; // resets G_interrupt to zero
1302 fputs(IS_BC 1318 fputs(IS_BC
1303 ? "\ninterrupt (type \"quit\" to exit)\n" 1319 ? "\ninterrupt (type \"quit\" to exit)\n"
1304 : "\ninterrupt (type \"q\" to exit)\n" 1320 : "\ninterrupt (type \"q\" to exit)\n"
1305 , stderr); 1321 , stderr);
1306 } 1322 }
1307#endif 1323#endif
1308 if (G.ttyin && !G_posix) 1324 if (G.ttyin && !G_posix)
1309 fputs(prompt, stderr); 1325 fputs(prompt, stderr);
1310 fflush_and_check();
1311 1326
1312#if ENABLE_FEATURE_BC_SIGNALS 1327#if ENABLE_FEATURE_BC_SIGNALS
1313 errno = 0; 1328 errno = 0;
1314#endif 1329#endif
1315 do { 1330 do {
1316 i = fgetc(stdin); 1331 i = fgetc(stdin);
1317 1332 if (i == EOF) {
1318 if (i == EOF) {
1319#if ENABLE_FEATURE_BC_SIGNALS 1333#if ENABLE_FEATURE_BC_SIGNALS
1320 // Both conditions appear simultaneously, check both just in case 1334 // Both conditions appear simultaneously, check both just in case
1321 if (errno == EINTR || bb_got_signal) { 1335 if (errno == EINTR || bb_got_signal) {
1322 // ^C was pressed 1336 // ^C was pressed
1323 clearerr(stdin); 1337 clearerr(stdin);
1324 goto intr; 1338 goto intr;
1325 } 1339 }
1326#endif 1340#endif
1327 if (ferror(stdin)) 1341 if (ferror(stdin))
1328 quit(); // this emits error message 1342 quit(); // this emits error message
1329 G.eof = 1; 1343 G.eof = 1;
1330 // Note: EOF does not append '\n', therefore: 1344 // Note: EOF does not append '\n', therefore:
1331 // printf 'print 123\n' | bc - works 1345 // printf 'print 123\n' | bc - works
1332 // printf 'print 123' | bc - fails (syntax error) 1346 // printf 'print 123' | bc - fails (syntax error)
1333 break; 1347 break;
1334 } 1348 }
1335 1349
1336 c = (signed char) i; 1350 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1337 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE; 1351 || i > 0x7e
1338 bc_vec_push(vec, &c); 1352 ) {
1339 } while (c != '\n'); 1353 // Bad chars on this line, ignore entire line
1354 bc_error("illegal character 0x%02x", i);
1355 bad_chars = 1;
1356 }
1357 c = (char) i;
1358 bc_vec_push(vec, &c);
1359 } while (i != '\n');
1360 } while (bad_chars);
1340 1361
1341 bc_vec_pushByte(vec, '\0'); 1362 bc_vec_pushByte(vec, '\0');
1342 1363
@@ -1352,7 +1373,10 @@ static char* bc_read_file(const char *path)
1352 buf = xmalloc_open_read_close(path, &size); 1373 buf = xmalloc_open_read_close(path, &size);
1353 1374
1354 for (i = 0; i < size; ++i) { 1375 for (i = 0; i < size; ++i) {
1355 if (BC_READ_BIN_CHAR(buf[i])) { 1376 char c = buf[i];
1377 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1378 || c > 0x7e
1379 ) {
1356 free(buf); 1380 free(buf);
1357 buf = NULL; 1381 buf = NULL;
1358 break; 1382 break;
@@ -3162,7 +3186,7 @@ static BcStatus bc_lex_token(BcLex *l)
3162 } 3186 }
3163 else { 3187 else {
3164 l->t.t = BC_LEX_INVALID; 3188 l->t.t = BC_LEX_INVALID;
3165 s = BC_STATUS_LEX_BAD_CHAR; 3189 s = bc_error("bad character '%c'", '&');
3166 } 3190 }
3167 3191
3168 break; 3192 break;
@@ -3291,7 +3315,7 @@ static BcStatus bc_lex_token(BcLex *l)
3291 ++l->i; 3315 ++l->i;
3292 } 3316 }
3293 else 3317 else
3294 s = BC_STATUS_LEX_BAD_CHAR; 3318 s = bc_error("bad character '%c'", c);
3295 break; 3319 break;
3296 } 3320 }
3297 3321
@@ -3353,7 +3377,7 @@ static BcStatus bc_lex_token(BcLex *l)
3353 } 3377 }
3354 else { 3378 else {
3355 l->t.t = BC_LEX_INVALID; 3379 l->t.t = BC_LEX_INVALID;
3356 s = BC_STATUS_LEX_BAD_CHAR; 3380 s = bc_error("bad character '%c'", c);
3357 } 3381 }
3358 3382
3359 break; 3383 break;
@@ -3362,7 +3386,7 @@ static BcStatus bc_lex_token(BcLex *l)
3362 default: 3386 default:
3363 { 3387 {
3364 l->t.t = BC_LEX_INVALID; 3388 l->t.t = BC_LEX_INVALID;
3365 s = BC_STATUS_LEX_BAD_CHAR; 3389 s = bc_error("bad character '%c'", c);
3366 break; 3390 break;
3367 } 3391 }
3368 } 3392 }
@@ -3473,7 +3497,7 @@ static BcStatus dc_lex_token(BcLex *l)
3473 else if (c2 == '>') 3497 else if (c2 == '>')
3474 l->t.t = BC_LEX_OP_REL_GE; 3498 l->t.t = BC_LEX_OP_REL_GE;
3475 else 3499 else
3476 return BC_STATUS_LEX_BAD_CHAR; 3500 return bc_error("bad character '%c'", c);
3477 3501
3478 ++l->i; 3502 ++l->i;
3479 break; 3503 break;
@@ -3490,7 +3514,7 @@ static BcStatus dc_lex_token(BcLex *l)
3490 if (isdigit(l->buf[l->i])) 3514 if (isdigit(l->buf[l->i]))
3491 s = bc_lex_number(l, c); 3515 s = bc_lex_number(l, c);
3492 else 3516 else
3493 s = BC_STATUS_LEX_BAD_CHAR; 3517 s = bc_error("bad character '%c'", c);
3494 break; 3518 break;
3495 } 3519 }
3496 3520
@@ -3524,7 +3548,7 @@ static BcStatus dc_lex_token(BcLex *l)
3524 default: 3548 default:
3525 { 3549 {
3526 l->t.t = BC_LEX_INVALID; 3550 l->t.t = BC_LEX_INVALID;
3527 s = BC_STATUS_LEX_BAD_CHAR; 3551 s = bc_error("bad character '%c'", c);
3528 break; 3552 break;
3529 } 3553 }
3530 } 3554 }
@@ -6938,7 +6962,7 @@ static BcStatus bc_vm_file(const char *file)
6938 6962
6939 G.prog.file = file; 6963 G.prog.file = file;
6940 data = bc_read_file(file); 6964 data = bc_read_file(file);
6941 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0); 6965 if (!data) return bc_error("file '%s' is not text", file);
6942 6966
6943 bc_lex_file(&G.prs.l, file); 6967 bc_lex_file(&G.prs.l, file);
6944 s = bc_vm_process(data); 6968 s = bc_vm_process(data);
@@ -7021,8 +7045,6 @@ static BcStatus bc_vm_stdin(void)
7021 bc_vec_npop(&buffer, buffer.len); 7045 bc_vec_npop(&buffer, buffer.len);
7022 } 7046 }
7023 7047
7024 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
7025
7026 if (str) 7048 if (str)
7027 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f, 7049 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7028 G.prs.l.line); 7050 G.prs.l.line);