Merge branch 'master' into fix-issue281

This commit is contained in:
Petri Lehtinen 2019-10-17 13:37:33 +03:00 committed by GitHub
commit 25e706cce7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 239 additions and 50 deletions

View File

@ -1,7 +1,7 @@
# Notes: # Notes:
# #
# Author: Paul Harris, June 2012 # Author: Paul Harris, June 2012
# Additions: Joakim Soderberg, Febuary 2013 # Additions: Joakim Soderberg, February 2013
# #
# Supports: building static/shared, release/debug/etc, can also build html docs # Supports: building static/shared, release/debug/etc, can also build html docs
# and some of the tests. # and some of the tests.
@ -35,7 +35,7 @@
# >> make test (to run the tests, if you enabled them) # >> make test (to run the tests, if you enabled them)
# #
# Brief description on how it works: # Brief description on how it works:
# There is a small heirachy of CMakeLists.txt files which define how the # There is a small hierarchy of CMakeLists.txt files which define how the
# project is built. # project is built.
# Header file detection etc is done, and the results are written into config.h # Header file detection etc is done, and the results are written into config.h
# and jansson_config.h, which are generated from the corresponding # and jansson_config.h, which are generated from the corresponding
@ -100,7 +100,7 @@ include (CheckFunctionKeywords)
include (CheckIncludeFiles) include (CheckIncludeFiles)
include (CheckTypeSize) include (CheckTypeSize)
# supress format-truncation warning # suppress format-truncation warning
include (CheckCCompilerFlag) include (CheckCCompilerFlag)
check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION) check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION)
if (HAS_NO_FORMAT_TRUNCATION) if (HAS_NO_FORMAT_TRUNCATION)
@ -215,7 +215,7 @@ else ()
set (JSON_UINT8 "unsigned char") set (JSON_UINT8 "unsigned char")
endif () endif ()
# Check for ssize_t and SSIZE_T existance. # Check for ssize_t and SSIZE_T existence.
check_type_size(ssize_t SSIZE_T) check_type_size(ssize_t SSIZE_T)
check_type_size(SSIZE_T UPPERCASE_SSIZE_T) check_type_size(SSIZE_T UPPERCASE_SSIZE_T)
if(NOT HAVE_SSIZE_T) if(NOT HAVE_SSIZE_T)

View File

@ -30,6 +30,18 @@ source distribution for details.
Compilation and Installation Compilation and Installation
---------------------------- ----------------------------
You can download and install Jansson using the `vcpkg <https://github.com/Microsoft/vcpkg/>`_ dependency manager:
.. code-block:: bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install jansson
The Jansson port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request <https://github.com/Microsoft/vcpkg/>`_ on the vcpkg repository.
If you obtained a `source tarball`_ from the "Releases" section of the main If you obtained a `source tarball`_ from the "Releases" section of the main
site just use the standard autotools commands:: site just use the standard autotools commands::

View File

@ -102,8 +102,8 @@ if (GIT_FOUND)
message("Git branch: ${GIT_BRANCH}") message("Git branch: ${GIT_BRANCH}")
message("Git author: ${GIT_AUTHOR_NAME}") message("Git author: ${GIT_AUTHOR_NAME}")
message("Git e-mail: ${GIT_AUTHOR_EMAIL}") message("Git e-mail: ${GIT_AUTHOR_EMAIL}")
message("Git commiter name: ${GIT_COMMITTER_NAME}") message("Git committer name: ${GIT_COMMITTER_NAME}")
message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}")
message("Git commit message: ${GIT_COMMIT_MESSAGE}") message("Git commit message: ${GIT_COMMIT_MESSAGE}")
endif() endif()
@ -265,7 +265,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
# Instead of trying to parse the source from the # Instead of trying to parse the source from the
# gcov file, simply read the file contents from the source file. # gcov file, simply read the file contents from the source file.
# (Parsing it from the gcov is hard because C-code uses ; in many places # (Parsing it from the gcov is hard because C-code uses ; in many places
# which also happens to be the same as the CMake list delimeter). # which also happens to be the same as the CMake list delimiter).
file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")

View File

@ -241,27 +241,42 @@ endif ()
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# determine Sphinx version # determine Sphinx version
# some quick experiments by @ploxiln
# - sphinx 1.7 and later have the version output format like "sphinx-build 1.7.2"
# - sphinx 1.2 through 1.6 have the version output format like "Sphinx (sphinx-build) 1.2.2"
# - sphinx 1.1 and before do not have a "--version" flag, but it causes the help output like "-h" does which includes version like "Sphinx v1.0.2"
if (Sphinx-build_EXECUTABLE) if (Sphinx-build_EXECUTABLE)
# intentionally use invalid -h option here as the help that is shown then # intentionally use invalid -h option here as the help that is shown then
# will include the Sphinx version information # will include the Sphinx version information
if (Sphinx_PYTHON_EXECUTABLE) if (Sphinx_PYTHON_EXECUTABLE)
execute_process ( execute_process (
COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" -h COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION ERROR_VARIABLE _Sphinx_VERSION
) )
elseif (UNIX) elseif (UNIX)
execute_process ( execute_process (
COMMAND "${Sphinx-build_EXECUTABLE}" -h COMMAND "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION ERROR_VARIABLE _Sphinx_VERSION
) )
endif () endif ()
# The sphinx version can also contain a "b" instead of the last dot. # The sphinx version can also contain a "b" instead of the last dot.
# For example "Sphinx v1.2b1" so we cannot just split on "." # For example "Sphinx v1.2b1" or "Sphinx 1.7.0b2" so we cannot just split on "."
if (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b)[0-9]+)") if (_Sphinx_VERSION MATCHES "sphinx-build ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
elseif (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
elseif (_Sphinx_VERSION MATCHES "Sphinx \\(sphinx-build\\) ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
endif ()
endif ()
if(_SPHINX_VERSION_FOUND)
string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING}) string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING}) string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING}) string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING})
@ -271,7 +286,6 @@ if (Sphinx-build_EXECUTABLE)
string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}") string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}")
endif () endif ()
endif () endif ()
endif ()
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# compatibility with FindPythonInterp.cmake and FindPerl.cmake # compatibility with FindPythonInterp.cmake and FindPerl.cmake

View File

@ -726,6 +726,12 @@ allowed in object keys.
The value of any existing key is not changed. Returns 0 on success The value of any existing key is not changed. Returns 0 on success
or -1 on error. or -1 on error.
.. function:: int json_object_update_recursive(json_t *object, json_t *other)
Like :func:`json_object_update()`, but object values in *other* are
recursively merged with the corresponding values in *object* if they are also
objects, instead of overwriting them. Returns 0 on success or -1 on error.
.. function:: json_object_foreach(object, key, value) .. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block Iterate over every key-value pair of ``object``, running the block
@ -1351,7 +1357,11 @@ If no error or position information is needed, you can pass *NULL*.
It is important to note that this function can only succeed on stream It is important to note that this function can only succeed on stream
file descriptors (such as SOCK_STREAM). Using this function on a file descriptors (such as SOCK_STREAM). Using this function on a
non-stream file descriptor will result in undefined behavior. For non-stream file descriptor will result in undefined behavior. For
non-stream file descriptors, see instead :func:`json_loadb()`. non-stream file descriptors, see instead :func:`json_loadb()`. In
addition, please note that this function cannot be used on non-blocking
file descriptors (such as a non-blocking socket). Using this function
on non-blocking file descriptors has a high risk of data loss because
it does not support resuming.
This function requires POSIX and fails on all non-POSIX systems. This function requires POSIX and fails on all non-POSIX systems.

View File

@ -74,7 +74,7 @@ function::
static char *request(const char *url); static char *request(const char *url);
It takes the URL as a parameter, preforms a HTTP GET request, and It takes the URL as a parameter, performs a HTTP GET request, and
returns a newly allocated string that contains the response body. If returns a newly allocated string that contains the response body. If
the request fails, an error message is printed to stderr and the the request fails, an error message is printed to stderr and the
return value is *NULL*. For full details, refer to :download:`the code return value is *NULL*. For full details, refer to :download:`the code

View File

@ -55,7 +55,7 @@ typedef struct hashtable {
* *
* Returns 0 on success, -1 on error (out of memory). * Returns 0 on success, -1 on error (out of memory).
*/ */
int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result); int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result));
/** /**
* hashtable_close - Release all resources used by a hashtable object * hashtable_close - Release all resources used by a hashtable object

View File

@ -41,6 +41,7 @@ EXPORTS
json_object_update json_object_update
json_object_update_existing json_object_update_existing
json_object_update_missing json_object_update_missing
json_object_update_recursive
json_object_iter json_object_iter
json_object_iter_at json_object_iter_at
json_object_iter_next json_object_iter_next

View File

@ -40,9 +40,9 @@ extern "C" {
#endif #endif
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__)) #define JANSSON_ATTRS(x) __attribute__(x)
#else #else
#define JANSSON_ATTRS(...) #define JANSSON_ATTRS(x)
#endif #endif
/* types */ /* types */
@ -191,7 +191,7 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
void json_object_seed(size_t seed); void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object); size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result); json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS((warn_unused_result));
int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key); int json_object_del(json_t *object, const char *key);
@ -199,6 +199,7 @@ int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other); int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other); int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other); int json_object_update_missing(json_t *object, json_t *other);
int json_object_update_recursive(json_t *object, json_t *other);
void *json_object_iter(json_t *object); void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key); void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key); void *json_object_key_to_iter(const char *key);
@ -267,7 +268,7 @@ int json_object_update_missing_new(json_t *object, json_t *other)
} }
size_t json_array_size(const json_t *array); size_t json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result); json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS((warn_unused_result));
int json_array_set_new(json_t *array, size_t index, json_t *value); int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value); int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value); int json_array_insert_new(json_t *array, size_t index, json_t *value);
@ -308,9 +309,9 @@ int json_real_set(json_t *real, double value);
/* pack, unpack */ /* pack, unpack */
json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result));
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS((warn_unused_result));
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result); json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS((warn_unused_result));
#define JSON_VALIDATE_ONLY 0x1 #define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2 #define JSON_STRICT 0x2
@ -321,8 +322,8 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char
/* sprintf */ /* sprintf */
json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2)); json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result, format(printf, 1, 2)));
json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0)); json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS((warn_unused_result, format(printf, 1, 0)));
/* equality */ /* equality */
@ -332,8 +333,8 @@ int json_equal(const json_t *value1, const json_t *value2);
/* copying */ /* copying */
json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result); json_t *json_copy(json_t *value) JANSSON_ATTRS((warn_unused_result));
json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result); json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS((warn_unused_result));
/* decoding */ /* decoding */
@ -346,12 +347,12 @@ json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS((warn_unused_result));
/* encoding */ /* encoding */
@ -369,7 +370,7 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result); char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS((warn_unused_result));
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags); int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dumpfd(const json_t *json, int output, size_t flags); int json_dumpfd(const json_t *json, int output, size_t flags);

View File

@ -84,11 +84,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec); int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */ /* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result); void* jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
void jsonp_free(void *ptr); void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result); char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result));
char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result); char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result));
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result); char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result));
/* Circular reference check*/ /* Circular reference check*/
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */

View File

@ -243,7 +243,7 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
* rest of the string. Every machine with memory protection I've seen * rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will * does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash * still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words). * noticeably faster for short strings (like English words).
*/ */
#ifndef NO_MASKING_TRICK #ifndef NO_MASKING_TRICK

View File

@ -16,7 +16,7 @@ typedef struct {
size_t size; /* bytes allocated */ size_t size; /* bytes allocated */
} strbuffer_t; } strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result); int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result));
void strbuffer_close(strbuffer_t *strbuff); void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff);

View File

@ -37,7 +37,7 @@ static JSON_INLINE int isnan(double x) { return x != x; }
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif #endif
json_t *do_deep_copy(const json_t *, hashtable_t *); json_t *do_deep_copy(const json_t *json, hashtable_t *parents);
static JSON_INLINE void json_init(json_t *json, json_type type) static JSON_INLINE void json_init(json_t *json, json_type type)
{ {
@ -214,6 +214,58 @@ int json_object_update_missing(json_t *object, json_t *other)
return 0; return 0;
} }
int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents)
{
const char *key;
json_t *value;
char loop_key[LOOP_KEY_LEN];
int res = 0;
if(!json_is_object(object) || !json_is_object(other))
return -1;
if(jsonp_loop_check(parents, other, loop_key, sizeof(loop_key)))
return -1;
json_object_foreach(other, key, value) {
json_t *v = json_object_get(object, key);
if(json_is_object(v) && json_is_object(value))
{
if(do_object_update_recursive(v, value, parents))
{
res = -1;
break;
}
}
else
{
if(json_object_set_nocheck(object, key, value))
{
res = -1;
break;
}
}
}
hashtable_del(parents, loop_key);
return res;
}
int json_object_update_recursive(json_t *object, json_t *other)
{
int res;
hashtable_t parents_set;
if (hashtable_init(&parents_set))
return -1;
res = do_object_update_recursive(object, other, &parents_set);
hashtable_close(&parents_set);
return res;
}
void *json_object_iter(json_t *json) void *json_object_iter(json_t *json)
{ {
json_object_t *object; json_object_t *object;
@ -329,7 +381,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
result = json_object(); result = json_object();
if(!result) if(!result)
return NULL; goto out;
/* Cannot use json_object_foreach because object has to be cast /* Cannot use json_object_foreach because object has to be cast
non-const */ non-const */
@ -348,6 +400,8 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
} }
iter = json_object_iter_next((json_t *)object, iter); iter = json_object_iter_next((json_t *)object, iter);
} }
out:
hashtable_del(parents, loop_key); hashtable_del(parents, loop_key);
return result; return result;
@ -648,7 +702,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
result = json_array(); result = json_array();
if(!result) if(!result)
return NULL; goto out;
for(i = 0; i < json_array_size(array); i++) for(i = 0; i < json_array_size(array); i++)
{ {
@ -659,6 +713,8 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents)
break; break;
} }
} }
out:
hashtable_del(parents, loop_key); hashtable_del(parents, loop_key);
return result; return result;

View File

@ -186,7 +186,7 @@ static void test_insert(void)
for(i = 0; i < 20; i++) { for(i = 0; i < 20; i++) {
if(json_array_insert(array, 0, seven)) if(json_array_insert(array, 0, seven))
fail("unable to insert value at the begining of an array"); fail("unable to insert value at the beginning of an array");
} }
for(i = 0; i < 20; i++) { for(i = 0; i < 20; i++) {
@ -479,9 +479,9 @@ static void test_bad_args(void)
if(!json_array_extend(num, arr)) if(!json_array_extend(num, arr))
fail("json_array_extend did not return error for first argument non-array"); fail("json_array_extend did not return error for first argument non-array");
if(!json_array_extend(arr, NULL)) if(!json_array_extend(arr, NULL))
fail("json_array_extend did not return error for second arguemnt non-array"); fail("json_array_extend did not return error for second argument non-array");
if(!json_array_extend(arr, num)) if(!json_array_extend(arr, num))
fail("json_array_extend did not return error for second arguemnt non-array"); fail("json_array_extend did not return error for second argument non-array");
if(num->refcount != 1) if(num->refcount != 1)
fail("unexpected reference count on num"); fail("unexpected reference count on num");

View File

@ -13,6 +13,10 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "util.h" #include "util.h"
#ifdef __MINGW32__
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
#endif
static int encode_null_callback(const char *buffer, size_t size, void *data) static int encode_null_callback(const char *buffer, size_t size, void *data)
{ {

View File

@ -159,7 +159,7 @@ static void test_equal_object()
static void test_equal_complex() static void test_equal_complex()
{ {
json_t *value1, *value2; json_t *value1, *value2, *value3;
const char *complex_json = const char *complex_json =
"{" "{"
@ -176,15 +176,25 @@ static void test_equal_complex()
value1 = json_loads(complex_json, 0, NULL); value1 = json_loads(complex_json, 0, NULL);
value2 = json_loads(complex_json, 0, NULL); value2 = json_loads(complex_json, 0, NULL);
value3 = json_loads(complex_json, 0, NULL);
if(!value1 || !value2) if(!value1 || !value2)
fail("unable to parse JSON"); fail("unable to parse JSON");
if(!json_equal(value1, value2)) if(!json_equal(value1, value2))
fail("json_equal fails for two inequal strings"); fail("json_equal fails for two equal objects");
json_array_set_new(json_object_get(json_object_get(value2, "object"),
"array-in-object"), 1, json_false());
if(json_equal(value1, value2))
fail("json_equal fails for two inequal objects");
json_object_set_new(json_object_get(json_object_get(value3, "object"),
"object-in-object"), "foo", json_string("baz"));
if(json_equal(value1, value3))
fail("json_equal fails for two inequal objects");
json_decref(value1); json_decref(value1);
json_decref(value2); json_decref(value2);
json_decref(value3);
/* TODO: There's no negative test case here */
} }
static void run_tests() static void run_tests()

View File

@ -59,7 +59,7 @@ static void test_update()
/* update an empty object with an empty object */ /* update an empty object with an empty object */
if(json_object_update(object, other)) if(json_object_update(object, other))
fail("unable to update an emtpy object with an empty object"); fail("unable to update an empty object with an empty object");
if(json_object_size(object) != 0) if(json_object_size(object) != 0)
fail("invalid size after update"); fail("invalid size after update");
@ -270,6 +270,86 @@ static void test_conditional_updates()
json_decref(other); json_decref(other);
} }
static void test_recursive_updates()
{
json_t *invalid, *object, *other, *barBefore, *barAfter;
invalid = json_integer(42);
object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
other = json_pack("{sisisi}", "foo", 3, "bar", 4, "baz", 5);
if(!json_object_update_recursive(invalid, other))
fail("json_object_update_recursive accepted non-object argument");
json_decref(invalid);
if(json_object_update_recursive(object, other))
fail("json_object_update_recursive failed");
if(json_object_size(object) != 3)
fail("invalid size after update");
if(json_integer_value(json_object_get(object, "foo")) != 3)
fail("json_object_update_recursive failed to update existing key");
if(json_integer_value(json_object_get(object, "bar")) != 4)
fail("json_object_update_recursive failed to overwrite object");
if(json_integer_value(json_object_get(object, "baz")) != 5)
fail("json_object_update_recursive didn't add new item");
json_decref(object);
json_decref(other);
object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
other = json_pack("{s{si}}", "bar", "baz", 3);
barBefore = json_object_get(object, "bar");
if(!barBefore)
fail("can't get bar object before json_object_update_recursive");
if(json_object_update_recursive(object, other))
fail("json_object_update_recursive failed");
if(json_object_size(object) != 2)
fail("invalid size after update");
if(!json_object_get(object, "foo"))
fail("json_object_update_recursive removed existing key");
if(json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3)
fail("json_object_update_recursive failed to update nested value");
barAfter = json_object_get(object, "bar");
if(!barAfter)
fail("can't get bar object after json_object_update_recursive");
if(barBefore != barAfter)
fail("bar object reference changed after json_object_update_recursive");
json_decref(object);
json_decref(other);
/* check circular reference */
object = json_pack("{s{s{s{si}}}}", "foo", "bar", "baz", "xxx", 2);
other = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2);
json_object_set(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
json_object_get(other, "foo"));
if(!json_object_update_recursive(object, other))
fail("json_object_update_recursive update a circular reference!");
json_object_set_new(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
json_integer(1));
if(json_object_update_recursive(object, other))
fail("json_object_update_recursive failed!");
json_decref(object);
json_decref(other);
}
static void test_circular() static void test_circular()
{ {
json_t *object1, *object2; json_t *object1, *object2;
@ -730,6 +810,7 @@ static void run_tests()
test_update(); test_update();
test_set_many_keys(); test_set_many_keys();
test_conditional_updates(); test_conditional_updates();
test_recursive_updates();
test_circular(); test_circular();
test_set_nocheck(); test_set_nocheck();
test_iterators(); test_iterators();