Improved error handling
This commit is contained in:
57
src/parse.c
57
src/parse.c
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user