summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c130
1 files changed, 76 insertions, 54 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index c819dec..dd01f54 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -169,13 +169,14 @@
typedef enum BcStatus {
BC_STATUS_SUCCESS,
+ BC_STATUS_FAILURE,
// BC_STATUS_ALLOC_ERR,
// BC_STATUS_INPUT_EOF,
- BC_STATUS_BIN_FILE,
+// BC_STATUS_BIN_FILE,
// BC_STATUS_PATH_IS_DIR,
- BC_STATUS_LEX_BAD_CHAR,
+// BC_STATUS_LEX_BAD_CHAR,
BC_STATUS_LEX_NO_STRING_END,
BC_STATUS_LEX_NO_COMMENT_END,
BC_STATUS_LEX_EOF,
@@ -239,12 +240,13 @@ typedef enum BcStatus {
// Keep enum above and messages below in sync!
static const char *const bc_err_msgs[] = {
NULL,
+ "",
// "memory allocation error",
// "I/O error",
- "file is not text:",
+// "file is not text:",
// "path is a directory:",
- "bad character",
+// "bad character",
"string end could not be found",
"comment end could not be found",
"end of file",
@@ -321,8 +323,6 @@ typedef struct BcVec {
#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
-#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
-
typedef signed char BcDig;
typedef struct BcNum {
@@ -1138,6 +1138,18 @@ static void quit(void)
exit(0);
}
+static int bc_error(const char *fmt, ...)
+{
+ va_list p;
+
+ va_start(p, fmt);
+ bb_verror_msg(fmt, p, NULL);
+ va_end(p);
+ if (!G.ttyin)
+ exit(1);
+ return BC_STATUS_FAILURE;
+}
+
static void bc_vec_grow(BcVec *v, size_t n)
{
size_t cap = v->cap * 2;
@@ -1289,54 +1301,63 @@ static size_t bc_map_index(const BcVec *v, const void *ptr)
static BcStatus bc_read_line(BcVec *vec, const char *prompt)
{
- int i;
- signed char c;
+ bool bad_chars;
- bc_vec_npop(vec, vec->len);
+ do {
+ int i;
+ char c;
- fflush_and_check();
+ bad_chars = 0;
+ bc_vec_npop(vec, vec->len);
+
+ fflush_and_check();
#if ENABLE_FEATURE_BC_SIGNALS
- if (bb_got_signal) { // ^C was pressed
+ if (bb_got_signal) { // ^C was pressed
intr:
- bb_got_signal = 0; // resets G_interrupt to zero
- fputs(IS_BC
- ? "\ninterrupt (type \"quit\" to exit)\n"
- : "\ninterrupt (type \"q\" to exit)\n"
- , stderr);
- }
+ bb_got_signal = 0; // resets G_interrupt to zero
+ fputs(IS_BC
+ ? "\ninterrupt (type \"quit\" to exit)\n"
+ : "\ninterrupt (type \"q\" to exit)\n"
+ , stderr);
+ }
#endif
- if (G.ttyin && !G_posix)
- fputs(prompt, stderr);
- fflush_and_check();
+ if (G.ttyin && !G_posix)
+ fputs(prompt, stderr);
#if ENABLE_FEATURE_BC_SIGNALS
- errno = 0;
+ errno = 0;
#endif
- do {
- i = fgetc(stdin);
-
- if (i == EOF) {
+ do {
+ i = fgetc(stdin);
+ if (i == EOF) {
#if ENABLE_FEATURE_BC_SIGNALS
- // Both conditions appear simultaneously, check both just in case
- if (errno == EINTR || bb_got_signal) {
- // ^C was pressed
- clearerr(stdin);
- goto intr;
- }
+ // Both conditions appear simultaneously, check both just in case
+ if (errno == EINTR || bb_got_signal) {
+ // ^C was pressed
+ clearerr(stdin);
+ goto intr;
+ }
#endif
- if (ferror(stdin))
- quit(); // this emits error message
- G.eof = 1;
- // Note: EOF does not append '\n', therefore:
- // printf 'print 123\n' | bc - works
- // printf 'print 123' | bc - fails (syntax error)
- break;
- }
+ if (ferror(stdin))
+ quit(); // this emits error message
+ G.eof = 1;
+ // Note: EOF does not append '\n', therefore:
+ // printf 'print 123\n' | bc - works
+ // printf 'print 123' | bc - fails (syntax error)
+ break;
+ }
- c = (signed char) i;
- if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
- bc_vec_push(vec, &c);
- } while (c != '\n');
+ if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
+ || i > 0x7e
+ ) {
+ // Bad chars on this line, ignore entire line
+ bc_error("illegal character 0x%02x", i);
+ bad_chars = 1;
+ }
+ c = (char) i;
+ bc_vec_push(vec, &c);
+ } while (i != '\n');
+ } while (bad_chars);
bc_vec_pushByte(vec, '\0');
@@ -1352,7 +1373,10 @@ static char* bc_read_file(const char *path)
buf = xmalloc_open_read_close(path, &size);
for (i = 0; i < size; ++i) {
- if (BC_READ_BIN_CHAR(buf[i])) {
+ char c = buf[i];
+ if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
+ || c > 0x7e
+ ) {
free(buf);
buf = NULL;
break;
@@ -3162,7 +3186,7 @@ static BcStatus bc_lex_token(BcLex *l)
}
else {
l->t.t = BC_LEX_INVALID;
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", '&');
}
break;
@@ -3291,7 +3315,7 @@ static BcStatus bc_lex_token(BcLex *l)
++l->i;
}
else
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", c);
break;
}
@@ -3353,7 +3377,7 @@ static BcStatus bc_lex_token(BcLex *l)
}
else {
l->t.t = BC_LEX_INVALID;
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", c);
}
break;
@@ -3362,7 +3386,7 @@ static BcStatus bc_lex_token(BcLex *l)
default:
{
l->t.t = BC_LEX_INVALID;
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", c);
break;
}
}
@@ -3473,7 +3497,7 @@ static BcStatus dc_lex_token(BcLex *l)
else if (c2 == '>')
l->t.t = BC_LEX_OP_REL_GE;
else
- return BC_STATUS_LEX_BAD_CHAR;
+ return bc_error("bad character '%c'", c);
++l->i;
break;
@@ -3490,7 +3514,7 @@ static BcStatus dc_lex_token(BcLex *l)
if (isdigit(l->buf[l->i]))
s = bc_lex_number(l, c);
else
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", c);
break;
}
@@ -3524,7 +3548,7 @@ static BcStatus dc_lex_token(BcLex *l)
default:
{
l->t.t = BC_LEX_INVALID;
- s = BC_STATUS_LEX_BAD_CHAR;
+ s = bc_error("bad character '%c'", c);
break;
}
}
@@ -6938,7 +6962,7 @@ static BcStatus bc_vm_file(const char *file)
G.prog.file = file;
data = bc_read_file(file);
- if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
+ if (!data) return bc_error("file '%s' is not text", file);
bc_lex_file(&G.prs.l, file);
s = bc_vm_process(data);
@@ -7021,8 +7045,6 @@ static BcStatus bc_vm_stdin(void)
bc_vec_npop(&buffer, buffer.len);
}
- if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
-
if (str)
s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
G.prs.l.line);