diff --git a/.gitignore b/.gitignore index a295965..f0f555e 100644 --- a/.gitignore +++ b/.gitignore @@ -72,7 +72,6 @@ *.dmg *.ipa -/INSTALL .deps/ .libs/ /aclocal.m4 @@ -99,3 +98,11 @@ /missing /stamp-h1 /stamp-h2 + +# cmake auto-generated files +/CMakeCache.txt +/CMakeFiles +/cmake_install.cmake +/include +/libjson-c.a +/libjson-c.so diff --git a/.travis.yml b/.travis.yml index 2aa2eef..1471983 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ os: before_install: - echo $LANG - echo $LC_ALL + - set -e install: - sh autogen.sh @@ -28,4 +29,4 @@ script: after_success: - make check - - cppcheck --quiet *.h *.c tests/ + - if type cppcheck &> /dev/null ; then cppcheck --error-exitcode=1 --quiet *.h *.c tests/ ; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b4e97e..212401a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,12 +11,24 @@ if(MSVC) file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/include/config.h.win32 ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) file(COPY ./json_config.h.win32 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/include/json_config.h.win32 ${CMAKE_CURRENT_BINARY_DIR}/include/json_config.h) +elseif(MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -D_GNU_SOURCE=1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -D_GNU_SOURCE=1") + if (MSYS OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") + execute_process(COMMAND echo ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + execute_process(COMMAND sh autogen.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + execute_process(COMMAND sh ./configure WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + file(COPY ./config.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + file(COPY ./json_config.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + else() + file(COPY ./config.h.win32 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/include/config.h.win32 ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) + file(COPY ./json_config.h.win32 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/include/json_config.h.win32 ${CMAKE_CURRENT_BINARY_DIR}/include/json_config.h) + endif() elseif(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - if(CMAKE_COMPILER_IS_GNUCC) - add_definitions(-D_GNU_SOURCE) - endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -D_GNU_SOURCE") execute_process(COMMAND echo ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) execute_process(COMMAND sh autogen.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) execute_process(COMMAND ./configure WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) @@ -56,16 +68,26 @@ set(JSON_C_SOURCES ./linkhash.c ./printbuf.c ./random_seed.c + ./strerror_override.c ) add_library(json-c + SHARED + ${JSON_C_SOURCES} + ${JSON_C_HEADERS} +) + +add_library(json-c-static + STATIC ${JSON_C_SOURCES} ${JSON_C_HEADERS} ) set_property(TARGET json-c PROPERTY C_STANDARD 99) +set_property(TARGET json-c-static PROPERTY C_STANDARD 99) +set_target_properties(json-c-static PROPERTIES OUTPUT_NAME json-c) -install(TARGETS json-c +install(TARGETS json-c json-c-static RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..5fb10a0 --- /dev/null +++ b/INSTALL @@ -0,0 +1,3 @@ + +See README.md for installation instructions. + diff --git a/Makefile.am b/Makefile.am index 126ceeb..cd32b4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ EXTRA_DIST = README.md README.html README-WIN32.html EXTRA_DIST += config.h.win32 json-c.vcproj json-c.vcxproj json-c.vcxproj.filters -EXTRA_DIST += Doxyfile doc +EXTRA_DIST += Doxyfile dist-hook: test -d "$(distdir)/doc" || mkdir "$(distdir)/doc" @@ -35,7 +35,8 @@ libjson_cinclude_HEADERS = \ strdup_compat.h \ vasprintf_compat.h \ printbuf.h \ - random_seed.h + random_seed.h \ + strerror_override.h libjson_c_la_LDFLAGS = -version-info 3:0:0 -no-undefined @JSON_BSYMBOLIC_LDFLAGS@ @@ -51,16 +52,47 @@ libjson_c_la_SOURCES = \ json_visit.c \ linkhash.c \ printbuf.c \ - random_seed.c + random_seed.c \ + strerror_override.c \ + strerror_override_private.h +DISTCLEANFILES= +DISTCLEANFILES+= \ + config.h \ + json-c-uninstalled.pc \ + json-c.pc \ + json_config.h + distclean-local: -rm -rf $(testsubdir) - -rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub depcomp install-sh ltmain.sh missing - -rm -f INSTALL test-driver tests/Makefile.in compile -maintainer-clean-local: - -rm -rf configure +JSON_CLEANFILES= +JSON_CLEANFILES+= \ + Makefile.in \ + aclocal.m4 \ + autom4te.cache/ \ + compile \ + config.guess \ + config.h.in \ + config.sub \ + configure \ + depcomp \ + install-sh \ + ltmain.sh \ + missing \ + test-driver \ + tests/Makefile.in +JSON_CLEANFILES+= \ + libtool \ + stamp-h1 \ + stamp-h2 + +# There's no built-in way to remove these after all the other +# maintainer-clean steps happen, so do it explicitly here. +really-clean: + $(MAKE) maintainer-clean + rm -rf ${JSON_CLEANFILES} uninstall-local: rm -rf "$(DESTDIR)@includedir@/json-c" diff --git a/README.md b/README.md index 7fcf676..0e87cd5 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ JSON-C - A JSON implementation in C ----------------------------------- +Build Status +* [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/json-c/json-c?branch=master&svg=true)](https://ci.appveyor.com/project/hawicz/json-c) +* [![Travis Build Status](https://travis-ci.org/json-c/json-c.svg?branch=master)](https://travis-ci.org/json-c/json-c) + JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. @@ -14,7 +18,9 @@ Building on Unix with `git`, `gcc` and `autotools` Home page for json-c: https://github.com/json-c/json-c/wiki -Prerequisites: +### Prerequisites: + +See also the "Installing prerequisites" section below. - `gcc`, `clang`, or another C compiler - `libtool>=2.2.6b` @@ -26,6 +32,8 @@ If you're not using a release tarball, you'll also need: Make sure you have a complete `libtool` install, including `libtoolize`. +### Build instructions: + `json-c` GitHub repo: https://github.com/json-c/json-c ```sh @@ -66,3 +74,52 @@ JSON_C_DIR=/path/to/json_c/install CFLAGS += -I$(JSON_C_DIR)/include/json-c LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c ``` + + +Install prerequisites +----------------------- + +If you are on a relatively modern system, you'll likely be able to install +the prerequisites using your OS's packaging system. + +### Install using apt (e.g. Ubuntu 16.04.2 LTS) +```sh +sudo apt install git +sudo apt install autoconf automake libtool +sudo apt install valgrind # optional +``` + +Then start from the "git clone" command, above. + +### Manually install and build autoconf, automake and libtool + +For older OS's that don't have up-to-date version of the packages will +require a bit more work. For example, CentOS release 5.11, etc... + +```sh +curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz +curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz +curl -O http://ftp.gnu.org/gnu/libtool/libtool-2.2.6b.tar.gz + +tar xzf autoconf-2.69.tar.gz +tar xzf automake-1.15.tar.gz +tar xzf libtool-2.2.6b.tar.gz + +export PATH=${HOME}/ac_install/bin:$PATH + +(cd autoconf-2.69 && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) + +(cd automake-1.15 && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) + +(cd libtool-2.2.6b && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) +``` + diff --git a/arraylist.c b/arraylist.c index 0be095f..ddeb8d4 100644 --- a/arraylist.c +++ b/arraylist.c @@ -98,7 +98,8 @@ array_list_put_idx(struct array_list *arr, size_t idx, void *data) { if (idx > SIZE_T_MAX - 1 ) return -1; if(array_list_expand_internal(arr, idx+1)) return -1; - if(arr->array[idx]) arr->free_fn(arr->array[idx]); + if(idx < arr->length && arr->array[idx]) + arr->free_fn(arr->array[idx]); arr->array[idx] = data; if(arr->length <= idx) arr->length = idx + 1; return 0; diff --git a/config.h.win32 b/config.h.win32 index e721aaf..2a70a9c 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -8,24 +8,24 @@ /* Define to 1 if you have the declaration of `INFINITY', and to 0 if you don't. */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) #define HAVE_DECL_INFINITY 1 #endif /* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) #define HAVE_DECL_ISINF 1 #endif /* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) #define HAVE_DECL_ISNAN 1 #endif /* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) #define HAVE_DECL_NAN 1 #endif @@ -76,7 +76,11 @@ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `snprintf' function. */ +#if defined(__MINGW32__) +#define HAVE_SNPRINTF 1 +#else #undef HAVE_SNPRINTF +#endif /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 @@ -103,7 +107,11 @@ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strncasecmp' function. */ +#if defined(__MINGW32__) +#define HAVE_STRNCASECMP 1 +#else #undef HAVE_STRNCASECMP +#endif /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H @@ -112,7 +120,11 @@ #define HAVE_SYS_CDEFS_H 1 /* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_SYS_PARAM_H 1 +#else #undef HAVE_SYS_PARAM_H +#endif /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 @@ -121,10 +133,18 @@ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_UNISTD_H 1 +#else #undef HAVE_UNISTD_H +#endif /* Define to 1 if you have the `vasprintf' function. */ +#if defined(__MINGW32__) +#define HAVE_VASPRINTF 1 +#else #undef HAVE_VASPRINTF +#endif /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 diff --git a/configure.ac b/configure.ac index f007be9..f191c86 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,8 @@ AM_INIT_AUTOMAKE AC_PROG_MAKE_SET +AC_CANONICAL_HOST + AC_ARG_ENABLE(rdrand, AS_HELP_STRING([--enable-rdrand], [Enable RDRAND Hardware RNG Hash Seed generation on supported x86/x64 platforms.]), @@ -41,6 +43,18 @@ AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public defin AC_C_CONST AC_TYPE_SIZE_T +AC_CACHE_CHECK([for __thread support], ac_cv___thread, [dnl +AC_LINK_IFELSE([dnl +AC_LANG_PROGRAM([[#undef __thread +static __thread int a; int foo (int b) { return a + b; }]], + [[exit (foo (0));]])], + ac_cv___thread=yes, ac_cv___thread=no) +]) +AS_IF([test "x$ac_cv___thread" != xno], +[AC_DEFINE(HAVE___THREAD, 1, [Have __thread]) + AC_DEFINE(SPEC___THREAD, [__thread], [Specifier for __thread])] +) + # Checks for library functions. AC_FUNC_VPRINTF AC_FUNC_MEMCMP @@ -53,6 +67,14 @@ AC_CHECK_DECLS([isinf], [], [], [[#include ]]) AC_CHECK_DECLS([_isnan], [], [], [[#include ]]) AC_CHECK_DECLS([_finite], [], [], [[#include ]]) +case "${host_os}" in + linux*) + AC_CHECK_FUNCS([uselocale]) + ;; + *) # Nothing + ;; +esac + if test "$ac_cv_have_decl_isnan" = "yes" ; then AC_TRY_LINK([#include ], [float f = 0.0; return isnan(f)], [], [LIBS="$LIBS -lm"]) fi @@ -75,7 +97,7 @@ int main(int c,char* v) {return 0;} AC_LANG_POP([C]) -AM_PROG_LIBTOOL +LT_INIT # Check for the -Bsymbolic-functions linker flag AC_ARG_ENABLE([Bsymbolic], diff --git a/json_object.c b/json_object.c index 57342b0..a317123 100644 --- a/json_object.c +++ b/json_object.c @@ -12,13 +12,14 @@ #include "config.h" +#include "strerror_override.h" + #include #include #include #include #include #include -#include #include "debug.h" #include "printbuf.h" @@ -30,13 +31,7 @@ #include "json_util.h" #include "math_compat.h" #include "strdup_compat.h" - -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ +#include "snprintf_compat.h" // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ @@ -143,11 +138,11 @@ static int json_escape_str(struct printbuf *pb, const char *str, int len, int fl default: if(c < ' ') { + char sbuf[7]; if(pos - start_offset > 0) printbuf_memappend(pb, str + start_offset, pos - start_offset); - static char sbuf[7]; snprintf(sbuf, sizeof(sbuf), "\\u00%c%c", json_hex_chars[c >> 4], @@ -589,7 +584,7 @@ static int json_object_int_to_json_string(struct json_object* jso, int flags) { /* room for 19 digits, the sign char, and a null term */ - static char sbuf[21]; + char sbuf[21]; snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int64); return printbuf_memappend (pb, sbuf, strlen(sbuf)); } @@ -634,6 +629,10 @@ int32_t json_object_get_int(const struct json_object *jso) return INT32_MAX; return (int32_t) cint64; case json_type_double: + if (jso->o.c_double <= INT32_MIN) + return INT32_MIN; + if (jso->o.c_double >= INT32_MAX) + return INT32_MAX; return (int32_t)jso->o.c_double; case json_type_boolean: return jso->o.c_boolean; @@ -692,52 +691,122 @@ int json_object_set_int64(struct json_object *jso,int64_t new_value){ /* json_object_double */ +#ifdef HAVE___THREAD +// i.e. __thread or __declspec(thread) +static SPEC___THREAD char *tls_serialization_float_format = NULL; +#endif +static char *global_serialization_float_format = NULL; + +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread) +{ + if (global_or_thread == JSON_C_OPTION_GLOBAL) + { +#ifdef HAVE___THREAD + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } +#endif + if (global_serialization_float_format) + free(global_serialization_float_format); + global_serialization_float_format = double_format ? strdup(double_format) : NULL; + } + else if (global_or_thread == JSON_C_OPTION_THREAD) + { +#ifdef HAVE___THREAD + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } + tls_serialization_float_format = double_format ? strdup(double_format) : NULL; +#else + _set_last_err("json_c_set_option: not compiled with __thread support\n"); + return -1; +#endif + } + else + { + _set_last_err("json_c_set_option: invalid global_or_thread value: %d\n", global_or_thread); + return -1; + } + return 0; +} + + static int json_object_double_to_json_string_format(struct json_object* jso, struct printbuf *pb, int level, int flags, const char *format) { - char buf[128], *p, *q; - int size; - double dummy; /* needed for modf() */ - /* Although JSON RFC does not support - NaN or Infinity as numeric values - ECMA 262 section 9.8.1 defines - how to handle these cases as strings */ - if(isnan(jso->o.c_double)) - size = snprintf(buf, sizeof(buf), "NaN"); - else if(isinf(jso->o.c_double)) - if(jso->o.c_double > 0) - size = snprintf(buf, sizeof(buf), "Infinity"); - else - size = snprintf(buf, sizeof(buf), "-Infinity"); - else - size = snprintf(buf, sizeof(buf), - format ? format : - (modf(jso->o.c_double, &dummy) == 0) ? "%.17g.0" : "%.17g", - jso->o.c_double); - if(size < 0 || size >= (int)sizeof(buf)) - size = (int)sizeof(buf); - - p = strchr(buf, ','); - if (p) { - *p = '.'; - } else { - p = strchr(buf, '.'); - } - if (p && (flags & JSON_C_TO_STRING_NOZERO)) { - /* last useful digit, always keep 1 zero */ - p++; - for (q=p ; *q ; q++) { - if (*q!='0') p=q; - } - /* drop trailing zeroes */ - *(++p) = 0; - size = p-buf; - } - printbuf_memappend(pb, buf, size); - return size; + char buf[128], *p, *q; + int size; + double dummy; /* needed for modf() */ + /* Although JSON RFC does not support + NaN or Infinity as numeric values + ECMA 262 section 9.8.1 defines + how to handle these cases as strings */ + if (isnan(jso->o.c_double)) + { + size = snprintf(buf, sizeof(buf), "NaN"); + } + else if (isinf(jso->o.c_double)) + { + if(jso->o.c_double > 0) + size = snprintf(buf, sizeof(buf), "Infinity"); + else + size = snprintf(buf, sizeof(buf), "-Infinity"); + } + else + { + const char *std_format = "%.17g"; + +#ifdef HAVE___THREAD + if (tls_serialization_float_format) + std_format = tls_serialization_float_format; + else +#endif + if (global_serialization_float_format) + std_format = global_serialization_float_format; + if (!format) + format = std_format; + size = snprintf(buf, sizeof(buf), format, jso->o.c_double); + if (modf(jso->o.c_double, &dummy) == 0 && size >= 0 && size < (int)sizeof(buf) - 2) + { + // Ensure it looks like a float, even if snprintf didn't. + strcat(buf, ".0"); + size += 2; + } + } + // although unlikely, snprintf can fail + if (size < 0) + return -1; + + p = strchr(buf, ','); + if (p) + *p = '.'; + else + p = strchr(buf, '.'); + if (p && (flags & JSON_C_TO_STRING_NOZERO)) + { + /* last useful digit, always keep 1 zero */ + p++; + for (q=p ; *q ; q++) { + if (*q!='0') p=q; + } + /* drop trailing zeroes */ + *(++p) = 0; + size = p-buf; + } + + if (size >= (int)sizeof(buf)) + // The standard formats are guaranteed not to overrun the buffer, + // but if a custom one happens to do so, just silently truncate. + size = sizeof(buf) - 1; + printbuf_memappend(pb, buf, size); + return size; } static int json_object_double_to_json_string_default(struct json_object* jso, @@ -1072,7 +1141,7 @@ struct json_object* json_object_array_bsearch( assert(json_object_get_type(jso) == json_type_array); result = (struct json_object **)array_list_bsearch( - (const void **)&key, jso->o.c_array, sort_fn); + (const void **)(void *)&key, jso->o.c_array, sort_fn); if (!result) return NULL; @@ -1139,7 +1208,7 @@ static int json_object_all_values_equal(struct json_object* jso1, /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { if (!lh_table_lookup_ex(jso2->o.c_object, (void*)iter.key, - (void**)&sub)) + (void**)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1148,7 +1217,7 @@ static int json_object_all_values_equal(struct json_object* jso1, /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { if (!lh_table_lookup_ex(jso1->o.c_object, (void*)iter.key, - (void**)&sub)) + (void**)(void *)&sub)) return 0; } diff --git a/json_object.h b/json_object.h index f86f678..4bbc367 100644 --- a/json_object.h +++ b/json_object.h @@ -21,6 +21,12 @@ #define THIS_FUNCTION_IS_DEPRECATED(func) func #endif +#if defined(_MSC_VER) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif + #include #include "json_inttypes.h" @@ -105,6 +111,22 @@ extern "C" { #undef TRUE #define TRUE ((json_bool)1) +/** + * Set the global value of an option, which will apply to all + * current and future threads that have not set a thread-local value. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_GLOBAL (0) +/** + * Set a thread-local value of an option, overriding the global value. + * This will fail if json-c is not compiled with threading enabled, and + * with the __thread specifier (or equivalent) available. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_THREAD (1) + extern const char *json_number_chars; extern const char *json_hex_chars; @@ -160,7 +182,7 @@ typedef enum json_type { * * @param obj the json_object instance */ -extern struct json_object* json_object_get(struct json_object *obj); +JSON_EXPORT struct json_object* json_object_get(struct json_object *obj); /** * Decrement the reference count of json_object and free if it reaches zero. @@ -170,7 +192,7 @@ extern struct json_object* json_object_get(struct json_object *obj); * @param obj the json_object instance * @returns 1 if the object was freed. */ -int json_object_put(struct json_object *obj); +JSON_EXPORT int json_object_put(struct json_object *obj); /** * Check if the json_object is of a given type @@ -184,7 +206,7 @@ int json_object_put(struct json_object *obj); json_type_array, json_type_string */ -extern int json_object_is_type(const struct json_object *obj, enum json_type type); +JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type); /** * Get the type of the json_object. See also json_type_to_name() to turn this @@ -200,7 +222,7 @@ extern int json_object_is_type(const struct json_object *obj, enum json_type typ json_type_array, json_type_string */ -extern enum json_type json_object_get_type(const struct json_object *obj); +JSON_EXPORT enum json_type json_object_get_type(const struct json_object *obj); /** Stringify object to json format. @@ -212,7 +234,7 @@ extern enum json_type json_object_get_type(const struct json_object *obj); * @param obj the json_object instance * @returns a string in JSON format */ -extern const char* json_object_to_json_string(struct json_object *obj); +JSON_EXPORT const char* json_object_to_json_string(struct json_object *obj); /** Stringify object to json format * @see json_object_to_json_string() for details on how to free string. @@ -220,7 +242,7 @@ extern const char* json_object_to_json_string(struct json_object *obj); * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants * @returns a string in JSON format */ -extern const char* json_object_to_json_string_ext(struct json_object *obj, int +JSON_EXPORT const char* json_object_to_json_string_ext(struct json_object *obj, int flags); /** Stringify object to json format @@ -230,7 +252,7 @@ flags); * @param length a pointer where, if not NULL, the length (without null) is stored * @returns a string in JSON format and the length if not NULL */ -extern const char* json_object_to_json_string_length(struct json_object *obj, int +JSON_EXPORT const char* json_object_to_json_string_length(struct json_object *obj, int flags, size_t *length); /** @@ -239,7 +261,7 @@ flags, size_t *length); * * @param jso the object to return the userdata for */ -extern void* json_object_get_userdata(json_object *jso); +JSON_EXPORT void* json_object_get_userdata(json_object *jso); /** * Set an opaque userdata value for an object @@ -266,7 +288,7 @@ extern void* json_object_get_userdata(json_object *jso); * @param userdata an optional opaque cookie * @param user_delete an optional function from freeing userdata */ -extern void json_object_set_userdata(json_object *jso, void *userdata, +JSON_EXPORT void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete); /** @@ -299,7 +321,7 @@ extern void json_object_set_userdata(json_object *jso, void *userdata, * @param userdata an optional opaque cookie * @param user_delete an optional function from freeing userdata */ -extern void json_object_set_serializer(json_object *jso, +JSON_EXPORT void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn to_string_func, void *userdata, json_object_delete_fn *user_delete); @@ -337,18 +359,18 @@ json_object_to_json_string_fn json_object_userdata_to_json_string; * * @returns a json_object of type json_type_object */ -extern struct json_object* json_object_new_object(void); +JSON_EXPORT struct json_object* json_object_new_object(void); /** Get the hashtable of a json_object of type json_type_object * @param obj the json_object instance * @returns a linkhash */ -extern struct lh_table* json_object_get_object(const struct json_object *obj); +JSON_EXPORT struct lh_table* json_object_get_object(const struct json_object *obj); /** Get the size of an object in terms of the number of fields it has. * @param obj the json_object whose length to return */ -extern int json_object_object_length(const struct json_object* obj); +JSON_EXPORT int json_object_object_length(const struct json_object* obj); /** Add an object field to a json_object of type json_type_object * @@ -369,7 +391,7 @@ extern int json_object_object_length(const struct json_object* obj); * @return On success, 0 is returned. * On error, a negative value is returned. */ -extern int json_object_object_add(struct json_object* obj, const char *key, +JSON_EXPORT int json_object_object_add(struct json_object* obj, const char *key, struct json_object *val); /** Add an object field to a json_object of type json_type_object @@ -385,7 +407,7 @@ extern int json_object_object_add(struct json_object* obj, const char *key, * @param opts process-modifying options. To specify multiple options, use * arithmetic or (OPT1|OPT2) */ -extern int json_object_object_add_ex(struct json_object* obj, +JSON_EXPORT int json_object_object_add_ex(struct json_object* obj, const char *const key, struct json_object *const val, const unsigned opts); @@ -411,7 +433,7 @@ extern int json_object_object_add_ex(struct json_object* obj, * @returns the json_object associated with the given field name * @deprecated Please use json_object_object_get_ex */ -extern struct json_object* json_object_object_get(const struct json_object* obj, +JSON_EXPORT struct json_object* json_object_object_get(const struct json_object* obj, const char *key); /** Get the json_object associated with a given object field. @@ -432,7 +454,7 @@ extern struct json_object* json_object_object_get(const struct json_object* obj, * It is safe to pass a NULL value. * @returns whether or not the key exists */ -extern json_bool json_object_object_get_ex(const struct json_object* obj, +JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object* obj, const char *key, struct json_object **value); @@ -445,7 +467,7 @@ extern json_bool json_object_object_get_ex(const struct json_object* obj, * @param obj the json_object instance * @param key the object field name */ -extern void json_object_object_del(struct json_object* obj, const char *key); +JSON_EXPORT void json_object_object_del(struct json_object* obj, const char *key); /** * Iterate through all keys and values of an object. @@ -504,19 +526,19 @@ extern void json_object_object_del(struct json_object* obj, const char *key); /** Create a new empty json_object of type json_type_array * @returns a json_object of type json_type_array */ -extern struct json_object* json_object_new_array(void); +JSON_EXPORT struct json_object* json_object_new_array(void); /** Get the arraylist of a json_object of type json_type_array * @param obj the json_object instance * @returns an arraylist */ -extern struct array_list* json_object_get_array(const struct json_object *obj); +JSON_EXPORT struct array_list* json_object_get_array(const struct json_object *obj); /** Get the length of a json_object of type json_type_array * @param obj the json_object instance * @returns an int */ -extern size_t json_object_array_length(const struct json_object *obj); +JSON_EXPORT size_t json_object_array_length(const struct json_object *obj); /** Sorts the elements of jso of type json_type_array * @@ -526,7 +548,7 @@ extern size_t json_object_array_length(const struct json_object *obj); * @param obj the json_object instance * @param sort_fn a sorting function */ -extern void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *)); +JSON_EXPORT void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *)); /** Binary search a sorted array for a specified key object. * @@ -542,7 +564,7 @@ extern void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const * * @return the wanted json_object instance */ -extern struct json_object* json_object_array_bsearch( +JSON_EXPORT struct json_object* json_object_array_bsearch( const struct json_object *key, const struct json_object *jso, int (*sort_fn)(const void *, const void *)); @@ -556,7 +578,7 @@ extern struct json_object* json_object_array_bsearch( * @param obj the json_object instance * @param val the json_object to be added */ -extern int json_object_array_add(struct json_object *obj, +JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_object *val); /** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) @@ -574,7 +596,7 @@ extern int json_object_array_add(struct json_object *obj, * @param idx the index to insert the element at * @param val the json_object to be added */ -extern int json_object_array_put_idx(struct json_object *obj, size_t idx, +JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, struct json_object *val); /** Get the element at specificed index of the array (a json_object of type json_type_array) @@ -582,7 +604,7 @@ extern int json_object_array_put_idx(struct json_object *obj, size_t idx, * @param idx the index to get the element at * @returns the json_object at the specified index (or NULL) */ -extern struct json_object* json_object_array_get_idx(const struct json_object *obj, +JSON_EXPORT struct json_object* json_object_array_get_idx(const struct json_object *obj, size_t idx); /** Delete an elements from a specified index in an array (a json_object of type json_type_array) @@ -596,7 +618,7 @@ extern struct json_object* json_object_array_get_idx(const struct json_object *o * @param count the number of elements to delete * @returns 0 if the elements were successfully deleted */ -extern int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); +JSON_EXPORT int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); /* json_bool type methods */ @@ -604,7 +626,7 @@ extern int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t * @param b a json_bool TRUE or FALSE (1 or 0) * @returns a json_object of type json_type_boolean */ -extern struct json_object* json_object_new_boolean(json_bool b); +JSON_EXPORT struct json_object* json_object_new_boolean(json_bool b); /** Get the json_bool value of a json_object * @@ -617,7 +639,7 @@ extern struct json_object* json_object_new_boolean(json_bool b); * @param obj the json_object instance * @returns a json_bool */ -extern json_bool json_object_get_boolean(const struct json_object *obj); +JSON_EXPORT json_bool json_object_get_boolean(const struct json_object *obj); /** Set the json_bool value of a json_object @@ -630,7 +652,7 @@ extern json_bool json_object_get_boolean(const struct json_object *obj); * @param new_value the value to be set * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_boolean(struct json_object *obj,json_bool new_value); +JSON_EXPORT int json_object_set_boolean(struct json_object *obj,json_bool new_value); /* int type methods */ @@ -641,14 +663,14 @@ extern int json_object_set_boolean(struct json_object *obj,json_bool new_value); * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int(int32_t i); +JSON_EXPORT struct json_object* json_object_new_int(int32_t i); /** Create a new empty json_object of type json_type_int * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int64(int64_t i); +JSON_EXPORT struct json_object* json_object_new_int64(int64_t i); /** Get the int value of a json_object @@ -665,7 +687,7 @@ extern struct json_object* json_object_new_int64(int64_t i); * @param obj the json_object instance * @returns an int */ -extern int32_t json_object_get_int(const struct json_object *obj); +JSON_EXPORT int32_t json_object_get_int(const struct json_object *obj); /** Set the int value of a json_object * @@ -677,7 +699,7 @@ extern int32_t json_object_get_int(const struct json_object *obj); * @param new_value the value to be set * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_int(struct json_object *obj,int new_value); +JSON_EXPORT int json_object_set_int(struct json_object *obj,int new_value); /** Get the int value of a json_object @@ -693,7 +715,7 @@ extern int json_object_set_int(struct json_object *obj,int new_value); * @param obj the json_object instance * @returns an int64 */ -extern int64_t json_object_get_int64(const struct json_object *obj); +JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj); /** Set the int64_t value of a json_object @@ -706,7 +728,7 @@ extern int64_t json_object_get_int64(const struct json_object *obj); * @param new_value the value to be set * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_int64(struct json_object *obj,int64_t new_value); +JSON_EXPORT int json_object_set_int64(struct json_object *obj,int64_t new_value); /* double type methods */ @@ -718,7 +740,7 @@ extern int json_object_set_int64(struct json_object *obj,int64_t new_value); * @param d the double * @returns a json_object of type json_type_double */ -extern struct json_object* json_object_new_double(double d); +JSON_EXPORT struct json_object* json_object_new_double(double d); /** * Create a new json_object of type json_type_double, using @@ -746,7 +768,22 @@ extern struct json_object* json_object_new_double(double d); * @param d the numeric value of the double. * @param ds the string representation of the double. This will be copied. */ -extern struct json_object* json_object_new_double_s(double d, const char *ds); +JSON_EXPORT struct json_object* json_object_new_double_s(double d, const char *ds); + +/** + * Set a global or thread-local json-c option, depending on whether + * JSON_C_OPTION_GLOBAL or JSON_C_OPTION_THREAD is passed. + * Thread-local options default to undefined, and inherit from the global + * value, even if the global value is changed after the thread is created. + * Attempting to set thread-local options when threading is not compiled in + * will result in an error. Be sure to check the return value. + * + * double_format is a "%g" printf format, such as "%.20g" + * + * @return -1 on errors, 0 on success. + */ +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread); + /** Serialize a json_object of type json_type_double to a string. @@ -768,7 +805,7 @@ extern struct json_object* json_object_new_double_s(double d, const char *ds); * @param level Ignored. * @param flags Ignored. */ -extern int json_object_double_to_json_string(struct json_object* jso, +JSON_EXPORT int json_object_double_to_json_string(struct json_object* jso, struct printbuf *pb, int level, int flags); @@ -796,7 +833,7 @@ extern int json_object_double_to_json_string(struct json_object* jso, * @param obj the json_object instance * @returns a double floating point number */ -extern double json_object_get_double(const struct json_object *obj); +JSON_EXPORT double json_object_get_double(const struct json_object *obj); /** Set the double value of a json_object @@ -809,7 +846,7 @@ extern double json_object_get_double(const struct json_object *obj); * @param new_value the value to be set * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_double(struct json_object *obj,double new_value); +JSON_EXPORT int json_object_set_double(struct json_object *obj,double new_value); @@ -822,9 +859,9 @@ extern int json_object_set_double(struct json_object *obj,double new_value); * @param s the string * @returns a json_object of type json_type_string */ -extern struct json_object* json_object_new_string(const char *s); +JSON_EXPORT struct json_object* json_object_new_string(const char *s); -extern struct json_object* json_object_new_string_len(const char *s, int len); +JSON_EXPORT struct json_object* json_object_new_string_len(const char *s, int len); /** Get the string value of a json_object * @@ -842,7 +879,7 @@ extern struct json_object* json_object_new_string_len(const char *s, int len); * @param obj the json_object instance * @returns a string or NULL */ -extern const char* json_object_get_string(struct json_object *obj); +JSON_EXPORT const char* json_object_get_string(struct json_object *obj); /** Get the string length of a json_object * @@ -852,14 +889,14 @@ extern const char* json_object_get_string(struct json_object *obj); * @param obj the json_object instance * @returns int */ -extern int json_object_get_string_len(const struct json_object *obj); +JSON_EXPORT int json_object_get_string_len(const struct json_object *obj); /** Set the string value of a json_object with zero terminated strings * equivalent to json_object_set_string_len (obj, new_value, strlen(new_value)) * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_string(json_object* obj, const char* new_value); +JSON_EXPORT int json_object_set_string(json_object* obj, const char* new_value); /** Set the string value of a json_object str * @@ -872,7 +909,7 @@ extern int json_object_set_string(json_object* obj, const char* new_value); * @param len the length of new_value * @returns 1 if value is set correctly, 0 otherwise */ -extern int json_object_set_string_len(json_object* obj, const char* new_value, int len); +JSON_EXPORT int json_object_set_string_len(json_object* obj, const char* new_value, int len); /** Check if two json_object's are equal * @@ -891,7 +928,7 @@ extern int json_object_set_string_len(json_object* obj, const char* new_value, i * @param obj2 the second json_object instance * @returns whether both objects are equal or not */ -extern int json_object_equal(struct json_object *obj1, +JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2); #ifdef __cplusplus diff --git a/json_object_private.h b/json_object_private.h index 67a77f8..1fe10be 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -48,6 +48,8 @@ struct json_object void *_userdata; }; +void _set_last_err(const char *err_fmt, ...); + #ifdef __cplusplus } #endif diff --git a/json_pointer.c b/json_pointer.c index d106e9e..2b2a9ef 100644 --- a/json_pointer.c +++ b/json_pointer.c @@ -8,10 +8,11 @@ #include "config.h" +#include "strerror_override.h" + #include #include #include -#include #include #include diff --git a/json_tokener.h b/json_tokener.h index f29be8b..414c9d6 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -116,19 +116,19 @@ const char *json_tokener_error_desc(enum json_tokener_error jerr); * * See also json_tokener_error_desc(). */ -enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); +JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); -extern struct json_tokener* json_tokener_new(void); -extern struct json_tokener* json_tokener_new_ex(int depth); -extern void json_tokener_free(struct json_tokener *tok); -extern void json_tokener_reset(struct json_tokener *tok); -extern struct json_object* json_tokener_parse(const char *str); -extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); +JSON_EXPORT struct json_tokener* json_tokener_new(void); +JSON_EXPORT struct json_tokener* json_tokener_new_ex(int depth); +JSON_EXPORT void json_tokener_free(struct json_tokener *tok); +JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); +JSON_EXPORT struct json_object* json_tokener_parse(const char *str); +JSON_EXPORT struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); /** * Set flags that control how parsing will be done. */ -extern void json_tokener_set_flags(struct json_tokener *tok, int flags); +JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); /** * Parse a string and return a non-NULL json_object if a valid JSON value @@ -198,7 +198,7 @@ if (tok->char_offset < stringlen) // XXX shouldn't access internal fields * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. * @param len the length of str */ -extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, +JSON_EXPORT struct json_object* json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len); #ifdef __cplusplus diff --git a/json_util.c b/json_util.c index b66c3dc..2121150 100644 --- a/json_util.c +++ b/json_util.c @@ -12,13 +12,14 @@ #include "config.h" #undef realloc +#include "strerror_override.h" + #include #include #include #include #include #include -#include #include #ifdef HAVE_SYS_TYPES_H @@ -47,12 +48,7 @@ # define open _open #endif -#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) - /* MSC has the version as _snprintf */ -# define snprintf _snprintf -#elif !defined(HAVE_SNPRINTF) -# error You do not have snprintf on your system. -#endif /* HAVE_SNPRINTF */ +#include "snprintf_compat.h" #include "debug.h" #include "printbuf.h" @@ -64,7 +60,8 @@ static int sscanf_is_broken = 0; static int sscanf_is_broken_testdone = 0; static void sscanf_is_broken_test(void); -static void _set_last_err(const char *err_fmt, ...); + +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); static char _last_err[256] = ""; @@ -75,7 +72,7 @@ const char *json_util_get_last_err() return _last_err; } -static void _set_last_err(const char *err_fmt, ...) +void _set_last_err(const char *err_fmt, ...) { va_list ap; va_start(ap, err_fmt); @@ -127,42 +124,61 @@ struct json_object* json_object_from_file(const char *filename) int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) { - const char *json_str; - int fd, ret; - unsigned int wpos, wsize; + int fd, ret; + int saved_errno; - if(!obj) { - _set_last_err("json_object_to_file: object is null\n"); - return -1; - } + if (!obj) { + _set_last_err("json_object_to_file: object is null\n"); + return -1; + } - if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { - _set_last_err("json_object_to_file: error opening file %s: %s\n", - filename, strerror(errno)); - return -1; - } + if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { + _set_last_err("json_object_to_file: error opening file %s: %s\n", + filename, strerror(errno)); + return -1; + } + ret = _json_object_to_fd(fd, obj, flags, filename); + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} - if(!(json_str = json_object_to_json_string_ext(obj,flags))) { - close(fd); - return -1; - } +int json_object_to_fd(int fd, struct json_object *obj, int flags) +{ + if (!obj) { + _set_last_err("json_object_to_fd: object is null\n"); + return -1; + } - wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ - wpos = 0; - while(wpos < wsize) { - if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { - close(fd); - _set_last_err("json_object_to_file: error writing file %s: %s\n", - filename, strerror(errno)); - return -1; - } + return _json_object_to_fd(fd, obj, flags, NULL); +} +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) +{ + int ret; + const char *json_str; + unsigned int wpos, wsize; - /* because of the above check for ret < 0, we can safely cast and add */ - wpos += (unsigned int)ret; - } + filename = filename ? filename : "(fd)"; - close(fd); - return 0; + if (!(json_str = json_object_to_json_string_ext(obj,flags))) { + return -1; + } + + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + wpos = 0; + while(wpos < wsize) { + if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { + _set_last_err("json_object_to_file: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; + } + + return 0; } // backwards compatible "format and write to file" function @@ -174,7 +190,9 @@ int json_object_to_file(const char *filename, struct json_object *obj) int json_parse_double(const char *buf, double *retval) { - return (sscanf(buf, "%lf", retval)==1 ? 0 : 1); + char *end; + *retval = strtod(buf, &end); + return end == buf ? 1 : 0; } /* diff --git a/json_util.h b/json_util.h index a913278..d8926db 100644 --- a/json_util.h +++ b/json_util.h @@ -67,7 +67,18 @@ extern int json_object_to_file(const char *filename, struct json_object *obj); extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); /** - * Return the last error from json_object_to_file{,_ext} or + * Convert the json_object to a string and write it to the file descriptor. + * Handles partial writes and will keep writing until done, or an error + * occurs. + * + * @param flags flags to pass to json_object_to_json_string_ext() + * @return -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_fd(int fd, struct json_object *obj, int flags); + +/** + * Return the last error from json_object_to_file{,_ext}, + * json_object_to_fd() or * json_object_from_{file,fd}, or NULL if there is none. */ const char *json_util_get_last_err(void); diff --git a/linkhash.c b/linkhash.c index fd52fe3..5497061 100644 --- a/linkhash.c +++ b/linkhash.c @@ -23,7 +23,7 @@ # include /* attempt to define endianness */ #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MINGW32__) # define WIN32_LEAN_AND_MEAN # include /* Get InterlockedCompareExchange */ #endif @@ -452,7 +452,7 @@ static unsigned long lh_perllike_str_hash(const void *k) static unsigned long lh_char_hash(const void *k) { -#if defined _MSC_VER +#if defined _MSC_VER || defined __MINGW32__ #define RANDOM_SEED_TYPE LONG #else #define RANDOM_SEED_TYPE int @@ -474,10 +474,10 @@ static unsigned long lh_char_hash(const void *k) #endif #if defined USE_SYNC_COMPARE_AND_SWAP (void)__sync_val_compare_and_swap(&random_seed, -1, seed); -#elif defined _MSC_VER +#elif defined _MSC_VER || defined __MINGW32__ InterlockedCompareExchange(&random_seed, seed, -1); #else -#warning "racy random seed initializtion if used by multiple threads" +//#warning "racy random seed initializtion if used by multiple threads" random_seed = seed; /* potentially racy */ #endif } diff --git a/printbuf.c b/printbuf.c index 2745339..6c77b5d 100644 --- a/printbuf.c +++ b/printbuf.c @@ -27,6 +27,7 @@ #include "debug.h" #include "printbuf.h" +#include "snprintf_compat.h" #include "vasprintf_compat.h" static int printbuf_extend(struct printbuf *p, int min_size); diff --git a/random_seed.c b/random_seed.c index 3b61b77..cb086d3 100644 --- a/random_seed.c +++ b/random_seed.c @@ -9,6 +9,7 @@ * */ +#include "strerror_override.h" #include #include "config.h" #include "random_seed.h" @@ -128,7 +129,6 @@ retry: #include #include #include -#include #include #include diff --git a/snprintf_compat.h b/snprintf_compat.h new file mode 100644 index 0000000..7323aaa --- /dev/null +++ b/snprintf_compat.h @@ -0,0 +1,36 @@ +#ifndef __snprintf_compat_h +#define __snprintf_compat_h + +/* + * Microsoft's _vsnprintf and _snprint don't always terminate + * the string, so use wrappers that ensure that. + */ + +#include + +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) +static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int ret; + ret = _vsnprintf(str, size, format, ap); + str[size - 1] = '\0'; + return ret; +} +#define vsnprintf json_c_vsnprintf + +static int json_c_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int ret; + va_start(ap, format); + ret = json_c_vsnprintf(str, size, format, ap); + va_end(ap); + return ret; +} +#define snprintf json_c_snprintf + +#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_SNPRINTF && defined(WIN32) */ + +#endif /* __snprintf_compat_h */ diff --git a/tests/strerror_override.c b/strerror_override.c similarity index 89% rename from tests/strerror_override.c rename to strerror_override.c index 980cbb9..90a1581 100644 --- a/tests/strerror_override.c +++ b/strerror_override.c @@ -1,4 +1,5 @@ -#include +#define STRERROR_OVERRIDE_IMPL 1 +#include "strerror_override.h" /* * Override strerror() to get consistent output across platforms. @@ -52,14 +53,20 @@ static struct { { 0, (char *)0 } }; +// Enabled during tests +int _json_c_strerror_enable = 0; + #define PREFIX "ERRNO=" static char errno_buf[128] = PREFIX; -char *strerror(int errno_in) +char *_json_c_strerror(int errno_in) { int start_idx; char digbuf[20]; int ii, jj; + if (!_json_c_strerror_enable) + return strerror(errno_in); + // Avoid standard functions, so we don't need to include any // headers, or guess at signatures. diff --git a/strerror_override.h b/strerror_override.h new file mode 100644 index 0000000..15d8320 --- /dev/null +++ b/strerror_override.h @@ -0,0 +1,25 @@ +#ifndef _json_strerror_override_h_ +#define _json_strerror_override_h_ + +#include "config.h" +#include + +#include "json_object.h" /* for JSON_EXPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +JSON_EXPORT char *_json_c_strerror(int errno_in); + +#ifndef STRERROR_OVERRIDE_IMPL +#define strerror _json_c_strerror +#else +#include +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _json_strerror_override_h_ */ diff --git a/strerror_override_private.h b/strerror_override_private.h new file mode 100644 index 0000000..c7db84c --- /dev/null +++ b/strerror_override_private.h @@ -0,0 +1,7 @@ +#ifndef __json_strerror_override_private_h__ +#define __json_strerror_override_private_h__ + +/* Used by tests to get consistent output */ +extern int _json_c_strerror_enable; + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 824ed30..917d20f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -52,7 +52,7 @@ EXTRA_DIST+= test2Formatted_plain.expected EXTRA_DIST+= test2Formatted_pretty.expected EXTRA_DIST+= test2Formatted_spaced.expected -test_util_file_SOURCES = test_util_file.c strerror_override.c +test_util_file_SOURCES = test_util_file.c testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/tests/test-defs.sh b/tests/test-defs.sh index 5a32d39..7e1739b 100755 --- a/tests/test-defs.sh +++ b/tests/test-defs.sh @@ -50,6 +50,14 @@ echo "=== Running test $progname" CMP="${CMP-cmp}" use_valgrind=${USE_VALGRIND-1} +case "${use_valgrind}" in + [0Nn]*) + use_valgrind=0 + ;; + *) + use_valgrind=1 + ;; +esac valgrind_path=$(which valgrind 2> /dev/null) if [ -z "${valgrind_path}" -o ! -x "${valgrind_path}" ] ; then use_valgrind=0 diff --git a/tests/test1.c b/tests/test1.c index a53c4ce..3ddaf72 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -120,6 +120,19 @@ void test_array_del_idx() (int)(orig_array_len + 1), rc, json_object_to_json_string(my_array)); json_object_put(my_array); + + /* Delete some array indexes, then add more */ + my_array = make_array(); + rc = json_object_array_del_idx(my_array, 0, orig_array_len - 1); + printf("after del_idx(0,%d)=%d, my_array.to_string()=%s\n", + (int)(orig_array_len - 1), rc, json_object_to_json_string(my_array)); + json_object_array_add(my_array, json_object_new_string("s1")); + json_object_array_add(my_array, json_object_new_string("s2")); + json_object_array_add(my_array, json_object_new_string("s3")); + + printf("after adding more entries, my_array.to_string()=%s\n", + json_object_to_json_string(my_array)); + json_object_put(my_array); } int main(int argc, char **argv) diff --git a/tests/test1.expected b/tests/test1.expected index 816a8c7..e36d372 100644 --- a/tests/test1.expected +++ b/tests/test1.expected @@ -38,6 +38,8 @@ after del_idx(0,1)=0, my_array.to_string()=[ ] after del_idx(0,1)=-1, my_array.to_string()=[ ] after del_idx(0,7)=0, my_array.to_string()=[ ] after del_idx(0,8)=-1, my_array.to_string()=[ 1, 2, 3, 4, 5, null, 7 ] +after del_idx(0,6)=0, my_array.to_string()=[ 7 ] +after adding more entries, my_array.to_string()=[ 7, "s1", "s2", "s3" ] my_array= [0]=3 [1]=1 diff --git a/tests/test1Formatted_plain.expected b/tests/test1Formatted_plain.expected index fe68f27..8a05723 100644 --- a/tests/test1Formatted_plain.expected +++ b/tests/test1Formatted_plain.expected @@ -38,6 +38,8 @@ after del_idx(0,1)=0, my_array.to_string()=[] after del_idx(0,1)=-1, my_array.to_string()=[] after del_idx(0,7)=0, my_array.to_string()=[] after del_idx(0,8)=-1, my_array.to_string()=[1,2,3,4,5,null,7] +after del_idx(0,6)=0, my_array.to_string()=[7] +after adding more entries, my_array.to_string()=[7,"s1","s2","s3"] my_array= [0]=3 [1]=1 diff --git a/tests/test1Formatted_pretty.expected b/tests/test1Formatted_pretty.expected index 85df4fc..809dfbe 100644 --- a/tests/test1Formatted_pretty.expected +++ b/tests/test1Formatted_pretty.expected @@ -44,6 +44,8 @@ after del_idx(0,1)=0, my_array.to_string()=[] after del_idx(0,1)=-1, my_array.to_string()=[] after del_idx(0,7)=0, my_array.to_string()=[] after del_idx(0,8)=-1, my_array.to_string()=[1,2,3,4,5,null,7] +after del_idx(0,6)=0, my_array.to_string()=[7] +after adding more entries, my_array.to_string()=[7,"s1","s2","s3"] my_array= [0]=3 [1]=1 diff --git a/tests/test1Formatted_spaced.expected b/tests/test1Formatted_spaced.expected index 57592f9..6afb39f 100644 --- a/tests/test1Formatted_spaced.expected +++ b/tests/test1Formatted_spaced.expected @@ -38,6 +38,8 @@ after del_idx(0,1)=0, my_array.to_string()=[] after del_idx(0,1)=-1, my_array.to_string()=[] after del_idx(0,7)=0, my_array.to_string()=[] after del_idx(0,8)=-1, my_array.to_string()=[1,2,3,4,5,null,7] +after del_idx(0,6)=0, my_array.to_string()=[7] +after adding more entries, my_array.to_string()=[7,"s1","s2","s3"] my_array= [0]=3 [1]=1 diff --git a/tests/test4.test b/tests/test4.test deleted file mode 100755 index 8bcc460..0000000 --- a/tests/test4.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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 $? diff --git a/tests/test4.test b/tests/test4.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test4.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/testReplaceExisting.test b/tests/testReplaceExisting.test deleted file mode 100755 index ec5cbf1..0000000 --- a/tests/testReplaceExisting.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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 testReplaceExisting -exit $? diff --git a/tests/testReplaceExisting.test b/tests/testReplaceExisting.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/testReplaceExisting.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_basic.test b/tests/test_basic.test new file mode 100755 index 0000000..154e036 --- /dev/null +++ b/tests/test_basic.test @@ -0,0 +1,19 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +filename=$(basename "$0") +filename="${filename%.*}" + +# This is only for the test_util_file.test ; +# more stuff could be extended +cp -f "$srcdir/valid.json" . + +run_output_test $filename "$srcdir" +exit $? diff --git a/tests/test_cast.test b/tests/test_cast.test deleted file mode 100755 index 2102467..0000000 --- a/tests/test_cast.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_cast -exit $? diff --git a/tests/test_cast.test b/tests/test_cast.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_cast.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_charcase.test b/tests/test_charcase.test deleted file mode 100755 index c967475..0000000 --- a/tests/test_charcase.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_charcase -exit $? diff --git a/tests/test_charcase.test b/tests/test_charcase.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_charcase.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_compare.test b/tests/test_compare.test deleted file mode 100755 index bcc4ff3..0000000 --- a/tests/test_compare.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_compare -exit $? diff --git a/tests/test_compare.test b/tests/test_compare.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_compare.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 4ef754d..c7b229e 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -27,5 +27,31 @@ int main() json_object_set_serializer(obj, NULL, NULL, NULL); printf("obj.to_string(reset)=%s\n", json_object_to_json_string(obj)); + json_object_put(obj); + obj = json_object_new_double(0.52381); + + printf("obj.to_string(default format)=%s\n", json_object_to_json_string(obj)); + if (json_c_set_serialization_double_format("x%0.3fy", JSON_C_OPTION_GLOBAL) < 0) + printf("ERROR: json_c_set_serialization_double_format() failed"); + printf("obj.to_string(with global format)=%s\n", json_object_to_json_string(obj)); +#ifdef HAVE___THREAD + if (json_c_set_serialization_double_format("T%0.2fX", JSON_C_OPTION_THREAD) < 0) + printf("ERROR: json_c_set_serialization_double_format() failed"); + printf("obj.to_string(with thread format)=%s\n", json_object_to_json_string(obj)); + if (json_c_set_serialization_double_format("Ttttttttttttt%0.2fxxxxxxxxxxxxxxxxxxX", JSON_C_OPTION_THREAD) < 0) + printf("ERROR: json_c_set_serialization_double_format() failed"); + printf("obj.to_string(long thread format)=%s\n", json_object_to_json_string(obj)); + if (json_c_set_serialization_double_format(NULL, JSON_C_OPTION_THREAD) < 0) + printf("ERROR: json_c_set_serialization_double_format() failed"); + printf("obj.to_string(back to global format)=%s\n", json_object_to_json_string(obj)); +#else + // Just fake it up, so the output matches. + printf("obj.to_string(with thread format)=%s\n", "T0.52X"); + printf("obj.to_string(back to global format)=%s\n", "x0.524y"); +#endif + if (json_c_set_serialization_double_format(NULL, JSON_C_OPTION_GLOBAL) < 0) + printf("ERROR: json_c_set_serialization_double_format() failed"); + printf("obj.to_string(back to default format)=%s\n", json_object_to_json_string(obj)); + json_object_put(obj); } diff --git a/tests/test_double_serializer.expected b/tests/test_double_serializer.expected index da645d7..cd5f02b 100644 --- a/tests/test_double_serializer.expected +++ b/tests/test_double_serializer.expected @@ -6,3 +6,9 @@ Test explicit serializer with custom userdata: obj.to_string(custom)=test Test reset serializer: obj.to_string(reset)=0.5 +obj.to_string(default format)=0.52381 +obj.to_string(with global format)=x0.524y +obj.to_string(with thread format)=T0.52X +obj.to_string(long thread format)=Ttttttttttttt0.52xxxxxxxxxxxxxxxxxxX +obj.to_string(back to global format)=x0.524y +obj.to_string(back to default format)=0.52381 diff --git a/tests/test_double_serializer.test b/tests/test_double_serializer.test deleted file mode 100755 index d4abac4..0000000 --- a/tests/test_double_serializer.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_double_serializer -exit $? diff --git a/tests/test_double_serializer.test b/tests/test_double_serializer.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_double_serializer.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_float.test b/tests/test_float.test deleted file mode 100755 index 8fb5d21..0000000 --- a/tests/test_float.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_float -exit $? diff --git a/tests/test_float.test b/tests/test_float.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_float.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_json_pointer.c b/tests/test_json_pointer.c index c3733de..97566e2 100644 --- a/tests/test_json_pointer.c +++ b/tests/test_json_pointer.c @@ -1,4 +1,5 @@ -#include +#include "strerror_override.h" +#include "strerror_override_private.h" #include #include #include @@ -280,6 +281,8 @@ static void test_wrong_inputs_set() int main(int argc, char **argv) { + _json_c_strerror_enable = 1; + test_example_get(); test_recursion_get(); test_wrong_inputs_get(); diff --git a/tests/test_json_pointer.test b/tests/test_json_pointer.test deleted file mode 100755 index 54e5a89..0000000 --- a/tests/test_json_pointer.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_json_pointer -exit $? diff --git a/tests/test_json_pointer.test b/tests/test_json_pointer.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_json_pointer.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_locale.c b/tests/test_locale.c index a3e319d..7d6541a 100644 --- a/tests/test_locale.c +++ b/tests/test_locale.c @@ -7,6 +7,7 @@ #include "config.h" #include "json.h" #include "json_tokener.h" +#include "snprintf_compat.h" #ifdef HAVE_LOCALE_H #include diff --git a/tests/test_locale.test b/tests/test_locale.test deleted file mode 100755 index e4b6c6d..0000000 --- a/tests/test_locale.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_locale -exit $? diff --git a/tests/test_locale.test b/tests/test_locale.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_locale.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_null.test b/tests/test_null.test deleted file mode 100755 index 469ec64..0000000 --- a/tests/test_null.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_null -exit $? diff --git a/tests/test_null.test b/tests/test_null.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_null.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_parse.test b/tests/test_parse.test deleted file mode 100755 index 70d1c82..0000000 --- a/tests/test_parse.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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 $? diff --git a/tests/test_parse.test b/tests/test_parse.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_parse.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_parse_int64.test b/tests/test_parse_int64.test deleted file mode 100755 index 2b7fbfb..0000000 --- a/tests/test_parse_int64.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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 $? diff --git a/tests/test_parse_int64.test b/tests/test_parse_int64.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_parse_int64.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_printbuf.test b/tests/test_printbuf.test deleted file mode 100755 index 09d27c2..0000000 --- a/tests/test_printbuf.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_printbuf -exit $? diff --git a/tests/test_printbuf.test b/tests/test_printbuf.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_printbuf.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_set_serializer.test b/tests/test_set_serializer.test deleted file mode 100755 index 728dfed..0000000 --- a/tests/test_set_serializer.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_set_serializer -exit $? diff --git a/tests/test_set_serializer.test b/tests/test_set_serializer.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_set_serializer.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_set_value.test b/tests/test_set_value.test deleted file mode 100755 index 4e8fdac..0000000 --- a/tests/test_set_value.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_set_value -exit $? diff --git a/tests/test_set_value.test b/tests/test_set_value.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_set_value.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_util_file.c b/tests/test_util_file.c index 1b4b066..5a8a8a0 100644 --- a/tests/test_util_file.c +++ b/tests/test_util_file.c @@ -1,4 +1,5 @@ -#include +#include "strerror_override.h" +#include "strerror_override_private.h" #include #include #include @@ -49,6 +50,25 @@ static void test_write_to_file() (rv == 0) ? "OK" : "FAIL", outfile2, rv); if (rv == 0) stat_and_cat(outfile2); + + const char *outfile3 = "json3.out"; + int d = open(outfile3, O_WRONLY|O_CREAT, 0600); + if (d < 0) + { + printf("FAIL: unable to open %s %s\n", outfile3, strerror(errno)); + return; + } + rv = json_object_to_fd(d, jso, JSON_C_TO_STRING_PRETTY); + printf("%s: json_object_to_fd(%s, jso, JSON_C_TO_STRING_PRETTY)=%d\n", + (rv == 0) ? "OK" : "FAIL", outfile3, rv); + // Write the same object twice + rv = json_object_to_fd(d, jso, JSON_C_TO_STRING_PLAIN); + printf("%s: json_object_to_fd(%s, jso, JSON_C_TO_STRING_PLAIN)=%d\n", + (rv == 0) ? "OK" : "FAIL", outfile3, rv); + close(d); + if (rv == 0) + stat_and_cat(outfile3); + json_object_put(jso); } @@ -87,6 +107,7 @@ static void stat_and_cat(const char *file) buf[sb.st_size] = '\0'; printf("file[%s], size=%d, contents=%s\n", file, (int)sb.st_size, buf); free(buf); + close(d); } int main(int argc, char **argv) @@ -94,6 +115,8 @@ int main(int argc, char **argv) // json_object_to_file(file, obj); // json_object_to_file_ext(file, obj, flags); + _json_c_strerror_enable = 1; + const char *testdir; if (argc < 2) { diff --git a/tests/test_util_file.expected b/tests/test_util_file.expected index 09121b9..f64a5a5 100644 --- a/tests/test_util_file.expected +++ b/tests/test_util_file.expected @@ -19,3 +19,17 @@ file[json2.out], size=367, contents={ "foo8":"abcdefghijklmnopqrstuvwxyz", "foo9":"abcdefghijklmnopqrstuvwxyz" } +OK: json_object_to_fd(json3.out, jso, JSON_C_TO_STRING_PRETTY)=0 +OK: json_object_to_fd(json3.out, jso, JSON_C_TO_STRING_PLAIN)=0 +file[json3.out], size=703, contents={ + "foo":1234, + "foo1":"abcdefghijklmnopqrstuvwxyz", + "foo2":"abcdefghijklmnopqrstuvwxyz", + "foo3":"abcdefghijklmnopqrstuvwxyz", + "foo4":"abcdefghijklmnopqrstuvwxyz", + "foo5":"abcdefghijklmnopqrstuvwxyz", + "foo6":"abcdefghijklmnopqrstuvwxyz", + "foo7":"abcdefghijklmnopqrstuvwxyz", + "foo8":"abcdefghijklmnopqrstuvwxyz", + "foo9":"abcdefghijklmnopqrstuvwxyz" +}{"foo":1234,"foo1":"abcdefghijklmnopqrstuvwxyz","foo2":"abcdefghijklmnopqrstuvwxyz","foo3":"abcdefghijklmnopqrstuvwxyz","foo4":"abcdefghijklmnopqrstuvwxyz","foo5":"abcdefghijklmnopqrstuvwxyz","foo6":"abcdefghijklmnopqrstuvwxyz","foo7":"abcdefghijklmnopqrstuvwxyz","foo8":"abcdefghijklmnopqrstuvwxyz","foo9":"abcdefghijklmnopqrstuvwxyz"} diff --git a/tests/test_util_file.test b/tests/test_util_file.test deleted file mode 100755 index 541aada..0000000 --- a/tests/test_util_file.test +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Common definitions -if test -z "$srcdir"; then - srcdir="${0%/*}" - test "$srcdir" = "$0" && srcdir=. - test -z "$srcdir" && srcdir=. -fi -. "$srcdir/test-defs.sh" - -cp -f "$srcdir/valid.json" . -run_output_test test_util_file "$srcdir" -_err=$? - -exit $_err diff --git a/tests/test_util_file.test b/tests/test_util_file.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_util_file.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_visit.test b/tests/test_visit.test deleted file mode 100755 index 87e2561..0000000 --- a/tests/test_visit.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/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_visit -exit $? diff --git a/tests/test_visit.test b/tests/test_visit.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_visit.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/vasprintf_compat.h b/vasprintf_compat.h index 51e234b..40ff550 100644 --- a/vasprintf_compat.h +++ b/vasprintf_compat.h @@ -1,11 +1,7 @@ #ifndef __vasprintf_compat_h #define __vasprintf_compat_h -#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) -# define vsnprintf _vsnprintf -#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ -# error Need vsnprintf! -#endif /* !HAVE_VSNPRINTF && defined(WIN32) */ +#include "snprintf_compat.h" #if !defined(HAVE_VASPRINTF) /* CAW: compliant version of vasprintf */