json_object_get_int64. Binary compatibility preserved.
Eric Haszlakiewicz, EHASZLA at transunion com
Rui Miguel Silva Seabra, rms at 1407 dot org
git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@56 327403b1-1117-474d-bef2-5cb71233fd97
tags/json-c-0.10-20120530
| @@ -1,4 +1,8 @@ | |||
| 0.10 | |||
| * Add int64 support. Two new functions json_object_net_int64 and | |||
| json_object_get_int64. Binary compatibility preserved. | |||
| Eric Haszlakiewicz, EHASZLA at transunion com | |||
| Rui Miguel Silva Seabra, rms at 1407 dot org | |||
| * Fix subtle bug in linkhash where lookup could hang after all slots | |||
| were filled then successively freed. | |||
| Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com | |||
| @@ -23,7 +23,7 @@ PROJECT_NAME = json-c | |||
| # This could be handy for archiving the generated documentation or | |||
| # if some version control system is used. | |||
| PROJECT_NUMBER = 0.2 | |||
| PROJECT_NUMBER = 0.10 | |||
| # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) | |||
| # base path where the generated documentation will be put. | |||
| @@ -9,16 +9,17 @@ pkgconfig_DATA = json.pc | |||
| libjsonincludedir = $(includedir)/json | |||
| libjsoninclude_HEADERS = \ | |||
| json.h \ | |||
| arraylist.h \ | |||
| bits.h \ | |||
| debug.h \ | |||
| linkhash.h \ | |||
| arraylist.h \ | |||
| printbuf.h \ | |||
| json_util.h \ | |||
| json.h \ | |||
| json_inttypes.h \ | |||
| json_object.h \ | |||
| json_object_private.h \ | |||
| json_tokener.h | |||
| json_object_private.h \ | |||
| json_tokener.h \ | |||
| json_util.h \ | |||
| linkhash.h \ | |||
| printbuf.h | |||
| libjson_la_LDFLAGS = -version-info 0:1:0 | |||
| @@ -31,7 +32,7 @@ libjson_la_SOURCES = \ | |||
| linkhash.c \ | |||
| printbuf.c | |||
| check_PROGRAMS = test1 test2 test3 test4 | |||
| check_PROGRAMS = test1 test2 test4 test_parse_int64 | |||
| test1_SOURCES = test1.c | |||
| test1_LDADD = $(lib_LTLIBRARIES) | |||
| @@ -39,8 +40,17 @@ test1_LDADD = $(lib_LTLIBRARIES) | |||
| test2_SOURCES = test2.c | |||
| test2_LDADD = $(lib_LTLIBRARIES) | |||
| test3_SOURCES = test3.c | |||
| test3_LDADD = $(lib_LTLIBRARIES) | |||
| test4_SOURCES = test4.c | |||
| test4_LDADD = $(lib_LTLIBRARIES) | |||
| test_parse_int64_SOURCES = test_parse_int64.c | |||
| test_parse_int64_LDADD = $(lib_LTLIBRARIES) | |||
| TESTS = test1.test test2.test test4.test parse_int64.test | |||
| EXTRA_DIST += $(TESTS) | |||
| testsubdir=testSubDir | |||
| TESTS_ENVIRONMENT = top_builddir=$(top_builddir) | |||
| distclean-local: | |||
| -rm -rf $(testsubdir) | |||
| @@ -80,10 +80,6 @@ | |||
| /* Define to 1 if you have the `vsyslog' function. */ | |||
| #undef HAVE_VSYSLOG | |||
| /* Define to the sub-directory in which libtool stores uninstalled libraries. | |||
| */ | |||
| #undef LT_OBJDIR | |||
| /* Name of package */ | |||
| #undef PACKAGE | |||
| @@ -117,5 +113,5 @@ | |||
| /* Define to rpl_realloc if the replacement function should be used. */ | |||
| #undef realloc | |||
| /* Define to `unsigned int' if <sys/types.h> does not define. */ | |||
| /* Define to `unsigned' if <sys/types.h> does not define. */ | |||
| #undef size_t | |||
| @@ -0,0 +1,21 @@ | |||
| #ifndef _json_inttypes_h_ | |||
| #define _json_inttypes_h_ | |||
| #if defined(_MSC_VER) && _MSC_VER < 1600 | |||
| /* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ | |||
| typedef __int64 int64_t; | |||
| #define PRId64 "I64d" | |||
| #define SCNd64 "I64d" | |||
| #else | |||
| #ifdef HAVE_INTTYPES_H | |||
| #include <inttypes.h> | |||
| #endif | |||
| /* inttypes.h includes stdint.h */ | |||
| #endif | |||
| #endif | |||
| @@ -20,8 +20,10 @@ | |||
| #include "printbuf.h" | |||
| #include "linkhash.h" | |||
| #include "arraylist.h" | |||
| #include "json_inttypes.h" | |||
| #include "json_object.h" | |||
| #include "json_object_private.h" | |||
| #include "json_util.h" | |||
| #if !HAVE_STRNDUP | |||
| char* strndup(const char* str, size_t n); | |||
| @@ -41,6 +43,7 @@ static const char* json_type_name[] = { | |||
| "object", | |||
| "array", | |||
| "string", | |||
| "int64", | |||
| }; | |||
| #endif /* REFCOUNT_DEBUG */ | |||
| @@ -304,6 +307,8 @@ boolean json_object_get_boolean(struct json_object *jso) | |||
| return jso->o.c_boolean; | |||
| case json_type_int: | |||
| return (jso->o.c_int != 0); | |||
| case json_type_int64: | |||
| return (jso->o.c_int64 != 0); | |||
| case json_type_double: | |||
| return (jso->o.c_double != 0); | |||
| case json_type_string: | |||
| @@ -322,7 +327,11 @@ static int json_object_int_to_json_string(struct json_object* jso, | |||
| return sprintbuf(pb, "%d", jso->o.c_int); | |||
| } | |||
| struct json_object* json_object_new_int(int i) | |||
| static int json_object_int64_to_json_string(struct json_object* jso, struct printbuf *pb) { | |||
| return sprintbuf(pb, "%"PRId64, jso->o.c_int64); | |||
| } | |||
| struct json_object* json_object_new_int(int32_t i) | |||
| { | |||
| struct json_object *jso = json_object_new(json_type_int); | |||
| if(!jso) return NULL; | |||
| @@ -331,20 +340,69 @@ struct json_object* json_object_new_int(int i) | |||
| return jso; | |||
| } | |||
| int json_object_get_int(struct json_object *jso) | |||
| int32_t json_object_get_int(struct json_object *jso) | |||
| { | |||
| int cint; | |||
| if(!jso) return 0; | |||
| enum json_type o_type = jso->o_type; | |||
| int64_t cint64 = jso->o.c_int64; | |||
| if (o_type == json_type_string) | |||
| { | |||
| /* | |||
| * Parse strings into 64-bit numbers, then use the | |||
| * 64-to-32-bit number handling below. | |||
| */ | |||
| if (json_parse_int64(jso->o.c_string, &cint64) != 0) | |||
| return 0; /* whoops, it didn't work. */ | |||
| o_type = json_type_int64; | |||
| } | |||
| switch(jso->o_type) { | |||
| case json_type_int: | |||
| return jso->o.c_int; | |||
| case json_type_int64: | |||
| /* Make sure we return the correct values for out of range numbers. */ | |||
| if (cint64 <= INT32_MIN) | |||
| return INT32_MIN; | |||
| else if (cint64 >= INT32_MAX) | |||
| return INT32_MAX; | |||
| else | |||
| return (int32_t)cint64; | |||
| case json_type_double: | |||
| return (int32_t)jso->o.c_double; | |||
| case json_type_boolean: | |||
| return jso->o.c_boolean; | |||
| default: | |||
| return 0; | |||
| } | |||
| } | |||
| struct json_object* json_object_new_int64(int64_t i) | |||
| { | |||
| struct json_object *jso = json_object_new(json_type_int64); | |||
| if(!jso) return NULL; | |||
| jso->_to_json_string = &json_object_int64_to_json_string; | |||
| jso->o.c_int64 = i; | |||
| return jso; | |||
| } | |||
| int64_t json_object_get_int64(struct json_object *jso) | |||
| { | |||
| int64_t cint; | |||
| if(!jso) return 0; | |||
| switch(jso->o_type) { | |||
| case json_type_int: | |||
| return (int64_t)jso->o.c_int; | |||
| case json_type_int64: | |||
| return jso->o.c_int64; | |||
| case json_type_double: | |||
| return (int)jso->o.c_double; | |||
| return (int64_t)jso->o.c_double; | |||
| case json_type_boolean: | |||
| return jso->o.c_boolean; | |||
| case json_type_string: | |||
| if(sscanf(jso->o.c_string, "%d", &cint) == 1) return cint; | |||
| if (json_parse_int64(jso->o.c_string, &cint) == 0) return cint; | |||
| default: | |||
| return 0; | |||
| } | |||
| @@ -378,6 +436,8 @@ double json_object_get_double(struct json_object *jso) | |||
| return jso->o.c_double; | |||
| case json_type_int: | |||
| return jso->o.c_int; | |||
| case json_type_int64: | |||
| return jso->o.c_int64; | |||
| case json_type_boolean: | |||
| return jso->o.c_boolean; | |||
| case json_type_string: | |||
| @@ -46,7 +46,8 @@ typedef enum json_type { | |||
| json_type_int, | |||
| json_type_object, | |||
| json_type_array, | |||
| json_type_string | |||
| json_type_string, | |||
| json_type_int64 | |||
| } json_type; | |||
| /* reference counting functions */ | |||
| @@ -74,6 +75,7 @@ extern void json_object_put(struct json_object *obj); | |||
| json_type_object, | |||
| json_type_array, | |||
| json_type_string, | |||
| json_type_int64, | |||
| */ | |||
| extern int json_object_is_type(struct json_object *obj, enum json_type type); | |||
| @@ -87,6 +89,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); | |||
| json_type_object, | |||
| json_type_array, | |||
| json_type_string, | |||
| json_type_int64, | |||
| */ | |||
| extern enum json_type json_object_get_type(struct json_object *obj); | |||
| @@ -252,7 +255,15 @@ extern boolean json_object_get_boolean(struct json_object *obj); | |||
| * @param i the integer | |||
| * @returns a json_object of type json_type_int | |||
| */ | |||
| extern struct json_object* json_object_new_int(int i); | |||
| extern struct json_object* json_object_new_int(int32_t i); | |||
| /** Create a new empty json_object of type json_type_int64 | |||
| * @param i the integer | |||
| * @returns a json_object of type json_type_int64 | |||
| */ | |||
| extern struct json_object* json_object_new_int64(int64_t i); | |||
| /** Get the int value of a json_object | |||
| * | |||
| @@ -263,7 +274,18 @@ extern struct json_object* json_object_new_int(int i); | |||
| * @param obj the json_object instance | |||
| * @returns an int | |||
| */ | |||
| extern int json_object_get_int(struct json_object *obj); | |||
| extern int32_t json_object_get_int(struct json_object *obj); | |||
| /** Get the int value of a json_object | |||
| * | |||
| * The type is coerced to a int64 if the passed object is not a int64. | |||
| * double objects will return their int64 conversion. Strings will be | |||
| * parsed as an int64. If no conversion exists then 0 is returned. | |||
| * | |||
| * @param obj the json_object instance | |||
| * @returns an int64 | |||
| */ | |||
| extern int64_t json_object_get_int64(struct json_object *obj); | |||
| /* double type methods */ | |||
| @@ -30,7 +30,8 @@ struct json_object | |||
| union data { | |||
| boolean c_boolean; | |||
| double c_double; | |||
| int c_int; | |||
| int32_t c_int; | |||
| int64_t c_int64; | |||
| struct lh_table *c_object; | |||
| struct array_list *c_array; | |||
| char *c_string; | |||
| @@ -20,14 +20,16 @@ | |||
| #include <stddef.h> | |||
| #include <ctype.h> | |||
| #include <string.h> | |||
| #include <limits.h> | |||
| #include "bits.h" | |||
| #include "debug.h" | |||
| #include "printbuf.h" | |||
| #include "arraylist.h" | |||
| #include "json_inttypes.h" | |||
| #include "json_object.h" | |||
| #include "json_tokener.h" | |||
| #include "json_util.h" | |||
| #if !HAVE_STRNCASECMP && defined(_MSC_VER) | |||
| /* MSC has the version as _strnicmp */ | |||
| @@ -542,11 +544,21 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||
| printbuf_memappend_fast(tok->pb, case_start, case_len); | |||
| } | |||
| { | |||
| int numi; | |||
| double numd; | |||
| if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { | |||
| current = json_object_new_int(numi); | |||
| } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { | |||
| int64_t num64; | |||
| double numd; | |||
| if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { | |||
| // Decode the type based on the value range to keep compatibilty | |||
| // with code that checks the type of objects. i.e. this: | |||
| // json_object_get_type(o) == json_type_int | |||
| // will continue to work. | |||
| // The other option would be to eliminate any distinction between | |||
| // int and int64 types, but that would change the ABI of | |||
| // json_object_get_int(). | |||
| if (num64 < INT32_MAX && num64 > INT32_MIN) | |||
| current = json_object_new_int(num64); | |||
| else | |||
| current = json_object_new_int64(num64); | |||
| } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { | |||
| current = json_object_new_double(numd); | |||
| } else { | |||
| tok->err = json_tokener_error_parse_number; | |||
| @@ -17,6 +17,7 @@ | |||
| #include <limits.h> | |||
| #include <string.h> | |||
| #include <errno.h> | |||
| #include <ctype.h> | |||
| #if HAVE_SYS_TYPES_H | |||
| #include <sys/types.h> | |||
| @@ -48,6 +49,7 @@ | |||
| #include "bits.h" | |||
| #include "debug.h" | |||
| #include "printbuf.h" | |||
| #include "json_inttypes.h" | |||
| #include "json_object.h" | |||
| #include "json_tokener.h" | |||
| #include "json_util.h" | |||
| @@ -120,3 +122,66 @@ int json_object_to_file(char *filename, struct json_object *obj) | |||
| close(fd); | |||
| return 0; | |||
| } | |||
| int json_parse_int64(const char *buf, int64_t *retval) | |||
| { | |||
| int64_t num64; | |||
| if (sscanf(buf, "%" SCNd64, &num64) != 1) | |||
| { | |||
| printf("Failed to parse, sscanf != 1\n"); | |||
| return 1; | |||
| } | |||
| const char *buf_skip_space = buf; | |||
| int orig_has_neg = 0; | |||
| // Skip leading spaces | |||
| while (isspace((int)*buf_skip_space) && *buf_skip_space) | |||
| buf_skip_space++; | |||
| if (*buf_skip_space == '-') | |||
| { | |||
| buf_skip_space++; | |||
| orig_has_neg = 1; | |||
| } | |||
| // Skip leading zeros | |||
| while (*buf_skip_space == '0' && *buf_skip_space) | |||
| buf_skip_space++; | |||
| if (errno != ERANGE) | |||
| { | |||
| char buf_cmp[100]; | |||
| char *buf_cmp_start = buf_cmp; | |||
| int recheck_has_neg = 0; | |||
| snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); | |||
| if (*buf_cmp_start == '-') | |||
| { | |||
| recheck_has_neg = 1; | |||
| buf_cmp_start++; | |||
| } | |||
| // No need to skip leading spaces or zeros here. | |||
| int buf_cmp_len = strlen(buf_cmp_start); | |||
| /** | |||
| * If the sign is different, or | |||
| * some of the digits are different, or | |||
| * there is another digit present in the original string | |||
| * then we NOT successfully parsed the value. | |||
| */ | |||
| if (orig_has_neg != recheck_has_neg || | |||
| strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 || | |||
| (strlen(buf_skip_space) != buf_cmp_len && | |||
| isdigit(buf_skip_space[buf_cmp_len]) | |||
| ) | |||
| ) | |||
| { | |||
| errno = ERANGE; | |||
| } | |||
| } | |||
| if (errno == ERANGE) | |||
| { | |||
| if (orig_has_neg) | |||
| num64 = INT64_MIN; | |||
| else | |||
| num64 = INT64_MAX; | |||
| } | |||
| *retval = num64; | |||
| return 0; | |||
| } | |||
| @@ -23,6 +23,7 @@ extern "C" { | |||
| /* utility functions */ | |||
| extern struct json_object* json_object_from_file(const char *filename); | |||
| extern int json_object_to_file(char *filename, struct json_object *obj); | |||
| extern int json_parse_int64(const char *buf, int64_t *retval); | |||
| #ifdef __cplusplus | |||
| } | |||
| @@ -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_int64 | |||
| exit $? | |||
| @@ -0,0 +1,114 @@ | |||
| #! /bin/sh | |||
| # Make sure srcdir is an absolute path. Supply the variable | |||
| # if it does not exist. We want to be able to run the tests | |||
| # stand-alone!! | |||
| # | |||
| srcdir=${srcdir-.} | |||
| if test ! -d $srcdir ; then | |||
| echo "test-defs.sh: installation error" 1>&2 | |||
| exit 1 | |||
| fi | |||
| # Use absolute paths | |||
| case "$srcdir" in | |||
| /* | [A-Za-z]:\\*) ;; | |||
| *) srcdir=`\cd $srcdir && pwd` ;; | |||
| esac | |||
| case "$top_builddir" in | |||
| /* | [A-Za-z]:\\*) ;; | |||
| *) top_builddir=`\cd ${top_builddir-..} && pwd` ;; | |||
| esac | |||
| progname=`echo "$0" | sed 's,^.*/,,'` | |||
| testname=`echo "$progname" | sed 's,-.*$,,'` | |||
| testsubdir=${testsubdir-testSubDir} | |||
| # User can set VERBOSE to cause output redirection | |||
| case "$VERBOSE" in | |||
| [Nn]|[Nn][Oo]|0|"") | |||
| VERBOSE=0 | |||
| exec > /dev/null 2>&1 | |||
| ;; | |||
| [Yy]|[Yy][Ee][Ss]) | |||
| VERBOSE=1 | |||
| ;; | |||
| esac | |||
| rm -rf "$testsubdir/$progname" > /dev/null 2>&1 | |||
| mkdir -p "$testsubdir/$progname" | |||
| cd "$testsubdir/$progname" \ | |||
| || { echo "Cannot make or change into $testsubdir/$progname"; exit 1; } | |||
| echo "=== Running test $progname" | |||
| CMP="${CMP-cmp}" | |||
| use_valgrind=${USE_VALGRIND-1} | |||
| valgrind_path=$(which valgrind 2> /dev/null) | |||
| if [ -z "${valgrind_path}" -o ! -x "${valgrind_path}" ] ; then | |||
| use_valgrind=0 | |||
| fi | |||
| # | |||
| # This is a common function to check the results of a test program | |||
| # that is intended to generate consistent output across runs. | |||
| # | |||
| # ${top_builddir} must be set to the top level build directory. | |||
| # | |||
| # Output will be written to the current directory. | |||
| # | |||
| # It must be passed the name of the test command to run, which must be present | |||
| # in the ${top_builddir} directory. | |||
| # | |||
| # It will compare the output of running that against <name of command>.expected | |||
| # | |||
| run_output_test() | |||
| { | |||
| TEST_COMMAND="$1" | |||
| REDIR_OUTPUT="> \"${TEST_COMMAND}.out\"" | |||
| if [ $VERBOSE -gt 1 ] ; then | |||
| REDIR_OUTPUT="| tee \"${TEST_COMMAND}.out\"" | |||
| fi | |||
| if [ $use_valgrind -eq 1 ] ; then | |||
| eval valgrind --tool=memcheck \ | |||
| --trace-children=yes \ | |||
| --demangle=yes \ | |||
| --log-file=vg.out \ | |||
| --leak-check=full \ | |||
| --show-reachable=yes \ | |||
| --run-libc-freeres=yes \ | |||
| "\"${top_builddir}/${TEST_COMMAND}\"" ${REDIR_OUTPUT} | |||
| err=$? | |||
| else | |||
| eval "\"${top_builddir}/${TEST_COMMAND}"\" ${REDIR_OUTPUT} | |||
| err=$? | |||
| fi | |||
| if [ $err -ne 0 ] ; then | |||
| echo "ERROR: ${TEST_COMMAND} exited with non-zero exit status: $err" 1>&2 | |||
| fi | |||
| if [ $use_valgrind -eq 1 ] ; then | |||
| if ! tail -1 "vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then | |||
| echo "ERROR: valgrind found errors during execution:" 1>&2 | |||
| cat vg.out | |||
| err=1 | |||
| fi | |||
| fi | |||
| if ! "$CMP" -s "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" ; then | |||
| echo "ERROR: ${TEST_COMMAND} failed:" 1>&2 | |||
| diff "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" 1>&2 | |||
| err=1 | |||
| fi | |||
| return $err | |||
| } | |||
| @@ -158,7 +158,7 @@ int main(int argc, char **argv) | |||
| json_object_put(my_string); | |||
| json_object_put(my_int); | |||
| json_object_put(my_object); | |||
| //json_object_put(my_array); | |||
| json_object_put(my_array); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| my_string= | |||
| my_string.to_string()="\t" | |||
| my_string=\ | |||
| my_string.to_string()="\\" | |||
| my_string=foo | |||
| my_string.to_string()="foo" | |||
| my_int=9 | |||
| my_int.to_string()=9 | |||
| my_array= | |||
| [0]=1 | |||
| [1]=2 | |||
| [2]=3 | |||
| [3]=null | |||
| [4]=5 | |||
| my_array.to_string()=[ 1, 2, 3, null, 5 ] | |||
| my_object= | |||
| abc: 12 | |||
| foo: "bar" | |||
| 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 } } | |||
| @@ -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 test1 | |||
| exit $? | |||
| @@ -0,0 +1 @@ | |||
| new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } } | |||
| @@ -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 test2 | |||
| exit $? | |||
| @@ -4,11 +4,14 @@ | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <json/json_object.h> | |||
| #include <json/json_tokener.h> | |||
| #include "config.h" | |||
| void print_hex( const unsigned char* s) { | |||
| const unsigned char *iter = s; | |||
| #include "json_inttypes.h" | |||
| #include "json_object.h" | |||
| #include "json_tokener.h" | |||
| void print_hex( const char* s) { | |||
| const char *iter = s; | |||
| unsigned char ch; | |||
| while ((ch = *iter++) != 0) { | |||
| if( ',' != ch) | |||
| @@ -28,10 +31,10 @@ int main() { | |||
| printf("input: %s\n", input); | |||
| int strings_match = !strcmp( expected, unjson); | |||
| int retval = 0; | |||
| if (strings_match) { | |||
| printf("JSON parse result is correct: %s\n", unjson); | |||
| printf("PASS\n"); | |||
| return(0); | |||
| } else { | |||
| printf("JSON parse result doesn't match expected string\n"); | |||
| printf("expected string bytes: "); | |||
| @@ -39,6 +42,8 @@ int main() { | |||
| printf("parsed string bytes: "); | |||
| print_hex( unjson); | |||
| printf("FAIL\n"); | |||
| return(1); | |||
| retval = 1; | |||
| } | |||
| json_object_put(parse_result); | |||
| return retval; | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27" | |||
| JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧 | |||
| PASS | |||
| @@ -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 test4 | |||
| exit $? | |||
| @@ -0,0 +1,99 @@ | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "json_inttypes.h" | |||
| #include "json_util.h" | |||
| void checkit(const char *buf) | |||
| { | |||
| int64_t cint64 = -666; | |||
| int retval = json_parse_int64(buf, &cint64); | |||
| printf("buf=%s parseit=%d, value=%" PRId64 " \n", buf, retval, cint64); | |||
| } | |||
| /** | |||
| * This test calls json_parse_int64 with a variety of different strings. | |||
| * It's purpose is to ensure that the results are consistent across all | |||
| * different environments that it might be executed in. | |||
| * | |||
| * This always exits with a 0 exit value. The output should be compared | |||
| * against previously saved expected output. | |||
| */ | |||
| int main() | |||
| { | |||
| char buf[100]; | |||
| checkit("x"); | |||
| checkit("1"); | |||
| strcpy(buf, "2147483647"); // aka INT32_MAX | |||
| checkit(buf); | |||
| strcpy(buf, "-1"); | |||
| checkit(buf); | |||
| strcpy(buf, " -1"); | |||
| checkit(buf); | |||
| strcpy(buf, "00001234"); | |||
| checkit(buf); | |||
| strcpy(buf, "0001234x"); | |||
| checkit(buf); | |||
| strcpy(buf, "-00001234"); | |||
| checkit(buf); | |||
| strcpy(buf, "-00001234x"); | |||
| checkit(buf); | |||
| strcpy(buf, "4294967295"); // aka UINT32_MAX | |||
| sprintf(buf, "4294967296"); // aka UINT32_MAX + 1 | |||
| strcpy(buf, "21474836470"); // INT32_MAX * 10 | |||
| checkit(buf); | |||
| strcpy(buf, "31474836470"); // INT32_MAX * 10 + a bunch | |||
| checkit(buf); | |||
| strcpy(buf, "-2147483647"); // INT32_MIN + 1 | |||
| checkit(buf); | |||
| strcpy(buf, "-2147483648"); // INT32_MIN | |||
| checkit(buf); | |||
| strcpy(buf, "-2147483649"); // INT32_MIN - 1 | |||
| checkit(buf); | |||
| strcpy(buf, "-21474836480"); // INT32_MIN * 10 | |||
| checkit(buf); | |||
| strcpy(buf, "9223372036854775807"); // INT64_MAX | |||
| checkit(buf); | |||
| strcpy(buf, "9223372036854775808"); // INT64_MAX + 1 | |||
| checkit(buf); | |||
| strcpy(buf, "-9223372036854775808"); // INT64_MIN | |||
| checkit(buf); | |||
| strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1 | |||
| checkit(buf); | |||
| strcpy(buf, "18446744073709551615"); // UINT64_MAX | |||
| checkit(buf); | |||
| strcpy(buf, "18446744073709551616"); // UINT64_MAX + 1 | |||
| checkit(buf); | |||
| strcpy(buf, "-18446744073709551616"); // -UINT64_MAX | |||
| checkit(buf); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| Failed to parse, sscanf != 1 | |||
| buf=x parseit=1, value=-666 | |||
| buf=1 parseit=0, value=1 | |||
| buf=2147483647 parseit=0, value=2147483647 | |||
| buf=-1 parseit=0, value=-1 | |||
| buf= -1 parseit=0, value=-1 | |||
| buf=00001234 parseit=0, value=1234 | |||
| buf=0001234x parseit=0, value=1234 | |||
| buf=-00001234 parseit=0, value=-1234 | |||
| buf=-00001234x parseit=0, value=-1234 | |||
| buf=21474836470 parseit=0, value=21474836470 | |||
| buf=31474836470 parseit=0, value=31474836470 | |||
| buf=-2147483647 parseit=0, value=-2147483647 | |||
| buf=-2147483648 parseit=0, value=-2147483648 | |||
| buf=-2147483649 parseit=0, value=-2147483649 | |||
| buf=-21474836480 parseit=0, value=-21474836480 | |||
| buf=9223372036854775807 parseit=0, value=9223372036854775807 | |||
| buf=9223372036854775808 parseit=0, value=9223372036854775807 | |||
| buf=-9223372036854775808 parseit=0, value=-9223372036854775808 | |||
| buf=-9223372036854775809 parseit=0, value=-9223372036854775808 | |||
| buf=18446744073709551615 parseit=0, value=9223372036854775807 | |||
| buf=18446744073709551616 parseit=0, value=9223372036854775807 | |||
| buf=-18446744073709551616 parseit=0, value=-9223372036854775808 | |||