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-5cb71233fd97tags/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 |