Improved error handling

This commit is contained in:
olemorud
2023-04-23 20:06:13 +02:00
parent 2445941ab6
commit 3839837dab

View File

@@ -26,24 +26,29 @@ double read_number(FILE* fp);
struct json_value** read_array(FILE* fp); struct json_value** read_array(FILE* fp);
void err_ctx(int exit_code, FILE* fp, const char* format, ...); void err_ctx(int exit_code, FILE* fp, const char* format, ...);
void print_object(obj_t obj, int cur_indent, int indent_amount); void print_object(obj_t obj, int cur_indent, int indent_amount);
void print_json_value(struct json_value val, int cur_indent, int indent_amount); void print_json_value(struct json_value val, int cur_indent, int indent_amount);
void print_array(struct json_value** arr, int cur_indent, int indent_amount); void print_array(struct json_value** arr, int cur_indent, int indent_amount);
// define as a macro to make debugging smoother // define as a macro to make debugging smoother
#define discard_whitespace(fp) \ #define discard_whitespace(fp) \
do { \ do { \
int c; \ int c; \
while (isspace(c = fgetc(fp))) { \ while (isspace(c = fgetc(fp))) { \
if (c == EOF) \ if (c == EOF) \
err(EARLY_EOF, "(%s) unexpected EOF", __func__); \ err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__); \
} \ } \
ungetc(c, fp); \ ungetc(c, fp); \
} while (0); } while (0);
/* /*
Prints parser errors with surrounding context. Prints parser errors with surrounding context and
terminates the program.
exit_code - code to exit with
fp - file causing parser errors
format - error message format string
... - format string arguments
*/ */
__attribute__((__noreturn__)) __attribute__((__noreturn__))
void err_ctx(int exit_code, FILE* fp, const char* format, ...) void err_ctx(int exit_code, FILE* fp, const char* format, ...)
@@ -57,13 +62,13 @@ void err_ctx(int exit_code, FILE* fp, const char* format, ...)
va_end(args); va_end(args);
if(fseek(fp, -(ERROR_CONTEXT_LEN/2), SEEK_CUR) == 0) { if(fseek(fp, -(ERROR_CONTEXT_LEN/2), SEEK_CUR) == 0) {
fread(context, sizeof(char), ERROR_CONTEXT_LEN, fp); size_t n_read = fread(context, sizeof(char), ERROR_CONTEXT_LEN, fp);
fprintf(stderr, "\ncontext:\n"); fprintf(stderr, "\ncontext:\n");
int arrow_offset = 0; int arrow_offset = 0;
int i; size_t i;
for (i = 0; i < ERROR_CONTEXT_LEN/2; i++) { for (i = 0; i < ERROR_CONTEXT_LEN/2 && i < n_read; i++) {
switch (context[i]) { switch (context[i]) {
case '\n': case '\n':
fprintf(stderr, "\\n"); fprintf(stderr, "\\n");
@@ -84,7 +89,7 @@ void err_ctx(int exit_code, FILE* fp, const char* format, ...)
} }
} }
for (; i < ERROR_CONTEXT_LEN; i++) { for (; i < ERROR_CONTEXT_LEN && i < n_read; i++) {
switch (context[i]) { switch (context[i]) {
case '\n': case '\n':
fprintf(stderr, "\\n"); fprintf(stderr, "\\n");
@@ -138,19 +143,19 @@ char* read_string(FILE* fp)
} }
switch (c = fgetc(fp)) { switch (c = fgetc(fp)) {
case '\\':
escaped = true;
result[i++] = c;
break;
default: default:
result[i++] = c; result[i++] = c;
break; break;
case '\\':
escaped = true;
// intentional fallthrough
case '"': case '"':
result[i++] = '\0'; result[i++] = '\0';
return realloc_or_die(result, i); return realloc_or_die(result, i);
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
} }
} }
} }
@@ -174,7 +179,7 @@ obj_t* read_object(FILE* fp)
switch (fgetc(fp)) { switch (fgetc(fp)) {
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
default: default:
err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected \"", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected \"", __func__);
@@ -195,7 +200,7 @@ obj_t* read_object(FILE* fp)
break; break;
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
default: default:
err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ':'", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) expected ':'", __func__);
@@ -216,7 +221,7 @@ obj_t* read_object(FILE* fp)
switch (fgetc(fp)) { switch (fgetc(fp)) {
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
case ',': case ',':
continue; continue;
@@ -256,7 +261,7 @@ struct json_value** read_array(FILE* fp)
switch (c) { switch (c) {
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
case ']': case ']':
output[i] = NULL; output[i] = NULL;
@@ -290,7 +295,7 @@ void read_null(FILE* fp)
size_t n_read = fread(buf, sizeof(char), sizeof(ok), fp); size_t n_read = fread(buf, sizeof(char), sizeof(ok), fp);
if (n_read != sizeof(ok)) if (n_read != sizeof(ok))
err(EXIT_FAILURE, "(%s) read failure", __func__); err_ctx(EXIT_FAILURE, fp, "(%s) read failure", __func__);
if (strncmp(buf, ok, sizeof(ok)) != 0) if (strncmp(buf, ok, sizeof(ok)) != 0)
err_ctx(UNEXPECTED_CHAR, fp, "(%s) unexpected symbol", __func__); err_ctx(UNEXPECTED_CHAR, fp, "(%s) unexpected symbol", __func__);
@@ -316,7 +321,7 @@ bool read_boolean(FILE* fp)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (strncmp(buf, t, sizeof(t)) == 0) { if (strncmp(buf, t, sizeof(t)) == 0) {
ungetc(buf[4], fp); ungetc('e', fp);
return true; return true;
} }
@@ -360,7 +365,7 @@ struct json_value parse_json_value(FILE* fp)
switch (c) { switch (c) {
case EOF: case EOF:
err(EARLY_EOF, "(%s) unexpected EOF", __func__); err_ctx(EARLY_EOF, fp, "(%s) unexpected EOF", __func__);
case '{': case '{':
result.type = object; result.type = object;