From 9885b30c0ef4c40117851cf54c9c7e1ee2c1f3a3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:52:59 -0500 Subject: [PATCH 01/16] Perform better error checking in json_tokener_parse_verbose and rewrite json_tokener_parse to use that instead of json_tokener_parse_ex. Fix a typo in the string represenations of the json_tokener_error_depth error (s/to deep/too deep/) --- json_tokener.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 6d973ecfd9..04950b5081 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -47,7 +47,7 @@ static const char* json_false_str = "false"; const char* json_tokener_errors[] = { "success", "continue", - "nesting to deep", + "nesting too deep", "unexpected end of data", "unexpected character", "null expected", @@ -122,17 +122,10 @@ void json_tokener_reset(struct json_tokener *tok) struct json_object* json_tokener_parse(const char *str) { - struct json_tokener* tok; - struct json_object* obj; - - tok = json_tokener_new(); - if (!tok) - return NULL; - obj = json_tokener_parse_ex(tok, str, -1); - if(tok->err != json_tokener_success) - obj = NULL; - json_tokener_free(tok); - return obj; + enum json_tokener_error jerr_ignored; + struct json_object* obj; + obj = json_tokener_parse_verbose(str, &jerr_ignored); + return obj; } struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) @@ -141,9 +134,13 @@ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokene struct json_object* obj; tok = json_tokener_new(); + if (!tok) + return NULL; obj = json_tokener_parse_ex(tok, str, -1); *error = tok->err; if(tok->err != json_tokener_success) { + if (obj != NULL) + json_object_put(obj); obj = NULL; } From d7db7e81a51282ffc097408aa47927af8d4a39c1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:55:52 -0500 Subject: [PATCH 02/16] Ignore several more files, include .o's, .lo's, etc... --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 6acd8193eb..21b927dc5c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,10 +17,16 @@ Makefile Makefile.in missing stamp-h1 +stamp-h2 test1 test2 test4 testSubDir test_parse_int64 +test_cast +test_null Debug Release +*.lo +*.o +libjson.la From e6668b1406de33e29a0f91bc93f448a2423230d2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 13:47:28 -0500 Subject: [PATCH 03/16] Adjust json_object_is_type and json_object_get_type so they return json_type_null for NULL objects. --- json_object.c | 4 ++++ json_object.h | 2 ++ test_cast.c | 42 ++++++++++++++++++++++++++++++++++++++++++ test_cast.expected | 17 +++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/json_object.c b/json_object.c index 784863059c..ef54ecd40b 100644 --- a/json_object.c +++ b/json_object.c @@ -166,11 +166,15 @@ static struct json_object* json_object_new(enum json_type o_type) int json_object_is_type(struct json_object *jso, enum json_type type) { + if (!jso) + return (type == json_type_null); return (jso->o_type == type); } enum json_type json_object_get_type(struct json_object *jso) { + if (!jso) + return json_type_null; return jso->o_type; } diff --git a/json_object.h b/json_object.h index 1ee9fb0be5..e9898f41ed 100644 --- a/json_object.h +++ b/json_object.h @@ -79,6 +79,7 @@ extern void json_object_put(struct json_object *obj); * Check if the json_object is of a given type * @param obj the json_object instance * @param type one of: + json_type_null (i.e. obj == NULL), json_type_boolean, json_type_double, json_type_int, @@ -92,6 +93,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); * Get the type of the json_object * @param obj the json_object instance * @returns type being one of: + json_type_null (i.e. obj == NULL), json_type_boolean, json_type_double, json_type_int, diff --git a/test_cast.c b/test_cast.c index 6459250b5a..aad44d0a12 100644 --- a/test_cast.c +++ b/test_cast.c @@ -1,5 +1,6 @@ /* * Tests if casting within the json_object_get_* functions work correctly. + * Also checks the json_object_get_type and json_object_is_type functions. */ #include @@ -13,6 +14,8 @@ #include "json_util.h" static void getit(struct json_object *new_obj, const char *field); +static void checktype_header(void); +static void checktype(struct json_object *new_obj, const char *field); int main(int argc, char **argv) { @@ -23,6 +26,7 @@ int main(int argc, char **argv) \"boolean_true\": true,\n\ \"boolean_false\": false,\n\ \"big_number\": 2147483649,\n\ + \"a_null\": null,\n\ }"; /* Note: 2147483649 = INT_MAX + 2 */ @@ -40,6 +44,19 @@ int main(int argc, char **argv) getit(new_obj, "boolean_true"); getit(new_obj, "boolean_false"); getit(new_obj, "big_number"); + getit(new_obj, "a_null"); + + // Now check the behaviour of the json_object_is_type() function. + printf("\n================================\n"); + checktype_header(); + checktype(new_obj, NULL); + checktype(new_obj, "string_of_digits"); + checktype(new_obj, "regular_number"); + checktype(new_obj, "decimal_number"); + checktype(new_obj, "boolean_true"); + checktype(new_obj, "boolean_false"); + checktype(new_obj, "big_number"); + checktype(new_obj, "a_null"); json_object_put(new_obj); @@ -62,3 +79,28 @@ static void getit(struct json_object *new_obj, const char *field) printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); } + +static void checktype_header() +{ + printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n", + json_type_to_name(json_type_null), + json_type_to_name(json_type_boolean), + json_type_to_name(json_type_double), + json_type_to_name(json_type_int), + json_type_to_name(json_type_object), + json_type_to_name(json_type_array), + json_type_to_name(json_type_string)); +} +static void checktype(struct json_object *new_obj, const char *field) +{ + struct json_object *o = field ? json_object_object_get(new_obj, field) : new_obj; + printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n", + field ? "." : " ", field ? field : "", + json_object_is_type(o, json_type_null), + json_object_is_type(o, json_type_boolean), + json_object_is_type(o, json_type_double), + json_object_is_type(o, json_type_int), + json_object_is_type(o, json_type_object), + json_object_is_type(o, json_type_array), + json_object_is_type(o, json_type_string)); +} diff --git a/test_cast.expected b/test_cast.expected index d079e04d39..76ff8231a5 100644 --- a/test_cast.expected +++ b/test_cast.expected @@ -5,6 +5,7 @@ Parsed input: { "boolean_true": true, "boolean_false": false, "big_number": 2147483649, + "a_null": null, } Result is not NULL new_obj.string_of_digits json_object_get_type()=string @@ -37,3 +38,19 @@ new_obj.big_number json_object_get_int()=2147483647 new_obj.big_number json_object_get_int64()=2147483649 new_obj.big_number json_object_get_boolean()=1 new_obj.big_number json_object_get_double()=2147483649.000000 +new_obj.a_null json_object_get_type()=null +new_obj.a_null json_object_get_int()=0 +new_obj.a_null json_object_get_int64()=0 +new_obj.a_null json_object_get_boolean()=0 +new_obj.a_null json_object_get_double()=0.000000 + +================================ +json_object_is_type: null,boolean,double,int,object,array,string +new_obj : 0,0,0,0,1,0,0 +new_obj.string_of_digits : 0,0,0,0,0,0,1 +new_obj.regular_number : 0,0,0,1,0,0,0 +new_obj.decimal_number : 0,0,1,0,0,0,0 +new_obj.boolean_true : 0,1,0,0,0,0,0 +new_obj.boolean_false : 0,1,0,0,0,0,0 +new_obj.big_number : 0,0,0,1,0,0,0 +new_obj.a_null : 1,0,0,0,0,0,0 From 7c4a9640028b6bf4ff635caeea75089cdad1a779 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 17:33:58 -0500 Subject: [PATCH 04/16] Define a LH_LOAD_FACTOR constant and note the range that it can be set to. Change the resize check from "count > size" to "count >= size" to avoid a potential infinite loop with high load factors and a full hash table. --- linkhash.c | 2 +- linkhash.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/linkhash.c b/linkhash.c index 3a9ba0e08f..88c0a7cfe8 100644 --- a/linkhash.c +++ b/linkhash.c @@ -125,7 +125,7 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) unsigned long h, n; t->inserts++; - if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2); + if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); h = t->hash_fn(k); n = h % t->size; diff --git a/linkhash.h b/linkhash.h index 90f219df36..9d894604c1 100644 --- a/linkhash.h +++ b/linkhash.h @@ -21,6 +21,13 @@ extern "C" { */ #define LH_PRIME 0x9e370001UL +/** + * The fraction of filled hash buckets until an insert will cause the table + * to be resized. + * This can range from just above 0 up to 1.0. + */ +#define LH_LOAD_FACTOR 0.66 + /** * sentinel pointer value for empty slots */ From 23d0da5870001b6faff76f21ab6dc57a00ae92e3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:47:47 -0500 Subject: [PATCH 05/16] Mention json_type_to_name() in the docs for json_object_get_type(). --- json_object.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/json_object.h b/json_object.h index e9898f41ed..72a870887d 100644 --- a/json_object.h +++ b/json_object.h @@ -90,7 +90,9 @@ extern void json_object_put(struct json_object *obj); extern int json_object_is_type(struct json_object *obj, enum json_type type); /** - * Get the type of the json_object + * Get the type of the json_object. See also json_type_to_name() to turn this + * into a string suitable, for instance, for logging. + * * @param obj the json_object instance * @returns type being one of: json_type_null (i.e. obj == NULL), From bb7978c95ffbb1afd78767309ef3c30a93ee62ab Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:49:58 -0500 Subject: [PATCH 06/16] For the prototype for json_tokener_error_desc(). --- json_tokener.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_tokener.h b/json_tokener.h index be7f87df39..d104c75f3d 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -88,13 +88,13 @@ struct json_tokener * * @return a generic error message is returned if an invalid error value is provided. */ -const char *json_tokeners_errors(enum json_tokener_error jerr); +const char *json_tokener_error_desc(enum json_tokener_error jerr); /** * @b XXX do not use json_tokener_errors directly. * After v0.10 this will be removed. * - * See json_tokeners_errors() instead. + * See json_tokener_error_desc() instead. */ extern const char* json_tokener_errors[]; @@ -162,7 +162,7 @@ do { } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); if (jerr != json_tokener_success) { - fprintf(stderr, "Error: %s\n", json_tokener_errors[jerr]); + fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); // Handle errors, as appropriate for your application. } if (tok->char_offset < stringlen) // XXX shouldn't access internal fields From 30c6c4a1be41a59ea9335bc3566371276a72763f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:51:39 -0500 Subject: [PATCH 07/16] Split the json_tokener_parse tests off from test1 into their own test and add several more cases to check various incremental parsing situations. --- .gitignore | 1 + Makefile.am | 7 +- test1.c | 108 ------------------ test1.expected | 23 ---- test_parse.c | 270 ++++++++++++++++++++++++++++++++++++++++++++ test_parse.expected | 46 ++++++++ test_parse.test | 12 ++ 7 files changed, 334 insertions(+), 133 deletions(-) create mode 100644 test_parse.c create mode 100644 test_parse.expected create mode 100755 test_parse.test diff --git a/.gitignore b/.gitignore index 21b927dc5c..091ae7a005 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ test2 test4 testSubDir test_parse_int64 +test_parse test_cast test_null Debug diff --git a/Makefile.am b/Makefile.am index e31da7730c..07e610d864 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -58,7 +58,10 @@ test_null_LDADD = $(lib_LTLIBRARIES) test_cast_SOURCES = test_cast.c test_cast_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test +test_parse_SOURCES = test_parse.c +test_parse_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/test1.c b/test1.c index 1ca4db9336..e1e411d96a 100644 --- a/test1.c +++ b/test1.c @@ -31,9 +31,7 @@ static int sort_fn (const void *j1, const void *j2) int main(int argc, char **argv) { - json_tokener *tok; json_object *my_string, *my_int, *my_object, *my_array; - json_object *new_obj; int i; MC_SET_DEBUG(1); @@ -104,112 +102,6 @@ int main(int argc, char **argv) } printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); - new_obj = json_tokener_parse("\"\003\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("/* hello */\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("// hello\n\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("null"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("True"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12.3"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[null]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[false]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{}"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - enum json_tokener_error error = json_tokener_success; - new_obj = json_tokener_parse_verbose("{ foo }", &error); - assert (error == json_tokener_error_parse_object_key_name); - assert (new_obj == NULL); - - new_obj = json_tokener_parse("{ foo }"); - assert (new_obj == NULL); - - // if(is_error(new_obj)) printf("got error as expected\n"); - - new_obj = json_tokener_parse("foo"); - assert (new_obj == NULL); - new_obj = json_tokener_parse_verbose("foo", &error); - assert (new_obj == NULL); - assert (error == json_tokener_error_parse_boolean); - - new_obj = json_tokener_parse("{ \"foo"); - if(is_error(new_obj)) printf("got error as expected\n"); - - /* test incremental parsing */ - tok = json_tokener_new(); - new_obj = json_tokener_parse_ex(tok, "{ \"foo", 6); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\": {\"bar", 8); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\":13}}", 6); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - json_tokener_free(tok); - json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); diff --git a/test1.expected b/test1.expected index aad9af0c05..6653fe0bc5 100644 --- a/test1.expected +++ b/test1.expected @@ -33,26 +33,3 @@ my_object= bool0: false bool1: true my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } -new_obj.to_string()="\u0003" -new_obj.to_string()="foo" -new_obj.to_string()="foo" -new_obj.to_string()="ABC" -new_obj.to_string()=null -new_obj.to_string()=true -new_obj.to_string()=12 -new_obj.to_string()=12.300000 -new_obj.to_string()=[ "\n" ] -new_obj.to_string()=[ "\nabc\n" ] -new_obj.to_string()=[ null ] -new_obj.to_string()=[ ] -new_obj.to_string()=[ false ] -new_obj.to_string()=[ "abc", null, "def", 12 ] -new_obj.to_string()={ } -new_obj.to_string()={ "foo": "bar" } -new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } -new_obj.to_string()={ "foo": [ null, "foo" ] } -new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } -got error as expected -got error as expected -got error as expected -new_obj.to_string()={ "foo": { "bar": 13 } } diff --git a/test_parse.c b/test_parse.c new file mode 100644 index 0000000000..0040760d76 --- /dev/null +++ b/test_parse.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +#include "json.h" +#include "json_tokener.h" + +static void test_basic_parse(void); +static void test_verbose_parse(void); +static void test_incremental_parse(void); + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + test_basic_parse(); + printf("==================================\n"); + test_verbose_parse(); + printf("==================================\n"); + test_incremental_parse(); + printf("==================================\n"); +} + +static void test_basic_parse() +{ + json_object *new_obj; + + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[false]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); +} + +static void test_verbose_parse() +{ + json_object *new_obj; + enum json_tokener_error error = json_tokener_success; + + new_obj = json_tokener_parse_verbose("{ foo }", &error); + assert (error == json_tokener_error_parse_object_key_name); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("{ foo }"); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("foo"); + assert (new_obj == NULL); + new_obj = json_tokener_parse_verbose("foo", &error); + assert (new_obj == NULL); + + /* b/c the string starts with 'f' parsing return a boolean error */ + assert (error == json_tokener_error_parse_boolean); + + printf("json_tokener_parse_versbose() OK\n"); +} + +struct incremental_step { + const char *string_to_parse; + int length; + int char_offset; + enum json_tokener_error expected_error; + int reset_tokener; +} incremental_steps[] = { + + /* Check that full json messages can be parsed, both w/ and w/o a reset */ + { "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 }, + { "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 }, + { "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 }, + + /* Check a basic incremental parse */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}", -1, -1, json_tokener_success, 1 }, + + /* Check that json_tokener_reset actually resets */ + { "{ \"foo", -1, -1, json_tokener_continue, 1 }, + { ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check incremental parsing with trailing characters */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}XXXX", 10, 6, json_tokener_success, 0 }, + { "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check that trailing characters can change w/o a reset */ + { "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 }, + { "\"Y\"", -1, -1, json_tokener_success, 1 }, + + /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ + { "1", 1, 1, json_tokener_continue, 0 }, + { "2", 2, 1, json_tokener_success, 0 }, + + /* Strings have a well defined end point, so we can stop at the quote */ + { "\"blue\"", -1, -1, json_tokener_success, 0 }, + + { "[1,2,3]", -1, -1, json_tokener_success, 0 }, + + /* This behaviour doesn't entirely follow the json spec, but until we have + a way to specify how strict to be we follow Postel's Law and be liberal + in what we accept (up to a point). */ + { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, + { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, + + { NULL, json_tokener_success }, +}; + +static void test_incremental_parse() +{ + json_object *new_obj; + enum json_tokener_error jerr; + json_tokener *tok; + const char *string_to_parse; + int ii; + int num_ok, num_error; + + num_ok = 0; + num_error = 0; + + printf("Starting incremental tests.\n"); + + string_to_parse = "{ \"foo"; /* } */ + printf("json_tokener_parse(%s) ... ", string_to_parse); + new_obj = json_tokener_parse(string_to_parse); + if (new_obj == NULL) printf("got error as expected\n"); + + /* test incremental parsing in various forms */ + tok = json_tokener_new(); + for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++) + { + int this_step_ok = 0; + struct incremental_step *step = &incremental_steps[ii]; + int length = step->length; + int expected_char_offset = step->char_offset; + if (length == -1) + length = strlen(step->string_to_parse); + if (expected_char_offset == -1) + expected_char_offset = length; + + printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ", + step->string_to_parse, length); + new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length); + + jerr = json_tokener_get_error(tok); + if (step->expected_error != json_tokener_success) + { + if (new_obj != NULL) + printf("ERROR: invalid object returned: %s\n", + json_object_to_json_string(new_obj)); + else if (jerr != step->expected_error) + printf("ERROR: got wrong error: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr)); + this_step_ok = 1; + } + } + else + { + if (new_obj == NULL) + printf("ERROR: expected valid object, instead: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got object of type [%s]: %s\n", + json_type_to_name(json_object_get_type(new_obj)), + json_object_to_json_string(new_obj)); + this_step_ok = 1; + } + } + + if (new_obj) + json_object_put(new_obj); + + if (step->reset_tokener) + json_tokener_reset(tok); + + if (this_step_ok) + num_ok++; + else + num_error++; + } + + json_tokener_free(tok); + + printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error); + + return; +} diff --git a/test_parse.expected b/test_parse.expected new file mode 100644 index 0000000000..2481bdeaab --- /dev/null +++ b/test_parse.expected @@ -0,0 +1,46 @@ +new_obj.to_string()="\u0003" +new_obj.to_string()="foo" +new_obj.to_string()="foo" +new_obj.to_string()="ABC" +new_obj.to_string()=null +new_obj.to_string()=true +new_obj.to_string()=12 +new_obj.to_string()=12.300000 +new_obj.to_string()=[ "\n" ] +new_obj.to_string()=[ "\nabc\n" ] +new_obj.to_string()=[ null ] +new_obj.to_string()=[ ] +new_obj.to_string()=[ false ] +new_obj.to_string()=[ "abc", null, "def", 12 ] +new_obj.to_string()={ } +new_obj.to_string()={ "foo": "bar" } +new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } +new_obj.to_string()={ "foo": [ null, "foo" ] } +new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } +================================== +json_tokener_parse_versbose() OK +================================== +Starting incremental tests. +json_tokener_parse({ "foo) ... got error as expected +json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 } +json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 } +json_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 } +json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" +json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 +json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" +json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character +End Incremental Tests OK=20 ERROR=0 +================================== diff --git a/test_parse.test b/test_parse.test new file mode 100755 index 0000000000..70d1c82e4a --- /dev/null +++ b/test_parse.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_parse +exit $? From f30a9ace77fd87d08b326688919abbeb3c8717d4 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:53:43 -0500 Subject: [PATCH 08/16] Fix a bug in json_tokener_parse_ex when re-using the same tokener to parse multiple objects. Now, json_tokener_reset() does not need to be called after a valid object is parsed. --- json_tokener.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 04950b5081..1dc06e4a84 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -715,7 +715,17 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_eof; } - if(tok->err == json_tokener_success) return json_object_get(current); + if (tok->err == json_tokener_success) + { + json_object *ret = json_object_get(current); + int ii; + + /* Partially reset, so we parse additional objects on subsequent calls. */ + for(ii = tok->depth; ii >= 0; ii--) + json_tokener_reset_level(tok, ii); + return ret; + } + MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", json_tokener_errors[tok->err], tok->char_offset); return NULL; From a7bd85caba88db2e91e7a4f74ca655c995d12df0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:00 -0500 Subject: [PATCH 09/16] Remove a few more things in the distclean target to get rid of *all* generated files. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 07e610d864..7f1abb138d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,4 +68,5 @@ TESTS_ENVIRONMENT = top_builddir=$(top_builddir) distclean-local: -rm -rf $(testsubdir) + -rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub configure depcomp install-sh ltmain.sh missing From 2b5929bb13eb2086466a8dfa5266ad5d6ff8c9d6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:31 -0500 Subject: [PATCH 10/16] Direct people to send bug reports to the json-c google group. --- config.h.win32 | 2 +- configure.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.h.win32 b/config.h.win32 index 7f7e6aee16..ec3a84aaf2 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -12,7 +12,7 @@ /* config.h.win32 Generated by configure. */ #define PACKAGE_STRING "JSON C Library 0.2" -#define PACKAGE_BUGREPORT "michael@metaparadigm.com" +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" #define PACKAGE_NAME "JSON C Library" #define PACKAGE_TARNAME "json-c" #define PACKAGE_VERSION "0.2" diff --git a/configure.in b/configure.in index 7334319e17..49b31953cb 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.10, [michael@metaparadigm.com]) +AC_INIT([json-c], 0.10, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 8310d3634cb3316cc71d0042282574788189e46b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 2 Apr 2012 15:39:55 -0500 Subject: [PATCH 11/16] Add a printbuf_memset() function to provide an effecient way to set and append things like whitespace indentation. --- printbuf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++---------- printbuf.h | 13 +++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/printbuf.c b/printbuf.c index e8902c844b..b4f79556c9 100644 --- a/printbuf.c +++ b/printbuf.c @@ -29,6 +29,8 @@ #include "debug.h" #include "printbuf.h" +static int printbuf_extend(struct printbuf *p, int min_size); + struct printbuf* printbuf_new(void) { struct printbuf *p; @@ -45,19 +47,32 @@ struct printbuf* printbuf_new(void) } -int printbuf_memappend(struct printbuf *p, const char *buf, int size) +static int printbuf_extend(struct printbuf *p, int min_size) { - char *t; - if(p->size - p->bpos <= size) { - int new_size = json_max(p->size * 2, p->bpos + size + 8); + char *t; + int new_size; + + if (p->size >= min_size) + return 0; + + new_size = json_max(p->size * 2, p->bpos + min_size + 8); #ifdef PRINTBUF_DEBUG - MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, size, p->size, new_size); + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d wrsize=%d old_size=%d new_size=%d\n", + p->bpos, size, p->size, new_size); #endif /* PRINTBUF_DEBUG */ - if(!(t = (char*)realloc(p->buf, new_size))) return -1; - p->size = new_size; - p->buf = t; + if(!(t = (char*)realloc(p->buf, new_size))) + return -1; + p->size = new_size; + p->buf = t; + return 0; +} + +int printbuf_memappend(struct printbuf *p, const char *buf, int size) +{ + if(p->size - p->bpos <= size) { + if (printbuf_extend(p, size) < 0) + return -1; } memcpy(p->buf + p->bpos, buf, size); p->bpos += size; @@ -65,6 +80,26 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) return size; } +int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) +{ + int size_needed; + + if (offset == -1) + offset = pb->bpos; + size_needed = offset + len; + if(pb->size - pb->bpos <= size_needed) + { + if (printbuf_extend(pb, size_needed) < 0) + return -1; + } + + memset(pb->buf + offset, charvalue, len); + if (pb->bpos < size_needed) + pb->bpos = size_needed; + + return 0; +} + #if !HAVE_VSNPRINTF && defined(_MSC_VER) # define vsnprintf _vsnprintf #elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ diff --git a/printbuf.h b/printbuf.h index 5d4963f0de..fc8ac61581 100644 --- a/printbuf.h +++ b/printbuf.h @@ -50,6 +50,19 @@ do { \ } else { printbuf_memappend(p, (bufptr), bufsize); } \ } while (0) +#define printbuf_length(p) ((p)->bpos) + +/** + * Set len bytes of the buffer to charvalue, starting at offset offset. + * Similar to calling memset(x, charvalue, len); + * + * The memory allocated for the buffer is extended as necessary. + * + * If offset is -1, this starts at the end of the current data in the buffer. + */ +extern int +printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len); + extern int sprintbuf(struct printbuf *p, const char *msg, ...); From 7f3298da8519a1f4be73957ae1eebb3b433dd0ae Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:48:15 -0500 Subject: [PATCH 12/16] Remove the "#undef PRINTBUF_DEBUG" from printbuf.h so it can be more easily turned on in the Makefile. --- printbuf.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/printbuf.h b/printbuf.h index fc8ac61581..b1bde7f9f8 100644 --- a/printbuf.h +++ b/printbuf.h @@ -20,8 +20,6 @@ extern "C" { #endif -#undef PRINTBUF_DEBUG - struct printbuf { char *buf; int bpos; From e0fa94ba3151b839104e6b344583ea3385d95daa Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:54:25 -0500 Subject: [PATCH 13/16] Fix some bugs with how buffer sizes were being calcuated in printbuf_memset and an off-by-one error in printbuf_memappend. --- printbuf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/printbuf.c b/printbuf.c index b4f79556c9..b951c7b4f4 100644 --- a/printbuf.c +++ b/printbuf.c @@ -47,6 +47,14 @@ struct printbuf* printbuf_new(void) } +/** + * Extend the buffer p so it has a size of at least min_size. + * + * If the current size is large enough, nothing is changed. + * + * Note: this does not check the available space! The caller + * is responsible for performing those calculations. + */ static int printbuf_extend(struct printbuf *p, int min_size) { char *t; @@ -55,11 +63,11 @@ static int printbuf_extend(struct printbuf *p, int min_size) if (p->size >= min_size) return 0; - new_size = json_max(p->size * 2, p->bpos + min_size + 8); + new_size = json_max(p->size * 2, min_size + 8); #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, size, p->size, new_size); + "bpos=%d min_size=%d old_size=%d new_size=%d\n", + p->bpos, min_size, p->size, new_size); #endif /* PRINTBUF_DEBUG */ if(!(t = (char*)realloc(p->buf, new_size))) return -1; @@ -70,8 +78,8 @@ static int printbuf_extend(struct printbuf *p, int min_size) int printbuf_memappend(struct printbuf *p, const char *buf, int size) { - if(p->size - p->bpos <= size) { - if (printbuf_extend(p, size) < 0) + if (p->size <= p->bpos + size + 1) { + if (printbuf_extend(p, p->bpos + size + 1) < 0) return -1; } memcpy(p->buf + p->bpos, buf, size); @@ -87,7 +95,7 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) if (offset == -1) offset = pb->bpos; size_needed = offset + len; - if(pb->size - pb->bpos <= size_needed) + if (pb->size < size_needed) { if (printbuf_extend(pb, size_needed) < 0) return -1; From 21d37061928a494ea629e1b47ccf9f4d7e01f4ee Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 5 Apr 2012 19:33:09 -0700 Subject: [PATCH 14/16] Added explanatory notes to documentation. --- json_object.h | 64 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/json_object.h b/json_object.h index 72a870887d..72b18299f7 100644 --- a/json_object.h +++ b/json_object.h @@ -115,7 +115,14 @@ extern const char* json_object_to_json_string(struct json_object *obj); /* object type methods */ -/** Create a new empty object +/** Create a new empty object with a reference count of 1. The caller of + * this object initially has sole ownership. Remember, when using + * json_object_object_add or json_object_array_put_idx, ownership will + * transfer to the object/array. Call json_object_get if you want to maintain + * shared ownership or also add this object as a child of multiple objects or + * arrays. Any ownerships you acquired but did not transfer must be released + * through json_object_put. + * * @returns a json_object of type json_type_object */ extern struct json_object* json_object_new_object(void); @@ -130,7 +137,13 @@ extern struct lh_table* json_object_get_object(struct json_object *obj); * * The reference count will *not* be incremented. This is to make adding * fields to objects in code more compact. If you want to retain a reference - * to an added object you must wrap the passed object with json_object_get + * to an added object, independent of the lifetime of obj, you must wrap the + * passed object with json_object_get. + * + * Upon calling this, the ownership of val transfers to obj. Thus you must + * make sure that you do in fact have ownership over this object. For instance, + * json_object_new_object will give you ownership until you transfer it, + * whereas json_object_object_get does not. * * @param obj the json_object instance * @param key the object field name (a private copy will be duplicated) @@ -140,6 +153,17 @@ extern void json_object_object_add(struct json_object* obj, const char *key, struct json_object *val); /** Get the json_object associate with a given object field + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of the returned value is retained + * by obj (do not do json_object_put unless you have done a json_object_get). + * If you delete the value from obj (json_object_object_del) and wish to access + * the returned reference afterwards, make sure you have first gotten shared + * ownership through json_object_get (& don't forget to do a json_object_put + * or transfer ownership to prevent a memory leak). + * * @param obj the json_object instance * @param key the object field name * @returns the json_object associated with the given field name @@ -149,7 +173,9 @@ extern struct json_object* json_object_object_get(struct json_object* obj, /** Delete the given json_object field * - * The reference count will be decremented for the deleted object + * The reference count will be decremented for the deleted object. If there + * are no more owners of the value represented by this key, then the value is + * freed. Otherwise, the reference to the value will remain in memory. * * @param obj the json_object instance * @param key the object field name @@ -159,7 +185,8 @@ extern void json_object_object_del(struct json_object* obj, const char *key); /** Iterate through all keys and values of an object * @param obj the json_object instance * @param key the local name for the char* key variable defined in the body - * @param val the local name for the json_object* object variable defined in the body + * @param val the local name for the json_object* object variable defined in + * the body */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) @@ -293,7 +320,8 @@ extern struct json_object* json_object_new_int64(int64_t i); * * The type is coerced to a int if the passed object is not a int. * double objects will return their integer conversion. Strings will be - * parsed as an integer. If no conversion exists then 0 is returned. + * parsed as an integer. If no conversion exists then 0 is returned + * and errno is set to EINVAL. null is equivalent to 0 (no error values set) * * Note that integers are stored internally as 64-bit values. * If the value of too big or too small to fit into 32-bit, INT32_MAX or @@ -310,6 +338,10 @@ extern int32_t json_object_get_int(struct json_object *obj); * double objects will return their int64 conversion. Strings will be * parsed as an int64. If no conversion exists then 0 is returned. * + * NOTE: Set errno to 0 directly before a call to this function to determine + * whether or not conversion was successful (it does not clear the value for + * you). + * * @param obj the json_object instance * @returns an int64 */ @@ -324,14 +356,28 @@ extern int64_t json_object_get_int64(struct json_object *obj); */ extern struct json_object* json_object_new_double(double d); -/** Get the double value of a json_object +/** Get the double floating point value of a json_object * * The type is coerced to a double if the passed object is not a double. - * integer objects will return their dboule conversion. Strings will be - * parsed as a double. If no conversion exists then 0.0 is returned. + * integer objects will return their double conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned and + * errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * If the value is too big to fit in a double, then the value is set to + * the closest infinity with errno set to ERANGE. If strings cannot be + * converted to their double value, then EINVAL is set & NaN is returned. + * + * Arrays of length 0 are interpreted as 0 (with no error flags set). + * Arrays of length 1 are effectively cast to the equivalent object and + * converted using the above rules. All other arrays set the error to + * EINVAL & return NaN. + * + * NOTE: Set errno to 0 directly before a call to this function to + * determine whether or not conversion was successful (it does not clear + * the value for you). * * @param obj the json_object instance - * @returns an double + * @returns a double floating point number */ extern double json_object_get_double(struct json_object *obj); From 30dd367c0a2467dc292f653ea3afd6ad4c6e034b Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Fri, 30 Mar 2012 12:28:32 -0700 Subject: [PATCH 15/16] Modify install names for library and include files Changing root name of library to json-c, and also the directory where header files are installed to .../jsdon-c/*. This avoids clashes with other implementations of JSON libraries. --- Makefile.am | 10 +++++----- configure.in | 2 +- json.pc.in => json-c.pc.in | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename json.pc.in => json-c.pc.in (67%) diff --git a/Makefile.am b/Makefile.am index 7f1abb138d..eafaf6a8d9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,12 +2,12 @@ AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj -lib_LTLIBRARIES = libjson.la +lib_LTLIBRARIES = libjson-c.la pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = json.pc +pkgconfig_DATA = json-c.pc -libjsonincludedir = $(includedir)/json +libjsonincludedir = $(includedir)/json-c libjsoninclude_HEADERS = \ arraylist.h \ bits.h \ @@ -27,9 +27,9 @@ libjsoninclude_HEADERS = \ #libjsonx_include_HEADERS = \ # json_config.h -libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined +libjson_c_la_LDFLAGS = -version-info 1:0:1 -no-undefined -libjson_la_SOURCES = \ +libjson_c_la_SOURCES = \ arraylist.c \ debug.c \ json_object.c \ diff --git a/configure.in b/configure.in index 49b31953cb..df0d82bdfd 100644 --- a/configure.in +++ b/configure.in @@ -31,5 +31,5 @@ AM_PROG_LIBTOOL AC_OUTPUT([ Makefile -json.pc +json-c.pc ]) diff --git a/json.pc.in b/json-c.pc.in similarity index 67% rename from json.pc.in rename to json-c.pc.in index b3d140be97..037739d27b 100644 --- a/json.pc.in +++ b/json-c.pc.in @@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: json +Name: json-c Description: JSON implementation in C Version: @VERSION@ Requires: -Libs: -L${libdir} -ljson -Cflags: -I${includedir}/json +Libs: -L${libdir} -ljson-c +Cflags: -I${includedir}/json-c From 65f649b7ba6bde1d42d8d9b4051eff47aec04099 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Fri, 30 Mar 2012 12:34:01 -0700 Subject: [PATCH 16/16] Ignoring additional build products --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 091ae7a005..5ccc37ad24 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ Release *.lo *.o libjson.la +json-c.pc +json_config.h