Compare commits

..

No commits in common. "master" and "v2.14" have entirely different histories.

55 changed files with 352 additions and 6693 deletions

View file

@ -1,15 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
groups:
github-actions:
patterns:
- "*"

View file

@ -24,7 +24,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View file

@ -10,7 +10,7 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- run: ./scripts/clang-format-check
autotools:
@ -18,19 +18,18 @@ jobs:
matrix:
os: ["ubuntu-latest", "macos-latest"]
cc: ["gcc", "clang"]
dtoa: ["yes", "no"]
runs-on: ${{ matrix.os }}
runs-on: ${{matrix.os}}
steps:
- if: ${{runner.os == 'macOS'}}
run: brew install autoconf automake libtool
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- run: autoreconf -fi
- env:
CC: ${{ matrix.cc }}
CC: ${{matrix.cc}}
CFLAGS: -Werror
run: ./configure --enable-dtoa=${{ matrix.dtoa }}
run: ./configure
- run: make check
cmake:
@ -50,18 +49,32 @@ jobs:
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- env:
CC: ${{matrix.cc}}
run: cmake .
- run: cmake --build .
- run: ctest --output-on-failure
- run: ctest
valgrind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- run: sudo apt update && sudo apt install valgrind
- run: cmake -DJANSSON_TEST_WITH_VALGRIND=ON .
- run: cmake --build .
- run: ctest --output-on-failure
- run: ctest
coveralls:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt update && sudo apt install curl lcov
- run: cmake -DJANSSON_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug .
- run: cmake --build .
- run: cmake --build . --target coverage
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.info

24
CHANGES
View file

@ -1,25 +1,3 @@
Version 2.14.1
==============
Released 2025-03-23
* Fixes:
- Fix thread safety of encoding and decoding when `uselocale` or `newlocale`
is used to switch locales inside the threads (#674, #675, #677. Thanks to
Bruno Haible for the report and help with fixing.)
- Use David M. Gay's `dtoa()` algorithm to avoid misprinting issues of real
numbers that are not exactly representable as a `double` (#680).
If this is not desirable, use `./configure --disable-dtoa` or `cmake
-DUSE_DTOA=OFF .`
* Build:
- Make test output nicer in CMake based builds (#683)
- Simplify tests (#685)
Version 2.14
============
@ -638,7 +616,7 @@ Released 2011-10-06
- Fix identifier decoding under non-UTF-8 locales. (#35)
- `json_load_file()`: Open the input file in binary mode for maximum
compatibility.
compatiblity.
* Documentation:

View file

@ -1,11 +1,10 @@
cmake_minimum_required (VERSION 3.10)
cmake_minimum_required (VERSION 3.1)
project(jansson C)
# Options
option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF)
option(USE_URANDOM "Use /dev/urandom to seed the hash function." ON)
option(USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON)
option(USE_DTOA "Use dtoa for optimal floating-point to string conversions." ON)
if (MSVC)
# This option must match the settings used in your program, in particular if you
@ -36,7 +35,7 @@ endif()
# set (JANSSON_VERSION "2.3.1")
# set (JANSSON_SOVERSION 2)
set(JANSSON_DISPLAY_VERSION "2.14.1")
set(JANSSON_DISPLAY_VERSION "2.14")
# This is what is required to match the same numbers as automake's
set(JANSSON_VERSION "4.14.0")
@ -94,9 +93,6 @@ check_function_exists (sched_yield HAVE_SCHED_YIELD)
# Check for the int-type includes
check_include_files (stdint.h HAVE_STDINT_H)
include (TestBigEndian)
TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
# Check our 64 bit integer sizes
check_type_size (__int64 __INT64)
check_type_size (int64_t INT64_T)
@ -197,8 +193,6 @@ endif ()
# detect what to use for the 64 bit type.
# Note: I will prefer long long if I can get it, as that is what the automake system aimed for.
if (NOT DEFINED JSON_INT_T)
set (JSON_INTEGER_IS_LONG_LONG 1)
if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8))
set (JSON_INT_T "long long")
elseif (HAVE_INT64_T)
@ -221,7 +215,18 @@ if (NOT DEFINED JSON_INT_T)
endif ()
endif ()
# If locale.h and localeconv() are available, define to 1, otherwise to 0.
check_include_files (locale.h HAVE_LOCALE_H)
check_function_exists (localeconv HAVE_LOCALECONV)
if (HAVE_LOCALECONV AND HAVE_LOCALE_H)
set (JSON_HAVE_LOCALECONV 1)
else ()
set (JSON_HAVE_LOCALECONV 0)
endif()
# check if we have setlocale
check_function_exists(setlocale HAVE_SETLOCALE)
# Check what the inline keyword is.
@ -266,20 +271,20 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake
file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/)
add_definitions(-DJANSSON_USING_CMAKE)
# configure the private config file
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)
# and tell the source code to include it
add_definitions(-DHAVE_CONFIG_H)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/include)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include)
# Configuration flags will be set on project later once we have defined the target
# Add the lib sources.
file(GLOB JANSSON_SRC src/*.c)
if (NOT USE_DTOA)
list(FILTER JANSSON_SRC EXCLUDE REGEX ".*dtoa\\.c$")
endif()
set(JANSSON_HDR_PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h
@ -337,7 +342,7 @@ if(JANSSON_BUILD_SHARED_LIBS)
)
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
if (VSCRIPT_WORKS)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
endif()
endif()
@ -353,20 +358,6 @@ else()
POSITION_INDEPENDENT_CODE true)
endif()
# Now target jansson is declared, set per-target values
target_compile_definitions(jansson PUBLIC JANSSON_USING_CMAKE)
target_compile_definitions(jansson PRIVATE HAVE_CONFIG_H)
target_include_directories(jansson
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
INTERFACE $<INSTALL_INTERFACE:include>
)
add_library( jansson::jansson ALIAS jansson )
if (JANSSON_EXAMPLES)
add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c")
target_link_libraries(simple_parse jansson)
@ -546,11 +537,6 @@ if (NOT JANSSON_WITHOUT_TESTS)
if (IS_DIRECTORY ${TESTDIR})
get_filename_component(TNAME ${TESTDIR} NAME)
if ((USE_DTOA AND EXISTS ${TESTDIR}/skip_if_dtoa) OR
(NOT USE_DTOA AND EXISTS ${TESTDIR}/skip_unless_dtoa))
continue()
endif()
if (JANSSON_TEST_WITH_VALGRIND)
add_test(memcheck__${SUITE}__${TNAME}
${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} ${TESTDIR})
@ -616,7 +602,9 @@ foreach(p LIB BIN INCLUDE CMAKE)
endforeach()
# Generate the config file for the build-tree.
set(JANSSON__INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/include")
set(JANSSON__INCLUDE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_BINARY_DIR}/include")
set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake

View file

@ -1,3 +0,0 @@
Hi, and thanks for contributing!
Please remember to add tests and documentation for new functionality. Backwards incompatible changes or features that are not directly related to JSON are likely to be rejected.

26
LICENSE
View file

@ -1,11 +1,4 @@
# License
This project is licensed under the MIT license, except where otherwise noted.
The full text of the MIT license is included below.
## MIT License
Copyright (c) 2009-2024 Petri Lehtinen <petri@digip.org>
Copyright (c) 2009-2020 Petri Lehtinen <petri@digip.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -24,20 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## Exceptions
### `src/dtoa.c`
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
Permission to use, copy, modify, and distribute this software for any
purpose without fee is hereby granted, provided that this entire notice
is included in all copies of any software which is or includes a copy
or modification of this software and in all copies of the supporting
documentation for such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.

View file

@ -1,10 +1,14 @@
Jansson README
==============
.. |tests| image:: https://github.com/akheron/jansson/workflows/tests/badge.svg
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko
.. image:: https://github.com/akheron/jansson/workflows/tests/badge.svg
:target: https://github.com/akheron/jansson/actions
|tests| |appveyor|
.. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko
:target: https://ci.appveyor.com/project/akheron/jansson
.. image:: https://coveralls.io/repos/akheron/jansson/badge.png?branch=master
:target: https://coveralls.io/r/akheron/jansson?branch=master
Jansson_ is a C library for encoding, decoding and manipulating JSON
data. Its main features and design principles are:
@ -22,11 +26,24 @@ data. Its main features and design principles are:
Jansson is licensed under the `MIT license`_; see LICENSE in the
source distribution for details.
Compilation and Installation
----------------------------
If you obtained a ``jansson-X.Y.tar.*`` tarball from GitHub Releases, just use
the standard autotools commands::
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
site just use the standard autotools commands::
$ ./configure
$ make
@ -36,8 +53,9 @@ To run the test suite, invoke::
$ make check
If the source has been checked out from a Git repository, the ``configure``
script has to be generated first. The easiest way is to use autoreconf::
If the source has been checked out from a Git repository, the
./configure script has to be generated first. The easiest way is to
use autoreconf::
$ autoreconf -i
@ -56,15 +74,8 @@ Then, point your browser to ``doc/_build/html/index.html``. Sphinx_
1.0 or newer is required to generate the documentation.
Community
---------
* `Documentation <http://jansson.readthedocs.io/en/latest/>`_
* `Issue tracker <https://github.com/akheron/jansson/issues>`_
* `Mailing list <http://groups.google.com/group/jansson-users>`_
* `Wiki <https://github.com/akheron/jansson/wiki>`_ contains some development documentation
.. _Jansson: http://www.digip.org/jansson/
.. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _`source tarball`: http://www.digip.org/jansson#releases
.. _Sphinx: http://sphinx.pocoo.org/

View file

@ -1,9 +0,0 @@
# Security Policy
## Supported Versions
Latest released version.
## Reporting a Vulnerability
Send an email to petri@digip.org.

View file

@ -32,6 +32,10 @@
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 0
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048

View file

@ -21,10 +21,9 @@
#define JANSSON_USING_CMAKE
#endif
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#cmakedefine JSON_INTEGER_IS_LONG_LONG 1
/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used,
* as we will also check for __int64 etc types.
* (the definition was used in the automake system) */
/* Bring in the cmake-detected defines */
#cmakedefine HAVE_STDINT_H 1
@ -57,6 +56,9 @@
#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@
/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */
#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@

View file

@ -21,8 +21,6 @@
#cmakedefine HAVE_LOCALE_H 1
#cmakedefine HAVE_SETLOCALE 1
#cmakedefine WORDS_BIGENDIAN 1
#cmakedefine HAVE_INT32_T 1
#ifndef HAVE_INT32_T
# define int32_t @JSON_INT32@
@ -52,11 +50,4 @@
#cmakedefine USE_URANDOM 1
#cmakedefine USE_WINDOWS_CRYPTOAPI 1
#cmakedefine USE_DTOA 1
#if USE_DTOA
# define DTOA_ENABLED 1
#else
# define DTOA_ENABLED 0
#endif
#define INITIAL_HASHTABLE_ORDER @JANSSON_INITIAL_HASHTABLE_ORDER@

View file

@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([jansson], [2.14.1], [https://github.com/akheron/jansson/issues])
AC_INIT([jansson], [2.14], [https://github.com/akheron/jansson/issues])
AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([1.10 foreign])
@ -25,8 +25,6 @@ AC_TYPE_UINT16_T
AC_TYPE_UINT8_T
AC_TYPE_LONG_LONG_INT
AC_C_BIGENDIAN
AC_C_INLINE
case $ac_cv_c_inline in
yes) json_inline=inline;;
@ -36,7 +34,7 @@ esac
AC_SUBST([json_inline])
# Checks for library functions.
AC_CHECK_FUNCS([close getpid gettimeofday open read setlocale sched_yield strtoll])
AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll])
AC_MSG_CHECKING([for gcc __sync builtins])
have_sync_builtins=no
@ -76,6 +74,12 @@ case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
esac
AC_SUBST([json_have_long_long])
case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in
yesyes) json_have_localeconv=1;;
*) json_have_localeconv=0;;
esac
AC_SUBST([json_have_localeconv])
# Features
AC_ARG_ENABLE([urandom],
[AS_HELP_STRING([--disable-urandom],
@ -138,19 +142,6 @@ JSON_SYMVER_LDFLAGS=
AC_CHECK_DECL([__GLIBC__], [JSON_SYMVER_LDFLAGS=-Wl,--default-symver])
AC_SUBST([JSON_SYMVER_LDFLAGS])
AC_ARG_ENABLE([dtoa],
[AS_HELP_STRING([--enable-dtoa], [Use dtoa for optimal floating point to string conversion])],
[case "$enableval" in
yes) dtoa=yes ;;
no) dtoa=no ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-dtoa]) ;;
esac], [dtoa=yes])
if test "$dtoa" = "yes"; then
AC_DEFINE([DTOA_ENABLED], [1],
[Define to 1 to use dtoa to convert floating points to strings])
fi
AM_CONDITIONAL([DTOA_ENABLED], [test "$dtoa" = "yes"])
AC_ARG_ENABLE([ossfuzzers],
[AS_HELP_STRING([--enable-ossfuzzers],
[Whether to generate the fuzzers for OSS-Fuzz])],

View file

@ -1,9 +0,0 @@
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.12"
sphinx:
configuration: doc/conf.py

View file

@ -48,7 +48,7 @@ copyright = u'2009-2020, Petri Lehtinen'
# built documents.
#
# The short X.Y version.
version = '2.14.1'
version = '2.14'
# The full version, including alpha/beta/rc tags.
release = version

View file

@ -153,7 +153,6 @@ int main(int argc, char *argv[]) {
sha = json_object_get(data, "sha");
if (!json_is_string(sha)) {
fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1));
json_decref(root);
return 1;
}

View file

@ -1,3 +1,3 @@
#!/bin/bash
git ls-files | grep '\.[ch]$' | xargs clang-format -i
find . -type f -a '(' -name '*.c' -o -name '*.h' ')' | xargs clang-format -i

View file

@ -12,16 +12,13 @@ fi
errors=0
paths=$(git ls-files | grep '\.[ch]$')
for path in $paths; do
echo "Checking $path"
$CLANG_FORMAT $path > $path.formatted
in=$(cat $path)
out=$(cat $path.formatted)
out=$($CLANG_FORMAT $path)
if [ "$in" != "$out" ]; then
diff -u $path $path.formatted
diff -u -L $path -L "$path.formatted" $path - <<<$out
errors=1
fi
rm $path.formatted
done
if [ $errors -ne 0 ]; then

View file

@ -1,4 +1,4 @@
EXTRA_DIST = jansson.def dtoa.c
EXTRA_DIST = jansson.def
include_HEADERS = jansson.h
nodist_include_HEADERS = jansson_config.h
@ -22,14 +22,9 @@ libjansson_la_SOURCES = \
utf.h \
value.c \
version.c
if DTOA_ENABLED
libjansson_la_SOURCES += dtoa.c
endif
libjansson_la_LDFLAGS = \
-no-undefined \
-export-symbols-regex '^json_|^jansson_' \
-version-info 18:1:14 \
-version-info 18:0:14 \
@JSON_SYMVER_LDFLAGS@ \
@JSON_BSYMBOLIC_LDFLAGS@

6265
src/dtoa.c

File diff suppressed because it is too large Load diff

View file

@ -23,10 +23,10 @@
#include "strbuffer.h"
#include "utf.h"
#define MAX_INTEGER_STR_LENGTH 25
#define MAX_REAL_STR_LENGTH 25
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_INDENT(f) ((f)&0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct buffer {

View file

@ -5,14 +5,14 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifdef HAVE_CONFIG_H
#if HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STDINT_H
#if HAVE_STDINT_H
#include <stdint.h>
#endif

View file

@ -22,10 +22,10 @@ extern "C" {
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 14
#define JANSSON_MICRO_VERSION 1
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.14.1"
#define JANSSON_VERSION "2.14"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@ -379,14 +379,14 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
/* encoding */
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
#define JSON_INDENT(n) ((n)&JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
#define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11)
#define JSON_EMBED 0x10000
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);

View file

@ -32,6 +32,10 @@
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@

View file

@ -562,7 +562,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
long unpacked = 0;
if (gotopt || json_object_size(root) != key_set.size) {
json_object_keylen_foreach(root, key, key_len, value) {
json_object_foreach(root, key, value) {
key_len = strlen(key);
if (!hashtable_get(&key_set, key, key_len)) {
unpacked++;

View file

@ -16,7 +16,7 @@
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)(-1))
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff) {
strbuff->size = STRBUFFER_MIN_SIZE;

View file

@ -11,42 +11,57 @@
#include <jansson_private_config.h>
#endif
#if JSON_HAVE_LOCALECONV
#include <locale.h>
/*
- This code assumes that the decimal separator is exactly one
character.
- If setlocale() is called by another thread between the call to
get_decimal_point() and the call to sprintf() or strtod(), the
result may be wrong. setlocale() is not thread-safe and should
not be used this way. Multi-threaded programs should use
uselocale() instead.
localeconv() and the call to sprintf() or strtod(), the result may
be wrong. setlocale() is not thread-safe and should not be used
this way. Multi-threaded programs should use uselocale() instead.
*/
static char get_decimal_point() {
char buf[3];
sprintf(buf, "%#.0f", 1.0); // "1." in the current locale
return buf[1];
}
static void to_locale(strbuffer_t *strbuffer) {
char point;
const char *point;
char *pos;
point = get_decimal_point();
if (point == '.') {
point = localeconv()->decimal_point;
if (*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if (pos)
*pos = point;
*pos = *point;
}
static void from_locale(char *buffer) {
const char *point;
char *pos;
point = localeconv()->decimal_point;
if (*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if (pos)
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
double value;
char *end;
#if JSON_HAVE_LOCALECONV
to_locale(strbuffer);
#endif
errno = 0;
value = strtod(strbuffer->value, &end);
@ -61,127 +76,6 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
return 0;
}
#if DTOA_ENABLED
/* see dtoa.c */
char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve,
char *buf, size_t blen);
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
/* adapted from `format_float_short()` in
* https://github.com/python/cpython/blob/2cf18a44303b6d84faa8ecffaecc427b53ae121e/Python/pystrtod.c#L969
*/
char digits[25];
char *digits_end;
int mode = precision == 0 ? 0 : 2;
int decpt, sign, exp_len, exp = 0, use_exp = 0;
int digits_len, vdigits_start, vdigits_end;
char *p;
if (dtoa_r(value, mode, precision, &decpt, &sign, &digits_end, digits, 25) == NULL) {
// digits is too short => should not happen
return -1;
}
digits_len = digits_end - digits;
if (decpt <= -4 || decpt > 16) {
use_exp = 1;
exp = decpt - 1;
decpt = 1;
}
vdigits_start = decpt <= 0 ? decpt - 1 : 0;
vdigits_end = digits_len;
if (!use_exp) {
/* decpt + 1 to add ".0" if value is an integer */
vdigits_end = vdigits_end > decpt ? vdigits_end : decpt + 1;
} else {
vdigits_end = vdigits_end > decpt ? vdigits_end : decpt;
}
if (
/* sign, decimal point and trailing 0 byte */
(size_t)(3 +
/* total digit count (including zero padding on both sides) */
(vdigits_end - vdigits_start) +
/* exponent "e+100", max 3 numerical digits */
(use_exp ? 5 : 0)) > size) {
/* buffer is too short */
return -1;
}
p = buffer;
if (sign == 1) {
*p++ = '-';
}
/* note that exactly one of the three 'if' conditions is true,
so we include exactly one decimal point */
/* Zero padding on left of digit string */
if (decpt <= 0) {
memset(p, '0', decpt - vdigits_start);
p += decpt - vdigits_start;
*p++ = '.';
memset(p, '0', 0 - decpt);
p += 0 - decpt;
} else {
memset(p, '0', 0 - vdigits_start);
p += 0 - vdigits_start;
}
/* Digits, with included decimal point */
if (0 < decpt && decpt <= digits_len) {
strncpy(p, digits, decpt - 0);
p += decpt - 0;
*p++ = '.';
strncpy(p, digits + decpt, digits_len - decpt);
p += digits_len - decpt;
} else {
strncpy(p, digits, digits_len);
p += digits_len;
}
/* And zeros on the right */
if (digits_len < decpt) {
memset(p, '0', decpt - digits_len);
p += decpt - digits_len;
*p++ = '.';
memset(p, '0', vdigits_end - decpt);
p += vdigits_end - decpt;
} else {
memset(p, '0', vdigits_end - digits_len);
p += vdigits_end - digits_len;
}
if (p[-1] == '.')
p--;
if (use_exp) {
*p++ = 'e';
exp_len = sprintf(p, "%d", exp);
p += exp_len;
}
*p = '\0';
return (int)(p - buffer);
}
#else /* DTOA_ENABLED == 0 */
static void from_locale(char *buffer) {
char point;
char *pos;
point = get_decimal_point();
if (point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, point);
if (pos)
*pos = '.';
}
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
int ret;
char *start, *end;
@ -198,7 +92,9 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
if (length >= size)
return -1;
#if JSON_HAVE_LOCALECONV
from_locale(buffer);
#endif
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
@ -234,4 +130,3 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
return (int)length;
}
#endif

View file

@ -191,14 +191,13 @@ int json_object_clear(json_t *json) {
int json_object_update(json_t *object, json_t *other) {
const char *key;
size_t key_len;
json_t *value;
if (!json_is_object(object) || !json_is_object(other))
return -1;
json_object_keylen_foreach(other, key, key_len, value) {
if (json_object_setn_nocheck(object, key, key_len, value))
json_object_foreach(other, key, value) {
if (json_object_set_nocheck(object, key, value))
return -1;
}
@ -223,15 +222,14 @@ int json_object_update_existing(json_t *object, json_t *other) {
int json_object_update_missing(json_t *object, json_t *other) {
const char *key;
size_t key_len;
json_t *value;
if (!json_is_object(object) || !json_is_object(other))
return -1;
json_object_keylen_foreach(other, key, key_len, value) {
if (!json_object_getn(object, key, key_len))
json_object_setn_nocheck(object, key, key_len, value);
json_object_foreach(other, key, value) {
if (!json_object_get(object, key))
json_object_set_nocheck(object, key, value);
}
return 0;
@ -252,7 +250,7 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren
return -1;
json_object_keylen_foreach(other, key, key_len, value) {
json_t *v = json_object_getn(object, key, key_len);
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)) {
@ -354,14 +352,13 @@ void *json_object_key_to_iter(const char *key) {
static int json_object_equal(const json_t *object1, const json_t *object2) {
const char *key;
size_t key_len;
const json_t *value1, *value2;
if (json_object_size(object1) != json_object_size(object2))
return 0;
json_object_keylen_foreach((json_t *)object1, key, key_len, value1) {
value2 = json_object_getn(object2, key, key_len);
json_object_foreach((json_t *)object1, key, value1) {
value2 = json_object_get(object2, key);
if (!json_equal(value1, value2))
return 0;
@ -374,15 +371,13 @@ static json_t *json_object_copy(json_t *object) {
json_t *result;
const char *key;
size_t key_len;
json_t *value;
result = json_object();
if (!result)
return NULL;
json_object_keylen_foreach(object, key, key_len, value)
json_object_setn_nocheck(result, key, key_len, value);
json_object_foreach(object, key, value) json_object_set_nocheck(result, key, value);
return result;
}
@ -405,14 +400,11 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
iter = json_object_iter((json_t *)object);
while (iter) {
const char *key;
size_t key_len;
const json_t *value;
key = json_object_iter_key(iter);
key_len = json_object_iter_key_len(iter);
value = json_object_iter_value(iter);
if (json_object_setn_new_nocheck(result, key, key_len,
do_deep_copy(value, parents))) {
if (json_object_set_new_nocheck(result, key, do_deep_copy(value, parents))) {
json_decref(result);
result = NULL;
break;

1
test/.gitignore vendored
View file

@ -7,7 +7,6 @@ suites/api/test_cpp
suites/api/test_dump
suites/api/test_dump_callback
suites/api/test_equal
suites/api/test_fixed_size
suites/api/test_load
suites/api/test_load_callback
suites/api/test_loadb

View file

@ -35,6 +35,7 @@ struct config {
int ensure_ascii;
int sort_keys;
int strip;
int use_env;
int have_hashseed;
int hashseed;
int precision;
@ -80,10 +81,11 @@ static char *loadfile(FILE *file) {
static void read_conf(FILE *conffile) {
char *buffer, *line, *val;
conf.have_hashseed = 0;
buffer = loadfile(conffile);
for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) {
if (!strncmp(line, "export ", 7))
continue;
val = strchr(line, '=');
if (!val) {
printf("invalid configuration line\n");
@ -108,6 +110,8 @@ static void read_conf(FILE *conffile) {
if (!strcmp(line, "HASHSEED")) {
conf.have_hashseed = 1;
conf.hashseed = atoi(val);
} else {
conf.have_hashseed = 0;
}
}
@ -134,16 +138,10 @@ static int cmpfile(const char *str, const char *path, const char *fname) {
}
buffer = loadfile(file);
if (strcmp(buffer, str) != 0) {
fprintf(stderr, "=== Expected %s ===\n", fname);
fprintf(stderr, "%s\n", buffer);
fprintf(stderr, "=== Actual %s ===\n", fname);
fprintf(stderr, "%s\n", str);
if (strcmp(buffer, str) != 0)
ret = 1;
} else {
else
ret = 0;
}
free(buffer);
fclose(file);
@ -208,9 +206,8 @@ int use_conf(char *test_path) {
buffer = loadfile(infile);
json = json_loads(strip(buffer), 0, &error);
free(buffer);
} else {
} else
json = json_loadf(infile, 0, &error);
}
fclose(infile);
@ -230,6 +227,108 @@ int use_conf(char *test_path) {
return ret;
}
static int getenv_int(const char *name) {
char *value, *end;
long result;
value = getenv(name);
if (!value)
return 0;
result = strtol(value, &end, 10);
if (*end != '\0')
return 0;
return (int)result;
}
int use_env() {
int indent, precision;
size_t flags = 0;
json_t *json;
json_error_t error;
#ifdef _WIN32
/* On Windows, set stdout and stderr to binary mode to avoid
outputting DOS line terminators */
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
indent = getenv_int("JSON_INDENT");
if (indent < 0 || indent > 31) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
return 2;
}
if (indent > 0)
flags |= JSON_INDENT(indent);
if (getenv_int("JSON_COMPACT") > 0)
flags |= JSON_COMPACT;
if (getenv_int("JSON_ENSURE_ASCII"))
flags |= JSON_ENSURE_ASCII;
if (getenv_int("JSON_PRESERVE_ORDER"))
flags |= JSON_PRESERVE_ORDER;
if (getenv_int("JSON_SORT_KEYS"))
flags |= JSON_SORT_KEYS;
precision = getenv_int("JSON_REAL_PRECISION");
if (precision < 0 || precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", precision);
return 2;
}
if (getenv("HASHSEED"))
json_object_seed(getenv_int("HASHSEED"));
if (precision > 0)
flags |= JSON_REAL_PRECISION(precision);
if (getenv_int("STRIP")) {
/* Load to memory, strip leading and trailing whitespace */
size_t size = 0, used = 0;
char *buffer = NULL, *buf_ck = NULL;
while (1) {
size_t count;
size = (size == 0 ? 128 : size * 2);
buf_ck = realloc(buffer, size);
if (!buf_ck) {
fprintf(stderr, "Unable to allocate %d bytes\n", (int)size);
free(buffer);
return 1;
}
buffer = buf_ck;
count = fread(buffer + used, 1, size - used, stdin);
if (count < size - used) {
buffer[used + count] = '\0';
break;
}
used += count;
}
json = json_loads(strip(buffer), 0, &error);
free(buffer);
} else
json = json_loadf(stdin, 0, &error);
if (!json) {
fprintf(stderr, "%d %d %d\n%s\n", error.line, error.column, error.position,
error.text);
return 1;
}
json_dumpf(json, stdout, flags);
json_decref(json);
return 0;
}
int main(int argc, char *argv[]) {
int i;
char *test_path = NULL;
@ -245,17 +344,23 @@ int main(int argc, char *argv[]) {
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--strip"))
conf.strip = 1;
else if (!strcmp(argv[i], "--env"))
conf.use_env = 1;
else
test_path = argv[i];
}
if (!test_path) {
goto usage;
if (conf.use_env)
return use_env();
else {
if (!test_path)
goto usage;
return use_conf(test_path);
}
return use_conf(test_path);
usage:
fprintf(stderr, "usage: %s [--strip] test_dir\n", argv[0]);
fprintf(stderr, "argc =%d\n", argc);
fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]);
return 2;
}

View file

@ -15,7 +15,7 @@ grep 'json_\|jansson_' $top_srcdir/src/jansson.def \
nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \
|| exit 77 # Skip if "nm -D" doesn't seem to work
grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sed 's/@@libjansson.*//' | sort >$test_log/output
grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sort >$test_log/output
if ! cmp -s $test_log/exports $test_log/output; then
diff -u $test_log/exports $test_log/output >&2

View file

@ -127,7 +127,6 @@ static void test_keylen(void) {
static void test_invalid_keylen(void) {
json_t *obj = json_object();
json_t *empty_obj = json_object();
const char key[] = {'t', 'e', 's', 't', '1'};
json_object_set_new_nocheck(obj, "test1", json_true());
@ -150,14 +149,7 @@ static void test_invalid_keylen(void) {
if (!json_object_del(obj, NULL))
fail("json_object_del with NULL failed");
if (!json_object_deln(empty_obj, key, sizeof(key)))
fail("json_object_deln with empty object failed");
if (!json_object_deln(obj, key, sizeof(key) - 1))
fail("json_object_deln with incomplete key failed");
json_decref(obj);
json_decref(empty_obj);
}
static void test_binary_keys(void) {
@ -174,21 +166,6 @@ static void test_binary_keys(void) {
if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key2))))
fail("cannot get integer key2");
if (json_object_size(obj) != 2)
fail("binary object size missmatch");
if (json_object_deln(obj, (const char *)&key1, sizeof(key1)))
fail("cannot del integer key1");
if (json_object_size(obj) != 1)
fail("binary object size missmatch");
if (json_object_deln(obj, (const char *)&key2, sizeof(key2)))
fail("cannot del integer key2");
if (json_object_size(obj) != 0)
fail("binary object size missmatch");
json_decref(obj);
}

View file

@ -1 +1,2 @@
JSON_COMPACT=1
export JSON_COMPACT

View file

@ -1,2 +1,3 @@
JSON_COMPACT=1
HASHSEED=1
export JSON_COMPACT HASHSEED

View file

@ -1 +1,2 @@
JSON_ENSURE_ASCII=1
export JSON_ENSURE_ASCII

View file

@ -1 +1,2 @@
JSON_INDENT=4
export JSON_INDENT

View file

@ -1,2 +1,3 @@
JSON_INDENT=4
JSON_COMPACT=1
export JSON_INDENT JSON_COMPACT

View file

@ -1,3 +1,4 @@
JSON_INDENT=4
JSON_COMPACT=1
HASHSEED=1
export JSON_INDENT JSON_COMPACT HASHSEED

View file

@ -1,2 +1,3 @@
JSON_INDENT=4
HASHSEED=1
export JSON_INDENT HASHSEED

View file

@ -1 +1,2 @@
HASHSEED=1
export HASHSEED

View file

@ -1 +1,2 @@
JSON_PRESERVE_ORDER=1
export JSON_PRESERVE_ORDER

View file

@ -1 +1,2 @@
JSON_REAL_PRECISION=4
export JSON_REAL_PRECISION

View file

@ -1 +1 @@
[1.23456789, 1.0, 1.0000000000000002, 1.23456e99, 1.23456e-99, 0.0000000000012345]
[1.23456789, 1.0, 1.0000000000000002]

View file

@ -1 +1 @@
[1.235, 1.0, 1.0, 1.235e99, 1.235e-99, 1.235e-12]
[1.235, 1.0, 1.0]

View file

@ -10,13 +10,23 @@ is_test() {
}
run_test() {
$json_process $test_path >$test_log/stdout 2>$test_log/stderr || return 1
(
if [ -f $test_path/env ]; then
. $test_path/env
fi
$json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr
)
valgrind_check $test_log/stderr || return 1
cmp -s $test_path/output $test_log/stdout
}
show_error() {
valgrind_show_error && return
cat $test_log/stderr
echo "EXPECTED OUTPUT:"
nl -bn $test_path/output
echo "ACTUAL OUTPUT:"
nl -bn $test_log/stdout
}
. $top_srcdir/test/scripts/run-tests.sh

View file

@ -1 +1,2 @@
JSON_SORT_KEYS=1
export JSON_SORT_KEYS

View file

@ -10,13 +10,18 @@ is_test() {
}
run_test() {
$json_process $test_path >$test_log/stdout 2>$test_log/stderr || return 1
valgrind_check $test_log/stderr$s || return 1
$json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr
valgrind_check $test_log/stderr || return 1
cmp -s $test_path/error $test_log/stderr
}
show_error() {
valgrind_show_error && return
cat $test_log/stderr
echo "EXPECTED ERROR:"
nl -bn $test_path/error
echo "ACTUAL ERROR:"
nl -bn $test_log/stderr
}
. $top_srcdir/test/scripts/run-tests.sh

View file

@ -13,18 +13,24 @@ do_run() {
variant=$1
s=".$1"
strip=""
strip=0
if [ "$variant" = "strip" ]; then
# This test should not be stripped
[ -f $test_path/nostrip ] && return
strip="--strip"
strip=1
fi
if ! $json_process $strip $test_path >$test_log/stdout$s 2>$test_log/stderr$s; then
echo $variant >$test_log/variant
STRIP=$strip $json_process --env \
<$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s
valgrind_check $test_log/stderr$s || return 1
ref=error
[ -f $test_path/error$s ] && ref=error$s
if ! cmp -s $test_path/$ref $test_log/stderr$s; then
echo $variant > $test_log/variant
return 1
fi
valgrind_check $test_log/stderr$s || return 1
}
run_test() {
@ -38,7 +44,14 @@ show_error() {
s=".$variant"
echo "VARIANT: $variant"
cat $test_log/stderr$s
echo "EXPECTED ERROR:"
ref=error
[ -f $test_path/error$s ] && ref=error$s
nl -bn $test_path/$ref
echo "ACTUAL ERROR:"
nl -bn $test_log/stderr$s
}
. $top_srcdir/test/scripts/run-tests.sh

View file

@ -1 +0,0 @@
[1.23e47, 0.1, 0.3, 9.99]

View file

@ -1 +0,0 @@
[1.2299999999999999e47, 0.10000000000000001, 0.29999999999999999, 9.9900000000000002]

View file

@ -1 +1 @@
[1.23e47, 0.1, 0.3, 9.99]
[123e45]

View file

@ -1 +1 @@
[1.23e47, 0.1, 0.3, 9.99]
[1.2299999999999999e47]

View file

@ -5,33 +5,31 @@
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
dtoa_enabled() {
grep -q "DTOA_ENABLED 1" $top_builddir/jansson_private_config.h
}
JSON_SORT_KEYS=1
export JSON_SORT_KEYS
is_test() {
test -d $test_path
}
do_run() {
if [ -f $test_path/skip_unless_dtoa ]; then
dtoa_enabled || return 77
fi
if [ -f $test_path/skip_if_dtoa ]; then
dtoa_enabled && return 77
fi
variant=$1
s=".$1"
strip=""
[ "$variant" = "strip" ] && strip="--strip"
strip=0
[ "$variant" = "strip" ] && strip=1
if ! $json_process $strip $test_path >$test_log/stdout$s 2>$test_log/stderr$s; then
echo $variant >$test_log/variant
STRIP=$strip $json_process --env \
<$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s
valgrind_check $test_log/stderr$s || return 1
ref=output
[ -f $test_path/output$s ] && ref=output$s
if ! cmp -s $test_path/$ref $test_log/stdout$s; then
echo $variant > $test_log/variant
return 1
fi
valgrind_check $test_log/stderr$s || return 1
}
run_test() {
@ -45,7 +43,14 @@ show_error() {
s=".$variant"
echo "VARIANT: $variant"
cat $test_log/stderr$s
echo "EXPECTED OUTPUT:"
ref=output
[ -f $test_path/output$s ] && ref=output$s
nl -bn $test_path/$ref
echo "ACTUAL OUTPUT:"
nl -bn $test_log/stdout$s
}
. $top_srcdir/test/scripts/run-tests.sh