From f471e63bb30d16b0288c5e2c0722de41fc4a138f Mon Sep 17 00:00:00 2001 From: Petri Lehtinen Date: Mon, 23 Jan 2012 21:18:04 +0200 Subject: [PATCH] Write number of bytes read to error position on successful decode Closes #49. --- doc/apiref.rst | 49 +++++++++++++++++++++++++++++---------------- src/load.c | 7 ++++++- test/suites/api/test_load.c | 18 +++++++++++++++++ 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/doc/apiref.rst b/doc/apiref.rst index d6b89e3..5003a04 100644 --- a/doc/apiref.rst +++ b/doc/apiref.rst @@ -675,7 +675,9 @@ and pass a pointer to a function. Example:: } Also note that if the call succeeded (``json != NULL`` in the above -example), the contents of ``error`` are unspecified. +example), the contents of ``error`` are generally left unspecified. +The decoding functions write to the ``position`` member also on +success. See :ref:`apiref-decoding` for more info. All functions also accept *NULL* as the :type:`json_error_t` pointer, in which case no error information is returned to the caller. @@ -819,6 +821,17 @@ macros can be ORed together to obtain *flags*. .. versionadded:: 2.1 +``JSON_DECODE_ANY`` + By default, the decoder expects an array or object as the input. + With this flag enabled, the decoder accepts any valid JSON value. + + **Note:** Decoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatiblity with + :rfc:`4627`. If you use this flag, don't expect interoperatibility + with other JSON systems. + + .. versionadded:: 2.3 + ``JSON_DISABLE_EOF_CHECK`` By default, the decoder expects that its whole input constitutes a valid JSON text, and issues an error if there's extra data after @@ -826,18 +839,28 @@ macros can be ORed together to obtain *flags*. stops after decoding a valid JSON array or object, and thus allows extra data after the JSON text. + Normally, reading will stop when the last ``]`` or ``}`` in the + JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and + ``JSON_DECODE_ANY`` flags are used, the decoder may read one extra + UTF-8 code unit (up to 4 bytes of input). For example, decoding + ``4true`` correctly decodes the integer 4, but also reads the + ``t``. For this reason, if reading multiple consecutive values that + are not arrays or objects, they should be separated by at least one + whitespace character. + .. versionadded:: 2.1 -``JSON_DECODE_ANY`` - By default, the decoder expects an array or object as the input. - With this flag enabled, the decoder accepts any valid JSON value. +Each function also takes an optional :type:`json_error_t` parameter +that is filled with error information if decoding fails. It's also +updated on success; the number of bytes of input read is written to +its ``position`` field. This is especially useful when using +``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts. - **Note:** Decoding any value may be useful in some scenarios, but - it's generally discouraged as it violates strict compatiblity with - :rfc:`4627`. If you use this flag, don't expect interoperatibility - with other JSON systems. +.. versionadded:: 2.3 + Number of bytes of input read is written to the ``position`` field + of the :type:`json_error_t` structure. - .. versionadded:: 2.3 +If no error or position information is needed, you can pass *NULL*. The following functions perform the actual JSON decoding. @@ -880,14 +903,6 @@ The following functions perform the actual JSON decoding. multiple times, if the input consists of consecutive JSON texts, possibly separated by whitespace. - If both ``JSON_DISABLE_EOF_CHECK`` and ``JSON_DECODE_ANY`` flags - are used, the decoder may read one extra UTF-8 code unit (up to 4 - bytes of input). For example, decoding ``4true`` correctly decodes - the integer 4, but leaves the file position pointing at ``r`` - instead of ``t``. For this reason, if reading multiple consecutive - values that are not arrays and objects, they should be separated by - at least one whitespace character. - .. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error) .. refcounting:: new diff --git a/src/load.c b/src/load.c index f5cbf68..193db45 100644 --- a/src/load.c +++ b/src/load.c @@ -836,10 +836,15 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) if(lex->token != TOKEN_EOF) { error_set(error, lex, "end of file expected"); json_decref(result); - result = NULL; + return NULL; } } + if(error) { + /* Save the position even though there was no error */ + error->position = lex->stream.position; + } + return result; } diff --git a/test/suites/api/test_load.c b/test/suites/api/test_load.c index 8143d46..d8cb912 100644 --- a/test/suites/api/test_load.c +++ b/test/suites/api/test_load.c @@ -98,6 +98,23 @@ static void load_wrong_args() fail("json_loadf should return NULL if the first argument is NULL"); } +static void position() +{ + json_t *json; + size_t flags = JSON_DISABLE_EOF_CHECK; + json_error_t error; + + json = json_loads("{\"foo\": \"bar\"}", 0, &error); + if(error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); + + json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error); + if(error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); +} + static void run_tests() { file_not_found(); @@ -105,4 +122,5 @@ static void run_tests() disable_eof_check(); decode_any(); load_wrong_args(); + position(); } -- 2.1.4