From 3246da21984e4e875adfb8263004a51587bbe71d Mon Sep 17 00:00:00 2001 From: benswick Date: Thu, 13 Jul 2017 11:23:14 -0500 Subject: [PATCH] Support returning a JSONError value from the parse functions --- parson.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- parson.h | 1 + 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/parson.c b/parson.c index 384280e..fb4dfb6 100644 --- a/parson.c +++ b/parson.c @@ -129,6 +129,7 @@ static JSON_Value * parse_boolean_value(const char **string); static JSON_Value * parse_number_value(const char **string); static JSON_Value * parse_null_value(const char **string); static JSON_Value * parse_value(const char **string, size_t nesting); +static JSON_Value * parse_error(const char* start, const char* end); /* Serialization */ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf); @@ -1049,14 +1050,100 @@ JSON_Value * json_parse_file_with_comments(const char *filename) { return output_value; } +#if defined(PARSON_RETURN_ERROR_VALUES) + +static size_t get_line_number(const char* start, const char* end, size_t max) { + size_t count = 1; + if (start == NULL || end == NULL) { + return 1; + } + while (start != end) { + if (*start == '\n') { + count++; + + /* bail out early if the max is reached */ + if (count >= max) { + count = max; + break; + } + } + start++; + } + return count; +} + +static size_t get_line_byte_count(const char* start, size_t max) { + size_t i = 0; + if (start == NULL) { + return 0; + } + while (i < max && start[i] != '\0' && start[i] != '\r' && start[i] != '\n') { + i++; + } + return i; +} + +static JSON_Value * parse_error(const char* start, const char* end) { + /* If the type of the display number is changed + the error format string and value of n need changed too. */ + unsigned long display_number, max_display_number = (unsigned long)-1; + size_t n, max_line_length, line_length, line_number; + char *error_string; + JSON_Value *value = NULL; + const char* error_format = "Error on line %lu: %.*s"; + + value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (value == NULL) { + return NULL; + } + + /* Create a string long enough for the error message */ + max_line_length = 50; + /* Subtract the specifier characters from the format and + add enough space to hold a 64 bit unsigned integer. */ + n = strlen(error_format) - 7 + 20 + max_line_length + 1; + error_string = (char*)parson_malloc(n); + if (!error_string) { + parson_free(value); + return NULL; + } + + line_length = get_line_byte_count(end, max_line_length); + line_number = get_line_number(start, end, max_display_number); + display_number = line_number; + + /* If the format string is changed, the malloc() size needs changed too */ + sprintf(error_string, error_format, display_number, (int)line_length, end); + error_string[n] = '\0'; + + value->parent = NULL; + value->type = JSONError; + value->value.string = error_string; + return value; +} +#else +static JSON_Value * parse_error(const char* start, const char* end) { + /* Ignore the unused arguments */ + (void)start; + (void)end; + return NULL; +} +#endif + JSON_Value * json_parse_string(const char *string) { + JSON_Value *value; + const char *string_start = string; if (string == NULL) { return NULL; } if (string[0] == '\xEF' && string[1] == '\xBB' && string[2] == '\xBF') { string = string + 3; /* Support for UTF-8 BOM */ } - return parse_value((const char**)&string, 0); + value = parse_value((const char**)&string, 0); + if (!value) { + value = parse_error(string_start, string); + } + return value; } JSON_Value * json_parse_string_with_comments(const char *string) { @@ -1070,6 +1157,10 @@ JSON_Value * json_parse_string_with_comments(const char *string) { remove_comments(string_mutable_copy, "//", "\n"); string_mutable_copy_ptr = string_mutable_copy; result = parse_value((const char**)&string_mutable_copy_ptr, 0); + if (!result) { + /* Note that line numbers may be off from multi-line comments */ + result = parse_error(string_mutable_copy, string_mutable_copy_ptr); + } parson_free(string_mutable_copy); return result; } @@ -1225,6 +1316,10 @@ const char * json_value_get_string(const JSON_Value *value) { return json_value_get_type(value) == JSONString ? value->value.string : NULL; } +const char * json_value_get_error(const JSON_Value *value) { + return json_value_get_type(value) == JSONError ? value->value.string : NULL; +} + double json_value_get_number(const JSON_Value *value) { return json_value_get_type(value) == JSONNumber ? value->value.number : 0; } @@ -1243,6 +1338,7 @@ void json_value_free(JSON_Value *value) { json_object_free(value->value.object); break; case JSONString: + case JSONError: parson_free(value->value.string); break; case JSONArray: @@ -2005,3 +2101,4 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu parson_malloc = malloc_fun; parson_free = free_fun; } + diff --git a/parson.h b/parson.h index 6438c93..291ebf9 100644 --- a/parson.h +++ b/parson.h @@ -215,6 +215,7 @@ JSON_Value_Type json_value_get_type (const JSON_Value *value); JSON_Object * json_value_get_object (const JSON_Value *value); JSON_Array * json_value_get_array (const JSON_Value *value); const char * json_value_get_string (const JSON_Value *value); +const char * json_value_get_error (const JSON_Value *value); double json_value_get_number (const JSON_Value *value); int json_value_get_boolean(const JSON_Value *value); JSON_Value * json_value_get_parent (const JSON_Value *value);