Merge branch 'master' into fix-issue281
This commit is contained in:
commit
25e706cce7
@ -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)
|
||||||
|
12
README.rst
12
README.rst
@ -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::
|
||||||
|
|
||||||
|
@ -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}")
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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. */
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
62
src/value.c
62
src/value.c
@ -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;
|
||||||
|
@ -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");
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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()
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user