From bb5d4efb2ef9609bcd1163238bccd11a1df28095 Mon Sep 17 00:00:00 2001 From: Petri Lehtinen Date: Tue, 26 Oct 2010 21:05:40 +0300 Subject: [PATCH] Make json_error_t transparent again After looking at the new code for a few days, I didn't like it anymore. To prepare for the future, a few fields will be added to the json_error_t struct later. This reverts commit 23dd078c8dcb17fd29d3b69f082b5b93f5f13b8f. Some adjustments were needed because of newer commits. --- doc/apiref.rst | 119 ++++++++++++++++++------------------------ src/jansson.h | 18 ++++--- src/jansson_private.h | 7 --- src/load.c | 71 +++++++++++-------------- src/variadic.c | 29 +++++----- test/bin/json_process.c | 7 +-- test/suites/api/check-exports | 2 - test/suites/api/test_load.c | 9 ++-- 8 files changed, 108 insertions(+), 154 deletions(-) diff --git a/doc/apiref.rst b/doc/apiref.rst index f11960d..ae55048 100644 --- a/doc/apiref.rst +++ b/doc/apiref.rst @@ -665,93 +665,74 @@ affect especially the behavior of the decoder. .. type:: json_error_t - This opaque structure is used to return information on errors from - the decoding functions. See below for more discussion on error - reporting. + This data structure is used to return information on decoding + errors from the decoding functions. Its definition is repeated + here:: -The following functions perform the JSON decoding: + #define JSON_ERROR_TEXT_LENGTH 160 -.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t **error) + typedef struct { + char text[JSON_ERROR_TEXT_LENGTH]; + int line; + } json_error_t; - .. refcounting:: new - - Decodes the JSON string *input* and returns the array or object it - contains, or *NULL* on error. If *error* is non-*NULL*, it's used - to return error information. See below for more discussion on error - reporting. *flags* is currently unused, and should be set to 0. - -.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t **error) + *line* is the line number on which the error occurred, or -1 if + this information is not available. *text* contains the error + message (in UTF-8), or an empty string if a message is not + available. - .. refcounting:: new + The normal usef of :type:`json_error_t` is to allocate it normally + on the stack, and pass a pointer to a decoding function. Example:: - Decodes the JSON text in stream *input* and returns the array or - object it contains, or *NULL* on error. If *error* is non-*NULL*, - it's used to return error information. See below for more - discussion on error reporting. *flags* is currently unused, and - should be set to 0. + int main() { + json_t *json; + json_error_t error; -.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t **error) + json = json_load_file("/path/to/file.json", 0, &error); + if(!json) { + /* the error variable contains error information */ + } + ... + } - .. refcounting:: new + Also note that if the decoding succeeded (``json != NULL`` in the + above example), the contents of ``error`` are unspecified. - Decodes the JSON text in file *path* and returns the array or - object it contains, or *NULL* on error. If *error* is non-*NULL*, - it's used to return error information. See below for more - discussion on error reporting. *flags* is currently unused, and - should be set to 0. - - -The :type:`json_error_t` parameter, that all decoding function accept -as their last parameter, is used to return information on decoding -errors to the caller. It is used by having a ``json_error_t *`` -variable and passing a pointer to this variable to a decoding -function. Example:: - - int main() { - json_t *json; - json_error_t *error; - - json = json_load_file("/path/to/file.json", 0, &error); - if(!json) { - /* the error variable contains error information */ - fprintf(stderr, "Decoding error occured on line %d: %s\n", json_error_line(error), json_error_msg(error)); - free(error); - } - - /* ... */ - } + All decoding functions also accept *NULL* as the + :type:`json_error_t` pointer, in which case no error information + is returned to the caller. -Note that **the caller must free the error structure** after use if a -decoding error occurs. If decoding is succesfully finished, *error* is -simply set to *NULL* by the decoding function. +The following functions perform the actual JSON decoding. -All decoding functions also accept *NULL* as the :type:`json_error_t` -pointer, in which case no error information is returned to the caller. -Example:: +.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error) - int main() { - json_t *json; + .. refcounting:: new - json = json_load_file("/path/to/file.json", 0, NULL); - if(!json) { - /* A decoding error occured but no error information is available */ - } + Decodes the JSON string *input* and returns the array or object it + contains, or *NULL* on error, in which case *error* is filled with + information about the error. See above for discussion on the + *error* parameter. *flags* is currently unused, and should be set + to 0. - /* ... */ - } +.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) -:type:`json_error_t` is totally opaque and must be queried using the -following functions: + .. refcounting:: new -.. function:: const char *json_error_msg(const json_error_t *error) + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. See above for discussion + on the *error* parameter. *flags* is currently unused, and should + be set to 0. - Return a pointer to an UTF-8 encoded string that describes the - error in human-readable text, or *NULL* if *error* is *NULL*. +.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error) -.. function:: int json_error_line(const json_error_t *error) + .. refcounting:: new - Return the line numer on which the error occurred, or -1 if this - information is not available or if *error* is *NULL*. + Decodes the JSON text in file *path* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. See above for discussion + on the *error* parameter. *flags* is currently unused, and should + be set to 0. Equality diff --git a/src/jansson.h b/src/jansson.h index 0f1de8d..130dc95 100644 --- a/src/jansson.h +++ b/src/jansson.h @@ -87,10 +87,12 @@ void json_decref(json_t *json) /* error reporting */ -typedef struct json_error_t json_error_t; +#define JSON_ERROR_TEXT_LENGTH 160 -const char *json_error_msg(const json_error_t *error); -int json_error_line(const json_error_t *error); +typedef struct { + char text[JSON_ERROR_TEXT_LENGTH]; + int line; +} json_error_t; /* getters, setters, manipulation */ @@ -164,8 +166,8 @@ int json_string_set_nocheck(json_t *string, const char *value); int json_integer_set(json_t *integer, json_int_t value); int json_real_set(json_t *real, double value); -json_t *json_pack(json_error_t **error, const char *fmt, ...); -int json_unpack(json_t *root, json_error_t **error, const char *fmt, ...); +json_t *json_pack(json_error_t *error, const char *fmt, ...); +int json_unpack(json_t *root, json_error_t *error, const char *fmt, ...); /* equality */ @@ -180,9 +182,9 @@ json_t *json_deep_copy(json_t *value); /* loading, printing */ -json_t *json_loads(const char *input, size_t flags, json_error_t **error); -json_t *json_loadf(FILE *input, size_t flags, json_error_t **error); -json_t *json_load_file(const char *path, size_t flags, json_error_t **error); +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); #define JSON_INDENT(n) (n & 0x1F) #define JSON_COMPACT 0x20 diff --git a/src/jansson_private.h b/src/jansson_private.h index 2d2af62..e9102ba 100644 --- a/src/jansson_private.h +++ b/src/jansson_private.h @@ -63,11 +63,4 @@ typedef struct { const object_key_t *jsonp_object_iter_fullkey(void *iter); -#define JSON_ERROR_MSG_LENGTH 160 - -struct json_error_t { - char msg[JSON_ERROR_MSG_LENGTH]; - int line; -}; - #endif diff --git a/src/load.c b/src/load.c index 54bfab8..925a850 100644 --- a/src/load.c +++ b/src/load.c @@ -60,64 +60,53 @@ typedef struct { /*** error reporting ***/ -const char *json_error_msg(const json_error_t *error) -{ - return error ? error->msg : NULL; -} - -int json_error_line(const json_error_t *error) -{ - return error ? error->line : -1; -} - -static void error_init(json_error_t **error) +static void error_init(json_error_t *error) { if(error) - *error = NULL; + { + error->text[0] = '\0'; + error->line = -1; + } } -static void error_set(json_error_t **error, const lex_t *lex, +static void error_set(json_error_t *error, const lex_t *lex, const char *msg, ...) { va_list ap; - char text[JSON_ERROR_MSG_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; - if(!error || *error) { - /* error not given or already set */ + if(!error || error->text[0] != '\0') { + /* error already set */ return; } - *error = malloc(sizeof(json_error_t)); - if(!(*error)) - return; - va_start(ap, msg); - vsnprintf(text, JSON_ERROR_MSG_LENGTH, msg, ap); + vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap); va_end(ap); if(lex) { const char *saved_text = strbuffer_value(&lex->saved_text); - (*error)->line = lex->line; + error->line = lex->line; if(saved_text && saved_text[0]) { if(lex->saved_text.length <= 20) { - snprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, + snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s near '%s'", text, saved_text); } else - snprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, "%s", text); + snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); } else { - snprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, + snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s near end of file", text); } } else { - (*error)->line = -1; - snprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, "%s", text); + error->line = -1; + snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); } } @@ -135,7 +124,7 @@ stream_init(stream_t *stream, get_func get, eof_func eof, void *data) stream->buffer_pos = 0; } -static char stream_get(stream_t *stream, json_error_t **error) +static char stream_get(stream_t *stream, json_error_t *error) { char c; @@ -193,7 +182,7 @@ static void stream_unget(stream_t *stream, char c) } -static int lex_get(lex_t *lex, json_error_t **error) +static int lex_get(lex_t *lex, json_error_t *error) { return stream_get(&lex->stream, error); } @@ -208,7 +197,7 @@ static void lex_save(lex_t *lex, char c) strbuffer_append_byte(&lex->saved_text, c); } -static int lex_get_save(lex_t *lex, json_error_t **error) +static int lex_get_save(lex_t *lex, json_error_t *error) { char c = stream_get(&lex->stream, error); lex_save(lex, c); @@ -256,7 +245,7 @@ static int32_t decode_unicode_escape(const char *str) return value; } -static void lex_scan_string(lex_t *lex, json_error_t **error) +static void lex_scan_string(lex_t *lex, json_error_t *error) { char c; const char *p; @@ -418,7 +407,7 @@ out: #define json_strtoint strtol #endif -static int lex_scan_number(lex_t *lex, char c, json_error_t **error) +static int lex_scan_number(lex_t *lex, char c, json_error_t *error) { const char *saved_text; char *end; @@ -515,7 +504,7 @@ out: return -1; } -static int lex_scan(lex_t *lex, json_error_t **error) +static int lex_scan(lex_t *lex, json_error_t *error) { char c; @@ -621,9 +610,9 @@ static void lex_close(lex_t *lex) /*** parser ***/ -static json_t *parse_value(lex_t *lex, json_error_t **error); +static json_t *parse_value(lex_t *lex, json_error_t *error); -static json_t *parse_object(lex_t *lex, json_error_t **error) +static json_t *parse_object(lex_t *lex, json_error_t *error) { json_t *object = json_object(); if(!object) @@ -688,7 +677,7 @@ error: return NULL; } -static json_t *parse_array(lex_t *lex, json_error_t **error) +static json_t *parse_array(lex_t *lex, json_error_t *error) { json_t *array = json_array(); if(!array) @@ -728,7 +717,7 @@ error: return NULL; } -static json_t *parse_value(lex_t *lex, json_error_t **error) +static json_t *parse_value(lex_t *lex, json_error_t *error) { json_t *json; @@ -783,7 +772,7 @@ static json_t *parse_value(lex_t *lex, json_error_t **error) return json; } -static json_t *parse_json(lex_t *lex, json_error_t **error) +static json_t *parse_json(lex_t *lex, json_error_t *error) { error_init(error); @@ -822,7 +811,7 @@ static int string_eof(void *data) return (stream->data[stream->pos] == '\0'); } -json_t *json_loads(const char *string, size_t flags, json_error_t **error) +json_t *json_loads(const char *string, size_t flags, json_error_t *error) { lex_t lex; json_t *result; @@ -849,7 +838,7 @@ out: return result; } -json_t *json_loadf(FILE *input, size_t flags, json_error_t **error) +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) { lex_t lex; json_t *result; @@ -874,7 +863,7 @@ out: return result; } -json_t *json_load_file(const char *path, size_t flags, json_error_t **error) +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) { json_t *result; FILE *fp; diff --git a/src/variadic.c b/src/variadic.c index 765be83..7b9c9fc 100644 --- a/src/variadic.c +++ b/src/variadic.c @@ -13,35 +13,32 @@ #include #include "jansson_private.h" -static void error_init(json_error_t **error) +static void error_init(json_error_t *error) { if(error) - *error = NULL; + { + error->text[0] = '\0'; + error->line = -1; + } } -static void error_set(json_error_t **error, const int line, const char *msg, ...) +static void error_set(json_error_t *error, const int line, const char *msg, ...) { va_list ap; - if(!error || *error) - return; - - *error = calloc(1, sizeof(json_error_t)); - if(!*error) + if(!error || error->text[0] != '\0') { + /* error already set */ return; + } - va_start(ap, msg); - vsnprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, msg, ap); - va_end(ap); + error->line = line; va_start(ap, msg); - vfprintf(stderr, msg, ap); + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); va_end(ap); - - (*error)->line = line; } -json_t *json_pack(json_error_t **error, const char *fmt, ...) { +json_t *json_pack(json_error_t *error, const char *fmt, ...) { int fmt_length = strlen(fmt); va_list ap; @@ -286,7 +283,7 @@ out: return(root); } -int json_unpack(json_t *root, json_error_t **error, const char *fmt, ...) { +int json_unpack(json_t *root, json_error_t *error, const char *fmt, ...) { va_list ap; int rv=0; /* Return value */ diff --git a/test/bin/json_process.c b/test/bin/json_process.c index 671127a..cff820b 100644 --- a/test/bin/json_process.c +++ b/test/bin/json_process.c @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) size_t flags = 0; json_t *json; - json_error_t *error; + json_error_t error; if(argc != 1) { fprintf(stderr, "usage: %s\n", argv[0]); @@ -61,10 +61,7 @@ int main(int argc, char *argv[]) json = json_loadf(stdin, 0, &error); if(!json) { - fprintf(stderr, "%d\n%s\n", - json_error_line(error), - json_error_msg(error)); - free(error); + fprintf(stderr, "%d\n%s\n", error.line, error.text); return 1; } diff --git a/test/suites/api/check-exports b/test/suites/api/check-exports index af22c28..f727bd4 100755 --- a/test/suites/api/check-exports +++ b/test/suites/api/check-exports @@ -47,8 +47,6 @@ json_object_iter_set_new json_dumps json_dumpf json_dump_file -json_error_line -json_error_msg json_loads json_loadf json_load_file diff --git a/test/suites/api/test_load.c b/test/suites/api/test_load.c index e121de3..b022a3a 100644 --- a/test/suites/api/test_load.c +++ b/test/suites/api/test_load.c @@ -12,16 +12,13 @@ int main() { json_t *json; - json_error_t *error; + json_error_t error; json = json_load_file("/path/to/nonexistent/file.json", 0, &error); - if(json) - fail("json_load didn't return an error!"); - if(json_error_line(error) != -1) + if(error.line != -1) fail("json_load_file returned an invalid line number"); - if(strcmp(json_error_msg(error), "unable to open /path/to/nonexistent/file.json: No such file or directory") != 0) + if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json: No such file or directory") != 0) fail("json_load_file returned an invalid error message"); - free(error); return 0; } -- 2.1.4