瀏覽代碼

Updated to Jansson 2.14.e23f558

Brucey 2 年之前
父節點
當前提交
32754bd131
共有 100 個文件被更改,包括 6640 次插入828 次删除
  1. 2 0
      .gitignore
  2. 5 3
      jansson.mod/jansson.bmx
  3. 5 0
      jansson.mod/jansson/.clang-format
  4. 31 0
      jansson.mod/jansson/.github/workflows/fuzz.yml
  5. 80 0
      jansson.mod/jansson/.github/workflows/tests.yml
  6. 0 34
      jansson.mod/jansson/.travis.yml
  7. 27 2
      jansson.mod/jansson/CHANGES
  8. 45 73
      jansson.mod/jansson/CMakeLists.txt
  9. 3 0
      jansson.mod/jansson/CONTRIBUTING.md
  10. 15 22
      jansson.mod/jansson/README.rst
  11. 2 0
      jansson.mod/jansson/appveyor.yml
  12. 3 3
      jansson.mod/jansson/cmake/CodeCoverage.cmake
  13. 0 111
      jansson.mod/jansson/cmake/Coveralls.cmake
  14. 0 24
      jansson.mod/jansson/cmake/CoverallsClear.cmake
  15. 0 380
      jansson.mod/jansson/cmake/CoverallsGenerateGcov.cmake
  16. 5 1
      jansson.mod/jansson/configure.ac
  17. 2 2
      jansson.mod/jansson/doc/Makefile.am
  18. 187 34
      jansson.mod/jansson/doc/apiref.rst
  19. 1 1
      jansson.mod/jansson/doc/conf.py
  20. 2 3
      jansson.mod/jansson/doc/conformance.rst
  21. 20 11
      jansson.mod/jansson/doc/ext/refcounting.py
  22. 1 0
      jansson.mod/jansson/doc/github_commits.c
  23. 1 1
      jansson.mod/jansson/doc/index.rst
  24. 4 7
      jansson.mod/jansson/doc/threadsafety.rst
  25. 8 8
      jansson.mod/jansson/doc/upgrading.rst
  26. 4 0
      jansson.mod/jansson/examples/README.rst
  27. 200 0
      jansson.mod/jansson/examples/simple_parse.c
  28. 3 0
      jansson.mod/jansson/release.sh
  29. 27 0
      jansson.mod/jansson/scripts/clang-format-check
  30. 2 1
      jansson.mod/jansson/src/Makefile.am
  31. 38 17
      jansson.mod/jansson/src/dump.c
  32. 57 35
      jansson.mod/jansson/src/hashtable.c
  33. 16 4
      jansson.mod/jansson/src/hashtable.h
  34. 5 0
      jansson.mod/jansson/src/jansson.def
  35. 36 4
      jansson.mod/jansson/src/jansson.h
  36. 3 3
      jansson.mod/jansson/src/jansson_private.h
  37. 2 2
      jansson.mod/jansson/src/load.c
  38. 1 1
      jansson.mod/jansson/src/lookup3.h
  39. 5 4
      jansson.mod/jansson/src/pack_unpack.c
  40. 2 3
      jansson.mod/jansson/src/strconv.c
  41. 92 34
      jansson.mod/jansson/src/value.c
  42. 20 0
      jansson.mod/jansson/test/.gitignore
  43. 10 0
      jansson.mod/jansson/test/Makefile.am
  44. 5 0
      jansson.mod/jansson/test/bin/Makefile.am
  45. 366 0
      jansson.mod/jansson/test/bin/json_process.c
  46. 1 0
      jansson.mod/jansson/test/ossfuzz/.gitignore
  47. 32 0
      jansson.mod/jansson/test/ossfuzz/Makefile.am
  48. 132 0
      jansson.mod/jansson/test/ossfuzz/json_load_dump_fuzzer.cc
  49. 30 0
      jansson.mod/jansson/test/ossfuzz/ossfuzz.sh
  50. 74 0
      jansson.mod/jansson/test/ossfuzz/standaloneengine.cc
  51. 3 0
      jansson.mod/jansson/test/ossfuzz/testinput.h
  52. 50 0
      jansson.mod/jansson/test/run-suites
  53. 100 0
      jansson.mod/jansson/test/scripts/run-tests.sh
  54. 35 0
      jansson.mod/jansson/test/scripts/valgrind.sh
  55. 2 0
      jansson.mod/jansson/test/suites/.gitattributes
  56. 2 0
      jansson.mod/jansson/test/suites/Makefile.am
  57. 42 0
      jansson.mod/jansson/test/suites/api/Makefile.am
  58. 23 0
      jansson.mod/jansson/test/suites/api/check-exports
  59. 36 0
      jansson.mod/jansson/test/suites/api/run
  60. 484 0
      jansson.mod/jansson/test/suites/api/test_array.c
  61. 168 0
      jansson.mod/jansson/test/suites/api/test_chaos.c
  62. 375 0
      jansson.mod/jansson/test/suites/api/test_copy.c
  63. 311 0
      jansson.mod/jansson/test/suites/api/test_dump.c
  64. 82 0
      jansson.mod/jansson/test/suites/api/test_dump_callback.c
  65. 202 0
      jansson.mod/jansson/test/suites/api/test_equal.c
  66. 228 0
      jansson.mod/jansson/test/suites/api/test_fixed_size.c
  67. 238 0
      jansson.mod/jansson/test/suites/api/test_load.c
  68. 77 0
      jansson.mod/jansson/test/suites/api/test_load_callback.c
  69. 37 0
      jansson.mod/jansson/test/suites/api/test_loadb.c
  70. 115 0
      jansson.mod/jansson/test/suites/api/test_memory_funcs.c
  71. 123 0
      jansson.mod/jansson/test/suites/api/test_number.c
  72. 797 0
      jansson.mod/jansson/test/suites/api/test_object.c
  73. 547 0
      jansson.mod/jansson/test/suites/api/test_pack.c
  74. 287 0
      jansson.mod/jansson/test/suites/api/test_simple.c
  75. 29 0
      jansson.mod/jansson/test/suites/api/test_sprintf.c
  76. 431 0
      jansson.mod/jansson/test/suites/api/test_unpack.c
  77. 61 0
      jansson.mod/jansson/test/suites/api/test_version.c
  78. 93 0
      jansson.mod/jansson/test/suites/api/util.h
  79. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/array/input
  80. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/array/output
  81. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/env
  82. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/input
  83. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/output
  84. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/env
  85. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/input
  86. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/output
  87. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/env
  88. 8 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/input
  89. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/output
  90. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/env
  91. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/input
  92. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/output
  93. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/env
  94. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/input
  95. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/output
  96. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/env
  97. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/input
  98. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/output
  99. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-object/env
  100. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-object/input

+ 2 - 0
.gitignore

@@ -5,3 +5,5 @@
 *.bak
 *.exe
 commands.html
+
+.DS_Store

+ 5 - 3
jansson.mod/jansson.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2014-2020 Bruce A Henderson
+' Copyright (c) 2014-2022 Bruce A Henderson
 ' 
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,13 @@ SuperStrict
 
 Module Text.Jansson
 
-ModuleInfo "Version: 1.06"
+ModuleInfo "Version: 1.07"
 ModuleInfo "Author: Bruce A Henderson"
 ModuleInfo "License: MIT"
-ModuleInfo "Copyright: 2014-2020 Bruce A Henderson"
+ModuleInfo "Copyright: 2014-2022 Bruce A Henderson"
 
+ModuleInfo "History: 1.07"
+ModuleInfo "History: Updated to Jansson 2.14.e23f558"
 ModuleInfo "History: 1.06"
 ModuleInfo "History: Updated to Jansson 2.13.1."
 ModuleInfo "History: 1.05"

+ 5 - 0
jansson.mod/jansson/.clang-format

@@ -0,0 +1,5 @@
+BasedOnStyle: LLVM
+AlignConsecutiveMacros: true
+ColumnLimit: 90
+IndentCaseLabels: true
+IndentWidth: 4

+ 31 - 0
jansson.mod/jansson/.github/workflows/fuzz.yml

@@ -0,0 +1,31 @@
+name: oss-fuzz
+
+on:
+  pull_request:
+    branches: [ master ]
+    paths:
+      - '**.c'
+      - '**.h'
+
+jobs:
+  fuzz:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'jansson'
+        dry-run: false
+    - name: Run Fuzzers
+      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'jansson'
+        fuzz-seconds: 600
+        dry-run: false
+    - name: Upload Crash
+      uses: actions/upload-artifact@v1
+      if: failure() && steps.build.outcome == 'success'
+      with:
+        name: artifacts
+        path: ./out/artifacts

+ 80 - 0
jansson.mod/jansson/.github/workflows/tests.yml

@@ -0,0 +1,80 @@
+name: tests
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - run: ./scripts/clang-format-check
+
+  autotools:
+    strategy:
+      matrix:
+        os: ["ubuntu-latest", "macos-latest"]
+        cc: ["gcc", "clang"]
+
+    runs-on: ${{matrix.os}}
+
+    steps:
+      - if: ${{runner.os == 'macOS'}}
+        run: brew install autoconf automake libtool
+      - uses: actions/checkout@v2
+      - run: autoreconf -fi
+      - env:
+          CC: ${{matrix.cc}}
+          CFLAGS: -Werror
+        run: ./configure
+      - run: make check
+
+  cmake:
+    strategy:
+      matrix:
+        os: ["ubuntu-latest", "macos-latest", "windows-latest"]
+        cc: ["gcc", "clang"]
+        exclude:
+          - os: windows-latest
+            cc: gcc
+          - os: windows-latest
+            cc: clang
+        include:
+          - os: windows-latest
+            cc: 'msvc'  # Doesn't really matter, MSVC is always used on Windows
+
+    runs-on: ${{matrix.os}}
+
+    steps:
+      - uses: actions/checkout@v2
+      - env:
+          CC: ${{matrix.cc}}
+        run: cmake .
+      - run: cmake --build .
+      - run: ctest
+
+  valgrind:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - run: sudo apt update && sudo apt install valgrind
+      - run: cmake -DJANSSON_TEST_WITH_VALGRIND=ON .
+      - run: cmake --build .
+      - 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

+ 0 - 34
jansson.mod/jansson/.travis.yml

@@ -1,34 +0,0 @@
-env:
-  global:
-    - CLANG_FORMAT_VERSION=9
-  matrix:
-    - JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind"
-    - JANSSON_BUILD_METHOD=autotools
-    - JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-    - JANSSON_BUILD_METHOD=fuzzer
-    - JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
-dist: bionic
-language: c
-compiler:
-  - gcc
-  - clang
-matrix:
-  exclude:
-    - compiler: clang
-      env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-    - compiler: clang
-      env: JANSSON_BUILD_METHOD=fuzzer
-    - compiler: gcc
-      env: JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
-  allow_failures:
-    - env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-install:
-  - sudo apt-get update -qq
-  - sudo apt-get install -y -qq cmake $JANSSON_EXTRA_INSTALL
-  - if [ "$TRAVIS_COMPILER" = "clang" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - && sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" -y && sudo apt-get install -y -qq clang-9 clang-format-9; fi
-script:
-  - if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && ctest --output-on-failure; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./test/ossfuzz/travisoss.sh; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "lint" ]; then ./scripts/clang-format-check; fi

+ 27 - 2
jansson.mod/jansson/CHANGES

@@ -1,3 +1,28 @@
+Version 2.14
+============
+
+Released 2021-09-09
+
+* New Features:
+
+  - Add `json_object_getn`, `json_object_setn`, `json_object_deln`, and the
+    corresponding `nocheck` functions. (#520, by Maxim Zhukov)
+
+* Fixes:
+
+  - Handle `sprintf` corner cases (#537, by Tobias Stoeckmann)
+
+* Build:
+
+  - Symbol versioning for all exported symbols (#540, by Simon McVittie)
+  - Fix compiler warnings (#555, by Kelvin Lee)
+
+* Documentation:
+
+  - Small fixes (#544, #546, by @i-ky)
+  - Sphinx 3 compatibility (#543, by Pierce Lopez)
+
+
 Version 2.13.1
 ==============
 
@@ -8,7 +33,7 @@ Released 2020-05-07
   - Include `jansson_version_str()` and `jansson_version_cmp()` in
     shared library. (#534)
 
-  - Include `scripts/` in tarball. (#535)
+  - Include ``scripts/`` in tarball. (#535)
 
 
 Version 2.13
@@ -127,7 +152,7 @@ Released 2018-02-09
 
   - Work around gcc's -Wimplicit-fallthrough.
 
-  - Fix CMake detection of `sys/types.h` header (#375).
+  - Fix CMake detection of ``sys/types.h`` header (#375).
 
   - Fix `jansson.pc` generated by CMake to be more consistent with the one
     generated using GNU Autotools (#368).

+ 45 - 73
jansson.mod/jansson/CMakeLists.txt

@@ -1,51 +1,3 @@
-# Notes:
-#
-# Author: Paul Harris, June 2012
-# Additions: Joakim Soderberg, February 2013
-#
-# Supports: building static/shared, release/debug/etc, can also build html docs
-# and some of the tests.
-# Note that its designed for out-of-tree builds, so it will not pollute your
-# source tree.
-#
-# TODO 1: Finish implementing tests. api tests are working, but the valgrind
-# variants are not flagging problems.
-#
-# TODO 2: There is a check_exports script that would try and incorporate.
-#
-# TODO 3: Consolidate version numbers, currently the version number is written
-# into: * cmake (here) * autotools (the configure) * source code header files.
-# Should not be written directly into header files, autotools/cmake can do
-# that job.
-#
-# Brief intro on how to use cmake:
-# > mkdir build (somewhere - we do out-of-tree builds)
-# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you
-# can only choose one variant: release,debug,etc... and static or shared.
-# >> example:
-# >> cd build
-# >> ccmake -i ../path_to_jansson_dir
-# >>  inside, configure your options. press C until there are no lines
-#     with * next to them.
-# >>  note, I like to configure the 'install' path to ../install, so I get
-#     self-contained clean installs I can point other projects to.
-# >>  press G to 'generate' the project files.
-# >> make (to build the project)
-# >> make install
-# >> make test (to run the tests, if you enabled them)
-#
-# Brief description on how it works:
-# There is a small hierarchy of CMakeLists.txt files which define how the
-# project is built.
-# Header file detection etc is done, and the results are written into config.h
-# and jansson_config.h, which are generated from the corresponding
-# config.h.cmake and jansson_config.h.cmake template files.
-# The generated header files end up in the build directory - not in
-# the source directory.
-# The rest is down to the usual make process.
-
-
-
 cmake_minimum_required (VERSION 3.1)
 project(jansson C)
 
@@ -64,8 +16,6 @@ option(JANSSON_EXAMPLES "Compile example applications" ON)
 
 if (UNIX)
    option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF)
-   option(JANSSON_COVERALLS "Generate coverage info for Coveralls" OFF)
-   option(JANSSON_COVERALLS_UPLOAD "Upload coverage info to Coveralls (Only works via Travis)" ON)
 endif ()
 
 # Set some nicer output dirs.
@@ -85,10 +35,10 @@ endif()
 # set (JANSSON_VERSION "2.3.1")
 # set (JANSSON_SOVERSION 2)
 
-set(JANSSON_DISPLAY_VERSION "2.13.1")
+set(JANSSON_DISPLAY_VERSION "2.14")
 
 # This is what is required to match the same numbers as automake's
-set(JANSSON_VERSION "4.13.0")
+set(JANSSON_VERSION "4.14.0")
 set(JANSSON_SOVERSION 4)
 
 # for CheckFunctionKeywords
@@ -119,17 +69,9 @@ endif()
 
 message("C compiler: ${CMAKE_C_COMPILER_ID}")
 
-# Coverage only works with GCC for a debug build.
-if (JANSSON_COVERALLS)
-   set(JANSSON_COVERAGE ON)
-endif()
-
 if (JANSSON_COVERAGE)
    include(CodeCoverage)
-   include(Coveralls)
-
-   # This adds coverage arguments to gcc/clang.
-   coveralls_turn_on_coverage()
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 endif()
 
 check_include_files (endian.h HAVE_ENDIAN_H)
@@ -366,6 +308,44 @@ if(JANSSON_BUILD_SHARED_LIBS)
       ${JANSSON_HDR_PUBLIC}
       src/jansson.def)
 
+# check if linker support --default-symver
+   list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver")
+   check_c_source_compiles(
+   "
+   int main (void)
+   {
+      return 0;
+   }
+   "
+   DSYMVER_WORKS
+   )
+   list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver")
+
+   if (SYMVER_WORKS)
+      set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--default-symver")
+   else()
+# some linkers may only support --version-script
+      file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/jansson.sym" "JANSSON_${JANSSON_SOVERSION} {
+    global:
+          *;
+};
+")
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
+      check_c_source_compiles(
+   "
+   int main (void)
+   {
+      return 0;
+   }
+   "
+   VSCRIPT_WORKS
+   )
+      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")
+      endif()
+   endif()
+
    set_target_properties(jansson PROPERTIES
       VERSION ${JANSSON_VERSION}
       SOVERSION ${JANSSON_SOVERSION})
@@ -501,14 +481,15 @@ if (NOT JANSSON_WITHOUT_TESTS)
 
    set(api_tests
          test_array
-         test_copy
          test_chaos
+         test_copy
          test_dump
          test_dump_callback
          test_equal
+         test_fixed_size
          test_load
-         test_loadb
          test_load_callback
+         test_loadb
          test_number
          test_object
          test_pack
@@ -578,16 +559,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
    endforeach ()
 
    if (JANSSON_COVERAGE)
-      setup_target_for_coverage(
-            coverage             # Coverage make target "make coverage".
-            coverage             # Name of output directory.
-            make                 # Name of test runner executable.
-            test)                # Arguments to the test runner above (make test).
-
-      if (JANSSON_COVERALLS)
-         set(COVERAGE_SRCS ${JANSSON_SRC})
-         coveralls_setup("${COVERAGE_SRCS}" ${JANSSON_COVERALLS_UPLOAD})
-      endif ()
+      SETUP_TARGET_FOR_COVERAGE(coverage coverage ctest)
    endif ()
 
    # Enable using "make check" just like the autotools project.

+ 3 - 0
jansson.mod/jansson/CONTRIBUTING.md

@@ -0,0 +1,3 @@
+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.

+ 15 - 22
jansson.mod/jansson/README.rst

@@ -1,9 +1,9 @@
 Jansson README
 ==============
 
-.. image:: https://travis-ci.org/akheron/jansson.png
-  :target: https://travis-ci.org/akheron/jansson
-  
+.. image:: https://github.com/akheron/jansson/workflows/tests/badge.svg
+  :target: https://github.com/akheron/jansson/actions
+
 .. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko
   :target: https://ci.appveyor.com/project/akheron/jansson
 
@@ -26,24 +26,11 @@ 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
 ----------------------------
 
-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::
+If you obtained a ``jansson-X.Y.tar.*`` tarball from GitHub Releases, just use
+the standard autotools commands::
 
    $ ./configure
    $ make
@@ -53,9 +40,8 @@ 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
 
@@ -74,8 +60,15 @@ 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/

+ 2 - 0
jansson.mod/jansson/appveyor.yml

@@ -7,6 +7,8 @@ environment:
     - VS: Visual Studio 14 2015
     - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
       VS: Visual Studio 15 2017
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      VS: Visual Studio 16 2019
 
 build_script:
   - md build

+ 3 - 3
jansson.mod/jansson/cmake/CodeCoverage.cmake

@@ -111,9 +111,9 @@ FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner)
 		
 		# Capturing lcov counters and generating report
 		COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1
-		COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info.cleaned --rc lcov_branch_coverage=1
-		COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned
-		COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+		COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info --rc lcov_branch_coverage=1
+		# COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned
+		# COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
 		
 		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 		COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."

+ 0 - 111
jansson.mod/jansson/cmake/Coveralls.cmake

@@ -1,111 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# 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.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-
-
-#
-# Param _COVERAGE_SRCS	A list of source files that coverage should be collected for.
-# Param _COVERALLS_UPLOAD Upload the result to coveralls?
-#
-function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD)
-	# When passing a CMake list to an external process, the list
-	# will be converted from the format "1;2;3" to "1 2 3".
-	# This means the script we're calling won't see it as a list
-	# of sources, but rather just one long path. We remedy this
-	# by replacing ";" with "*" and then reversing that in the script
-	# that we're calling.
-	# http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html
-	set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS})
-	set(COVERAGE_SRCS "")
-	foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP})
-		set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}")
-	endforeach()
-
-	#message("Coverage sources: ${COVERAGE_SRCS}")
-	set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json)
-
-	add_custom_target(coveralls_generate
-
-		# Zero the coverage counters.
-		COMMAND ${CMAKE_COMMAND}
-				-P "${PROJECT_SOURCE_DIR}/cmake/CoverallsClear.cmake"
-
-		# Run regress tests.
-		COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
-
-		# Generate Gcov and translate it into coveralls JSON.
-		# We do this by executing an external CMake script.
-		# (We don't want this to run at CMake generation time, but after compilation and everything has run).
-		COMMAND ${CMAKE_COMMAND}
-				-DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c"
-				-DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}"
-				-DCOV_PATH="${PROJECT_BINARY_DIR}"
-				-DPROJECT_ROOT="${PROJECT_SOURCE_DIR}"
-				-P "${PROJECT_SOURCE_DIR}/cmake/CoverallsGenerateGcov.cmake"
-
-		WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
-		COMMENT "Generating coveralls output..."
-		)
-
-	if (_COVERALLS_UPLOAD)
-		message("COVERALLS UPLOAD: ON")
-
-		find_program(CURL_EXECUTABLE curl)
-
-		if (NOT CURL_EXECUTABLE)
-			message(FATAL_ERROR "Coveralls: curl not found! Aborting")
-		endif()
-
-		add_custom_target(coveralls_upload
-			# Upload the JSON to coveralls.
-			COMMAND ${CURL_EXECUTABLE}
-					-S -F json_file=@${COVERALLS_FILE}
-					https://coveralls.io/api/v1/jobs
-
-			DEPENDS coveralls_generate
-
-			WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
-			COMMENT "Uploading coveralls output...")
-
-		add_custom_target(coveralls DEPENDS coveralls_upload)
-	else()
-		message("COVERALLS UPLOAD: OFF")
-		add_custom_target(coveralls DEPENDS coveralls_generate)
-	endif()
-
-endfunction()
-
-macro(coveralls_turn_on_coverage)
-	if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
-		AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"))
-		message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake <options> ..")
-	endif()
-
-	if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
-		message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug")
-	endif()
-
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-endmacro()
-
-
-

+ 0 - 24
jansson.mod/jansson/cmake/CoverallsClear.cmake

@@ -1,24 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# 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.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-
-file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/*.gcda)
-

+ 0 - 380
jansson.mod/jansson/cmake/CoverallsGenerateGcov.cmake

@@ -1,380 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# 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.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-# This is intended to be run by a custom target in a CMake project like this.
-# 0. Compile program with coverage support.
-# 1. Clear coverage data. (Recursively delete *.gcda in build dir)
-# 2. Run the unit tests.
-# 3. Run this script specifying which source files the coverage should be performed on.
-#
-# This script will then use gcov to generate .gcov files in the directory specified
-# via the COV_PATH var. This should probably be the same as your cmake build dir.
-#
-# It then parses the .gcov files to convert them into the Coveralls JSON format:
-# https://coveralls.io/docs/api
-#
-# Example for running as standalone CMake script from the command line:
-# (Note it is important the -P is at the end...)
-# $ cmake -DCOV_PATH=$(pwd) 
-#         -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" 
-#         -P ../cmake/CoverallsGcovUpload.cmake
-#
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-
-
-#
-# Make sure we have the needed arguments.
-#
-if (NOT COVERALLS_OUTPUT_FILE)
-	message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE")
-endif()
-
-if (NOT COV_PATH)
-	message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH")
-endif()
-
-if (NOT COVERAGE_SRCS)
-	message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS")
-endif()
-
-if (NOT PROJECT_ROOT)
-	message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.")
-endif()
-
-# Since it's not possible to pass a CMake list properly in the
-# "1;2;3" format to an external process, we have replaced the
-# ";" with "*", so reverse that here so we get it back into the
-# CMake list format.
-string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS})
-
-find_program(GCOV_EXECUTABLE gcov)
-
-if (NOT GCOV_EXECUTABLE)
-	message(FATAL_ERROR "gcov not found! Aborting...")
-endif()
-
-find_package(Git)
-
-# TODO: Add these git things to the coveralls json.
-if (GIT_FOUND)
-	# Branch.
-	execute_process(
-		COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
-		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-		OUTPUT_VARIABLE GIT_BRANCH
-		OUTPUT_STRIP_TRAILING_WHITESPACE
-	)
-
-	macro (git_log_format FORMAT_CHARS VAR_NAME)
-		execute_process(
-			COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS}
-			WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-			OUTPUT_VARIABLE ${VAR_NAME}
-			OUTPUT_STRIP_TRAILING_WHITESPACE
-		)
-	endmacro()
-
-	git_log_format(an GIT_AUTHOR_EMAIL)
-	git_log_format(ae GIT_AUTHOR_EMAIL)
-	git_log_format(cn GIT_COMMITTER_NAME)
-	git_log_format(ce GIT_COMMITTER_EMAIL)
-	git_log_format(B GIT_COMMIT_MESSAGE)
-
-	message("Git exe: ${GIT_EXECUTABLE}")
-	message("Git branch: ${GIT_BRANCH}")
-	message("Git author: ${GIT_AUTHOR_NAME}")
-	message("Git e-mail: ${GIT_AUTHOR_EMAIL}")
-	message("Git committer name: ${GIT_COMMITTER_NAME}")
-	message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}")
-	message("Git commit message: ${GIT_COMMIT_MESSAGE}")
-
-endif()
-
-############################# Macros #########################################
-
-#
-# This macro converts from the full path format gcov outputs:
-#
-#    /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#
-# to the original source file path the .gcov is for:
-#
-#   /path/to/project/root/subdir/the_file.c
-#
-macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME)
-
-	# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 
-	# -> 
-	# #path#to#project#root#subdir#the_file.c.gcov   
-	get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME)
-
-	# #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c
-	string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT})
-	string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP})
-	set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}")
-endmacro()
-
-##############################################################################
-
-# Get the coverage data.
-file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda")
-message("GCDA files:")
-
-# Get a list of all the object directories needed by gcov
-# (The directories the .gcda files and .o files are found in)
-# and run gcov on those.
-foreach(GCDA ${GCDA_FILES})
-	message("Process: ${GCDA}")
-	message("------------------------------------------------------------------------------")
-	get_filename_component(GCDA_DIR ${GCDA} PATH)
-
-	#
-	# The -p below refers to "Preserve path components",
-	# This means that the generated gcov filename of a source file will
-	# keep the original files entire filepath, but / is replaced with #.
-	# Example:
-	#
-	# /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda
-	# ------------------------------------------------------------------------------
-	# File '/path/to/project/root/subdir/the_file.c'
-	# Lines executed:68.34% of 199
-	# /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov'
-	#
-	# If -p is not specified then the file is named only "the_file.c.gcov"
-	#
-	execute_process(
-		COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA}
-		WORKING_DIRECTORY ${COV_PATH}
-	)
-endforeach()
-
-# TODO: Make these be absolute path
-file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov)
-
-# Get only the filenames to use for filtering.
-#set(COVERAGE_SRCS_NAMES "")
-#foreach (COVSRC ${COVERAGE_SRCS})
-#	get_filename_component(COVSRC_NAME ${COVSRC} NAME)
-#	message("${COVSRC} -> ${COVSRC_NAME}")
-#	list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}")
-#endforeach()
-
-#
-# Filter out all but the gcov files we want.
-#
-# We do this by comparing the list of COVERAGE_SRCS filepaths that the
-# user wants the coverage data for with the paths of the generated .gcov files,
-# so that we only keep the relevant gcov files.
-#
-# Example:
-# COVERAGE_SRCS =
-#				/path/to/project/root/subdir/the_file.c
-#
-# ALL_GCOV_FILES =
-#				/path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#				/path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov
-# 
-# Result should be:
-# GCOV_FILES = 
-#				/path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#
-set(GCOV_FILES "")
-#message("Look in coverage sources: ${COVERAGE_SRCS}")
-message("\nFilter out unwanted GCOV files:")
-message("===============================")
-
-set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS})
-
-foreach (GCOV_FILE ${ALL_GCOV_FILES})
-
-	#
-	# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 
-	# -> 
-	# /path/to/project/root/subdir/the_file.c 
-	get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE})
-
-	# Is this in the list of source files?
-	# TODO: We want to match against relative path filenames from the source file root...
-	list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND)
-
-	if (NOT WAS_FOUND EQUAL -1)
-		message("YES: ${GCOV_FILE}")
-		list(APPEND GCOV_FILES ${GCOV_FILE})
-
-		# We remove it from the list, so we don't bother searching for it again.
-		# Also files left in COVERAGE_SRCS_REMAINING after this loop ends should
-		# have coverage data generated from them (no lines are covered).
-		list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH})
-	else()
-		message("NO:  ${GCOV_FILE}")
-	endif()
-endforeach()
-
-# TODO: Enable setting these
-set(JSON_SERVICE_NAME "travis-ci")
-set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID})
-
-set(JSON_TEMPLATE
-"{
-  \"service_name\": \"\@JSON_SERVICE_NAME\@\",
-  \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\",
-  \"source_files\": \@JSON_GCOV_FILES\@
-}"
-)
-
-set(SRC_FILE_TEMPLATE
-"{
-  \"name\": \"\@GCOV_SRC_REL_PATH\@\",
-  \"source\": \"\@GCOV_FILE_SOURCE\@\",
-  \"coverage\": \@GCOV_FILE_COVERAGE\@
-}"
-)
-
-message("\nGenerate JSON for files:")
-message("=========================")
-
-set(JSON_GCOV_FILES "[")
-
-# Read the GCOV files line by line and get the coverage data.
-foreach (GCOV_FILE ${GCOV_FILES})
-
-	get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE})
-	file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}")
-
-	# Loads the gcov file as a list of lines.
-	file(STRINGS ${GCOV_FILE} GCOV_LINES)
-
-	# Instead of trying to parse the source from the
-	# 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
-	#  which also happens to be the same as the CMake list delimiter).
-	file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
-
-	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	# According to http://json.org/ these should be escaped as well.
-	# Don't know how to do that in CMake however...
-	#string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	#string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	#string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-
-	# We want a json array of coverage data as a single string
-	# start building them from the contents of the .gcov
-	set(GCOV_FILE_COVERAGE "[")
-
-	foreach (GCOV_LINE ${GCOV_LINES})
-		# Example of what we're parsing:
-		# Hitcount  |Line | Source
-		# "        8:   26:        if (!allowed || (strlen(allowed) == 0))"
-		string(REGEX REPLACE 
-			"^([^:]*):([^:]*):(.*)$" 
-			"\\1;\\2;\\3"
-			RES
-			"${GCOV_LINE}")
-
-		list(LENGTH RES RES_COUNT)
-		if (RES_COUNT GREATER 2)
-			list(GET RES 0 HITCOUNT)
-			list(GET RES 1 LINE)
-			list(GET RES 2 SOURCE)
-
-			string(STRIP ${HITCOUNT} HITCOUNT)
-			string(STRIP ${LINE} LINE)
-
-			# Lines with 0 line numbers are metadata and can be ignored.
-			if (NOT ${LINE} EQUAL 0)
-				
-				# Translate the hitcount into valid JSON values.
-				if (${HITCOUNT} STREQUAL "#####")
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ")
-				elseif (${HITCOUNT} STREQUAL "-")
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ")
-				else()
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ")
-				endif()
-				# TODO: Look for LCOV_EXCL_LINE in SOURCE to get rid of false positives.
-			endif()
-		else()
-			message(WARNING "Failed to properly parse line --> ${GCOV_LINE}")
-		endif()
-	endforeach()
-
-	# Advanced way of removing the trailing comma in the JSON array.
-	# "[1, 2, 3, " -> "[1, 2, 3"
-	string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE})
-
-	# Append the trailing ] to complete the JSON array.
-	set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]")
-
-	# Generate the final JSON for this file.
-	message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...")
-	string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON)
-
-	set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ")
-endforeach()
-
-# Loop through all files we couldn't find any coverage for
-# as well, and generate JSON for those as well with 0% coverage.
-foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING})
-
-	# Loads the source file as a list of lines.
-	file(STRINGS ${NOT_COVERED_SRC} SRC_LINES)
-
-	set(GCOV_FILE_COVERAGE "[")
-	set(GCOV_FILE_SOURCE "")
-
-	foreach (SOURCE ${SRC_LINES})
-		set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ")
-
-		string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}")
-		string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}")
-		string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}")
-		string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}")
-		set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n")
-	endforeach()
-
-	# Remove trailing comma, and complete JSON array with ]
-	string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE})
-	set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]")
-
-	# Generate the final JSON for this file.
-	message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...")
-	string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON)
-	set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ")
-endforeach()
-
-# Get rid of trailing comma.
-string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES})
-set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]")
-
-# Generate the final complete JSON!
-message("Generate final JSON...")
-string(CONFIGURE ${JSON_TEMPLATE} JSON)
-
-file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}")
-message("###########################################################################")
-message("Generated coveralls JSON containing coverage data:") 
-message("${COVERALLS_OUTPUT_FILE}")
-message("###########################################################################")
-

+ 5 - 1
jansson.mod/jansson/configure.ac

@@ -1,5 +1,5 @@
 AC_PREREQ([2.60])
-AC_INIT([jansson], [2.13.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])
@@ -137,6 +137,10 @@ fi
 AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
 AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
 
+# Enable symbol versioning on GNU libc
+JSON_SYMVER_LDFLAGS=
+AC_CHECK_DECL([__GLIBC__], [JSON_SYMVER_LDFLAGS=-Wl,--default-symver])
+AC_SUBST([JSON_SYMVER_LDFLAGS])
 
 AC_ARG_ENABLE([ossfuzzers],
   [AS_HELP_STRING([--enable-ossfuzzers],

+ 2 - 2
jansson.mod/jansson/doc/Makefile.am

@@ -1,5 +1,5 @@
-EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst		\
-	gettingstarted.rst github_commits.c index.rst portability.rst	\
+EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst  \
+	gettingstarted.rst github_commits.c index.rst threadsafety.rst  \
 	tutorial.rst upgrading.rst ext/refcounting.py
 
 SPHINXBUILD = sphinx-build

+ 187 - 34
jansson.mod/jansson/doc/apiref.rst

@@ -114,7 +114,7 @@ also cause errors.
 Type
 ----
 
-.. type:: enum json_type
+.. c:enum:: json_type
 
    The type of a JSON value. The following members are defined:
 
@@ -145,33 +145,33 @@ Type
 .. function:: int json_typeof(const json_t *json)
 
    Return the type of the JSON value (a :type:`json_type` cast to
-   :type:`int`). *json* MUST NOT be *NULL*. This function is actually
+   ``int``). *json* MUST NOT be *NULL*. This function is actually
    implemented as a macro for speed.
 
-.. function:: json_is_object(const json_t *json)
-               json_is_array(const json_t *json)
-               json_is_string(const json_t *json)
-               json_is_integer(const json_t *json)
-               json_is_real(const json_t *json)
-               json_is_true(const json_t *json)
-               json_is_false(const json_t *json)
-               json_is_null(const json_t *json)
+.. function:: int json_is_object(const json_t *json)
+              int json_is_array(const json_t *json)
+              int json_is_string(const json_t *json)
+              int json_is_integer(const json_t *json)
+              int json_is_real(const json_t *json)
+              int json_is_true(const json_t *json)
+              int json_is_false(const json_t *json)
+              int json_is_null(const json_t *json)
 
    These functions (actually macros) return true (non-zero) for values
    of the given type, and false (zero) for values of other types and
    for *NULL*.
 
-.. function:: json_is_number(const json_t *json)
+.. function:: int json_is_number(const json_t *json)
 
    Returns true for values of types ``JSON_INTEGER`` and
    ``JSON_REAL``, and false for other types and for *NULL*.
 
-.. function:: json_is_boolean(const json_t *json)
+.. function:: int json_is_boolean(const json_t *json)
 
    Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false
    for values of other types and for *NULL*.
 
-.. function:: json_boolean_value(const json_t *json)
+.. function:: int json_boolean_value(const json_t *json)
 
    Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE``
    and 0 otherwise.
@@ -594,12 +594,12 @@ A JSON array is an ordered collection of other JSON values.
    Appends all elements in *other_array* to the end of *array*.
    Returns 0 on success and -1 on error.
 
-.. function:: json_array_foreach(array, index, value)
+.. function:: void json_array_foreach(array, index, value)
 
    Iterate over every element of ``array``, running the block
    of code that follows each time with the proper values set to
    variables ``index`` and ``value``, of types :type:`size_t` and
-   :type:`json_t *` respectively. Example::
+   :type:`json_t` pointer respectively. Example::
 
        /* array is a JSON array */
        size_t index;
@@ -648,6 +648,15 @@ allowed in object keys.
    Get a value corresponding to *key* from *object*. Returns *NULL* if
    *key* is not found and on error.
 
+.. function:: json_t *json_object_getn(const json_t *object, const char *key, size_t key_len)
+
+   .. refcounting:: borrow
+
+   Like :func:`json_object_get`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set(json_t *object, const char *key, json_t *value)
 
    Set the value of *key* to *value* in *object*. *key* must be a
@@ -655,6 +664,13 @@ allowed in object keys.
    already is a value for *key*, it is replaced by the new value.
    Returns 0 on success and -1 on error.
 
+.. function:: int json_object_setn(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
 
    Like :func:`json_object_set`, but doesn't check that *key* is
@@ -662,12 +678,26 @@ allowed in object keys.
    really is the case (e.g. you have already checked it by other
    means).
 
+.. function:: int json_object_setn_nocheck(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_nocheck`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_new(json_t *object, const char *key, json_t *value)
 
    Like :func:`json_object_set()` but steals the reference to
    *value*. This is useful when *value* is newly created and not used
    after the call.
 
+.. function:: int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_new`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value)
 
    Like :func:`json_object_set_new`, but doesn't check that *key* is
@@ -675,12 +705,26 @@ allowed in object keys.
    really is the case (e.g. you have already checked it by other
    means).
 
+.. function:: int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_new_nocheck`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_del(json_t *object, const char *key)
 
    Delete *key* from *object* if it exists. Returns 0 on success, or
    -1 if *key* was not found. The reference count of the removed value
    is decremented.
 
+.. function:: int json_object_deln(json_t *object, const char *key, size_t key_len)
+
+   Like :func:`json_object_del`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_clear(json_t *object)
 
    Remove all elements from *object*. Returns 0 on success and -1 if
@@ -732,12 +776,12 @@ allowed in object keys.
    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:: void json_object_foreach(object, key, value)
 
    Iterate over every key-value pair of ``object``, running the block
    of code that follows each time with the proper values set to
-   variables ``key`` and ``value``, of types :type:`const char *` and
-   :type:`json_t *` respectively. Example::
+   variables ``key`` and ``value``, of types ``const char *`` and
+   :type:`json_t` pointer respectively. Example::
 
        /* obj is a JSON object */
        const char *key;
@@ -750,7 +794,7 @@ allowed in object keys.
    The items are returned in the order they were inserted to the
    object.
 
-   **Note:** It's not safe to call ``json_object_del(object, key)``
+   **Note:** It's not safe to call ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)``
    during iteration. If you need to, use
    :func:`json_object_foreach_safe` instead.
 
@@ -764,14 +808,42 @@ allowed in object keys.
    .. versionadded:: 2.3
 
 
-.. function:: json_object_foreach_safe(object, tmp, key, value)
+.. function:: void json_object_foreach_safe(object, tmp, key, value)
 
    Like :func:`json_object_foreach()`, but it's safe to call
-   ``json_object_del(object, key)`` during iteration. You need to pass
-   an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
+   ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)`` during iteration.
+   You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
 
    .. versionadded:: 2.8
 
+.. function:: void json_object_keylen_foreach(object, key, key_len, value)
+
+   Like :c:func:`json_object_foreach`, but in *key_len* stored length of the *key*.
+   Example::
+
+       /* obj is a JSON object */
+       const char *key;
+       json_t *value;
+       size_t len;
+
+       json_object_keylen_foreach(obj, key, len, value) {
+            printf("got key %s with length %zu\n", key, len);
+       }
+
+   **Note:** It's not safe to call ``json_object_deln(object, key, key_len)``
+   during iteration. If you need to, use
+   :func:`json_object_keylen_foreach_safe` instead.
+
+   .. versionadded:: 2.14
+
+
+.. function:: void json_object_keylen_foreach_safe(object, tmp, key, key_len, value)
+
+   Like :func:`json_object_keylen_foreach()`, but it's safe to call
+   ``json_object_deln(object, key, key_len)`` during iteration.
+   You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
+
+   .. versionadded:: 2.14
 
 The following functions can be used to iterate through all key-value
 pairs in an object. The items are returned in the order they were
@@ -800,6 +872,12 @@ inserted to the object.
 
    Extract the associated key from *iter*.
 
+.. function:: size_t json_object_iter_key_len(void *iter)
+
+   Extract the associated key length from *iter*.
+
+   .. versionadded:: 2.14
+
 .. function:: json_t *json_object_iter_value(void *iter)
 
    .. refcounting:: borrow
@@ -855,8 +933,7 @@ inserted to the object.
     :func:`json_object()`, either explicit or implicit. If this
     function is not called by the user, the first call to
     :func:`json_object()` (either explicit or implicit) seeds the hash
-    function. See :ref:`portability-thread-safety` for notes on thread
-    safety.
+    function. See :ref:`thread-safety` for notes on thread safety.
 
     If repeatable results are required, for e.g. unit tests, the hash
     function can be "unrandomized" by calling :func:`json_object_seed`
@@ -926,7 +1003,7 @@ success. See :ref:`apiref-decoding` for more info.
 All functions also accept *NULL* as the :type:`json_error_t` pointer,
 in which case no error information is returned to the caller.
 
-.. type:: enum json_error_code
+.. c:enum:: json_error_code
 
    An enumeration containing numeric error codes.  The following errors are
    currently defined:
@@ -1021,7 +1098,7 @@ in which case no error information is returned to the caller.
 Encoding
 ========
 
-This sections describes the functions that can be used to encode
+This section describes the functions that can be used to encode
 values to JSON. By default, only objects and arrays can be encoded
 directly, since they are the only valid *root* values of a JSON text.
 To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see
@@ -1206,7 +1283,7 @@ These functions output UTF-8:
 Decoding
 ========
 
-This sections describes the functions that can be used to decode JSON
+This section describes the functions that can be used to decode JSON
 text to the Jansson representation of JSON data. The JSON
 specification requires that a JSON text is either a serialized array
 or object, and this requirement is also enforced with the following
@@ -1488,17 +1565,17 @@ arguments.
     Output a JSON null value. No argument is consumed.
 
 ``b`` (boolean) [int]
-    Convert a C :type:`int` to JSON boolean value. Zero is converted
+    Convert a C ``int`` to JSON boolean value. Zero is converted
     to ``false`` and non-zero to ``true``.
 
 ``i`` (integer) [int]
-    Convert a C :type:`int` to JSON integer.
+    Convert a C ``int`` to JSON integer.
 
 ``I`` (integer) [json_int_t]
     Convert a C :type:`json_int_t` to JSON integer.
 
 ``f`` (real) [double]
-    Convert a C :type:`double` to JSON real.
+    Convert a C ``double`` to JSON real.
 
 ``o`` (any value) [json_t \*]
     Output any given JSON value as-is. If the value is added to an
@@ -1625,20 +1702,20 @@ type whose address should be passed.
     Expect a JSON null value. Nothing is extracted.
 
 ``b`` (boolean) [int]
-    Convert a JSON boolean value to a C :type:`int`, so that ``true``
+    Convert a JSON boolean value to a C ``int``, so that ``true``
     is converted to 1 and ``false`` to 0.
 
 ``i`` (integer) [int]
-    Convert a JSON integer to C :type:`int`.
+    Convert a JSON integer to C ``int``.
 
 ``I`` (integer) [json_int_t]
     Convert a JSON integer to C :type:`json_int_t`.
 
 ``f`` (real) [double]
-    Convert a JSON real to C :type:`double`.
+    Convert a JSON real to C ``double``.
 
 ``F`` (integer or real) [double]
-    Convert a JSON number (integer or real) to C :type:`double`.
+    Convert a JSON number (integer or real) to C ``double``.
 
 ``o`` (any value) [json_t \*]
     Store a JSON value with no conversion to a :type:`json_t` pointer.
@@ -1909,3 +1986,79 @@ memory, see
 http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html.
 The page also explains the :func:`guaranteed_memset()` function used
 in the example and gives a sample implementation for it.
+
+.. _fixed_length_keys:
+
+Fixed-Length keys
+=================
+
+The Jansson API allows work with fixed-length keys. This can be useful in the following cases:
+
+* The key is contained inside a buffer and is not null-terminated. In this case creating a new temporary buffer is not needed.
+* The key contains U+0000 inside it.
+
+List of API for fixed-length keys:
+
+* :c:func:`json_object_getn`
+* :c:func:`json_object_setn`
+* :c:func:`json_object_setn_nocheck`
+* :c:func:`json_object_setn_new`
+* :c:func:`json_object_setn_new_nocheck`
+* :c:func:`json_object_deln`
+* :c:func:`json_object_iter_key_len`
+* :c:func:`json_object_keylen_foreach`
+* :c:func:`json_object_keylen_foreach_safe`
+
+**Examples:**
+
+Try to write a new function to get :c:struct:`json_t` by path separated by ``.``
+
+This requires:
+
+* string iterator (no need to modify the input for better performance)
+* API for working with fixed-size keys
+
+The iterator::
+
+    struct string {
+        const char *string;
+        size_t length;
+    };
+
+    size_t string_try_next(struct string *str, const char *delimiter) {
+        str->string += strspn(str->string, delimiter);
+        str->length = strcspn(str->string, delimiter);
+        return str->length;
+    }
+
+    #define string_foreach(_string, _delimiter) \
+            for (; string_try_next(&(_string), _delimiter); (_string).string += (_string).length)
+
+
+The function::
+
+    json_t *json_object_get_by_path(json_t *object, const char *path) {
+        struct string str;
+        json_t *out = object;
+
+        str.string = path;
+
+        string_foreach(str, ".") {
+            out = json_object_getn(out, str.string, str.length);
+            if (out == NULL)
+                return NULL;
+        }
+
+        return out;
+    }
+
+And usage::
+
+    int main(void) {
+        json_t *obj = json_pack("{s:{s:{s:b}}}", "a", "b", "c", 1);
+
+        json_t *c = json_object_get_by_path(obj, "a.b.c");
+        assert(json_is_true(c));
+
+        json_decref(obj);
+    }

+ 1 - 1
jansson.mod/jansson/doc/conf.py

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

+ 2 - 3
jansson.mod/jansson/doc/conformance.rst

@@ -22,8 +22,7 @@ JSON strings are mapped to C-style null-terminated character arrays,
 and UTF-8 encoding is used internally.
 
 All Unicode codepoints U+0000 through U+10FFFF are allowed in string
-values. However, U+0000 is not allowed in object keys because of API
-restrictions.
+values. However, U+0000 is allowed in object keys only for length-aware functions.
 
 Unicode normalization or any other transformation is never performed
 on any strings (string values or object keys). When checking for
@@ -110,7 +109,7 @@ to overflow semantics). Also, no support or hooks are provided for any
 supplemental "bignum" type add-on packages.
 
 Depth of nested values
-----------------------
+======================
 
 To avoid stack exhaustion, Jansson currently limits the nesting depth
 for arrays and objects to a certain value (default: 2048), defined as

+ 20 - 11
jansson.mod/jansson/doc/ext/refcounting.py

@@ -24,8 +24,8 @@
 """
 
 from docutils import nodes
+from docutils.parsers.rst import Directive
 
-class refcounting(nodes.emphasis): pass
 
 def visit(self, node):
     self.visit_emphasis(node)
@@ -40,16 +40,25 @@ def html_depart(self, node):
     self.body.append('</em>')
 
 
-def refcounting_directive(name, arguments, options, content, lineno,
-                   content_offset, block_text, state, state_machine):
-    if arguments[0] == 'borrow':
-        text = 'Return value: Borrowed reference.'
-    elif arguments[0] == 'new':
-        text = 'Return value: New reference.'
-    else:
-        raise Error('Valid arguments: new, borrow')
+class refcounting(nodes.emphasis):
+    pass
+
+class refcounting_directive(Directive):
+    has_content = False
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = False
+
+    def run(self):
+        if self.arguments[0] == 'borrow':
+            text = 'Return value: Borrowed reference.'
+        elif self.arguments[0] == 'new':
+            text = 'Return value: New reference.'
+        else:
+            raise Error('Valid arguments: new, borrow')
+
+        return [refcounting(text, text)]
 
-    return [refcounting(text, text)]
 
 def setup(app):
     app.add_node(refcounting,
@@ -57,4 +66,4 @@ def setup(app):
                  latex=(visit, depart),
                  text=(visit, depart),
                  man=(visit, depart))
-    app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0))
+    app.add_directive('refcounting', refcounting_directive)

+ 1 - 0
jansson.mod/jansson/doc/github_commits.c

@@ -153,6 +153,7 @@ 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;
         }
 

+ 1 - 1
jansson.mod/jansson/doc/index.rst

@@ -41,7 +41,7 @@ Contents
    upgrading
    tutorial
    conformance
-   portability
+   threadsafety
    apiref
    changes
 

+ 4 - 7
jansson.mod/jansson/doc/portability.rst → jansson.mod/jansson/doc/threadsafety.rst

@@ -1,11 +1,8 @@
-***********
-Portability
-***********
-
-.. _portability-thread-safety:
+.. _thread-safety:
 
+*************
 Thread safety
--------------
+*************
 
 Jansson as a library is thread safe and has no mutable global state.
 The only exceptions are the hash function seed and memory allocation
@@ -64,7 +61,7 @@ program startup. See :ref:`apiref-custom-memory-allocation`.
 
 
 Locale
-------
+======
 
 Jansson works fine under any locale.
 

+ 8 - 8
jansson.mod/jansson/doc/upgrading.rst

@@ -47,13 +47,13 @@ List of Incompatible Changes
 
 **Underlying type of JSON integers**
     The underlying C type of JSON integers has been changed from
-    :type:`int` to the widest available signed integer type, i.e.
-    :type:`long long` or :type:`long`, depending on whether
-    :type:`long long` is supported on your system or not. This makes
+    ``int`` to the widest available signed integer type, i.e.
+    ``long long`` or ``long``, depending on whether
+    ``long long`` is supported on your system or not. This makes
     the whole 64-bit integer range available on most modern systems.
 
     ``jansson.h`` has a typedef :type:`json_int_t` to the underlying
-    integer type. :type:`int` should still be used in most cases when
+    integer type. ``int`` should still be used in most cases when
     dealing with smallish JSON integers, as the compiler handles
     implicit type coercion. Only when the full 64-bit range is needed,
     :type:`json_int_t` should be explicitly used.
@@ -69,8 +69,8 @@ List of Incompatible Changes
 
 **Unsigned integers in API functions**
     Version 2.0 unifies unsigned integer usage in the API. All uses of
-    :type:`unsigned int` and :type:`unsigned long` have been replaced
-    with :type:`size_t`. This includes flags, container sizes, etc.
+    ``unsigned int`` and ``unsigned long`` have been replaced
+    with ``size_t``. This includes flags, container sizes, etc.
     This should not require source code changes, as both
-    :type:`unsigned int` and :type:`unsigned long` are usually
-    compatible with :type:`size_t`.
+    ``unsigned int`` and ``unsigned long`` are usually
+    compatible with ``size_t``.

+ 4 - 0
jansson.mod/jansson/examples/README.rst

@@ -0,0 +1,4 @@
+Jansson examples
+================
+
+This directory contains simple example programs that use Jansson.

+ 200 - 0
jansson.mod/jansson/examples/simple_parse.c

@@ -0,0 +1,200 @@
+/*
+ * Simple example of parsing and printing JSON using jansson.
+ *
+ * SYNOPSIS:
+ * $ examples/simple_parse
+ * Type some JSON > [true, false, null, 1, 0.0, -0.0, "", {"name": "barney"}]
+ * JSON Array of 8 elements:
+ *   JSON True
+ *   JSON False
+ *   JSON Null
+ *   JSON Integer: "1"
+ *   JSON Real: 0.000000
+ *   JSON Real: -0.000000
+ *   JSON String: ""
+ *   JSON Object of 1 pair:
+ *     JSON Key: "name"
+ *     JSON String: "barney"
+ *
+ * Copyright (c) 2014 Robert Poor <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* forward refs */
+void print_json(json_t *root);
+void print_json_aux(json_t *element, int indent);
+void print_json_indent(int indent);
+const char *json_plural(size_t count);
+void print_json_object(json_t *element, int indent);
+void print_json_array(json_t *element, int indent);
+void print_json_string(json_t *element, int indent);
+void print_json_integer(json_t *element, int indent);
+void print_json_real(json_t *element, int indent);
+void print_json_true(json_t *element, int indent);
+void print_json_false(json_t *element, int indent);
+void print_json_null(json_t *element, int indent);
+
+void print_json(json_t *root) { print_json_aux(root, 0); }
+
+void print_json_aux(json_t *element, int indent) {
+    switch (json_typeof(element)) {
+        case JSON_OBJECT:
+            print_json_object(element, indent);
+            break;
+        case JSON_ARRAY:
+            print_json_array(element, indent);
+            break;
+        case JSON_STRING:
+            print_json_string(element, indent);
+            break;
+        case JSON_INTEGER:
+            print_json_integer(element, indent);
+            break;
+        case JSON_REAL:
+            print_json_real(element, indent);
+            break;
+        case JSON_TRUE:
+            print_json_true(element, indent);
+            break;
+        case JSON_FALSE:
+            print_json_false(element, indent);
+            break;
+        case JSON_NULL:
+            print_json_null(element, indent);
+            break;
+        default:
+            fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element));
+    }
+}
+
+void print_json_indent(int indent) {
+    int i;
+    for (i = 0; i < indent; i++) {
+        putchar(' ');
+    }
+}
+
+const char *json_plural(size_t count) { return count == 1 ? "" : "s"; }
+
+void print_json_object(json_t *element, int indent) {
+    size_t size;
+    const char *key;
+    json_t *value;
+
+    print_json_indent(indent);
+    size = json_object_size(element);
+
+    printf("JSON Object of %lld pair%s:\n", (long long)size, json_plural(size));
+    json_object_foreach(element, key, value) {
+        print_json_indent(indent + 2);
+        printf("JSON Key: \"%s\"\n", key);
+        print_json_aux(value, indent + 2);
+    }
+}
+
+void print_json_array(json_t *element, int indent) {
+    size_t i;
+    size_t size = json_array_size(element);
+    print_json_indent(indent);
+
+    printf("JSON Array of %lld element%s:\n", (long long)size, json_plural(size));
+    for (i = 0; i < size; i++) {
+        print_json_aux(json_array_get(element, i), indent + 2);
+    }
+}
+
+void print_json_string(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON String: \"%s\"\n", json_string_value(element));
+}
+
+void print_json_integer(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON Integer: \"%" JSON_INTEGER_FORMAT "\"\n", json_integer_value(element));
+}
+
+void print_json_real(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON Real: %f\n", json_real_value(element));
+}
+
+void print_json_true(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON True\n");
+}
+
+void print_json_false(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON False\n");
+}
+
+void print_json_null(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON Null\n");
+}
+
+/*
+ * Parse text into a JSON object. If text is valid JSON, returns a
+ * json_t structure, otherwise prints and error and returns null.
+ */
+json_t *load_json(const char *text) {
+    json_t *root;
+    json_error_t error;
+
+    root = json_loads(text, 0, &error);
+
+    if (root) {
+        return root;
+    } else {
+        fprintf(stderr, "json error on line %d: %s\n", error.line, error.text);
+        return (json_t *)0;
+    }
+}
+
+/*
+ * Print a prompt and return (by reference) a null-terminated line of
+ * text.  Returns NULL on eof or some error.
+ */
+char *read_line(char *line, int max_chars) {
+    printf("Type some JSON > ");
+    fflush(stdout);
+    return fgets(line, max_chars, stdin);
+}
+
+/* ================================================================
+ * main
+ */
+
+#define MAX_CHARS 4096
+
+int main(int argc, char *argv[]) {
+    char line[MAX_CHARS];
+
+    if (argc != 1) {
+        fprintf(stderr, "Usage: %s\n", argv[0]);
+        exit(-1);
+    }
+
+    while (read_line(line, MAX_CHARS) != (char *)NULL) {
+
+        /* parse text into JSON structure */
+        json_t *root = load_json(line);
+
+        if (root) {
+            /* print and release the JSON structure */
+            print_json(root);
+            json_decref(root);
+        }
+    }
+
+    return 0;
+}

+ 3 - 0
jansson.mod/jansson/release.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+find . -type f -a '(' -name '*.c' -o -name '*.h' ')' | xargs clang-format -i

+ 27 - 0
jansson.mod/jansson/scripts/clang-format-check

@@ -0,0 +1,27 @@
+#!/bin/bash
+
+CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
+CLANG_FORMAT_VERSION=${CLANG_FORMAT_VERSION:-}
+
+if ! type $CLANG_FORMAT >/dev/null || \
+        ! $CLANG_FORMAT --version | grep -q "version ${CLANG_FORMAT_VERSION}"; then
+    # If running tests, mark this test as skipped.
+    exit 77
+fi
+
+errors=0
+paths=$(git ls-files | grep '\.[ch]$')
+for path in $paths; do
+    in=$(cat $path)
+    out=$($CLANG_FORMAT $path)
+
+    if [ "$in" != "$out" ]; then
+        diff -u -L $path -L "$path.formatted" $path - <<<$out
+        errors=1
+    fi
+done
+
+if [ $errors -ne 0 ]; then
+    echo "Formatting errors detected, run ./scripts/clang-format to fix!"
+    exit 1
+fi

+ 2 - 1
jansson.mod/jansson/src/Makefile.am

@@ -25,5 +25,6 @@ libjansson_la_SOURCES = \
 libjansson_la_LDFLAGS = \
 	-no-undefined \
 	-export-symbols-regex '^json_|^jansson_' \
-	-version-info 17:0:13 \
+	-version-info 18:0:14 \
+	@JSON_SYMVER_LDFLAGS@ \
 	@JSON_BSYMBOLIC_LDFLAGS@

+ 38 - 17
jansson.mod/jansson/src/dump.c

@@ -195,8 +195,21 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v
     return dump("\"", 1, data);
 }
 
+struct key_len {
+    const char *key;
+    int len;
+};
+
 static int compare_keys(const void *key1, const void *key2) {
-    return strcmp(*(const char **)key1, *(const char **)key2);
+    const struct key_len *k1 = key1;
+    const struct key_len *k2 = key2;
+    const size_t min_size = k1->len < k2->len ? k1->len : k2->len;
+    int res = memcmp(k1->key, k2->key, min_size);
+
+    if (res)
+        return res;
+
+    return k1->len - k2->len;
 }
 
 static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
@@ -236,7 +249,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             double value = json_real_value(json);
 
             size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
-                                FLAGS_TO_PRECISION(flags), flags & JSON_FRACTIONAL_DIGITS);
+                                FLAGS_TO_PRECISION(flags));
             if (size < 0)
                 return -1;
 
@@ -253,9 +266,10 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             /* Space for "0x", double the sizeof a pointer for the hex and a
              * terminator. */
             char key[2 + (sizeof(json) * 2) + 1];
+            size_t key_len;
 
             /* detect circular references */
-            if (jsonp_loop_check(parents, json, key, sizeof(key)))
+            if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len))
                 return -1;
 
             n = json_array_size(json);
@@ -263,7 +277,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             if (!embed && dump("[", 1, data))
                 return -1;
             if (n == 0) {
-                hashtable_del(parents, key);
+                hashtable_del(parents, key, key_len);
                 return embed ? 0 : dump("]", 1, data);
             }
             if (dump_indent(flags, depth + 1, 0, dump, data))
@@ -284,7 +298,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 }
             }
 
-            hashtable_del(parents, key);
+            hashtable_del(parents, key, key_len);
             return embed ? 0 : dump("]", 1, data);
         }
 
@@ -293,6 +307,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             const char *separator;
             int separator_length;
             char loop_key[LOOP_KEY_LEN];
+            size_t loop_key_len;
 
             if (flags & JSON_COMPACT) {
                 separator = ":";
@@ -303,7 +318,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             }
 
             /* detect circular references */
-            if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key)))
+            if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key),
+                                 &loop_key_len))
                 return -1;
 
             iter = json_object_iter((json_t *)json);
@@ -311,40 +327,44 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             if (!embed && dump("{", 1, data))
                 return -1;
             if (!iter) {
-                hashtable_del(parents, loop_key);
+                hashtable_del(parents, loop_key, loop_key_len);
                 return embed ? 0 : dump("}", 1, data);
             }
             if (dump_indent(flags, depth + 1, 0, dump, data))
                 return -1;
 
             if (flags & JSON_SORT_KEYS) {
-                const char **keys;
+                struct key_len *keys;
                 size_t size, i;
 
                 size = json_object_size(json);
-                keys = jsonp_malloc(size * sizeof(const char *));
+                keys = jsonp_malloc(size * sizeof(struct key_len));
                 if (!keys)
                     return -1;
 
                 i = 0;
                 while (iter) {
-                    keys[i] = json_object_iter_key(iter);
+                    struct key_len *keylen = &keys[i];
+
+                    keylen->key = json_object_iter_key(iter);
+                    keylen->len = json_object_iter_key_len(iter);
+
                     iter = json_object_iter_next((json_t *)json, iter);
                     i++;
                 }
                 assert(i == size);
 
-                qsort(keys, size, sizeof(const char *), compare_keys);
+                qsort(keys, size, sizeof(struct key_len), compare_keys);
 
                 for (i = 0; i < size; i++) {
-                    const char *key;
+                    const struct key_len *key;
                     json_t *value;
 
-                    key = keys[i];
-                    value = json_object_get(json, key);
+                    key = &keys[i];
+                    value = json_object_getn(json, key->key, key->len);
                     assert(value);
 
-                    dump_string(key, strlen(key), dump, data, flags);
+                    dump_string(key->key, key->len, dump, data, flags);
                     if (dump(separator, separator_length, data) ||
                         do_dump(value, flags, depth + 1, parents, dump, data)) {
                         jsonp_free(keys);
@@ -372,8 +392,9 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 while (iter) {
                     void *next = json_object_iter_next((json_t *)json, iter);
                     const char *key = json_object_iter_key(iter);
+                    const size_t key_len = json_object_iter_key_len(iter);
 
-                    dump_string(key, strlen(key), dump, data, flags);
+                    dump_string(key, key_len, dump, data, flags);
                     if (dump(separator, separator_length, data) ||
                         do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
                                 dump, data))
@@ -392,7 +413,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 }
             }
 
-            hashtable_del(parents, loop_key);
+            hashtable_del(parents, loop_key, loop_key_len);
             return embed ? 0 : dump("}", 1, data);
         }
 

+ 57 - 35
jansson.mod/jansson/src/hashtable.c

@@ -5,14 +5,14 @@
  * it under the terms of the MIT license. See LICENSE for details.
  */
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 #include <jansson_private_config.h>
 #endif
 
 #include <stdlib.h>
 #include <string.h>
 
-#if HAVE_STDINT_H
+#ifdef HAVE_STDINT_H
 #include <stdint.h>
 #endif
 
@@ -35,7 +35,7 @@ extern volatile uint32_t hashtable_seed;
 
 #define list_to_pair(list_)         container_of(list_, pair_t, list)
 #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
-#define hash_str(key)               ((size_t)hashlittle((key), strlen(key), hashtable_seed))
+#define hash_str(key, len)          ((size_t)hashlittle((key), len, hashtable_seed))
 
 static JSON_INLINE void list_init(list_t *list) {
     list->next = list;
@@ -69,7 +69,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *l
 }
 
 static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
-                                   const char *key, size_t hash) {
+                                   const char *key, size_t key_len, size_t hash) {
     list_t *list;
     pair_t *pair;
 
@@ -79,7 +79,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
     list = bucket->first;
     while (1) {
         pair = list_to_pair(list);
-        if (pair->hash == hash && strcmp(pair->key, key) == 0)
+        if (pair->hash == hash && pair->key_len == key_len &&
+            memcmp(pair->key, key, key_len) == 0)
             return pair;
 
         if (list == bucket->last)
@@ -92,7 +93,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
 }
 
 /* returns 0 on success, -1 if key was not found */
-static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) {
+static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len,
+                            size_t hash) {
     pair_t *pair;
     bucket_t *bucket;
     size_t index;
@@ -100,7 +102,7 @@ static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash
     index = hash & hashmask(hashtable->order);
     bucket = &hashtable->buckets[index];
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
         return -1;
 
@@ -193,7 +195,37 @@ void hashtable_close(hashtable_t *hashtable) {
     jsonp_free(hashtable->buckets);
 }
 
-int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
+static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) {
+    pair_t *pair;
+
+    /* offsetof(...) returns the size of pair_t without the last,
+   flexible member. This way, the correct amount is
+   allocated. */
+
+    if (key_len >= (size_t)-1 - offsetof(pair_t, key)) {
+        /* Avoid an overflow if the key is very long */
+        return NULL;
+    }
+
+    pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1);
+
+    if (!pair)
+        return NULL;
+
+    pair->hash = hash;
+    memcpy(pair->key, key, key_len);
+    pair->key[key_len] = '\0';
+    pair->key_len = key_len;
+    pair->value = value;
+
+    list_init(&pair->list);
+    list_init(&pair->ordered_list);
+
+    return pair;
+}
+
+int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len,
+                  json_t *value) {
     pair_t *pair;
     bucket_t *bucket;
     size_t hash, index;
@@ -203,35 +235,20 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
         if (hashtable_do_rehash(hashtable))
             return -1;
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     index = hash & hashmask(hashtable->order);
     bucket = &hashtable->buckets[index];
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
 
     if (pair) {
         json_decref(pair->value);
         pair->value = value;
     } else {
-        /* offsetof(...) returns the size of pair_t without the last,
-           flexible member. This way, the correct amount is
-           allocated. */
-
-        size_t len = strlen(key);
-        if (len >= (size_t)-1 - offsetof(pair_t, key)) {
-            /* Avoid an overflow if the key is very long */
-            return -1;
-        }
+        pair = init_pair(value, key, key_len, hash);
 
-        pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
         if (!pair)
             return -1;
 
-        pair->hash = hash;
-        strncpy(pair->key, key, len + 1);
-        pair->value = value;
-        list_init(&pair->list);
-        list_init(&pair->ordered_list);
-
         insert_to_bucket(hashtable, bucket, &pair->list);
         list_insert(&hashtable->ordered_list, &pair->ordered_list);
 
@@ -240,24 +257,24 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
     return 0;
 }
 
-void *hashtable_get(hashtable_t *hashtable, const char *key) {
+void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) {
     pair_t *pair;
     size_t hash;
     bucket_t *bucket;
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
         return NULL;
 
     return pair->value;
 }
 
-int hashtable_del(hashtable_t *hashtable, const char *key) {
-    size_t hash = hash_str(key);
-    return hashtable_do_del(hashtable, key, hash);
+int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) {
+    size_t hash = hash_str(key, key_len);
+    return hashtable_do_del(hashtable, key, key_len, hash);
 }
 
 void hashtable_clear(hashtable_t *hashtable) {
@@ -278,15 +295,15 @@ void *hashtable_iter(hashtable_t *hashtable) {
     return hashtable_iter_next(hashtable, &hashtable->ordered_list);
 }
 
-void *hashtable_iter_at(hashtable_t *hashtable, const char *key) {
+void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) {
     pair_t *pair;
     size_t hash;
     bucket_t *bucket;
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
         return NULL;
 
@@ -305,6 +322,11 @@ void *hashtable_iter_key(void *iter) {
     return pair->key;
 }
 
+size_t hashtable_iter_key_len(void *iter) {
+    pair_t *pair = ordered_list_to_pair((list_t *)iter);
+    return pair->key_len;
+}
+
 void *hashtable_iter_value(void *iter) {
     pair_t *pair = ordered_list_to_pair((list_t *)iter);
     return pair->value;

+ 16 - 4
jansson.mod/jansson/src/hashtable.h

@@ -24,6 +24,7 @@ struct hashtable_pair {
     struct hashtable_list ordered_list;
     size_t hash;
     json_t *value;
+    size_t key_len;
     char key[1];
 };
 
@@ -69,6 +70,7 @@ void hashtable_close(hashtable_t *hashtable);
  *
  * @hashtable: The hashtable object
  * @key: The key
+ * @key: The length of key
  * @serial: For addition order of keys
  * @value: The value
  *
@@ -79,27 +81,29 @@ void hashtable_close(hashtable_t *hashtable);
  *
  * Returns 0 on success, -1 on failure (out of memory).
  */
-int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
+int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value);
 
 /**
  * hashtable_get - Get a value associated with a key
  *
  * @hashtable: The hashtable object
  * @key: The key
+ * @key: The length of key
  *
  * Returns value if it is found, or NULL otherwise.
  */
-void *hashtable_get(hashtable_t *hashtable, const char *key);
+void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len);
 
 /**
  * hashtable_del - Remove a value from the hashtable
  *
  * @hashtable: The hashtable object
  * @key: The key
+ * @key: The length of key
  *
  * Returns 0 on success, or -1 if the key was not found.
  */
-int hashtable_del(hashtable_t *hashtable, const char *key);
+int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len);
 
 /**
  * hashtable_clear - Clear hashtable
@@ -132,11 +136,12 @@ void *hashtable_iter(hashtable_t *hashtable);
  *
  * @hashtable: The hashtable object
  * @key: The key that the iterator should point to
+ * @key: The length of key
  *
  * Like hashtable_iter() but returns an iterator pointing to a
  * specific key.
  */
-void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
+void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len);
 
 /**
  * hashtable_iter_next - Advance an iterator
@@ -156,6 +161,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
  */
 void *hashtable_iter_key(void *iter);
 
+/**
+ * hashtable_iter_key_len - Retrieve the key length pointed by an iterator
+ *
+ * @iter: The iterator
+ */
+size_t hashtable_iter_key_len(void *iter);
+
 /**
  * hashtable_iter_value - Retrieve the value pointed by an iterator
  *

+ 5 - 0
jansson.mod/jansson/src/jansson.def

@@ -34,9 +34,13 @@ EXPORTS
     json_object
     json_object_size
     json_object_get
+    json_object_getn
     json_object_set_new
+    json_object_setn_new
     json_object_set_new_nocheck
+    json_object_setn_new_nocheck
     json_object_del
+    json_object_deln
     json_object_clear
     json_object_update
     json_object_update_existing
@@ -46,6 +50,7 @@ EXPORTS
     json_object_iter_at
     json_object_iter_next
     json_object_iter_key
+    json_object_iter_key_len
     json_object_iter_value
     json_object_iter_set_new
     json_object_key_to_iter

+ 36 - 4
jansson.mod/jansson/src/jansson.h

@@ -21,11 +21,11 @@ extern "C" {
 /* version */
 
 #define JANSSON_MAJOR_VERSION 2
-#define JANSSON_MINOR_VERSION 13
-#define JANSSON_MICRO_VERSION 1
+#define JANSSON_MINOR_VERSION 14
+#define JANSSON_MICRO_VERSION 0
 
 /* Micro version is omitted if it's 0 */
-#define JANSSON_VERSION "2.13.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 >= ... */
@@ -188,9 +188,15 @@ void json_object_seed(size_t seed);
 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_getn(const json_t *object, const char *key, size_t key_len)
+    JANSSON_ATTRS((warn_unused_result));
 int json_object_set_new(json_t *object, const char *key, json_t *value);
+int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value);
 int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
+int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len,
+                                 json_t *value);
 int json_object_del(json_t *object, const char *key);
+int json_object_deln(json_t *object, const char *key, size_t key_len);
 int json_object_clear(json_t *object);
 int json_object_update(json_t *object, json_t *other);
 int json_object_update_existing(json_t *object, json_t *other);
@@ -201,6 +207,7 @@ void *json_object_iter_at(json_t *object, const char *key);
 void *json_object_key_to_iter(const char *key);
 void *json_object_iter_next(json_t *object, void *iter);
 const char *json_object_iter_key(void *iter);
+size_t json_object_iter_key_len(void *iter);
 json_t *json_object_iter_value(void *iter);
 int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
 
@@ -210,6 +217,14 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
          key = json_object_iter_key(                                                     \
              json_object_iter_next(object, json_object_key_to_iter(key))))
 
+#define json_object_keylen_foreach(object, key, key_len, value)                          \
+    for (key = json_object_iter_key(json_object_iter(object)),                           \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key));                \
+         key && (value = json_object_iter_value(json_object_key_to_iter(key)));          \
+         key = json_object_iter_key(                                                     \
+             json_object_iter_next(object, json_object_key_to_iter(key))),               \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key)))
+
 #define json_object_foreach_safe(object, n, key, value)                                  \
     for (key = json_object_iter_key(json_object_iter(object)),                           \
         n = json_object_iter_next(object, json_object_key_to_iter(key));                 \
@@ -217,6 +232,14 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
          key = json_object_iter_key(n),                                                  \
         n = json_object_iter_next(object, json_object_key_to_iter(key)))
 
+#define json_object_keylen_foreach_safe(object, n, key, key_len, value)                  \
+    for (key = json_object_iter_key(json_object_iter(object)),                           \
+        n = json_object_iter_next(object, json_object_key_to_iter(key)),                 \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key));                \
+         key && (value = json_object_iter_value(json_object_key_to_iter(key)));          \
+         key = json_object_iter_key(n), key_len = json_object_iter_key_len(n),           \
+        n = json_object_iter_next(object, json_object_key_to_iter(key)))
+
 #define json_array_foreach(array, index, value)                                          \
     for (index = 0;                                                                      \
          index < json_array_size(array) && (value = json_array_get(array, index));       \
@@ -226,11 +249,21 @@ static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *
     return json_object_set_new(object, key, json_incref(value));
 }
 
+static JSON_INLINE int json_object_setn(json_t *object, const char *key, size_t key_len,
+                                        json_t *value) {
+    return json_object_setn_new(object, key, key_len, json_incref(value));
+}
+
 static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key,
                                                json_t *value) {
     return json_object_set_new_nocheck(object, key, json_incref(value));
 }
 
+static JSON_INLINE int json_object_setn_nocheck(json_t *object, const char *key,
+                                                size_t key_len, json_t *value) {
+    return json_object_setn_new_nocheck(object, key, key_len, json_incref(value));
+}
+
 static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) {
     return json_object_iter_set_new(object, iter, json_incref(value));
 }
@@ -355,7 +388,6 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
 #define JSON_ESCAPE_SLASH      0x400
 #define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11)
 #define JSON_EMBED             0x10000
-#define JSON_FRACTIONAL_DIGITS  0x20000
 
 typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
 

+ 3 - 3
jansson.mod/jansson/src/jansson_private.h

@@ -79,7 +79,7 @@ void jsonp_error_vset(json_error_t *error, int line, int column, size_t position
 
 /* Locale independent string<->double conversions */
 int jsonp_strtod(strbuffer_t *strbuffer, double *out);
-int jsonp_dtostr(char *buffer, size_t size, double value, int prec, int frac_digits);
+int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
 
 /* Wrappers for custom memory functions */
 void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
@@ -91,8 +91,8 @@ char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_resu
 /* Circular reference check*/
 /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
 #define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
-int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
-                     size_t key_size);
+int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
+                     size_t *key_len_out);
 
 /* Windows compatibility */
 #if defined(_WIN32) || defined(WIN32)

+ 2 - 2
jansson.mod/jansson/src/load.c

@@ -689,7 +689,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {
         }
 
         if (flags & JSON_REJECT_DUPLICATES) {
-            if (json_object_get(object, key)) {
+            if (json_object_getn(object, key, len)) {
                 jsonp_free(key);
                 error_set(error, lex, json_error_duplicate_key, "duplicate object key");
                 goto error;
@@ -710,7 +710,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {
             goto error;
         }
 
-        if (json_object_set_new_nocheck(object, key, value)) {
+        if (json_object_setn_new_nocheck(object, key, len, value)) {
             jsonp_free(key);
             goto error;
         }

+ 1 - 1
jansson.mod/jansson/src/lookup3.h

@@ -73,7 +73,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
 # define HASH_BIG_ENDIAN 0
 #endif
 
-#define hashsize(n) ((uint32_t)1<<(n))
+#define hashsize(n) ((size_t)1<<(n))
 #define hashmask(n) (hashsize(n)-1)
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 

+ 5 - 4
jansson.mod/jansson/src/pack_unpack.c

@@ -544,7 +544,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
         if (unpack(s, value, ap))
             goto out;
 
-        hashtable_set(&key_set, key, json_null());
+        hashtable_set(&key_set, key, strlen(key), json_null());
         next_token(s);
     }
 
@@ -554,6 +554,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
     if (root && strict == 1) {
         /* We need to check that all non optional items have been parsed */
         const char *key;
+        size_t key_len;
         /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
         int keys_res = 1;
         strbuffer_t unrecognized_keys;
@@ -561,8 +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_foreach(root, key, value) {
-                if (!hashtable_get(&key_set, key)) {
+            json_object_keylen_foreach(root, key, key_len, value) {
+                if (!hashtable_get(&key_set, key, key_len)) {
                     unpacked++;
 
                     /* Save unrecognized keys for the error message */
@@ -574,7 +575,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
 
                     if (!keys_res)
                         keys_res =
-                            strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
+                            strbuffer_append_bytes(&unrecognized_keys, key, key_len);
                 }
             }
         }

+ 2 - 3
jansson.mod/jansson/src/strconv.c

@@ -76,8 +76,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
     return 0;
 }
 
-int jsonp_dtostr(char *buffer, size_t size, double value, int precision, int fractional_digits)
-{
+int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
     int ret;
     char *start, *end;
     size_t length;
@@ -85,7 +84,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision, int fra
     if (precision == 0)
         precision = 17;
 
-    ret = snprintf(buffer, size, fractional_digits ? "%.*f" : "%.*g", precision, value);
+    ret = snprintf(buffer, size, "%.*g", precision, value);
     if (ret < 0)
         return -1;
 

+ 92 - 34
jansson.mod/jansson/src/value.c

@@ -44,13 +44,17 @@ static JSON_INLINE void json_init(json_t *json, json_type type) {
     json->refcount = 1;
 }
 
-int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
-                     size_t key_size) {
-    snprintf(key, key_size, "%p", json);
-    if (hashtable_get(parents, key))
+int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
+                     size_t *key_len_out) {
+    size_t key_len = snprintf(key, key_size, "%p", json);
+
+    if (key_len_out)
+        *key_len_out = key_len;
+
+    if (hashtable_get(parents, key, key_len))
         return -1;
 
-    return hashtable_set(parents, key, json_null());
+    return hashtable_set(parents, key, key_len, json_null());
 }
 
 /*** object ***/
@@ -93,16 +97,32 @@ size_t json_object_size(const json_t *json) {
 }
 
 json_t *json_object_get(const json_t *json, const char *key) {
+    if (!key)
+        return NULL;
+
+    return json_object_getn(json, key, strlen(key));
+}
+
+json_t *json_object_getn(const json_t *json, const char *key, size_t key_len) {
     json_object_t *object;
 
     if (!key || !json_is_object(json))
         return NULL;
 
     object = json_to_object(json);
-    return hashtable_get(&object->hashtable, key);
+    return hashtable_get(&object->hashtable, key, key_len);
 }
 
 int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
+    if (!key) {
+        json_decref(value);
+        return -1;
+    }
+    return json_object_setn_new_nocheck(json, key, strlen(key), value);
+}
+
+int json_object_setn_new_nocheck(json_t *json, const char *key, size_t key_len,
+                                 json_t *value) {
     json_object_t *object;
 
     if (!value)
@@ -114,7 +134,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
     }
     object = json_to_object(json);
 
-    if (hashtable_set(&object->hashtable, key, value)) {
+    if (hashtable_set(&object->hashtable, key, key_len, value)) {
         json_decref(value);
         return -1;
     }
@@ -123,22 +143,38 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
 }
 
 int json_object_set_new(json_t *json, const char *key, json_t *value) {
-    if (!key || !utf8_check_string(key, strlen(key))) {
+    if (!key) {
         json_decref(value);
         return -1;
     }
 
-    return json_object_set_new_nocheck(json, key, value);
+    return json_object_setn_new(json, key, strlen(key), value);
+}
+
+int json_object_setn_new(json_t *json, const char *key, size_t key_len, json_t *value) {
+    if (!key || !utf8_check_string(key, key_len)) {
+        json_decref(value);
+        return -1;
+    }
+
+    return json_object_setn_new_nocheck(json, key, key_len, value);
 }
 
 int json_object_del(json_t *json, const char *key) {
+    if (!key)
+        return -1;
+
+    return json_object_deln(json, key, strlen(key));
+}
+
+int json_object_deln(json_t *json, const char *key, size_t key_len) {
     json_object_t *object;
 
     if (!key || !json_is_object(json))
         return -1;
 
     object = json_to_object(json);
-    return hashtable_del(&object->hashtable, key);
+    return hashtable_del(&object->hashtable, key, key_len);
 }
 
 int json_object_clear(json_t *json) {
@@ -155,13 +191,14 @@ 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_foreach(other, key, value) {
-        if (json_object_set_nocheck(object, key, value))
+    json_object_keylen_foreach(other, key, key_len, value) {
+        if (json_object_setn_nocheck(object, key, key_len, value))
             return -1;
     }
 
@@ -170,14 +207,15 @@ int json_object_update(json_t *object, json_t *other) {
 
 int json_object_update_existing(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_foreach(other, key, value) {
-        if (json_object_get(object, key))
-            json_object_set_nocheck(object, key, value);
+    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);
     }
 
     return 0;
@@ -185,14 +223,15 @@ 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_foreach(other, key, value) {
-        if (!json_object_get(object, key))
-            json_object_set_nocheck(object, key, value);
+    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);
     }
 
     return 0;
@@ -200,18 +239,20 @@ int json_object_update_missing(json_t *object, json_t *other) {
 
 int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) {
     const char *key;
+    size_t key_len;
     json_t *value;
     char loop_key[LOOP_KEY_LEN];
     int res = 0;
+    size_t loop_key_len;
 
     if (!json_is_object(object) || !json_is_object(other))
         return -1;
 
-    if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key), &loop_key_len))
         return -1;
 
-    json_object_foreach(other, key, value) {
-        json_t *v = json_object_get(object, key);
+    json_object_keylen_foreach(other, key, key_len, value) {
+        json_t *v = json_object_getn(object, key, key_len);
 
         if (json_is_object(v) && json_is_object(value)) {
             if (do_object_update_recursive(v, value, parents)) {
@@ -219,14 +260,14 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren
                 break;
             }
         } else {
-            if (json_object_set_nocheck(object, key, value)) {
+            if (json_object_setn_nocheck(object, key, key_len, value)) {
                 res = -1;
                 break;
             }
         }
     }
 
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
     return res;
 }
@@ -260,7 +301,7 @@ void *json_object_iter_at(json_t *json, const char *key) {
         return NULL;
 
     object = json_to_object(json);
-    return hashtable_iter_at(&object->hashtable, key);
+    return hashtable_iter_at(&object->hashtable, key, strlen(key));
 }
 
 void *json_object_iter_next(json_t *json, void *iter) {
@@ -280,6 +321,13 @@ const char *json_object_iter_key(void *iter) {
     return hashtable_iter_key(iter);
 }
 
+size_t json_object_iter_key_len(void *iter) {
+    if (!iter)
+        return 0;
+
+    return hashtable_iter_key_len(iter);
+}
+
 json_t *json_object_iter_value(void *iter) {
     if (!iter)
         return NULL;
@@ -306,13 +354,14 @@ 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_foreach((json_t *)object1, key, value1) {
-        value2 = json_object_get(object2, key);
+    json_object_keylen_foreach((json_t *)object1, key, key_len, value1) {
+        value2 = json_object_getn(object2, key, key_len);
 
         if (!json_equal(value1, value2))
             return 0;
@@ -325,13 +374,15 @@ 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_foreach(object, key, value) json_object_set_nocheck(result, key, value);
+    json_object_keylen_foreach(object, key, key_len, value)
+        json_object_setn_nocheck(result, key, key_len, value);
 
     return result;
 }
@@ -340,8 +391,9 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
     json_t *result;
     void *iter;
     char loop_key[LOOP_KEY_LEN];
+    size_t loop_key_len;
 
-    if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key), &loop_key_len))
         return NULL;
 
     result = json_object();
@@ -353,11 +405,14 @@ 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_set_new_nocheck(result, key, do_deep_copy(value, parents))) {
+        if (json_object_setn_new_nocheck(result, key, key_len,
+                                         do_deep_copy(value, parents))) {
             json_decref(result);
             result = NULL;
             break;
@@ -366,7 +421,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
     }
 
 out:
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
     return result;
 }
@@ -633,8 +688,9 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
     json_t *result;
     size_t i;
     char loop_key[LOOP_KEY_LEN];
+    size_t loop_key_len;
 
-    if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key), &loop_key_len))
         return NULL;
 
     result = json_array();
@@ -651,7 +707,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
     }
 
 out:
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
     return result;
 }
@@ -797,16 +853,18 @@ json_t *json_vsprintf(const char *fmt, va_list ap) {
     va_copy(aq, ap);
 
     length = vsnprintf(NULL, 0, fmt, ap);
+    if (length < 0)
+        goto out;
     if (length == 0) {
         json = json_string("");
         goto out;
     }
 
-    buf = jsonp_malloc(length + 1);
+    buf = jsonp_malloc((size_t)length + 1);
     if (!buf)
         goto out;
 
-    vsnprintf(buf, length + 1, fmt, aq);
+    vsnprintf(buf, (size_t)length + 1, fmt, aq);
     if (!utf8_check_string(buf, length)) {
         jsonp_free(buf);
         goto out;

+ 20 - 0
jansson.mod/jansson/test/.gitignore

@@ -0,0 +1,20 @@
+logs
+bin/json_process
+suites/api/test_array
+suites/api/test_chaos
+suites/api/test_copy
+suites/api/test_cpp
+suites/api/test_dump
+suites/api/test_dump_callback
+suites/api/test_equal
+suites/api/test_load
+suites/api/test_load_callback
+suites/api/test_loadb
+suites/api/test_memory_funcs
+suites/api/test_number
+suites/api/test_object
+suites/api/test_pack
+suites/api/test_simple
+suites/api/test_sprintf
+suites/api/test_unpack
+suites/api/test_version

+ 10 - 0
jansson.mod/jansson/test/Makefile.am

@@ -0,0 +1,10 @@
+SUBDIRS = bin suites ossfuzz
+EXTRA_DIST = scripts run-suites
+
+TESTS = run-suites
+TESTS_ENVIRONMENT = \
+	top_srcdir=$(top_srcdir) \
+	top_builddir=$(top_builddir)
+
+clean-local:
+	rm -rf logs

+ 5 - 0
jansson.mod/jansson/test/bin/Makefile.am

@@ -0,0 +1,5 @@
+check_PROGRAMS = json_process
+
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDFLAGS = -static  # for speed and Valgrind
+LDADD = $(top_builddir)/src/libjansson.la

+ 366 - 0
jansson.mod/jansson/test/bin/json_process.c

@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <jansson_private_config.h>
+#endif
+
+#include <ctype.h>
+#include <jansson.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if _WIN32
+#include <fcntl.h> /* for _O_BINARY */
+#include <io.h>    /* for _setmode() */
+
+static const char dir_sep = '\\';
+#else
+static const char dir_sep = '/';
+#endif
+
+struct config {
+    int indent;
+    int compact;
+    int preserve_order;
+    int ensure_ascii;
+    int sort_keys;
+    int strip;
+    int use_env;
+    int have_hashseed;
+    int hashseed;
+    int precision;
+} conf;
+
+#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
+
+/* Return a pointer to the first non-whitespace character of str.
+   Modifies str so that all trailing whitespace characters are
+   replaced by '\0'. */
+static const char *strip(char *str) {
+    size_t length;
+    char *result = str;
+    while (*result && l_isspace(*result))
+        result++;
+
+    length = strlen(result);
+    if (length == 0)
+        return result;
+
+    while (l_isspace(result[length - 1]))
+        result[--length] = '\0';
+
+    return result;
+}
+
+static char *loadfile(FILE *file) {
+    size_t fsize, ret;
+    char *buf;
+
+    fseek(file, 0, SEEK_END);
+    fsize = ftell(file);
+    fseek(file, 0, SEEK_SET);
+
+    buf = malloc(fsize + 1);
+    ret = fread(buf, 1, fsize, file);
+    if (ret != fsize)
+        exit(1);
+    buf[fsize] = '\0';
+
+    return buf;
+}
+
+static void read_conf(FILE *conffile) {
+    char *buffer, *line, *val;
+
+    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");
+            break;
+        }
+        *val++ = '\0';
+
+        if (!strcmp(line, "JSON_INDENT"))
+            conf.indent = atoi(val);
+        if (!strcmp(line, "JSON_COMPACT"))
+            conf.compact = atoi(val);
+        if (!strcmp(line, "JSON_ENSURE_ASCII"))
+            conf.ensure_ascii = atoi(val);
+        if (!strcmp(line, "JSON_PRESERVE_ORDER"))
+            conf.preserve_order = atoi(val);
+        if (!strcmp(line, "JSON_SORT_KEYS"))
+            conf.sort_keys = atoi(val);
+        if (!strcmp(line, "JSON_REAL_PRECISION"))
+            conf.precision = atoi(val);
+        if (!strcmp(line, "STRIP"))
+            conf.strip = atoi(val);
+        if (!strcmp(line, "HASHSEED")) {
+            conf.have_hashseed = 1;
+            conf.hashseed = atoi(val);
+        } else {
+            conf.have_hashseed = 0;
+        }
+    }
+
+    free(buffer);
+}
+
+static int cmpfile(const char *str, const char *path, const char *fname) {
+    char filename[1024], *buffer;
+    int ret;
+    FILE *file;
+
+    sprintf(filename, "%s%c%s", path, dir_sep, fname);
+    file = fopen(filename, "rb");
+    if (!file) {
+        if (conf.strip)
+            strcat(filename, ".strip");
+        else
+            strcat(filename, ".normal");
+        file = fopen(filename, "rb");
+    }
+    if (!file) {
+        printf("Error: test result file could not be opened.\n");
+        exit(1);
+    }
+
+    buffer = loadfile(file);
+    if (strcmp(buffer, str) != 0)
+        ret = 1;
+    else
+        ret = 0;
+    free(buffer);
+    fclose(file);
+
+    return ret;
+}
+
+int use_conf(char *test_path) {
+    int ret;
+    size_t flags = 0;
+    char filename[1024], errstr[1024];
+    char *buffer;
+    FILE *infile, *conffile;
+    json_t *json;
+    json_error_t error;
+
+    sprintf(filename, "%s%cinput", test_path, dir_sep);
+    if (!(infile = fopen(filename, "rb"))) {
+        fprintf(stderr, "Could not open \"%s\"\n", filename);
+        return 2;
+    }
+
+    sprintf(filename, "%s%cenv", test_path, dir_sep);
+    conffile = fopen(filename, "rb");
+    if (conffile) {
+        read_conf(conffile);
+        fclose(conffile);
+    }
+
+    if (conf.indent < 0 || conf.indent > 31) {
+        fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent);
+        fclose(infile);
+        return 2;
+    }
+    if (conf.indent)
+        flags |= JSON_INDENT(conf.indent);
+
+    if (conf.compact)
+        flags |= JSON_COMPACT;
+
+    if (conf.ensure_ascii)
+        flags |= JSON_ENSURE_ASCII;
+
+    if (conf.preserve_order)
+        flags |= JSON_PRESERVE_ORDER;
+
+    if (conf.sort_keys)
+        flags |= JSON_SORT_KEYS;
+
+    if (conf.precision < 0 || conf.precision > 31) {
+        fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", conf.precision);
+        fclose(infile);
+        return 2;
+    }
+    if (conf.precision)
+        flags |= JSON_REAL_PRECISION(conf.precision);
+
+    if (conf.have_hashseed)
+        json_object_seed(conf.hashseed);
+
+    if (conf.strip) {
+        /* Load to memory, strip leading and trailing whitespace */
+        buffer = loadfile(infile);
+        json = json_loads(strip(buffer), 0, &error);
+        free(buffer);
+    } else
+        json = json_loadf(infile, 0, &error);
+
+    fclose(infile);
+
+    if (!json) {
+        sprintf(errstr, "%d %d %d\n%s\n", error.line, error.column, error.position,
+                error.text);
+
+        ret = cmpfile(errstr, test_path, "error");
+        return ret;
+    }
+
+    buffer = json_dumps(json, flags);
+    ret = cmpfile(buffer, test_path, "output");
+    free(buffer);
+    json_decref(json);
+
+    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;
+
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+
+    if (argc < 2) {
+        goto usage;
+    }
+
+    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 (conf.use_env)
+        return use_env();
+    else {
+        if (!test_path)
+            goto usage;
+
+        return use_conf(test_path);
+    }
+
+usage:
+    fprintf(stderr, "argc =%d\n", argc);
+    fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]);
+    return 2;
+}

+ 1 - 0
jansson.mod/jansson/test/ossfuzz/.gitignore

@@ -0,0 +1 @@
+json_load_dump_fuzzer

+ 32 - 0
jansson.mod/jansson/test/ossfuzz/Makefile.am

@@ -0,0 +1,32 @@
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDADD = $(top_builddir)/src/libjansson.la
+
+if USE_OSSFUZZ_FLAG
+FUZZ_FLAG = $(LIB_FUZZING_ENGINE)
+else
+if USE_OSSFUZZ_STATIC
+LDADD += $(LIB_FUZZING_ENGINE)
+FUZZ_FLAG =
+else
+LDADD += libstandaloneengine.a
+FUZZ_FLAG =
+endif
+endif
+
+noinst_PROGRAMS =
+noinst_LIBRARIES =
+
+if USE_OSSFUZZERS
+noinst_PROGRAMS += \
+	json_load_dump_fuzzer
+
+noinst_LIBRARIES += \
+	libstandaloneengine.a
+endif
+
+json_load_dump_fuzzer_SOURCES = json_load_dump_fuzzer.cc testinput.h
+json_load_dump_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
+json_load_dump_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static
+
+libstandaloneengine_a_SOURCES = standaloneengine.cc
+libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS)

+ 132 - 0
jansson.mod/jansson/test/ossfuzz/json_load_dump_fuzzer.cc

@@ -0,0 +1,132 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include "jansson.h"
+
+static int enable_diags;
+
+#define FUZZ_DEBUG(FMT, ...)                                                  \
+        if (enable_diags)                                                     \
+        {                                                                     \
+          fprintf(stderr, FMT, ##__VA_ARGS__);                                \
+          fprintf(stderr, "\n");                                              \
+        }
+
+
+static int json_dump_counter(const char *buffer, size_t size, void *data)
+{
+  uint64_t *counter = reinterpret_cast<uint64_t *>(data);
+  *counter += size;
+  return 0;
+}
+
+
+#define NUM_COMMAND_BYTES  (sizeof(size_t) + sizeof(size_t) + 1)
+
+#define FUZZ_DUMP_CALLBACK 0x00
+#define FUZZ_DUMP_STRING   0x01
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  json_error_t error;
+  unsigned char dump_mode;
+
+  // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag.
+  enable_diags = (getenv("FUZZ_VERBOSE") != NULL);
+
+  FUZZ_DEBUG("Input data length: %zd", size);
+
+  if (size < NUM_COMMAND_BYTES)
+  {
+    return 0;
+  }
+
+  // Use the first sizeof(size_t) bytes as load flags.
+  size_t load_flags = *(const size_t*)data;
+  data += sizeof(size_t);
+
+  FUZZ_DEBUG("load_flags: 0x%zx\n"
+             "& JSON_REJECT_DUPLICATES =  0x%zx\n"
+             "& JSON_DECODE_ANY =         0x%zx\n"
+             "& JSON_DISABLE_EOF_CHECK =  0x%zx\n"
+             "& JSON_DECODE_INT_AS_REAL = 0x%zx\n"
+             "& JSON_ALLOW_NUL =          0x%zx\n",
+             load_flags,
+             load_flags & JSON_REJECT_DUPLICATES,
+             load_flags & JSON_DECODE_ANY,
+             load_flags & JSON_DISABLE_EOF_CHECK,
+             load_flags & JSON_DECODE_INT_AS_REAL,
+             load_flags & JSON_ALLOW_NUL);
+
+  // Use the next sizeof(size_t) bytes as dump flags.
+  size_t dump_flags = *(const size_t*)data;
+  data += sizeof(size_t);
+
+  FUZZ_DEBUG("dump_flags: 0x%zx\n"
+             "& JSON_MAX_INDENT =     0x%zx\n"
+             "& JSON_COMPACT =        0x%zx\n"
+             "& JSON_ENSURE_ASCII =   0x%zx\n"
+             "& JSON_SORT_KEYS =      0x%zx\n"
+             "& JSON_PRESERVE_ORDER = 0x%zx\n"
+             "& JSON_ENCODE_ANY =     0x%zx\n"
+             "& JSON_ESCAPE_SLASH =   0x%zx\n"
+             "& JSON_REAL_PRECISION = 0x%zx\n"
+             "& JSON_EMBED =          0x%zx\n",
+             dump_flags,
+             dump_flags & JSON_MAX_INDENT,
+             dump_flags & JSON_COMPACT,
+             dump_flags & JSON_ENSURE_ASCII,
+             dump_flags & JSON_SORT_KEYS,
+             dump_flags & JSON_PRESERVE_ORDER,
+             dump_flags & JSON_ENCODE_ANY,
+             dump_flags & JSON_ESCAPE_SLASH,
+             ((dump_flags >> 11) & 0x1F) << 11,
+             dump_flags & JSON_EMBED);
+
+  // Use the next byte as the dump mode.
+  dump_mode = data[0];
+  data++;
+
+  FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode);
+
+  // Remove the command bytes from the size total.
+  size -= NUM_COMMAND_BYTES;
+
+  // Attempt to load the remainder of the data with the given load flags.
+  const char* text = reinterpret_cast<const char *>(data);
+  json_t* jobj = json_loadb(text, size, load_flags, &error);
+
+  if (jobj == NULL)
+  {
+    return 0;
+  }
+
+  if (dump_mode & FUZZ_DUMP_STRING)
+  {
+    // Dump as a string. Remove indents so that we don't run out of memory.
+    char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT);
+    if (out != NULL)
+    {
+      free(out);
+    }
+  }
+  else
+  {
+    // Default is callback mode.
+    //
+    // Attempt to dump the loaded json object with the given dump flags.
+    uint64_t counter = 0;
+
+    json_dump_callback(jobj, json_dump_counter, &counter, dump_flags);
+    FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter);
+  }
+
+  if (jobj)
+  {
+    json_decref(jobj);
+  }
+
+  return 0;
+}

+ 30 - 0
jansson.mod/jansson/test/ossfuzz/ossfuzz.sh

@@ -0,0 +1,30 @@
+#!/bin/bash -eu
+
+# This script is called by the oss-fuzz main project when compiling the fuzz
+# targets. This script is regression tested by travisoss.sh.
+
+# Save off the current folder as the build root.
+export BUILD_ROOT=$PWD
+
+echo "CC: $CC"
+echo "CXX: $CXX"
+echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE"
+echo "CFLAGS: $CFLAGS"
+echo "CXXFLAGS: $CXXFLAGS"
+echo "OUT: $OUT"
+
+export MAKEFLAGS+="-j$(nproc)"
+
+# Install dependencies
+apt-get -y install automake libtool
+
+# Compile the fuzzer.
+autoreconf -i
+./configure --enable-ossfuzzers
+make
+
+# Copy the fuzzer to the output directory.
+cp -v test/ossfuzz/json_load_dump_fuzzer $OUT/
+
+# Zip up all input files to use as a test corpus
+find test/suites -name "input" -print | zip $OUT/json_load_dump_fuzzer_seed_corpus.zip -@

+ 74 - 0
jansson.mod/jansson/test/ossfuzz/standaloneengine.cc

@@ -0,0 +1,74 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testinput.h"
+
+/**
+ * Main procedure for standalone fuzzing engine.
+ *
+ * Reads filenames from the argument array. For each filename, read the file
+ * into memory and then call the fuzzing interface with the data.
+ */
+int main(int argc, char **argv)
+{
+  int ii;
+  for(ii = 1; ii < argc; ii++)
+  {
+    FILE *infile;
+    printf("[%s] ", argv[ii]);
+
+    /* Try and open the file. */
+    infile = fopen(argv[ii], "rb");
+    if(infile)
+    {
+      uint8_t *buffer = NULL;
+      size_t buffer_len;
+
+      printf("Opened.. ");
+
+      /* Get the length of the file. */
+      fseek(infile, 0L, SEEK_END);
+      buffer_len = ftell(infile);
+
+      /* Reset the file indicator to the beginning of the file. */
+      fseek(infile, 0L, SEEK_SET);
+
+      /* Allocate a buffer for the file contents. */
+      buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t));
+      if(buffer)
+      {
+        /* Read all the text from the file into the buffer. */
+        fread(buffer, sizeof(uint8_t), buffer_len, infile);
+        printf("Read %zu bytes, fuzzing.. ", buffer_len);
+
+        /* Call the fuzzer with the data. */
+        LLVMFuzzerTestOneInput(buffer, buffer_len);
+
+        printf("complete !!");
+
+        /* Free the buffer as it's no longer needed. */
+        free(buffer);
+        buffer = NULL;
+      }
+      else
+      {
+        fprintf(stderr,
+                "[%s] Failed to allocate %zu bytes \n",
+                argv[ii],
+                buffer_len);
+      }
+
+      /* Close the file as it's no longer needed. */
+      fclose(infile);
+      infile = NULL;
+    }
+    else
+    {
+      /* Failed to open the file. Maybe wrong name or wrong permissions? */
+      fprintf(stderr, "[%s] Open failed. \n", argv[ii]);
+    }
+
+    printf("\n");
+  }
+}

+ 3 - 0
jansson.mod/jansson/test/ossfuzz/testinput.h

@@ -0,0 +1,3 @@
+#include <inttypes.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);

+ 50 - 0
jansson.mod/jansson/test/run-suites

@@ -0,0 +1,50 @@
+#!/bin/sh
+
+while [ -n "$1" ]; do
+    suite=$1
+    if [ -x $top_srcdir/test/suites/$suite/run ]; then
+        SUITES="$SUITES $suite"
+    else
+        echo "No such suite: $suite"
+        exit 1
+    fi
+    shift
+done
+
+if [ -z "$SUITES" ]; then
+    suitedirs=$top_srcdir/test/suites/*
+    for suitedir in $suitedirs; do
+        if [ -d $suitedir ]; then
+            SUITES="$SUITES `basename $suitedir`"
+        fi
+    done
+fi
+
+[ -z "$STOP" ] && STOP=0
+
+suites_srcdir=$top_srcdir/test/suites
+suites_builddir=suites
+scriptdir=$top_srcdir/test/scripts
+logdir=logs
+bindir=bin
+export suites_srcdir suites_builddir scriptdir logdir bindir
+
+passed=0
+failed=0
+for suite in $SUITES; do
+    echo "Suite: $suite"
+    if $suites_srcdir/$suite/run $suite; then
+        passed=`expr $passed + 1`
+    else
+        failed=`expr $failed + 1`
+        [ $STOP -eq 1 ] && break
+    fi
+done
+
+if [ $failed -gt 0 ]; then
+    echo "$failed of `expr $passed + $failed` test suites failed"
+    exit 1
+else
+    echo "$passed test suites passed"
+    rm -rf $logdir
+fi

+ 100 - 0
jansson.mod/jansson/test/scripts/run-tests.sh

@@ -0,0 +1,100 @@
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+die() {
+    echo "$1" >&2
+    exit 1
+}
+
+[ -n "$1" ] || die "Usage: $0 suite-name"
+[ -n "$bindir" ] || die "Set bindir"
+[ -n "$logdir" ] || die "Set logdir"
+[ -n "$scriptdir" ] || die "Set scriptdir"
+[ -n "$suites_srcdir" ] || die "Set suites_srcdir"
+[ -n "$suites_builddir" ] || die "Set suites_builddir"
+
+json_process=$bindir/json_process
+
+suite_name=$1
+suite_srcdir=$suites_srcdir/$suite_name
+suite_builddir=$suites_builddir/$suite_name
+suite_log=$logdir/$suite_name
+
+[ -z "$VERBOSE" ] && VERBOSE=0
+[ -z "$STOP" ] && STOP=0
+
+. $scriptdir/valgrind.sh
+
+rm -rf $suite_log
+mkdir -p $suite_log
+
+for test_path in $suite_srcdir/*; do
+    test_name=$(basename $test_path)
+    test_builddir=$suite_builddir/$test_name
+    test_log=$suite_log/$test_name
+
+    [ "$test_name" = "run" ] && continue
+    is_test || continue
+
+    rm -rf $test_log
+    mkdir -p $test_log
+    if [ $VERBOSE -eq 1 ]; then
+        printf '%s... ' "$test_name"
+    fi
+
+    run_test
+    case $? in
+        0)
+            # Success
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'ok\n'
+            else
+                printf '.'
+            fi
+            rm -rf $test_log
+            ;;
+
+        77)
+            # Skip
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'skipped\n'
+            else
+                printf 'S'
+            fi
+            rm -rf $test_log
+            ;;
+
+        *)
+            # Failure
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'FAILED\n'
+            else
+                printf 'F'
+            fi
+
+            [ $STOP -eq 1 ] && break
+            ;;
+    esac
+done
+
+if [ $VERBOSE -eq 0 ]; then
+    printf '\n'
+fi
+
+if [ -n "$(ls -A $suite_log)" ]; then
+    for test_log in $suite_log/*; do
+        test_name=$(basename $test_log)
+        test_path=$suite_srcdir/$test_name
+        echo "================================================================="
+        echo "$suite_name/$test_name"
+        echo "================================================================="
+        show_error
+        echo
+    done
+    echo "================================================================="
+    exit 1
+else
+    rm -rf $suite_log
+fi

+ 35 - 0
jansson.mod/jansson/test/scripts/valgrind.sh

@@ -0,0 +1,35 @@
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+[ -z "$VALGRIND" ] && VALGRIND=0
+
+VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q"
+
+if [ $VALGRIND -eq 1 ]; then
+    test_runner="$VALGRIND_CMDLINE"
+    json_process="$VALGRIND_CMDLINE $json_process"
+else
+    test_runner=""
+fi
+
+valgrind_check() {
+    if [ $VALGRIND -eq 1 ]; then
+        # Check for Valgrind error output. The valgrind option
+        # --error-exitcode is not enough because Valgrind doesn't
+        # think unfreed allocs are errors.
+        if grep -E -q '^==[0-9]+== ' $1; then
+            touch $test_log/valgrind_error
+            return 1
+        fi
+    fi
+}
+
+valgrind_show_error() {
+    if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then
+        echo "valgrind detected an error"
+        return 0
+    fi
+    return 1
+}

+ 2 - 0
jansson.mod/jansson/test/suites/.gitattributes

@@ -0,0 +1,2 @@
+api/ text=auto
+* text eol=lf

+ 2 - 0
jansson.mod/jansson/test/suites/Makefile.am

@@ -0,0 +1,2 @@
+SUBDIRS = api
+EXTRA_DIST = invalid invalid-unicode valid

+ 42 - 0
jansson.mod/jansson/test/suites/api/Makefile.am

@@ -0,0 +1,42 @@
+EXTRA_DIST = run check-exports
+
+check_PROGRAMS = \
+	test_array \
+	test_chaos \
+	test_copy \
+	test_dump \
+	test_dump_callback \
+	test_equal \
+	test_fixed_size \
+	test_load \
+	test_load_callback \
+	test_loadb \
+	test_memory_funcs \
+	test_number \
+	test_object \
+	test_pack \
+	test_simple \
+	test_sprintf \
+	test_unpack \
+	test_version
+
+test_array_SOURCES = test_array.c util.h
+test_chaos_SOURCES = test_chaos.c util.h
+test_copy_SOURCES = test_copy.c util.h
+test_dump_SOURCES = test_dump.c util.h
+test_dump_callback_SOURCES = test_dump_callback.c util.h
+test_fixed_size_SOURCES = test_fixed_size.c util.h
+test_load_SOURCES = test_load.c util.h
+test_loadb_SOURCES = test_loadb.c util.h
+test_memory_funcs_SOURCES = test_memory_funcs.c util.h
+test_number_SOURCES = test_number.c util.h
+test_object_SOURCES = test_object.c util.h
+test_pack_SOURCES = test_pack.c util.h
+test_simple_SOURCES = test_simple.c util.h
+test_sprintf_SOURCES = test_sprintf.c util.h
+test_unpack_SOURCES = test_unpack.c util.h
+test_version_SOURCES = test_version.c util.h
+
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDFLAGS = -static  # for speed and Valgrind
+LDADD = $(top_builddir)/src/libjansson.la

+ 23 - 0
jansson.mod/jansson/test/suites/api/check-exports

@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# This test checks that libjansson.so exports the correct symbols.
+#
+
+SOFILE="../src/.libs/libjansson.so"
+
+# The list of symbols, which the shared object should export, is read
+# from the def file, which is used in Windows builds
+grep 'json_\|jansson_' $top_srcdir/src/jansson.def \
+    | sed -e 's/ //g' \
+    | sort \
+    >$test_log/exports
+
+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
+
+if ! cmp -s $test_log/exports $test_log/output; then
+    diff -u $test_log/exports $test_log/output >&2
+    exit 1
+fi

+ 36 - 0
jansson.mod/jansson/test/suites/api/run

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+is_test() {
+    case "$test_name" in
+        *.c|check-exports)
+            return 0
+            ;;
+        *)
+            return 1
+            ;;
+    esac
+}
+
+run_test() {
+    if [ "$test_name" = "check-exports" ]; then
+        test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr
+    else
+        $test_runner $suite_builddir/${test_name%.c} \
+            >$test_log/stdout \
+            2>$test_log/stderr \
+            || return 1
+        valgrind_check $test_log/stderr || return 1
+    fi
+}
+
+show_error() {
+    valgrind_show_error && return
+    cat $test_log/stderr
+}
+
+. $top_srcdir/test/scripts/run-tests.sh

+ 484 - 0
jansson.mod/jansson/test/suites/api/test_array.c

@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+
+static void test_misc(void) {
+    json_t *array, *five, *seven, *value;
+    size_t i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    if (json_array_size(array) != 0)
+        fail("empty array has nonzero size");
+
+    if (!json_array_append(array, NULL))
+        fail("able to append NULL");
+
+    if (json_array_append(array, five))
+        fail("unable to append");
+
+    if (json_array_size(array) != 1)
+        fail("wrong array size");
+
+    value = json_array_get(array, 0);
+    if (!value)
+        fail("unable to get item");
+    if (value != five)
+        fail("got wrong value");
+
+    if (json_array_append(array, seven))
+        fail("unable to append value");
+
+    if (json_array_size(array) != 2)
+        fail("wrong array size");
+
+    value = json_array_get(array, 1);
+    if (!value)
+        fail("unable to get item");
+    if (value != seven)
+        fail("got wrong value");
+
+    if (json_array_set(array, 0, seven))
+        fail("unable to set value");
+
+    if (!json_array_set(array, 0, NULL))
+        fail("able to set NULL");
+
+    if (json_array_size(array) != 2)
+        fail("wrong array size");
+
+    value = json_array_get(array, 0);
+    if (!value)
+        fail("unable to get item");
+    if (value != seven)
+        fail("got wrong value");
+
+    if (json_array_get(array, 2) != NULL)
+        fail("able to get value out of bounds");
+
+    if (!json_array_set(array, 2, seven))
+        fail("able to set value out of bounds");
+
+    for (i = 2; i < 30; i++) {
+        if (json_array_append(array, seven))
+            fail("unable to append value");
+
+        if (json_array_size(array) != i + 1)
+            fail("wrong array size");
+    }
+
+    for (i = 0; i < 30; i++) {
+        value = json_array_get(array, i);
+        if (!value)
+            fail("unable to get item");
+        if (value != seven)
+            fail("got wrong value");
+    }
+
+    if (json_array_set_new(array, 15, json_integer(123)))
+        fail("unable to set new value");
+
+    value = json_array_get(array, 15);
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_array_set_new works incorrectly");
+
+    if (!json_array_set_new(array, 15, NULL))
+        fail("able to set_new NULL value");
+
+    if (json_array_append_new(array, json_integer(321)))
+        fail("unable to append new value");
+
+    value = json_array_get(array, json_array_size(array) - 1);
+    if (!json_is_integer(value) || json_integer_value(value) != 321)
+        fail("json_array_append_new works incorrectly");
+
+    if (!json_array_append_new(array, NULL))
+        fail("able to append_new NULL value");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_insert(void) {
+    json_t *array, *five, *seven, *eleven, *value;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+    eleven = json_integer(11);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven || !eleven)
+        fail("unable to create integer");
+
+    if (!json_array_insert(array, 1, five))
+        fail("able to insert value out of bounds");
+
+    if (json_array_insert(array, 0, five))
+        fail("unable to insert value in an empty array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 1)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert(array, 1, seven))
+        fail("unable to insert value at the end of an array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 1) != seven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 2)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert(array, 1, eleven))
+        fail("unable to insert value in the middle of an array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 1) != eleven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 2) != seven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 3)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert_new(array, 2, json_integer(123)))
+        fail("unable to insert value in the middle of an array");
+
+    value = json_array_get(array, 2);
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_array_insert_new works incorrectly");
+
+    if (json_array_size(array) != 4)
+        fail("array size is invalid after insertion");
+
+    for (i = 0; i < 20; i++) {
+        if (json_array_insert(array, 0, seven))
+            fail("unable to insert value at the beginning of an array");
+    }
+
+    for (i = 0; i < 20; i++) {
+        if (json_array_get(array, i) != seven)
+            fail("json_aray_insert works incorrectly");
+    }
+
+    if (json_array_size(array) != 24)
+        fail("array size is invalid after loop insertion");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(eleven);
+    json_decref(array);
+}
+
+static void test_remove(void) {
+    json_t *array, *five, *seven;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five)
+        fail("unable to create integer");
+    if (!seven)
+        fail("unable to create integer");
+
+    if (!json_array_remove(array, 0))
+        fail("able to remove an unexisting index");
+
+    if (json_array_append(array, five))
+        fail("unable to append");
+
+    if (!json_array_remove(array, 1))
+        fail("able to remove an unexisting index");
+
+    if (json_array_remove(array, 0))
+        fail("unable to remove");
+
+    if (json_array_size(array) != 0)
+        fail("array size is invalid after removing");
+
+    if (json_array_append(array, five) || json_array_append(array, seven) ||
+        json_array_append(array, five) || json_array_append(array, seven))
+        fail("unable to append");
+
+    if (json_array_remove(array, 2))
+        fail("unable to remove");
+
+    if (json_array_size(array) != 3)
+        fail("array size is invalid after removing");
+
+    if (json_array_get(array, 0) != five || json_array_get(array, 1) != seven ||
+        json_array_get(array, 2) != seven)
+        fail("remove works incorrectly");
+
+    json_decref(array);
+
+    array = json_array();
+    for (i = 0; i < 4; i++) {
+        json_array_append(array, five);
+        json_array_append(array, seven);
+    }
+    if (json_array_size(array) != 8)
+        fail("unable to append 8 items to array");
+
+    /* Remove an element from a "full" array. */
+    json_array_remove(array, 5);
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_clear(void) {
+    json_t *array, *five, *seven;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array, five))
+            fail("unable to append");
+    }
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array, seven))
+            fail("unable to append");
+    }
+
+    if (json_array_size(array) != 20)
+        fail("array size is invalid after appending");
+
+    if (json_array_clear(array))
+        fail("unable to clear");
+
+    if (json_array_size(array) != 0)
+        fail("array size is invalid after clearing");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_extend(void) {
+    json_t *array1, *array2, *five, *seven;
+    int i;
+
+    array1 = json_array();
+    array2 = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array1 || !array2)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array1, five))
+            fail("unable to append");
+    }
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array2, seven))
+            fail("unable to append");
+    }
+
+    if (json_array_size(array1) != 10 || json_array_size(array2) != 10)
+        fail("array size is invalid after appending");
+
+    if (json_array_extend(array1, array2))
+        fail("unable to extend");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_get(array1, i) != five)
+            fail("invalid array contents after extending");
+    }
+    for (i = 10; i < 20; i++) {
+        if (json_array_get(array1, i) != seven)
+            fail("invalid array contents after extending");
+    }
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_circular() {
+    json_t *array1, *array2;
+
+    /* the simple cases are checked */
+
+    array1 = json_array();
+    if (!array1)
+        fail("unable to create array");
+
+    if (json_array_append(array1, array1) == 0)
+        fail("able to append self");
+
+    if (json_array_insert(array1, 0, array1) == 0)
+        fail("able to insert self");
+
+    if (json_array_append_new(array1, json_true()))
+        fail("failed to append true");
+
+    if (json_array_set(array1, 0, array1) == 0)
+        fail("able to set self");
+
+    json_decref(array1);
+
+    /* create circular references */
+
+    array1 = json_array();
+    array2 = json_array();
+    if (!array1 || !array2)
+        fail("unable to create array");
+
+    if (json_array_append(array1, array2) || json_array_append(array2, array1))
+        fail("unable to append");
+
+    /* circularity is detected when dumping */
+    if (json_dumps(array1, 0) != NULL)
+        fail("able to dump circulars");
+
+    /* decref twice to deal with the circular references */
+    json_decref(array1);
+    json_decref(array2);
+    json_decref(array1);
+}
+
+static void test_array_foreach() {
+    size_t index;
+    json_t *array1, *array2, *value;
+
+    array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3);
+    array2 = json_array();
+
+    json_array_foreach(array1, index, value) { json_array_append(array2, value); }
+
+    if (!json_equal(array1, array2))
+        fail("json_array_foreach failed to iterate all elements");
+
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_bad_args(void) {
+    json_t *arr = json_array();
+    json_t *num = json_integer(1);
+
+    if (!arr || !num)
+        fail("failed to create required objects");
+
+    if (json_array_size(NULL) != 0)
+        fail("NULL array has nonzero size");
+    if (json_array_size(num) != 0)
+        fail("non-array has nonzero array size");
+
+    if (json_array_get(NULL, 0))
+        fail("json_array_get did not return NULL for non-array");
+    if (json_array_get(num, 0))
+        fail("json_array_get did not return NULL for non-array");
+
+    if (!json_array_set_new(NULL, 0, json_incref(num)))
+        fail("json_array_set_new did not return error for non-array");
+    if (!json_array_set_new(num, 0, json_incref(num)))
+        fail("json_array_set_new did not return error for non-array");
+    if (!json_array_set_new(arr, 0, NULL))
+        fail("json_array_set_new did not return error for NULL value");
+    if (!json_array_set_new(arr, 0, json_incref(arr)))
+        fail("json_array_set_new did not return error for value == array");
+
+    if (!json_array_remove(NULL, 0))
+        fail("json_array_remove did not return error for non-array");
+    if (!json_array_remove(num, 0))
+        fail("json_array_remove did not return error for non-array");
+
+    if (!json_array_clear(NULL))
+        fail("json_array_clear did not return error for non-array");
+    if (!json_array_clear(num))
+        fail("json_array_clear did not return error for non-array");
+
+    if (!json_array_append_new(NULL, json_incref(num)))
+        fail("json_array_append_new did not return error for non-array");
+    if (!json_array_append_new(num, json_incref(num)))
+        fail("json_array_append_new did not return error for non-array");
+    if (!json_array_append_new(arr, NULL))
+        fail("json_array_append_new did not return error for NULL value");
+    if (!json_array_append_new(arr, json_incref(arr)))
+        fail("json_array_append_new did not return error for value == array");
+
+    if (!json_array_insert_new(NULL, 0, json_incref(num)))
+        fail("json_array_insert_new did not return error for non-array");
+    if (!json_array_insert_new(num, 0, json_incref(num)))
+        fail("json_array_insert_new did not return error for non-array");
+    if (!json_array_insert_new(arr, 0, NULL))
+        fail("json_array_insert_new did not return error for NULL value");
+    if (!json_array_insert_new(arr, 0, json_incref(arr)))
+        fail("json_array_insert_new did not return error for value == array");
+
+    if (!json_array_extend(NULL, arr))
+        fail("json_array_extend did not return error for first argument "
+             "non-array");
+    if (!json_array_extend(num, arr))
+        fail("json_array_extend did not return error for first argument "
+             "non-array");
+    if (!json_array_extend(arr, NULL))
+        fail("json_array_extend did not return error for second argument "
+             "non-array");
+    if (!json_array_extend(arr, num))
+        fail("json_array_extend did not return error for second argument "
+             "non-array");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count on num");
+    if (arr->refcount != 1)
+        fail("unexpected reference count on arr");
+
+    json_decref(num);
+    json_decref(arr);
+}
+
+static void run_tests() {
+    test_misc();
+    test_insert();
+    test_remove();
+    test_clear();
+    test_extend();
+    test_circular();
+    test_array_foreach();
+    test_bad_args();
+}

+ 168 - 0
jansson.mod/jansson/test/suites/api/test_chaos.c

@@ -0,0 +1,168 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "util.h"
+#include <jansson.h>
+#include <stdio.h>
+#include <string.h>
+
+static int chaos_pos = 0;
+static int chaos_fail = 0;
+#define CHAOS_MAX_FAILURE 100
+
+void *chaos_malloc(size_t size) {
+    if (chaos_pos == chaos_fail)
+        return NULL;
+
+    chaos_pos++;
+
+    return malloc(size);
+}
+
+void chaos_free(void *obj) { free(obj); }
+
+/* Test all potential allocation failures. */
+#define chaos_loop(condition, code, cleanup)                                             \
+    {                                                                                    \
+        chaos_pos = chaos_fail = 0;                                                      \
+        while (condition) {                                                              \
+            if (chaos_fail > CHAOS_MAX_FAILURE)                                          \
+                fail("too many chaos failures");                                         \
+            code chaos_pos = 0;                                                          \
+            chaos_fail++;                                                                \
+        }                                                                                \
+        cleanup                                                                          \
+    }
+
+#define chaos_loop_new_value(json, initcall)                                             \
+    chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;)
+
+int test_unpack() {
+    int ret = -1;
+    int v1;
+    int v2;
+    json_error_t error;
+    json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4);
+
+    if (!root)
+        return -1;
+
+    if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2))
+        fail("Unexpected success");
+
+    if (json_error_code(&error) != json_error_end_of_input_expected) {
+        if (json_error_code(&error) != json_error_out_of_memory)
+            fail("Unexpected error code");
+
+        goto out;
+    }
+
+    if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4"))
+        goto out;
+
+    ret = 0;
+
+out:
+    json_decref(root);
+    return ret;
+}
+
+int dump_chaos_callback(const char *buffer, size_t size, void *data) {
+    json_t *obj = json_object();
+
+    (void)buffer;
+    (void)size;
+    (void)data;
+
+    if (!obj)
+        return -1;
+
+    json_decref(obj);
+
+    return 0;
+}
+
+static void test_chaos() {
+    json_malloc_t orig_malloc;
+    json_free_t orig_free;
+    json_t *json = NULL;
+    json_t *obj = json_object();
+    json_t *arr1 = json_array();
+    json_t *arr2 = json_array();
+    json_t *txt = json_string("test");
+    json_t *intnum = json_integer(1);
+    json_t *dblnum = json_real(0.5);
+    char *dumptxt = NULL;
+    json_t *dumpobj = json_pack("{s:[iiis], s:s}", "key1", 1, 2, 3, "txt", "key2", "v2");
+    int keyno;
+
+    if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj)
+        fail("failed to allocate basic objects");
+
+    json_get_alloc_funcs(&orig_malloc, &orig_free);
+    json_set_alloc_funcs(chaos_malloc, chaos_free);
+
+    chaos_loop_new_value(json, json_pack("{s:s}", "key", "value"));
+    chaos_loop_new_value(json, json_pack("{s:[]}", "key"));
+    chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0));
+    chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2"));
+    chaos_loop_new_value(json, json_pack("o", json_incref(txt)));
+    chaos_loop_new_value(json, json_pack("O", txt));
+    chaos_loop_new_value(json, json_pack("s++", "a", "long string to force realloc",
+                                         "another long string to force yet another "
+                                         "reallocation of the string because "
+                                         "that's what we are testing."));
+
+    chaos_loop(test_unpack(), , );
+
+    chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)),
+               , );
+    chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL,
+                                  JSON_INDENT(1) | JSON_SORT_KEYS),
+               , );
+    chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt);
+               dumptxt = NULL;);
+
+    chaos_loop_new_value(json, json_copy(obj));
+    chaos_loop_new_value(json, json_deep_copy(obj));
+
+    chaos_loop_new_value(json, json_copy(arr1));
+    chaos_loop_new_value(json, json_deep_copy(arr1));
+
+    chaos_loop_new_value(json, json_copy(txt));
+    chaos_loop_new_value(json, json_copy(intnum));
+    chaos_loop_new_value(json, json_copy(dblnum));
+
+#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}"
+    chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL));
+    chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL));
+
+    chaos_loop_new_value(json, json_sprintf("%s", "string"));
+
+    for (keyno = 0; keyno < 100; ++keyno) {
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+        /* Skip this test on old Windows compilers. */
+        char testkey[10];
+
+        snprintf(testkey, sizeof(testkey), "test%d", keyno);
+        chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()), , );
+#endif
+        chaos_loop(json_array_append_new(arr1, json_null()), , );
+        chaos_loop(json_array_insert_new(arr2, 0, json_null()), , );
+    }
+
+    chaos_loop(json_array_extend(arr1, arr2), , );
+    chaos_loop(json_string_set_nocheck(txt, "test"), , );
+
+    json_set_alloc_funcs(orig_malloc, orig_free);
+    json_decref(obj);
+    json_decref(arr1);
+    json_decref(arr2);
+    json_decref(txt);
+    json_decref(intnum);
+    json_decref(dblnum);
+    json_decref(dumpobj);
+}
+
+static void run_tests() { test_chaos(); }

+ 375 - 0
jansson.mod/jansson/test/suites/api/test_copy.c

@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_copy_simple(void) {
+    json_t *value, *copy;
+
+    if (json_copy(NULL))
+        fail("copying NULL doesn't return NULL");
+
+    /* true */
+    value = json_true();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying true failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* false */
+    value = json_false();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying false failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* null */
+    value = json_null();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying null failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* string */
+    value = json_string("foo");
+    if (!value)
+        fail("unable to create a string");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy a string");
+    if (copy == value)
+        fail("copying a string doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying a string produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* integer */
+    value = json_integer(543);
+    if (!value)
+        fail("unable to create an integer");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy an integer");
+    if (copy == value)
+        fail("copying an integer doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying an integer produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* real */
+    value = json_real(123e9);
+    if (!value)
+        fail("unable to create a real");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy a real");
+    if (copy == value)
+        fail("copying a real doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying a real produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+}
+
+static void test_deep_copy_simple(void) {
+    json_t *value, *copy;
+
+    if (json_deep_copy(NULL))
+        fail("deep copying NULL doesn't return NULL");
+
+    /* true */
+    value = json_true();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying true failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* false */
+    value = json_false();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying false failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* null */
+    value = json_null();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying null failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* string */
+    value = json_string("foo");
+    if (!value)
+        fail("unable to create a string");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy a string");
+    if (copy == value)
+        fail("deep copying a string doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying a string produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* integer */
+    value = json_integer(543);
+    if (!value)
+        fail("unable to create an integer");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy an integer");
+    if (copy == value)
+        fail("deep copying an integer doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying an integer produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* real */
+    value = json_real(123e9);
+    if (!value)
+        fail("unable to create a real");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy a real");
+    if (copy == value)
+        fail("deep copying a real doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying a real produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+}
+
+static void test_copy_array(void) {
+    const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
+
+    json_t *array, *copy;
+    size_t i;
+
+    array = json_loads(json_array_text, 0, NULL);
+    if (!array)
+        fail("unable to parse an array");
+
+    copy = json_copy(array);
+    if (!copy)
+        fail("unable to copy an array");
+    if (copy == array)
+        fail("copying an array doesn't copy");
+    if (!json_equal(copy, array))
+        fail("copying an array produces an inequal copy");
+
+    for (i = 0; i < json_array_size(copy); i++) {
+        if (json_array_get(array, i) != json_array_get(copy, i))
+            fail("copying an array modifies its elements");
+    }
+
+    json_decref(array);
+    json_decref(copy);
+}
+
+static void test_deep_copy_array(void) {
+    const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
+
+    json_t *array, *copy;
+    size_t i;
+
+    array = json_loads(json_array_text, 0, NULL);
+    if (!array)
+        fail("unable to parse an array");
+
+    copy = json_deep_copy(array);
+    if (!copy)
+        fail("unable to deep copy an array");
+    if (copy == array)
+        fail("deep copying an array doesn't copy");
+    if (!json_equal(copy, array))
+        fail("deep copying an array produces an inequal copy");
+
+    for (i = 0; i < json_array_size(copy); i++) {
+        if (json_array_get(array, i) == json_array_get(copy, i))
+            fail("deep copying an array doesn't copy its elements");
+    }
+
+    json_decref(array);
+    json_decref(copy);
+}
+
+static void test_copy_object(void) {
+    const char *json_object_text =
+        "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
+
+    const char *keys[] = {"foo", "a", "b", "c"};
+    int i;
+
+    json_t *object, *copy;
+    void *iter;
+
+    object = json_loads(json_object_text, 0, NULL);
+    if (!object)
+        fail("unable to parse an object");
+
+    copy = json_copy(object);
+    if (!copy)
+        fail("unable to copy an object");
+    if (copy == object)
+        fail("copying an object doesn't copy");
+    if (!json_equal(copy, object))
+        fail("copying an object produces an inequal copy");
+
+    i = 0;
+    iter = json_object_iter(object);
+    while (iter) {
+        const char *key;
+        json_t *value1, *value2;
+
+        key = json_object_iter_key(iter);
+        value1 = json_object_iter_value(iter);
+        value2 = json_object_get(copy, key);
+
+        if (value1 != value2)
+            fail("copying an object modifies its items");
+
+        if (strcmp(key, keys[i]) != 0)
+            fail("copying an object doesn't preserve key order");
+
+        iter = json_object_iter_next(object, iter);
+        i++;
+    }
+
+    json_decref(object);
+    json_decref(copy);
+}
+
+static void test_deep_copy_object(void) {
+    const char *json_object_text =
+        "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
+
+    const char *keys[] = {"foo", "a", "b", "c"};
+    int i;
+
+    json_t *object, *copy;
+    void *iter;
+
+    object = json_loads(json_object_text, 0, NULL);
+    if (!object)
+        fail("unable to parse an object");
+
+    copy = json_deep_copy(object);
+    if (!copy)
+        fail("unable to deep copy an object");
+    if (copy == object)
+        fail("deep copying an object doesn't copy");
+    if (!json_equal(copy, object))
+        fail("deep copying an object produces an inequal copy");
+
+    i = 0;
+    iter = json_object_iter(object);
+    while (iter) {
+        const char *key;
+        json_t *value1, *value2;
+
+        key = json_object_iter_key(iter);
+        value1 = json_object_iter_value(iter);
+        value2 = json_object_get(copy, key);
+
+        if (value1 == value2)
+            fail("deep copying an object doesn't copy its items");
+
+        if (strcmp(key, keys[i]) != 0)
+            fail("deep copying an object doesn't preserve key order");
+
+        iter = json_object_iter_next(object, iter);
+        i++;
+    }
+
+    json_decref(object);
+    json_decref(copy);
+}
+
+static void test_deep_copy_circular_references(void) {
+    /* Construct a JSON object/array with a circular reference:
+
+      object: {"a": {"b": {"c": <circular reference to $.a>}}}
+      array: [[[<circular reference to the $[0] array>]]]
+
+      Deep copy it, remove the circular reference and deep copy again.
+   */
+
+    json_t *json;
+    json_t *copy;
+
+    json = json_object();
+    json_object_set_new(json, "a", json_object());
+    json_object_set_new(json_object_get(json, "a"), "b", json_object());
+    json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
+                    json_object_get(json, "a"));
+
+    copy = json_deep_copy(json);
+    if (copy)
+        fail("json_deep_copy copied a circular reference!");
+
+    json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
+
+    copy = json_deep_copy(json);
+    if (!copy)
+        fail("json_deep_copy failed!");
+
+    json_decref(copy);
+    json_decref(json);
+
+    json = json_array();
+    json_array_append_new(json, json_array());
+    json_array_append_new(json_array_get(json, 0), json_array());
+    json_array_append(json_array_get(json_array_get(json, 0), 0),
+                      json_array_get(json, 0));
+
+    copy = json_deep_copy(json);
+    if (copy)
+        fail("json_deep_copy copied a circular reference!");
+
+    json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
+
+    copy = json_deep_copy(json);
+    if (!copy)
+        fail("json_deep_copy failed!");
+
+    json_decref(copy);
+    json_decref(json);
+}
+
+static void run_tests() {
+    test_copy_simple();
+    test_deep_copy_simple();
+    test_copy_array();
+    test_deep_copy_array();
+    test_copy_object();
+    test_deep_copy_object();
+    test_deep_copy_circular_references();
+}

+ 311 - 0
jansson.mod/jansson/test/suites/api/test_dump.c

@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "jansson_private_config.h"
+
+#include <jansson.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#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) {
+    (void)buffer;
+    (void)size;
+    (void)data;
+    return 0;
+}
+
+static void encode_null() {
+    if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
+        fail("json_dumps didn't fail for NULL");
+
+    if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
+        fail("json_dumpb didn't fail for NULL");
+
+    if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
+        fail("json_dumpf didn't fail for NULL");
+
+#ifdef HAVE_UNISTD_H
+    if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
+        fail("json_dumpfd didn't fail for NULL");
+#endif
+
+    /* Don't test json_dump_file to avoid creating a file */
+
+    if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
+        fail("json_dump_callback didn't fail for NULL");
+}
+
+static void encode_twice() {
+    /* Encode an empty object/array, add an item, encode again */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{}"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_object_set_new(json, "foo", json_integer(5));
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"foo\": 5}"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_decref(json);
+
+    json = json_array();
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[]"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_array_append_new(json, json_integer(5));
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[5]"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_decref(json);
+}
+
+static void circular_references() {
+    /* Construct a JSON object/array with a circular reference:
+
+       object: {"a": {"b": {"c": <circular reference to $.a>}}}
+       array: [[[<circular reference to the $[0] array>]]]
+
+       Encode it, remove the circular reference and encode again.
+    */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    json_object_set_new(json, "a", json_object());
+    json_object_set_new(json_object_get(json, "a"), "b", json_object());
+    json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
+                    json_object_get(json, "a"));
+
+    if (json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+
+    json = json_array();
+    json_array_append_new(json, json_array());
+    json_array_append_new(json_array_get(json, 0), json_array());
+    json_array_append(json_array_get(json_array_get(json, 0), 0),
+                      json_array_get(json, 0));
+
+    if (json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[[[]]]"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+}
+
+static void encode_other_than_array_or_object() {
+    /* Encoding anything other than array or object should only
+     * succeed if the JSON_ENCODE_ANY flag is used */
+
+    json_t *json;
+    char *result;
+
+    json = json_string("foo");
+    if (json_dumps(json, 0) != NULL)
+        fail("json_dumps encoded a string!");
+    if (json_dumpf(json, NULL, 0) == 0)
+        fail("json_dumpf encoded a string!");
+    if (json_dumpfd(json, -1, 0) == 0)
+        fail("json_dumpfd encoded a string!");
+
+    result = json_dumps(json, JSON_ENCODE_ANY);
+    if (!result || strcmp(result, "\"foo\"") != 0)
+        fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
+
+    free(result);
+    json_decref(json);
+
+    json = json_integer(42);
+    if (json_dumps(json, 0) != NULL)
+        fail("json_dumps encoded an integer!");
+    if (json_dumpf(json, NULL, 0) == 0)
+        fail("json_dumpf encoded an integer!");
+    if (json_dumpfd(json, -1, 0) == 0)
+        fail("json_dumpfd encoded an integer!");
+
+    result = json_dumps(json, JSON_ENCODE_ANY);
+    if (!result || strcmp(result, "42") != 0)
+        fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
+
+    free(result);
+    json_decref(json);
+}
+
+static void escape_slashes() {
+    /* Test dump escaping slashes */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
+        fail("json_dumps failed to not escape slashes");
+
+    free(result);
+
+    result = json_dumps(json, JSON_ESCAPE_SLASH);
+    if (!result ||
+        strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
+        fail("json_dumps failed to escape slashes");
+
+    free(result);
+    json_decref(json);
+}
+
+static void encode_nul_byte() {
+    json_t *json;
+    char *result;
+
+    json = json_stringn("nul byte \0 in string", 20);
+    result = json_dumps(json, JSON_ENCODE_ANY);
+    if (!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
+        fail("json_dumps failed to dump an embedded NUL byte");
+
+    free(result);
+    json_decref(json);
+}
+
+static void dump_file() {
+    json_t *json;
+    int result;
+
+    result = json_dump_file(NULL, "", 0);
+    if (result != -1)
+        fail("json_dump_file succeeded with invalid args");
+
+    json = json_object();
+    result = json_dump_file(json, "json_dump_file.json", 0);
+    if (result != 0)
+        fail("json_dump_file failed");
+
+    json_decref(json);
+    remove("json_dump_file.json");
+}
+
+static void dumpb() {
+    char buf[2];
+    json_t *obj;
+    size_t size;
+
+    obj = json_object();
+
+    size = json_dumpb(obj, buf, sizeof(buf), 0);
+    if (size != 2 || strncmp(buf, "{}", 2))
+        fail("json_dumpb failed");
+
+    json_decref(obj);
+    obj = json_pack("{s:s}", "foo", "bar");
+
+    size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
+    if (size != 13)
+        fail("json_dumpb size check failed");
+
+    json_decref(obj);
+}
+
+static void dumpfd() {
+#ifdef HAVE_UNISTD_H
+    int fds[2] = {-1, -1};
+    json_t *a, *b;
+
+    if (pipe(fds))
+        fail("pipe() failed");
+
+    a = json_pack("{s:s}", "foo", "bar");
+
+    if (json_dumpfd(a, fds[1], 0))
+        fail("json_dumpfd() failed");
+    close(fds[1]);
+
+    b = json_loadfd(fds[0], 0, NULL);
+    if (!b)
+        fail("json_loadfd() failed");
+    close(fds[0]);
+
+    if (!json_equal(a, b))
+        fail("json_equal() failed for fd test");
+
+    json_decref(a);
+    json_decref(b);
+#endif
+}
+
+static void embed() {
+    static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]",
+                                   NULL};
+
+    size_t i;
+
+    for (i = 0; plains[i]; i++) {
+        const char *plain = plains[i];
+        json_t *parse = NULL;
+        char *embed = NULL;
+        size_t psize = 0;
+        size_t esize = 0;
+
+        psize = strlen(plain) - 2;
+        embed = calloc(1, psize);
+        parse = json_loads(plain, 0, NULL);
+        esize =
+            json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
+        json_decref(parse);
+        if (esize != psize)
+            fail("json_dumpb(JSON_EMBED) returned an invalid size");
+        if (strncmp(plain + 1, embed, esize) != 0)
+            fail("json_dumps(JSON_EMBED) returned an invalid value");
+        free(embed);
+    }
+}
+
+static void run_tests() {
+    encode_null();
+    encode_twice();
+    circular_references();
+    encode_other_than_array_or_object();
+    escape_slashes();
+    encode_nul_byte();
+    dump_file();
+    dumpb();
+    dumpfd();
+    embed();
+}

+ 82 - 0
jansson.mod/jansson/test/suites/api/test_dump_callback.c

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct my_sink {
+    char *buf;
+    size_t off;
+    size_t cap;
+};
+
+static int my_writer(const char *buffer, size_t len, void *data) {
+    struct my_sink *s = data;
+    if (len > s->cap - s->off) {
+        return -1;
+    }
+    memcpy(s->buf + s->off, buffer, len);
+    s->off += len;
+    return 0;
+}
+
+static void run_tests() {
+    struct my_sink s;
+    json_t *json;
+    const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+    char *dumped_to_string;
+
+    json = json_loads(str, 0, NULL);
+    if (!json) {
+        fail("json_loads failed");
+    }
+
+    dumped_to_string = json_dumps(json, 0);
+    if (!dumped_to_string) {
+        json_decref(json);
+        fail("json_dumps failed");
+    }
+
+    s.off = 0;
+    s.cap = strlen(dumped_to_string);
+    s.buf = malloc(s.cap);
+    if (!s.buf) {
+        json_decref(json);
+        free(dumped_to_string);
+        fail("malloc failed");
+    }
+
+    if (json_dump_callback(json, my_writer, &s, 0) == -1) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback failed on an exact-length sink buffer");
+    }
+
+    if (strncmp(dumped_to_string, s.buf, s.off) != 0) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback and json_dumps did not produce identical "
+             "output");
+    }
+
+    s.off = 1;
+    if (json_dump_callback(json, my_writer, &s, 0) != -1) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback succeeded on a short buffer when it should "
+             "have failed");
+    }
+
+    json_decref(json);
+    free(dumped_to_string);
+    free(s.buf);
+}

+ 202 - 0
jansson.mod/jansson/test/suites/api/test_equal.c

@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+
+static void test_equal_simple() {
+    json_t *value1, *value2;
+
+    if (json_equal(NULL, NULL))
+        fail("json_equal fails for two NULLs");
+
+    value1 = json_true();
+    if (json_equal(value1, NULL) || json_equal(NULL, value1))
+        fail("json_equal fails for NULL");
+
+    /* this covers true, false and null as they are singletons */
+    if (!json_equal(value1, value1))
+        fail("identical objects are not equal");
+    json_decref(value1);
+
+    /* integer */
+    value1 = json_integer(1);
+    value2 = json_integer(1);
+    if (!value1 || !value2)
+        fail("unable to create integers");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal integers");
+    json_decref(value2);
+
+    value2 = json_integer(2);
+    if (!value2)
+        fail("unable to create an integer");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal integers");
+
+    json_decref(value1);
+    json_decref(value2);
+
+    /* real */
+    value1 = json_real(1.2);
+    value2 = json_real(1.2);
+    if (!value1 || !value2)
+        fail("unable to create reals");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal reals");
+    json_decref(value2);
+
+    value2 = json_real(3.141592);
+    if (!value2)
+        fail("unable to create an real");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal reals");
+
+    json_decref(value1);
+    json_decref(value2);
+
+    /* string */
+    value1 = json_string("foo");
+    value2 = json_string("foo");
+    if (!value1 || !value2)
+        fail("unable to create strings");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal strings");
+    json_decref(value2);
+
+    value2 = json_string("bar");
+    if (!value2)
+        fail("unable to create an string");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal strings");
+    json_decref(value2);
+
+    value2 = json_string("bar2");
+    if (!value2)
+        fail("unable to create an string");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal length strings");
+
+    json_decref(value1);
+    json_decref(value2);
+}
+
+static void test_equal_array() {
+    json_t *array1, *array2;
+
+    array1 = json_array();
+    array2 = json_array();
+    if (!array1 || !array2)
+        fail("unable to create arrays");
+
+    if (!json_equal(array1, array2))
+        fail("json_equal fails for two empty arrays");
+
+    json_array_append_new(array1, json_integer(1));
+    json_array_append_new(array2, json_integer(1));
+    json_array_append_new(array1, json_string("foo"));
+    json_array_append_new(array2, json_string("foo"));
+    json_array_append_new(array1, json_integer(2));
+    json_array_append_new(array2, json_integer(2));
+    if (!json_equal(array1, array2))
+        fail("json_equal fails for two equal arrays");
+
+    json_array_remove(array2, 2);
+    if (json_equal(array1, array2))
+        fail("json_equal fails for two inequal arrays");
+
+    json_array_append_new(array2, json_integer(3));
+    if (json_equal(array1, array2))
+        fail("json_equal fails for two inequal arrays");
+
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_equal_object() {
+    json_t *object1, *object2;
+
+    object1 = json_object();
+    object2 = json_object();
+    if (!object1 || !object2)
+        fail("unable to create objects");
+
+    if (!json_equal(object1, object2))
+        fail("json_equal fails for two empty objects");
+
+    json_object_set_new(object1, "a", json_integer(1));
+    json_object_set_new(object2, "a", json_integer(1));
+    json_object_set_new(object1, "b", json_string("foo"));
+    json_object_set_new(object2, "b", json_string("foo"));
+    json_object_set_new(object1, "c", json_integer(2));
+    json_object_set_new(object2, "c", json_integer(2));
+    if (!json_equal(object1, object2))
+        fail("json_equal fails for two equal objects");
+
+    json_object_del(object2, "c");
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_object_set_new(object2, "c", json_integer(3));
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_object_del(object2, "c");
+    json_object_set_new(object2, "d", json_integer(2));
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_decref(object1);
+    json_decref(object2);
+}
+
+static void test_equal_complex() {
+    json_t *value1, *value2, *value3;
+
+    const char *complex_json = "{"
+                               "    \"integer\": 1, "
+                               "    \"real\": 3.141592, "
+                               "    \"string\": \"foobar\", "
+                               "    \"true\": true, "
+                               "    \"object\": {"
+                               "        \"array-in-object\": [1,true,\"foo\",{}],"
+                               "        \"object-in-object\": {\"foo\": \"bar\"}"
+                               "    },"
+                               "    \"array\": [\"foo\", false, null, 1.234]"
+                               "}";
+
+    value1 = json_loads(complex_json, 0, NULL);
+    value2 = json_loads(complex_json, 0, NULL);
+    value3 = json_loads(complex_json, 0, NULL);
+    if (!value1 || !value2)
+        fail("unable to parse JSON");
+    if (!json_equal(value1, value2))
+        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(value2);
+    json_decref(value3);
+}
+
+static void run_tests() {
+    test_equal_simple();
+    test_equal_array();
+    test_equal_object();
+    test_equal_complex();
+}

+ 228 - 0
jansson.mod/jansson/test/suites/api/test_fixed_size.c

@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2020 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_keylen_iterator(json_t *object) {
+    const char key1[] = {'t', 'e', 's', 't', '1'};
+    const char key2[] = {'t', 'e', 's', 't'};
+    const char key3[] = {'t', 'e', 's', '\0', 't'};
+    const char key4[] = {'t', 'e', 's', 't', '\0'};
+    const char *reference_keys[] = {key1, key2, key3, key4};
+    const size_t reference_keys_len[] = {sizeof(key1), sizeof(key2), sizeof(key3),
+                                         sizeof(key4)};
+    size_t index = 0;
+    json_t *value;
+    const char *key;
+    size_t keylen;
+
+    json_object_keylen_foreach(object, key, keylen, value) {
+        if (keylen != reference_keys_len[index])
+            fail("invalid key len in iterator");
+        if (memcmp(key, reference_keys[index], reference_keys_len[index]) != 0)
+            fail("invalid key in iterator");
+
+        index++;
+    }
+}
+
+static void test_keylen(void) {
+    json_t *obj = json_object();
+    const char key[] = {'t', 'e', 's', 't', '1'};
+    const char key2[] = {'t', 'e', 's', 't'};
+    const char key3[] = {'t', 'e', 's', '\0', 't'};
+    const char key4[] = {'t', 'e', 's', 't', '\0'};
+
+    if (json_object_size(obj) != 0)
+        fail("incorrect json");
+
+    json_object_set_new_nocheck(obj, "test1", json_true());
+
+    if (json_object_size(obj) != 1)
+        fail("incorrect json");
+
+    if (json_object_getn(obj, key, sizeof(key)) != json_true())
+        fail("json_object_getn failed");
+
+    if (json_object_getn(obj, key2, sizeof(key2)) != NULL)
+        fail("false positive json_object_getn by key2");
+
+    if (json_object_setn_nocheck(obj, key2, sizeof(key2), json_false()))
+        fail("json_object_setn_nocheck for key2 failed");
+
+    if (json_object_size(obj) != 2)
+        fail("incorrect json");
+
+    if (json_object_get(obj, "test") != json_false())
+        fail("json_object_setn_nocheck for key2 failed");
+
+    if (json_object_getn(obj, key2, sizeof(key2)) != json_false())
+        fail("json_object_getn by key 2 failed");
+
+    if (json_object_getn(obj, key3, sizeof(key3)) != NULL)
+        fail("false positive json_object_getn by key3");
+
+    if (json_object_setn_nocheck(obj, key3, sizeof(key3), json_false()))
+        fail("json_object_setn_nocheck for key3 failed");
+
+    if (json_object_size(obj) != 3)
+        fail("incorrect json");
+
+    if (json_object_getn(obj, key3, sizeof(key3)) != json_false())
+        fail("json_object_getn by key 3 failed");
+
+    if (json_object_getn(obj, key4, sizeof(key4)) != NULL)
+        fail("false positive json_object_getn by key3");
+
+    if (json_object_setn_nocheck(obj, key4, sizeof(key4), json_false()))
+        fail("json_object_setn_nocheck for key3 failed");
+
+    if (json_object_size(obj) != 4)
+        fail("incorrect json");
+
+    test_keylen_iterator(obj);
+
+    if (json_object_getn(obj, key4, sizeof(key4)) != json_false())
+        fail("json_object_getn by key 3 failed");
+
+    if (json_object_size(obj) != 4)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key4, sizeof(key4)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key4, sizeof(key4)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 3)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key3, sizeof(key3)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key3, sizeof(key3)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 2)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key2, sizeof(key2)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key2, sizeof(key2)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 1)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key, sizeof(key)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key, sizeof(key)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 0)
+        fail("incorrect json");
+
+    json_decref(obj);
+}
+
+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());
+
+    if (json_object_getn(NULL, key, sizeof(key)) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (json_object_getn(obj, NULL, sizeof(key)) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (json_object_getn(obj, key, 0) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (!json_object_setn_new(obj, NULL, sizeof(key), json_true()))
+        fail("json_object_setn_new with NULL key failed");
+
+    if (!json_object_setn_new_nocheck(obj, NULL, sizeof(key), json_true()))
+        fail("json_object_setn_new_nocheck with NULL key failed");
+
+    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) {
+    json_t *obj = json_object();
+    int key1 = 0;
+    int key2 = 1;
+
+    json_object_setn_nocheck(obj, (const char *)&key1, sizeof(key1), json_true());
+    json_object_setn_nocheck(obj, (const char *)&key2, sizeof(key2), json_true());
+
+    if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key1))))
+        fail("cannot get integer key1");
+
+    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);
+}
+
+static void test_dump_order(void) {
+    json_t *obj = json_object();
+    char key1[] = {'k', '\0', '-', '2'};
+    char key2[] = {'k', '\0', '-', '1'};
+    const char expected_sorted_str[] =
+        "{\"k\\u0000-1\": \"first\", \"k\\u0000-2\": \"second\"}";
+    const char expected_nonsorted_str[] =
+        "{\"k\\u0000-2\": \"second\", \"k\\u0000-1\": \"first\"}";
+    char *out;
+
+    json_object_setn_new_nocheck(obj, key1, sizeof(key1), json_string("second"));
+    json_object_setn_new_nocheck(obj, key2, sizeof(key2), json_string("first"));
+
+    out = malloc(512);
+
+    json_dumpb(obj, out, 512, 0);
+
+    if (memcmp(expected_nonsorted_str, out, sizeof(expected_nonsorted_str) - 1) != 0)
+        fail("preserve order failed");
+
+    json_dumpb(obj, out, 512, JSON_SORT_KEYS);
+    if (memcmp(expected_sorted_str, out, sizeof(expected_sorted_str) - 1) != 0)
+        fail("utf-8 sort failed");
+
+    free(out);
+    json_decref(obj);
+}
+
+static void run_tests() {
+    test_keylen();
+    test_invalid_keylen();
+    test_binary_keys();
+    test_dump_order();
+}

+ 238 - 0
jansson.mod/jansson/test/suites/api/test_load.c

@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void file_not_found() {
+    json_t *json;
+    json_error_t error;
+    char *pos;
+
+    json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
+    if (json)
+        fail("json_load_file returned non-NULL for a nonexistent file");
+    if (error.line != -1)
+        fail("json_load_file returned an invalid line number");
+
+    /* The error message is locale specific, only check the beginning
+       of the error message. */
+
+    pos = strchr(error.text, ':');
+    if (!pos)
+        fail("json_load_file returne an invalid error message");
+
+    *pos = '\0';
+
+    if (strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
+        fail("json_load_file returned an invalid error message");
+    if (json_error_code(&error) != json_error_cannot_open_file)
+        fail("json_load_file returned an invalid error code");
+}
+
+static void very_long_file_name() {
+    json_t *json;
+    json_error_t error;
+
+    json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+                          "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                          0, &error);
+    if (json)
+        fail("json_load_file returned non-NULL for a nonexistent file");
+    if (error.line != -1)
+        fail("json_load_file returned an invalid line number");
+
+    if (strncmp(error.source, "...aaa", 6) != 0)
+        fail("error source was set incorrectly");
+    if (json_error_code(&error) != json_error_cannot_open_file)
+        fail("error code was set incorrectly");
+}
+
+static void reject_duplicates() {
+    json_error_t error;
+
+    if (json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
+        fail("json_loads did not detect a duplicate key");
+    check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'",
+                "<string>", 1, 16, 16);
+}
+
+static void disable_eof_check() {
+    json_error_t error;
+    json_t *json;
+
+    const char *text = "{\"foo\": 1} garbage";
+
+    if (json_loads(text, 0, &error))
+        fail("json_loads did not detect garbage after JSON text");
+    check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'",
+                "<string>", 1, 18, 18);
+
+    json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
+    if (!json)
+        fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
+
+    json_decref(json);
+}
+
+static void decode_any() {
+    json_t *json;
+    json_error_t error;
+
+    json = json_loads("\"foo\"", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_string(json))
+        fail("json_load decoded any failed - string");
+    json_decref(json);
+
+    json = json_loads("42", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_integer(json))
+        fail("json_load decoded any failed - integer");
+    json_decref(json);
+
+    json = json_loads("true", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_true(json))
+        fail("json_load decoded any failed - boolean");
+    json_decref(json);
+
+    json = json_loads("null", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_null(json))
+        fail("json_load decoded any failed - null");
+    json_decref(json);
+}
+
+static void decode_int_as_real() {
+    json_t *json;
+    json_error_t error;
+
+#if JSON_INTEGER_IS_LONG_LONG
+    const char *imprecise;
+    json_int_t expected;
+#endif
+
+    char big[311];
+
+    json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (!json || !json_is_real(json) || json_real_value(json) != 42.0)
+        fail("json_load decode int as real failed - int");
+    json_decref(json);
+
+#if JSON_INTEGER_IS_LONG_LONG
+    /* This number cannot be represented exactly by a double */
+    imprecise = "9007199254740993";
+    expected = 9007199254740992ll;
+
+    json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json))
+        fail("json_load decode int as real failed - expected imprecision");
+    json_decref(json);
+#endif
+
+    /* 1E309 overflows. Here we create 1E309 as a decimal number, i.e.
+       1000...(309 zeroes)...0. */
+    big[0] = '1';
+    memset(big + 1, '0', 309);
+    big[310] = '\0';
+
+    json = json_loads(big, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (json || strcmp(error.text, "real number overflow") != 0 ||
+        json_error_code(&error) != json_error_numeric_overflow)
+        fail("json_load decode int as real failed - expected overflow");
+    json_decref(json);
+}
+
+static void allow_nul() {
+    const char *text = "\"nul byte \\u0000 in string\"";
+    const char *expected = "nul byte \0 in string";
+    size_t len = 20;
+    json_t *json;
+
+    json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL);
+    if (!json || !json_is_string(json))
+        fail("unable to decode embedded NUL byte");
+
+    if (json_string_length(json) != len)
+        fail("decoder returned wrong string length");
+
+    if (memcmp(json_string_value(json), expected, len + 1))
+        fail("decoder returned wrong string content");
+
+    json_decref(json);
+}
+
+static void load_wrong_args() {
+    json_t *json;
+    json_error_t error;
+
+    json = json_loads(NULL, 0, &error);
+    if (json)
+        fail("json_loads should return NULL if the first argument is NULL");
+
+    json = json_loadb(NULL, 0, 0, &error);
+    if (json)
+        fail("json_loadb should return NULL if the first argument is NULL");
+
+    json = json_loadf(NULL, 0, &error);
+    if (json)
+        fail("json_loadf should return NULL if the first argument is NULL");
+
+    json = json_loadfd(-1, 0, &error);
+    if (json)
+        fail("json_loadfd should return NULL if the first argument is < 0");
+
+    json = json_load_file(NULL, 0, &error);
+    if (json)
+        fail("json_load_file should return NULL if the first argument is NULL");
+}
+
+static void position() {
+    json_t *json;
+    size_t flags = JSON_DISABLE_EOF_CHECK;
+    json_error_t error;
+
+    json = json_loads("{\"foo\": \"bar\"}", 0, &error);
+    if (error.position != 14)
+        fail("json_loads returned a wrong position");
+    json_decref(json);
+
+    json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
+    if (error.position != 14)
+        fail("json_loads returned a wrong position");
+    json_decref(json);
+}
+
+static void error_code() {
+    json_error_t error;
+    json_t *json = json_loads("[123] garbage", 0, &error);
+    if (json != NULL)
+        fail("json_loads returned not NULL");
+    if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
+        fail("error.text longer than expected");
+    if (json_error_code(&error) != json_error_end_of_input_expected)
+        fail("json_loads returned incorrect error code");
+
+    json = json_loads("{\"foo\": ", 0, &error);
+    if (json != NULL)
+        fail("json_loads returned not NULL");
+    if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
+        fail("error.text longer than expected");
+    if (json_error_code(&error) != json_error_premature_end_of_input)
+        fail("json_loads returned incorrect error code");
+}
+
+static void run_tests() {
+    file_not_found();
+    very_long_file_name();
+    reject_duplicates();
+    disable_eof_check();
+    decode_any();
+    decode_int_as_real();
+    allow_nul();
+    load_wrong_args();
+    position();
+    error_code();
+}

+ 77 - 0
jansson.mod/jansson/test/suites/api/test_load_callback.c

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct my_source {
+    const char *buf;
+    size_t off;
+    size_t cap;
+};
+
+static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+
+static size_t greedy_reader(void *buf, size_t buflen, void *arg) {
+    struct my_source *s = arg;
+    if (buflen > s->cap - s->off)
+        buflen = s->cap - s->off;
+    if (buflen > 0) {
+        memcpy(buf, s->buf + s->off, buflen);
+        s->off += buflen;
+        return buflen;
+    } else {
+        return 0;
+    }
+}
+
+static void run_tests() {
+    struct my_source s;
+    json_t *json;
+    json_error_t error;
+
+    s.off = 0;
+    s.cap = strlen(my_str);
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+
+    if (!json)
+        fail("json_load_callback failed on a valid callback");
+    json_decref(json);
+
+    s.off = 0;
+    s.cap = strlen(my_str) - 1;
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on an incomplete stream, "
+             "but it didn't");
+    }
+    if (strcmp(error.source, "<callback>") != 0) {
+        fail("json_load_callback returned an invalid error source");
+    }
+    if (strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_load_callback returned an invalid error message for an "
+             "unclosed top-level array");
+    }
+
+    json = json_load_callback(NULL, NULL, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on NULL load callback, but "
+             "it didn't");
+    }
+    if (strcmp(error.text, "wrong arguments") != 0) {
+        fail("json_load_callback returned an invalid error message for a NULL "
+             "load callback");
+    }
+}

+ 37 - 0
jansson.mod/jansson/test/suites/api/test_loadb.c

@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void run_tests() {
+    json_t *json;
+    json_error_t error;
+    const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
+    size_t len = strlen(str) - strlen("garbage");
+
+    json = json_loadb(str, len, 0, &error);
+    if (!json) {
+        fail("json_loadb failed on a valid JSON buffer");
+    }
+    json_decref(json);
+
+    json = json_loadb(str, len - 1, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_loadb should have failed on an incomplete buffer, but it "
+             "didn't");
+    }
+    if (error.line != 1) {
+        fail("json_loadb returned an invalid line number on fail");
+    }
+    if (strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_loadb returned an invalid error message for an unclosed "
+             "top-level array");
+    }
+}

+ 115 - 0
jansson.mod/jansson/test/suites/api/test_memory_funcs.c

@@ -0,0 +1,115 @@
+#include <jansson.h>
+#include <string.h>
+
+#include "util.h"
+
+static int malloc_called = 0;
+static int free_called = 0;
+static size_t malloc_used = 0;
+
+/* helpers */
+static void create_and_free_complex_object() {
+    json_t *obj;
+
+    obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]}", "foo", 42, "bar", "baz", 1,
+                    "qux", 0, "alice", "bar", "baz", "bob", 9, 8, 7);
+
+    json_decref(obj);
+}
+
+static void create_and_free_object_with_oom() {
+    int i;
+    char key[4];
+    json_t *obj = json_object();
+
+    for (i = 0; i < 10; i++) {
+        snprintf(key, sizeof key, "%d", i);
+        json_object_set_new(obj, key, json_integer(i));
+    }
+
+    json_decref(obj);
+}
+
+static void *my_malloc(size_t size) {
+    malloc_called = 1;
+    return malloc(size);
+}
+
+static void my_free(void *ptr) {
+    free_called = 1;
+    free(ptr);
+}
+
+static void test_simple() {
+    json_malloc_t mfunc = NULL;
+    json_free_t ffunc = NULL;
+
+    json_set_alloc_funcs(my_malloc, my_free);
+    json_get_alloc_funcs(&mfunc, &ffunc);
+    create_and_free_complex_object();
+
+    if (malloc_called != 1 || free_called != 1 || mfunc != my_malloc || ffunc != my_free)
+        fail("Custom allocation failed");
+}
+
+static void *oom_malloc(size_t size) {
+    if (malloc_used + size > 800)
+        return NULL;
+
+    malloc_used += size;
+    return malloc(size);
+}
+
+static void oom_free(void *ptr) {
+    free_called++;
+    free(ptr);
+}
+
+static void test_oom() {
+    free_called = 0;
+    json_set_alloc_funcs(oom_malloc, oom_free);
+    create_and_free_object_with_oom();
+
+    if (free_called == 0)
+        fail("Allocation with OOM failed");
+}
+
+/*
+  Test the secure memory functions code given in the API reference
+  documentation, but by using plain memset instead of
+  guaranteed_memset().
+*/
+
+static void *secure_malloc(size_t size) {
+    /* Store the memory area size in the beginning of the block */
+    void *ptr = malloc(size + 8);
+    *((size_t *)ptr) = size;
+    return (char *)ptr + 8;
+}
+
+static void secure_free(void *ptr) {
+    size_t size;
+
+    ptr = (char *)ptr - 8;
+    size = *((size_t *)ptr);
+
+    /*guaranteed_*/ memset(ptr, 0, size + 8);
+    free(ptr);
+}
+
+static void test_secure_funcs(void) {
+    json_set_alloc_funcs(secure_malloc, secure_free);
+    create_and_free_complex_object();
+}
+
+static void test_bad_args(void) {
+    /* The result of this test is not crashing. */
+    json_get_alloc_funcs(NULL, NULL);
+}
+
+static void run_tests() {
+    test_simple();
+    test_secure_funcs();
+    test_oom();
+    test_bad_args();
+}

+ 123 - 0
jansson.mod/jansson/test/suites/api/test_number.c

@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <math.h>
+
+#ifdef INFINITY
+// This test triggers "warning C4756: overflow in constant arithmetic"
+// in Visual Studio. This warning is triggered here by design, so disable it.
+// (This can only be done on function level so we keep these tests separate)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4756)
+#endif
+static void test_inifity() {
+    json_t *real = json_real(INFINITY);
+    if (real != NULL)
+        fail("could construct a real from Inf");
+
+    real = json_real(1.0);
+    if (json_real_set(real, INFINITY) != -1)
+        fail("could set a real to Inf");
+
+    if (json_real_value(real) != 1.0)
+        fail("real value changed unexpectedly");
+
+    json_decref(real);
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+#endif // INFINITY
+
+static void test_bad_args(void) {
+    json_t *txt = json_string("test");
+
+    if (json_integer_value(NULL) != 0)
+        fail("json_integer_value did not return 0 for non-integer");
+    if (json_integer_value(txt) != 0)
+        fail("json_integer_value did not return 0 for non-integer");
+
+    if (!json_integer_set(NULL, 0))
+        fail("json_integer_set did not return error for non-integer");
+    if (!json_integer_set(txt, 0))
+        fail("json_integer_set did not return error for non-integer");
+
+    if (json_real_value(NULL) != 0.0)
+        fail("json_real_value did not return 0.0 for non-real");
+    if (json_real_value(txt) != 0.0)
+        fail("json_real_value did not return 0.0 for non-real");
+
+    if (!json_real_set(NULL, 0.0))
+        fail("json_real_set did not return error for non-real");
+    if (!json_real_set(txt, 0.0))
+        fail("json_real_set did not return error for non-real");
+
+    if (json_number_value(NULL) != 0.0)
+        fail("json_number_value did not return 0.0 for non-numeric");
+    if (json_number_value(txt) != 0.0)
+        fail("json_number_value did not return 0.0 for non-numeric");
+
+    if (txt->refcount != 1)
+        fail("unexpected reference count for txt");
+
+    json_decref(txt);
+}
+
+static void run_tests() {
+    json_t *integer, *real;
+    json_int_t i;
+    double d;
+
+    integer = json_integer(5);
+    real = json_real(100.1);
+
+    if (!integer)
+        fail("unable to create integer");
+    if (!real)
+        fail("unable to create real");
+
+    i = json_integer_value(integer);
+    if (i != 5)
+        fail("wrong integer value");
+
+    d = json_real_value(real);
+    if (d != 100.1)
+        fail("wrong real value");
+
+    d = json_number_value(integer);
+    if (d != 5.0)
+        fail("wrong number value");
+    d = json_number_value(real);
+    if (d != 100.1)
+        fail("wrong number value");
+
+    json_decref(integer);
+    json_decref(real);
+
+#ifdef NAN
+    real = json_real(NAN);
+    if (real != NULL)
+        fail("could construct a real from NaN");
+
+    real = json_real(1.0);
+    if (json_real_set(real, NAN) != -1)
+        fail("could set a real to NaN");
+
+    if (json_real_value(real) != 1.0)
+        fail("real value changed unexpectedly");
+
+    json_decref(real);
+#endif
+
+#ifdef INFINITY
+    test_inifity();
+#endif
+    test_bad_args();
+}

+ 797 - 0
jansson.mod/jansson/test/suites/api/test_object.c

@@ -0,0 +1,797 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_clear() {
+    json_t *object, *ten;
+
+    object = json_object();
+    ten = json_integer(10);
+
+    if (!object)
+        fail("unable to create object");
+    if (!ten)
+        fail("unable to create integer");
+
+    if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) ||
+        json_object_set(object, "c", ten) || json_object_set(object, "d", ten) ||
+        json_object_set(object, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size");
+
+    json_object_clear(object);
+
+    if (json_object_size(object) != 0)
+        fail("invalid size after clear");
+
+    json_decref(ten);
+    json_decref(object);
+}
+
+static void test_update() {
+    json_t *object, *other, *nine, *ten;
+
+    object = json_object();
+    other = json_object();
+
+    nine = json_integer(9);
+    ten = json_integer(10);
+
+    if (!object || !other)
+        fail("unable to create object");
+    if (!nine || !ten)
+        fail("unable to create integer");
+
+    /* update an empty object with an empty object */
+
+    if (json_object_update(object, other))
+        fail("unable to update an empty object with an empty object");
+
+    if (json_object_size(object) != 0)
+        fail("invalid size after update");
+
+    if (json_object_size(other) != 0)
+        fail("invalid size for updater after update");
+
+    /* update an empty object with a nonempty object */
+
+    if (json_object_set(other, "a", ten) || json_object_set(other, "b", ten) ||
+        json_object_set(other, "c", ten) || json_object_set(other, "d", ten) ||
+        json_object_set(other, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_update(object, other))
+        fail("unable to update an empty object");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten)
+        fail("update works incorrectly");
+
+    /* perform the same update again */
+
+    if (json_object_update(object, other))
+        fail("unable to update a non-empty object");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten)
+        fail("update works incorrectly");
+
+    /* update a nonempty object with a nonempty object with both old
+       and new keys */
+
+    if (json_object_clear(other))
+        fail("clear failed");
+
+    if (json_object_set(other, "a", nine) || json_object_set(other, "b", nine) ||
+        json_object_set(other, "f", nine) || json_object_set(other, "g", nine) ||
+        json_object_set(other, "h", nine))
+        fail("unable to set value");
+
+    if (json_object_update(object, other))
+        fail("unable to update a nonempty object");
+
+    if (json_object_size(object) != 8)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != nine || json_object_get(object, "b") != nine ||
+        json_object_get(object, "f") != nine || json_object_get(object, "g") != nine ||
+        json_object_get(object, "h") != nine)
+        fail("update works incorrectly");
+
+    /* update_new check */
+    if (json_object_clear(object))
+        fail("clear failed");
+
+    if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) ||
+        json_object_set(object, "c", ten) || json_object_set(object, "d", ten) ||
+        json_object_set(object, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_update_new(
+            object, json_pack("{s:O, s:O, s:O}", "b", nine, "f", nine, "g", nine)))
+        fail("unable to update_new a nonempty object");
+
+    if (json_object_size(object) != 7)
+        fail("invalid size after update_new");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != nine ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten || json_object_get(object, "f") != nine ||
+        json_object_get(object, "g") != nine)
+        fail("update_new works incorrectly");
+
+    json_decref(nine);
+    json_decref(ten);
+    json_decref(other);
+    json_decref(object);
+}
+
+static void test_set_many_keys() {
+    json_t *object, *value;
+    const char *keys = "abcdefghijklmnopqrstuvwxyz";
+    char buf[2];
+    size_t i;
+
+    object = json_object();
+    if (!object)
+        fail("unable to create object");
+
+    value = json_string("a");
+    if (!value)
+        fail("unable to create string");
+
+    buf[1] = '\0';
+    for (i = 0; i < strlen(keys); i++) {
+        buf[0] = keys[i];
+        if (json_object_set(object, buf, value))
+            fail("unable to set object key");
+    }
+
+    json_decref(object);
+    json_decref(value);
+}
+
+static void test_conditional_updates() {
+    json_t *object, *other;
+
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+    other = json_pack("{sisi}", "foo", 3, "baz", 4);
+
+    if (json_object_update_existing(object, other))
+        fail("json_object_update_existing failed");
+
+    if (json_object_size(object) != 2)
+        fail("json_object_update_existing added new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 3)
+        fail("json_object_update_existing failed to update existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_existing updated wrong key");
+
+    json_decref(object);
+
+    /* json_object_update_existing_new check */
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_existing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4)))
+        fail("json_object_update_existing_new failed");
+
+    if (json_object_size(object) != 2)
+        fail("json_object_update_existing_new added new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 3)
+        fail("json_object_update_existing_new failed to update existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_existing_new updated wrong key");
+
+    json_decref(object);
+
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_missing(object, other))
+        fail("json_object_update_missing failed");
+
+    if (json_object_size(object) != 3)
+        fail("json_object_update_missing didn't add new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 1)
+        fail("json_object_update_missing updated existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_missing updated wrong key");
+
+    if (json_integer_value(json_object_get(object, "baz")) != 4)
+        fail("json_object_update_missing didn't add new items");
+
+    json_decref(object);
+
+    /* json_object_update_missing_new check */
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_missing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4)))
+        fail("json_object_update_missing_new failed");
+
+    if (json_object_size(object) != 3)
+        fail("json_object_update_missing_new didn't add new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 1)
+        fail("json_object_update_missing_new updated existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_missing_new updated wrong key");
+
+    if (json_integer_value(json_object_get(object, "baz")) != 4)
+        fail("json_object_update_missing_new didn't add new items");
+
+    json_decref(object);
+    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() {
+    json_t *object1, *object2;
+
+    object1 = json_object();
+    object2 = json_object();
+    if (!object1 || !object2)
+        fail("unable to create object");
+
+    /* the simple case is checked */
+    if (json_object_set(object1, "a", object1) == 0)
+        fail("able to set self");
+
+    /* create circular references */
+    if (json_object_set(object1, "a", object2) || json_object_set(object2, "a", object1))
+        fail("unable to set value");
+
+    /* circularity is detected when dumping */
+    if (json_dumps(object1, 0) != NULL)
+        fail("able to dump circulars");
+
+    /* decref twice to deal with the circular references */
+    json_decref(object1);
+    json_decref(object2);
+    json_decref(object1);
+}
+
+static void test_set_nocheck() {
+    json_t *object, *string;
+
+    object = json_object();
+    string = json_string("bar");
+
+    if (!object)
+        fail("unable to create object");
+    if (!string)
+        fail("unable to create string");
+
+    if (json_object_set_nocheck(object, "foo", string))
+        fail("json_object_set_nocheck failed");
+    if (json_object_get(object, "foo") != string)
+        fail("json_object_get after json_object_set_nocheck failed");
+
+    /* invalid UTF-8 in key */
+    if (json_object_set_nocheck(object, "a\xefz", string))
+        fail("json_object_set_nocheck failed for invalid UTF-8");
+    if (json_object_get(object, "a\xefz") != string)
+        fail("json_object_get after json_object_set_nocheck failed");
+
+    if (json_object_set_new_nocheck(object, "bax", json_integer(123)))
+        fail("json_object_set_new_nocheck failed");
+    if (json_integer_value(json_object_get(object, "bax")) != 123)
+        fail("json_object_get after json_object_set_new_nocheck failed");
+
+    /* invalid UTF-8 in key */
+    if (json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321)))
+        fail("json_object_set_new_nocheck failed for invalid UTF-8");
+    if (json_integer_value(json_object_get(object, "asdf\xfe")) != 321)
+        fail("json_object_get after json_object_set_new_nocheck failed");
+
+    json_decref(string);
+    json_decref(object);
+}
+
+static void test_iterators() {
+    json_t *object, *foo, *bar, *baz;
+    void *iter;
+
+    if (json_object_iter(NULL))
+        fail("able to iterate over NULL");
+
+    if (json_object_iter_next(NULL, NULL))
+        fail("able to increment an iterator on a NULL object");
+
+    object = json_object();
+    foo = json_string("foo");
+    bar = json_string("bar");
+    baz = json_string("baz");
+    if (!object || !foo || !bar || !baz)
+        fail("unable to create values");
+
+    if (json_object_iter_next(object, NULL))
+        fail("able to increment a NULL iterator");
+
+    if (json_object_set(object, "a", foo) || json_object_set(object, "b", bar) ||
+        json_object_set(object, "c", baz))
+        fail("unable to populate object");
+
+    iter = json_object_iter(object);
+    if (!iter)
+        fail("unable to get iterator");
+    if (strcmp(json_object_iter_key(iter), "a") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != foo)
+        fail("iterating doesn't yield values in order");
+
+    iter = json_object_iter_next(object, iter);
+    if (!iter)
+        fail("unable to increment iterator");
+    if (strcmp(json_object_iter_key(iter), "b") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != bar)
+        fail("iterating doesn't yield values in order");
+
+    iter = json_object_iter_next(object, iter);
+    if (!iter)
+        fail("unable to increment iterator");
+    if (strcmp(json_object_iter_key(iter), "c") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != baz)
+        fail("iterating doesn't yield values in order");
+
+    if (json_object_iter_next(object, iter) != NULL)
+        fail("able to iterate over the end");
+
+    if (json_object_iter_at(object, "foo"))
+        fail("json_object_iter_at() succeeds for non-existent key");
+
+    iter = json_object_iter_at(object, "b");
+    if (!iter)
+        fail("json_object_iter_at() fails for an existing key");
+
+    if (strcmp(json_object_iter_key(iter), "b"))
+        fail("iterating failed: wrong key");
+    if (json_object_iter_value(iter) != bar)
+        fail("iterating failed: wrong value");
+
+    if (json_object_iter_set(object, iter, baz))
+        fail("unable to set value at iterator");
+
+    if (strcmp(json_object_iter_key(iter), "b"))
+        fail("json_object_iter_key() fails after json_object_iter_set()");
+    if (json_object_iter_value(iter) != baz)
+        fail("json_object_iter_value() fails after json_object_iter_set()");
+    if (json_object_get(object, "b") != baz)
+        fail("json_object_get() fails after json_object_iter_set()");
+
+    json_decref(object);
+    json_decref(foo);
+    json_decref(bar);
+    json_decref(baz);
+}
+
+static void test_misc() {
+    json_t *object, *string, *other_string, *value;
+
+    object = json_object();
+    string = json_string("test");
+    other_string = json_string("other");
+
+    if (!object)
+        fail("unable to create object");
+    if (!string || !other_string)
+        fail("unable to create string");
+
+    if (json_object_get(object, "a"))
+        fail("value for nonexisting key");
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (!json_object_set(object, NULL, string))
+        fail("able to set NULL key");
+
+    if (json_object_del(object, "a"))
+        fail("unable to del the only key");
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (!json_object_set(object, "a", NULL))
+        fail("able to set NULL value");
+
+    /* invalid UTF-8 in key */
+    if (!json_object_set(object, "a\xefz", string))
+        fail("able to set invalid unicode key");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != string)
+        fail("got different value than what was added");
+
+    /* "a", "lp" and "px" collide in a five-bucket hashtable */
+    if (json_object_set(object, "b", string) || json_object_set(object, "lp", string) ||
+        json_object_set(object, "px", string))
+        fail("unable to set value");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != string)
+        fail("got different value than what was added");
+
+    if (json_object_set(object, "a", other_string))
+        fail("unable to replace an existing key");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != other_string)
+        fail("got different value than what was set");
+
+    if (!json_object_del(object, "nonexisting"))
+        fail("able to delete a nonexisting key");
+
+    if (json_object_del(object, "px"))
+        fail("unable to delete an existing key");
+
+    if (json_object_del(object, "a"))
+        fail("unable to delete an existing key");
+
+    if (json_object_del(object, "lp"))
+        fail("unable to delete an existing key");
+
+    /* add many keys to initiate rehashing */
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "lp", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "px", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "c", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "d", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "e", string))
+        fail("unable to set value");
+
+    if (json_object_set_new(object, "foo", json_integer(123)))
+        fail("unable to set new value");
+
+    value = json_object_get(object, "foo");
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_object_set_new works incorrectly");
+
+    if (!json_object_set_new(object, NULL, json_integer(432)))
+        fail("able to set_new NULL key");
+
+    if (!json_object_set_new(object, "foo", NULL))
+        fail("able to set_new NULL value");
+
+    json_decref(string);
+    json_decref(other_string);
+    json_decref(object);
+}
+
+static void test_preserve_order() {
+    json_t *object;
+    char *result;
+
+    const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": "
+                           "3, \"sit amet\": 5, \"helicopter\": 7}";
+
+    object = json_object();
+
+    json_object_set_new(object, "foobar", json_integer(1));
+    json_object_set_new(object, "bazquux", json_integer(2));
+    json_object_set_new(object, "lorem ipsum", json_integer(3));
+    json_object_set_new(object, "dolor", json_integer(4));
+    json_object_set_new(object, "sit amet", json_integer(5));
+
+    /* changing a value should preserve the order */
+    json_object_set_new(object, "bazquux", json_integer(6));
+
+    /* deletion shouldn't change the order of others */
+    json_object_del(object, "dolor");
+
+    /* add a new item just to make sure */
+    json_object_set_new(object, "helicopter", json_integer(7));
+
+    result = json_dumps(object, JSON_PRESERVE_ORDER);
+
+    if (strcmp(expected, result) != 0) {
+        fprintf(stderr, "%s != %s", expected, result);
+        fail("JSON_PRESERVE_ORDER doesn't work");
+    }
+
+    free(result);
+    json_decref(object);
+}
+
+static void test_object_foreach() {
+    const char *key;
+    json_t *object1, *object2, *value;
+
+    object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
+    object2 = json_object();
+
+    json_object_foreach(object1, key, value) json_object_set(object2, key, value);
+
+    if (!json_equal(object1, object2))
+        fail("json_object_foreach failed to iterate all key-value pairs");
+
+    json_decref(object1);
+    json_decref(object2);
+}
+
+static void test_object_foreach_safe() {
+    const char *key;
+    void *tmp;
+    json_t *object, *value;
+
+    object = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
+
+    json_object_foreach_safe(object, tmp, key, value) { json_object_del(object, key); }
+
+    if (json_object_size(object) != 0)
+        fail("json_object_foreach_safe failed to iterate all key-value pairs");
+
+    json_decref(object);
+}
+
+static void test_bad_args(void) {
+    json_t *obj = json_object();
+    json_t *num = json_integer(1);
+    void *iter;
+
+    if (!obj || !num)
+        fail("failed to allocate test objects");
+
+    if (json_object_set(obj, "testkey", json_null()))
+        fail("failed to set testkey on object");
+
+    iter = json_object_iter(obj);
+    if (!iter)
+        fail("failed to retrieve test iterator");
+
+    if (json_object_size(NULL) != 0)
+        fail("json_object_size with non-object argument returned non-zero");
+    if (json_object_size(num) != 0)
+        fail("json_object_size with non-object argument returned non-zero");
+
+    if (json_object_get(NULL, "test") != NULL)
+        fail("json_object_get with non-object argument returned non-NULL");
+    if (json_object_get(num, "test") != NULL)
+        fail("json_object_get with non-object argument returned non-NULL");
+    if (json_object_get(obj, NULL) != NULL)
+        fail("json_object_get with NULL key returned non-NULL");
+
+    if (!json_object_set_new_nocheck(NULL, "test", json_null()))
+        fail("json_object_set_new_nocheck with non-object argument did not "
+             "return error");
+    if (!json_object_set_new_nocheck(num, "test", json_null()))
+        fail("json_object_set_new_nocheck with non-object argument did not "
+             "return error");
+    if (!json_object_set_new_nocheck(obj, "test", json_incref(obj)))
+        fail("json_object_set_new_nocheck with object == value did not return "
+             "error");
+    if (!json_object_set_new_nocheck(obj, NULL, json_object()))
+        fail("json_object_set_new_nocheck with NULL key did not return error");
+
+    if (!json_object_del(NULL, "test"))
+        fail("json_object_del with non-object argument did not return error");
+    if (!json_object_del(num, "test"))
+        fail("json_object_del with non-object argument did not return error");
+    if (!json_object_del(obj, NULL))
+        fail("json_object_del with NULL key did not return error");
+
+    if (!json_object_clear(NULL))
+        fail("json_object_clear with non-object argument did not return error");
+    if (!json_object_clear(num))
+        fail("json_object_clear with non-object argument did not return error");
+
+    if (!json_object_update(NULL, obj))
+        fail("json_object_update with non-object first argument did not return "
+             "error");
+    if (!json_object_update(num, obj))
+        fail("json_object_update with non-object first argument did not return "
+             "error");
+    if (!json_object_update(obj, NULL))
+        fail("json_object_update with non-object second argument did not "
+             "return error");
+    if (!json_object_update(obj, num))
+        fail("json_object_update with non-object second argument did not "
+             "return error");
+
+    if (!json_object_update_existing(NULL, obj))
+        fail("json_object_update_existing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_existing(num, obj))
+        fail("json_object_update_existing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_existing(obj, NULL))
+        fail("json_object_update_existing with non-object second argument did "
+             "not return error");
+    if (!json_object_update_existing(obj, num))
+        fail("json_object_update_existing with non-object second argument did "
+             "not return error");
+
+    if (!json_object_update_missing(NULL, obj))
+        fail("json_object_update_missing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_missing(num, obj))
+        fail("json_object_update_missing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_missing(obj, NULL))
+        fail("json_object_update_missing with non-object second argument did "
+             "not return error");
+    if (!json_object_update_missing(obj, num))
+        fail("json_object_update_missing with non-object second argument did "
+             "not return error");
+
+    if (json_object_iter(NULL) != NULL)
+        fail("json_object_iter with non-object argument returned non-NULL");
+    if (json_object_iter(num) != NULL)
+        fail("json_object_iter with non-object argument returned non-NULL");
+
+    if (json_object_iter_at(NULL, "test") != NULL)
+        fail("json_object_iter_at with non-object argument returned non-NULL");
+    if (json_object_iter_at(num, "test") != NULL)
+        fail("json_object_iter_at with non-object argument returned non-NULL");
+    if (json_object_iter_at(obj, NULL) != NULL)
+        fail("json_object_iter_at with NULL iter returned non-NULL");
+
+    if (json_object_iter_next(obj, NULL) != NULL)
+        fail("json_object_iter_next with NULL iter returned non-NULL");
+    if (json_object_iter_next(num, iter) != NULL)
+        fail("json_object_iter_next with non-object argument returned non-NULL");
+
+    if (json_object_iter_key(NULL) != NULL)
+        fail("json_object_iter_key with NULL iter returned non-NULL");
+
+    if (json_object_key_to_iter(NULL) != NULL)
+        fail("json_object_key_to_iter with NULL iter returned non-NULL");
+
+    if (json_object_iter_value(NULL) != NULL)
+        fail("json_object_iter_value with NULL iter returned non-NULL");
+
+    if (!json_object_iter_set_new(NULL, iter, json_incref(num)))
+        fail("json_object_iter_set_new with non-object argument did not return "
+             "error");
+    if (!json_object_iter_set_new(num, iter, json_incref(num)))
+        fail("json_object_iter_set_new with non-object argument did not return "
+             "error");
+    if (!json_object_iter_set_new(obj, NULL, json_incref(num)))
+        fail("json_object_iter_set_new with NULL iter did not return error");
+    if (!json_object_iter_set_new(obj, iter, NULL))
+        fail("json_object_iter_set_new with NULL value did not return error");
+
+    if (obj->refcount != 1)
+        fail("unexpected reference count for obj");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count for num");
+
+    json_decref(obj);
+    json_decref(num);
+}
+
+static void run_tests() {
+    test_misc();
+    test_clear();
+    test_update();
+    test_set_many_keys();
+    test_conditional_updates();
+    test_recursive_updates();
+    test_circular();
+    test_set_nocheck();
+    test_iterators();
+    test_preserve_order();
+    test_object_foreach();
+    test_object_foreach_safe();
+    test_bad_args();
+}

+ 547 - 0
jansson.mod/jansson/test/suites/api/test_pack.c

@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ * Copyright (c) 2010-2012 Graeme Smecher <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <jansson_private_config.h>
+#endif
+
+#include <jansson_config.h>
+
+#include "util.h"
+#include <jansson.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef INFINITY
+// This test triggers "warning C4756: overflow in constant arithmetic"
+// in Visual Studio. This warning is triggered here by design, so disable it.
+// (This can only be done on function level so we keep these tests separate)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4756)
+#endif
+static void test_inifity() {
+    json_error_t error;
+
+    if (json_pack_ex(&error, 0, "f", INFINITY))
+        fail("json_pack infinity incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                1, 1);
+
+    if (json_pack_ex(&error, 0, "[f]", INFINITY))
+        fail("json_pack infinity array element incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                2, 2);
+
+    if (json_pack_ex(&error, 0, "{s:f}", "key", INFINITY))
+        fail("json_pack infinity object value incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                4, 4);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+#endif // INFINITY
+
+static void run_tests() {
+    json_t *value;
+    int i;
+    char buffer[4] = {'t', 'e', 's', 't'};
+    json_error_t error;
+
+    /*
+     * Simple, valid json_pack cases
+     */
+    /* true */
+    value = json_pack("b", 1);
+    if (!json_is_true(value))
+        fail("json_pack boolean failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack boolean refcount failed");
+    json_decref(value);
+
+    /* false */
+    value = json_pack("b", 0);
+    if (!json_is_false(value))
+        fail("json_pack boolean failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack boolean refcount failed");
+    json_decref(value);
+
+    /* null */
+    value = json_pack("n");
+    if (!json_is_null(value))
+        fail("json_pack null failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack null refcount failed");
+    json_decref(value);
+
+    /* integer */
+    value = json_pack("i", 1);
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack integer failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* integer from json_int_t */
+    value = json_pack("I", (json_int_t)555555);
+    if (!json_is_integer(value) || json_integer_value(value) != 555555)
+        fail("json_pack json_int_t failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* real */
+    value = json_pack("f", 1.0);
+    if (!json_is_real(value) || json_real_value(value) != 1.0)
+        fail("json_pack real failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack real refcount failed");
+    json_decref(value);
+
+    /* string */
+    value = json_pack("s", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string refcount failed");
+    json_decref(value);
+
+    /* nullable string (defined case) */
+    value = json_pack("s?", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack nullable string (defined case) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack nullable string (defined case) refcount failed");
+    json_decref(value);
+
+    /* nullable string (NULL case) */
+    value = json_pack("s?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack nullable string (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack nullable string (NULL case) refcount failed");
+    json_decref(value);
+
+    /* nullable string concatenation */
+    if (json_pack_ex(&error, 0, "s?+", "test", "ing"))
+        fail("json_pack failed to catch invalid format 's?+'");
+    check_error(json_error_invalid_format, "Cannot use '+' on optional strings",
+                "<format>", 1, 2, 2);
+
+    /* nullable string with integer length */
+    if (json_pack_ex(&error, 0, "s?#", "test", 4))
+        fail("json_pack failed to catch invalid format 's?#'");
+    check_error(json_error_invalid_format, "Cannot use '#' on optional strings",
+                "<format>", 1, 2, 2);
+
+    /* string and length (int) */
+    value = json_pack("s#", "test asdf", 4);
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string and length failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string and length refcount failed");
+    json_decref(value);
+
+    /* string and length (size_t) */
+    value = json_pack("s%", "test asdf", (size_t)4);
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string and length failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string and length refcount failed");
+    json_decref(value);
+
+    /* string and length (int), non-NUL terminated string */
+    value = json_pack("s#", buffer, 4);
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string and length (int) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string and length (int) refcount failed");
+    json_decref(value);
+
+    /* string and length (size_t), non-NUL terminated string */
+    value = json_pack("s%", buffer, (size_t)4);
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string and length (size_t) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string and length (size_t) refcount failed");
+    json_decref(value);
+
+    /* string concatenation */
+    if (json_pack("s+", "test", NULL))
+        fail("json_pack string concatenation succeeded with NULL string");
+
+    value = json_pack("s++", "te", "st", "ing");
+    if (!json_is_string(value) || strcmp("testing", json_string_value(value)))
+        fail("json_pack string concatenation failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string concatenation refcount failed");
+    json_decref(value);
+
+    /* string concatenation and length (int) */
+    value = json_pack("s#+#+", "test", 1, "test", 2, "test");
+    if (!json_is_string(value) || strcmp("ttetest", json_string_value(value)))
+        fail("json_pack string concatenation and length (int) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string concatenation and length (int) refcount failed");
+    json_decref(value);
+
+    /* string concatenation and length (size_t) */
+    value = json_pack("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
+    if (!json_is_string(value) || strcmp("ttetest", json_string_value(value)))
+        fail("json_pack string concatenation and length (size_t) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string concatenation and length (size_t) refcount "
+             "failed");
+    json_decref(value);
+
+    /* empty object */
+    value = json_pack("{}", 1.0);
+    if (!json_is_object(value) || json_object_size(value) != 0)
+        fail("json_pack empty object failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack empty object refcount failed");
+    json_decref(value);
+
+    /* empty list */
+    value = json_pack("[]", 1.0);
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack empty list failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack empty list failed");
+    json_decref(value);
+
+    /* non-incref'd object */
+    value = json_pack("o", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack object failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* non-incref'd nullable object (defined case) */
+    value = json_pack("o?", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack nullable object (defined case) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack nullable object (defined case) refcount failed");
+    json_decref(value);
+
+    /* non-incref'd nullable object (NULL case) */
+    value = json_pack("o?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack nullable object (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack nullable object (NULL case) refcount failed");
+    json_decref(value);
+
+    /* incref'd object */
+    value = json_pack("O", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack object failed");
+    if (value->refcount != (size_t)2)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+    json_decref(value);
+
+    /* incref'd nullable object (defined case) */
+    value = json_pack("O?", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack incref'd nullable object (defined case) failed");
+    if (value->refcount != (size_t)2)
+        fail("json_pack incref'd nullable object (defined case) refcount "
+             "failed");
+    json_decref(value);
+    json_decref(value);
+
+    /* incref'd nullable object (NULL case) */
+    value = json_pack("O?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack incref'd nullable object (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack incref'd nullable object (NULL case) refcount failed");
+
+    /* simple object */
+    value = json_pack("{s:[]}", "foo");
+    if (!json_is_object(value) || json_object_size(value) != 1)
+        fail("json_pack array failed");
+    if (!json_is_array(json_object_get(value, "foo")))
+        fail("json_pack array failed");
+    if (json_object_get(value, "foo")->refcount != (size_t)1)
+        fail("json_pack object refcount failed");
+    json_decref(value);
+
+    /* object with complex key */
+    value = json_pack("{s+#+: []}", "foo", "barbar", 3, "baz");
+    if (!json_is_object(value) || json_object_size(value) != 1)
+        fail("json_pack array failed");
+    if (!json_is_array(json_object_get(value, "foobarbaz")))
+        fail("json_pack array failed");
+    if (json_object_get(value, "foobarbaz")->refcount != (size_t)1)
+        fail("json_pack object refcount failed");
+    json_decref(value);
+
+    /* object with optional members */
+    value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
+    if (value)
+        fail("json_pack object optional incorrectly succeeded");
+
+    value = json_pack("{s:**}", "a", NULL);
+    if (value)
+        fail("json_pack object optional invalid incorrectly succeeded");
+
+    if (json_pack_ex(&error, 0, "{s:i*}", "a", 1))
+        fail("json_pack object optional invalid incorrectly succeeded");
+    check_error(json_error_invalid_format, "Expected format 's', got '*'", "<format>", 1,
+                5, 5);
+
+    value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
+    if (!json_is_object(value) || json_object_size(value) != 0)
+        fail("json_pack object optional failed");
+    json_decref(value);
+
+    value = json_pack("{s:s*}", "key", "\xff\xff");
+    if (value)
+        fail("json_pack object optional with invalid UTF-8 incorrectly "
+             "succeeded");
+
+    if (json_pack_ex(&error, 0, "{s: s*#}", "key", "test", 1))
+        fail("json_pack failed to catch invalid format 's*#'");
+    check_error(json_error_invalid_format, "Cannot use '#' on optional strings",
+                "<format>", 1, 6, 6);
+
+    if (json_pack_ex(&error, 0, "{s: s*+}", "key", "test", "ing"))
+        fail("json_pack failed to catch invalid format 's*+'");
+    check_error(json_error_invalid_format, "Cannot use '+' on optional strings",
+                "<format>", 1, 6, 6);
+
+    /* simple array */
+    value = json_pack("[i,i,i]", 0, 1, 2);
+    if (!json_is_array(value) || json_array_size(value) != 3)
+        fail("json_pack object failed");
+    for (i = 0; i < 3; i++) {
+        if (!json_is_integer(json_array_get(value, i)) ||
+            json_integer_value(json_array_get(value, i)) != i)
+
+            fail("json_pack integer array failed");
+    }
+    json_decref(value);
+
+    /* simple array with optional members */
+    value = json_pack("[s,o,O]", NULL, NULL, NULL);
+    if (value)
+        fail("json_pack array optional incorrectly succeeded");
+
+    if (json_pack_ex(&error, 0, "[i*]", 1))
+        fail("json_pack array optional invalid incorrectly succeeded");
+    check_error(json_error_invalid_format, "Unexpected format character '*'", "<format>",
+                1, 3, 3);
+
+    value = json_pack("[**]", NULL);
+    if (value)
+        fail("json_pack array optional invalid incorrectly succeeded");
+    value = json_pack("[s*,o*,O*]", NULL, NULL, NULL);
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack array optional failed");
+    json_decref(value);
+
+#ifdef NAN
+    /* Invalid float values */
+    if (json_pack_ex(&error, 0, "f", NAN))
+        fail("json_pack NAN incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                1, 1);
+
+    if (json_pack_ex(&error, 0, "[f]", NAN))
+        fail("json_pack NAN array element incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                2, 2);
+
+    if (json_pack_ex(&error, 0, "{s:f}", "key", NAN))
+        fail("json_pack NAN object value incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                4, 4);
+#endif
+
+#ifdef INFINITY
+    test_inifity();
+#endif
+
+    /* Whitespace; regular string */
+    value = json_pack(" s\t ", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string (with whitespace) failed");
+    json_decref(value);
+
+    /* Whitespace; empty array */
+    value = json_pack("[ ]");
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack empty array (with whitespace) failed");
+    json_decref(value);
+
+    /* Whitespace; array */
+    value = json_pack("[ i , i,  i ] ", 1, 2, 3);
+    if (!json_is_array(value) || json_array_size(value) != 3)
+        fail("json_pack array (with whitespace) failed");
+    json_decref(value);
+
+    /*
+     * Invalid cases
+     */
+
+    /* newline in format string */
+    if (json_pack_ex(&error, 0, "{\n\n1"))
+        fail("json_pack failed to catch invalid format '1'");
+    check_error(json_error_invalid_format, "Expected format 's', got '1'", "<format>", 3,
+                1, 4);
+
+    /* mismatched open/close array/object */
+    if (json_pack_ex(&error, 0, "[}"))
+        fail("json_pack failed to catch mismatched '}'");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "{]"))
+        fail("json_pack failed to catch mismatched ']'");
+    check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1,
+                2, 2);
+
+    /* missing close array */
+    if (json_pack_ex(&error, 0, "["))
+        fail("json_pack failed to catch missing ']'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+
+    /* missing close object */
+    if (json_pack_ex(&error, 0, "{"))
+        fail("json_pack failed to catch missing '}'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+
+    /* garbage after format string */
+    if (json_pack_ex(&error, 0, "[i]a", 42))
+        fail("json_pack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                4, 4);
+
+    if (json_pack_ex(&error, 0, "ia", 42))
+        fail("json_pack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                2, 2);
+
+    /* NULL string */
+    if (json_pack_ex(&error, 0, "s", NULL))
+        fail("json_pack failed to catch null argument string");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 1, 1);
+
+    /* + on its own */
+    if (json_pack_ex(&error, 0, "+", NULL))
+        fail("json_pack failed to a lone +");
+    check_error(json_error_invalid_format, "Unexpected format character '+'", "<format>",
+                1, 1, 1);
+
+    /* Empty format */
+    if (json_pack_ex(&error, 0, ""))
+        fail("json_pack failed to catch empty format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+
+    /* NULL format */
+    if (json_pack_ex(&error, 0, NULL))
+        fail("json_pack failed to catch NULL format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+
+    /* NULL key */
+    if (json_pack_ex(&error, 0, "{s:i}", NULL, 1))
+        fail("json_pack failed to catch NULL key");
+    check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2);
+
+    /* NULL value followed by object still steals the object's ref */
+    value = json_incref(json_object());
+    if (json_pack_ex(&error, 0, "{s:s,s:o}", "badnull", NULL, "dontleak", value))
+        fail("json_pack failed to catch NULL value");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 4, 4);
+    if (value->refcount != (size_t)1)
+        fail("json_pack failed to steal reference after error.");
+    json_decref(value);
+
+    /* More complicated checks for row/columns */
+    if (json_pack_ex(&error, 0, "{ {}: s }", "foo"))
+        fail("json_pack failed to catch object as key");
+    check_error(json_error_invalid_format, "Expected format 's', got '{'", "<format>", 1,
+                3, 3);
+
+    /* Complex object */
+    if (json_pack_ex(&error, 0, "{ s: {},  s:[ii{} }", "foo", "bar", 12, 13))
+        fail("json_pack failed to catch missing ]");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 19, 19);
+
+    /* Complex array */
+    if (json_pack_ex(&error, 0, "[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]"))
+        fail("json_pack failed to catch extra }");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 21, 21);
+
+    /* Invalid UTF-8 in object key */
+    if (json_pack_ex(&error, 0, "{s:i}", "\xff\xff", 42))
+        fail("json_pack failed to catch invalid UTF-8 in an object key");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 2, 2);
+
+    /* Invalid UTF-8 in a string */
+    if (json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in a string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 4, 4);
+
+    /* Invalid UTF-8 in an optional '?' string */
+    if (json_pack_ex(&error, 0, "{s:s?}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in an optional '?' "
+             "string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
+
+    /* Invalid UTF-8 in an optional '*' string */
+    if (json_pack_ex(&error, 0, "{s:s*}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in an optional '*' "
+             "string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
+
+    /* Invalid UTF-8 in a concatenated key */
+    if (json_pack_ex(&error, 0, "{s+:i}", "\xff\xff", "concat", 42))
+        fail("json_pack failed to catch invalid UTF-8 in an object key");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 3, 3);
+
+    if (json_pack_ex(&error, 0, "{s:o}", "foo", NULL))
+        fail("json_pack failed to catch nullable object");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
+
+    if (json_pack_ex(&error, 0, "{s:O}", "foo", NULL))
+        fail("json_pack failed to catch nullable incref object");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
+
+    if (json_pack_ex(&error, 0, "{s+:o}", "foo", "bar", NULL))
+        fail("json_pack failed to catch non-nullable object value");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 5, 5);
+
+    if (json_pack_ex(&error, 0, "[1s", "Hi"))
+        fail("json_pack failed to catch invalid format");
+    check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "[1s+", "Hi", "ya"))
+        fail("json_pack failed to catch invalid format");
+    check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "[so]", NULL, json_object()))
+        fail("json_pack failed to catch NULL value");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 2, 2);
+}

+ 287 - 0
jansson.mod/jansson/test/suites/api/test_simple.c

@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_bad_args(void) {
+    json_t *num = json_integer(1);
+    json_t *txt = json_string("test");
+
+    if (!num || !txt)
+        fail("failed to allocate test objects");
+
+    if (json_string_nocheck(NULL) != NULL)
+        fail("json_string_nocheck with NULL argument did not return NULL");
+    if (json_stringn_nocheck(NULL, 0) != NULL)
+        fail("json_stringn_nocheck with NULL argument did not return NULL");
+    if (json_string(NULL) != NULL)
+        fail("json_string with NULL argument did not return NULL");
+    if (json_stringn(NULL, 0) != NULL)
+        fail("json_stringn with NULL argument did not return NULL");
+
+    if (json_string_length(NULL) != 0)
+        fail("json_string_length with non-string argument did not return 0");
+    if (json_string_length(num) != 0)
+        fail("json_string_length with non-string argument did not return 0");
+
+    if (json_string_value(NULL) != NULL)
+        fail("json_string_value with non-string argument did not return NULL");
+    if (json_string_value(num) != NULL)
+        fail("json_string_value with non-string argument did not return NULL");
+
+    if (!json_string_setn_nocheck(NULL, "", 0))
+        fail("json_string_setn with non-string argument did not return error");
+    if (!json_string_setn_nocheck(num, "", 0))
+        fail("json_string_setn with non-string argument did not return error");
+    if (!json_string_setn_nocheck(txt, NULL, 0))
+        fail("json_string_setn_nocheck with NULL value did not return error");
+
+    if (!json_string_set_nocheck(txt, NULL))
+        fail("json_string_set_nocheck with NULL value did not return error");
+    if (!json_string_set(txt, NULL))
+        fail("json_string_set with NULL value did not return error");
+    if (!json_string_setn(txt, NULL, 0))
+        fail("json_string_setn with NULL value did not return error");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count for num");
+    if (txt->refcount != 1)
+        fail("unexpected reference count for txt");
+
+    json_decref(num);
+    json_decref(txt);
+}
+
+/* Call the simple functions not covered by other tests of the public API */
+static void run_tests() {
+    json_t *value;
+
+    value = json_boolean(1);
+    if (!json_is_true(value))
+        fail("json_boolean(1) failed");
+    json_decref(value);
+
+    value = json_boolean(-123);
+    if (!json_is_true(value))
+        fail("json_boolean(-123) failed");
+    json_decref(value);
+
+    value = json_boolean(0);
+    if (!json_is_false(value))
+        fail("json_boolean(0) failed");
+    if (json_boolean_value(value) != 0)
+        fail("json_boolean_value failed");
+    json_decref(value);
+
+    value = json_integer(1);
+    if (json_typeof(value) != JSON_INTEGER)
+        fail("json_typeof failed");
+
+    if (json_is_object(value))
+        fail("json_is_object failed");
+
+    if (json_is_array(value))
+        fail("json_is_array failed");
+
+    if (json_is_string(value))
+        fail("json_is_string failed");
+
+    if (!json_is_integer(value))
+        fail("json_is_integer failed");
+
+    if (json_is_real(value))
+        fail("json_is_real failed");
+
+    if (!json_is_number(value))
+        fail("json_is_number failed");
+
+    if (json_is_true(value))
+        fail("json_is_true failed");
+
+    if (json_is_false(value))
+        fail("json_is_false failed");
+
+    if (json_is_boolean(value))
+        fail("json_is_boolean failed");
+
+    if (json_is_null(value))
+        fail("json_is_null failed");
+
+    json_decref(value);
+
+    value = json_string("foo");
+    if (!value)
+        fail("json_string failed");
+    if (strcmp(json_string_value(value), "foo"))
+        fail("invalid string value");
+    if (json_string_length(value) != 3)
+        fail("invalid string length");
+
+    if (json_string_set(value, "barr"))
+        fail("json_string_set failed");
+    if (strcmp(json_string_value(value), "barr"))
+        fail("invalid string value");
+    if (json_string_length(value) != 4)
+        fail("invalid string length");
+
+    if (json_string_setn(value, "hi\0ho", 5))
+        fail("json_string_set failed");
+    if (memcmp(json_string_value(value), "hi\0ho\0", 6))
+        fail("invalid string value");
+    if (json_string_length(value) != 5)
+        fail("invalid string length");
+
+    json_decref(value);
+
+    value = json_string(NULL);
+    if (value)
+        fail("json_string(NULL) failed");
+
+    /* invalid UTF-8  */
+    value = json_string("a\xefz");
+    if (value)
+        fail("json_string(<invalid utf-8>) failed");
+
+    value = json_string_nocheck("foo");
+    if (!value)
+        fail("json_string_nocheck failed");
+    if (strcmp(json_string_value(value), "foo"))
+        fail("invalid string value");
+    if (json_string_length(value) != 3)
+        fail("invalid string length");
+
+    if (json_string_set_nocheck(value, "barr"))
+        fail("json_string_set_nocheck failed");
+    if (strcmp(json_string_value(value), "barr"))
+        fail("invalid string value");
+    if (json_string_length(value) != 4)
+        fail("invalid string length");
+
+    if (json_string_setn_nocheck(value, "hi\0ho", 5))
+        fail("json_string_set failed");
+    if (memcmp(json_string_value(value), "hi\0ho\0", 6))
+        fail("invalid string value");
+    if (json_string_length(value) != 5)
+        fail("invalid string length");
+
+    json_decref(value);
+
+    /* invalid UTF-8 */
+    value = json_string_nocheck("qu\xff");
+    if (!value)
+        fail("json_string_nocheck failed");
+    if (strcmp(json_string_value(value), "qu\xff"))
+        fail("invalid string value");
+    if (json_string_length(value) != 3)
+        fail("invalid string length");
+
+    if (json_string_set_nocheck(value, "\xfd\xfe\xff"))
+        fail("json_string_set_nocheck failed");
+    if (strcmp(json_string_value(value), "\xfd\xfe\xff"))
+        fail("invalid string value");
+    if (json_string_length(value) != 3)
+        fail("invalid string length");
+
+    json_decref(value);
+
+    value = json_integer(123);
+    if (!value)
+        fail("json_integer failed");
+    if (json_integer_value(value) != 123)
+        fail("invalid integer value");
+    if (json_number_value(value) != 123.0)
+        fail("invalid number value");
+
+    if (json_integer_set(value, 321))
+        fail("json_integer_set failed");
+    if (json_integer_value(value) != 321)
+        fail("invalid integer value");
+    if (json_number_value(value) != 321.0)
+        fail("invalid number value");
+
+    json_decref(value);
+
+    value = json_real(123.123);
+    if (!value)
+        fail("json_real failed");
+    if (json_real_value(value) != 123.123)
+        fail("invalid integer value");
+    if (json_number_value(value) != 123.123)
+        fail("invalid number value");
+
+    if (json_real_set(value, 321.321))
+        fail("json_real_set failed");
+    if (json_real_value(value) != 321.321)
+        fail("invalid real value");
+    if (json_number_value(value) != 321.321)
+        fail("invalid number value");
+
+    json_decref(value);
+
+    value = json_true();
+    if (!value)
+        fail("json_true failed");
+    json_decref(value);
+
+    value = json_false();
+    if (!value)
+        fail("json_false failed");
+    json_decref(value);
+
+    value = json_null();
+    if (!value)
+        fail("json_null failed");
+    json_decref(value);
+
+    /* Test reference counting on singletons (true, false, null) */
+    value = json_true();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+
+    value = json_false();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+
+    value = json_null();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+
+#ifdef json_auto_t
+    value = json_string("foo");
+    {
+        json_auto_t *test = json_incref(value);
+        /* Use test so GCC doesn't complain it is unused. */
+        if (!json_is_string(test))
+            fail("value type check failed");
+    }
+    if (value->refcount != 1)
+        fail("automatic decrement failed");
+    json_decref(value);
+#endif
+
+    test_bad_args();
+}

+ 29 - 0
jansson.mod/jansson/test/suites/api/test_sprintf.c

@@ -0,0 +1,29 @@
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_sprintf() {
+    json_t *s = json_sprintf("foo bar %d", 42);
+    if (!s)
+        fail("json_sprintf returned NULL");
+    if (!json_is_string(s))
+        fail("json_sprintf didn't return a JSON string");
+    if (strcmp(json_string_value(s), "foo bar 42"))
+        fail("json_sprintf generated an unexpected string");
+
+    json_decref(s);
+
+    s = json_sprintf("%s", "");
+    if (!s)
+        fail("json_sprintf returned NULL");
+    if (!json_is_string(s))
+        fail("json_sprintf didn't return a JSON string");
+    if (json_string_length(s) != 0)
+        fail("string is not empty");
+    json_decref(s);
+
+    if (json_sprintf("%s", "\xff\xff"))
+        fail("json_sprintf unexpected success with invalid UTF");
+}
+
+static void run_tests() { test_sprintf(); }

+ 431 - 0
jansson.mod/jansson/test/suites/api/test_unpack.c

@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ * Copyright (c) 2010-2012 Graeme Smecher <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdio.h>
+#include <string.h>
+
+static void run_tests() {
+    json_t *j, *j2;
+    int i1, i2, i3;
+    json_int_t I1;
+    int rv;
+    size_t z;
+    double f;
+    char *s;
+
+    json_error_t error;
+
+    /*
+     * Simple, valid json_pack cases
+     */
+
+    /* true */
+    rv = json_unpack(json_true(), "b", &i1);
+    if (rv || !i1)
+        fail("json_unpack boolean failed");
+
+    /* false */
+    rv = json_unpack(json_false(), "b", &i1);
+    if (rv || i1)
+        fail("json_unpack boolean failed");
+
+    /* null */
+    if (json_unpack(json_null(), "n"))
+        fail("json_unpack null failed");
+
+    /* integer */
+    j = json_integer(42);
+    rv = json_unpack(j, "i", &i1);
+    if (rv || i1 != 42)
+        fail("json_unpack integer failed");
+    json_decref(j);
+
+    /* json_int_t */
+    j = json_integer(5555555);
+    rv = json_unpack(j, "I", &I1);
+    if (rv || I1 != 5555555)
+        fail("json_unpack json_int_t failed");
+    json_decref(j);
+
+    /* real */
+    j = json_real(1.7);
+    rv = json_unpack(j, "f", &f);
+    if (rv || f != 1.7)
+        fail("json_unpack real failed");
+    json_decref(j);
+
+    /* number */
+    j = json_integer(12345);
+    rv = json_unpack(j, "F", &f);
+    if (rv || f != 12345.0)
+        fail("json_unpack (real or) integer failed");
+    json_decref(j);
+
+    j = json_real(1.7);
+    rv = json_unpack(j, "F", &f);
+    if (rv || f != 1.7)
+        fail("json_unpack real (or integer) failed");
+    json_decref(j);
+
+    /* string */
+    j = json_string("foo");
+    rv = json_unpack(j, "s", &s);
+    if (rv || strcmp(s, "foo"))
+        fail("json_unpack string failed");
+    json_decref(j);
+
+    /* string with length (size_t) */
+    j = json_string("foo");
+    rv = json_unpack(j, "s%", &s, &z);
+    if (rv || strcmp(s, "foo") || z != 3)
+        fail("json_unpack string with length (size_t) failed");
+    json_decref(j);
+
+    /* empty object */
+    j = json_object();
+    if (json_unpack(j, "{}"))
+        fail("json_unpack empty object failed");
+    json_decref(j);
+
+    /* empty list */
+    j = json_array();
+    if (json_unpack(j, "[]"))
+        fail("json_unpack empty list failed");
+    json_decref(j);
+
+    /* non-incref'd object */
+    j = json_object();
+    rv = json_unpack(j, "o", &j2);
+    if (rv || j2 != j || j->refcount != 1)
+        fail("json_unpack object failed");
+    json_decref(j);
+
+    /* incref'd object */
+    j = json_object();
+    rv = json_unpack(j, "O", &j2);
+    if (rv || j2 != j || j->refcount != 2)
+        fail("json_unpack object failed");
+    json_decref(j);
+    json_decref(j);
+
+    /* simple object */
+    j = json_pack("{s:i}", "foo", 42);
+    rv = json_unpack(j, "{s:i}", "foo", &i1);
+    if (rv || i1 != 42)
+        fail("json_unpack simple object failed");
+    json_decref(j);
+
+    /* simple array */
+    j = json_pack("[iii]", 1, 2, 3);
+    rv = json_unpack(j, "[i,i,i]", &i1, &i2, &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack simple array failed");
+    json_decref(j);
+
+    /* object with many items & strict checking */
+    j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3);
+    rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack object with many items failed");
+    json_decref(j);
+
+    /*
+     * Invalid cases
+     */
+
+    j = json_integer(42);
+    if (!json_unpack_ex(j, &error, 0, "z"))
+        fail("json_unpack succeeded with invalid format character");
+    check_error(json_error_invalid_format, "Unexpected format character 'z'", "<format>",
+                1, 1, 1);
+
+    if (!json_unpack_ex(NULL, &error, 0, "[i]"))
+        fail("json_unpack succeeded with NULL root");
+    check_error(json_error_null_value, "NULL root value", "<root>", -1, -1, 0);
+    json_decref(j);
+
+    /* mismatched open/close array/object */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, "[}"))
+        fail("json_unpack failed to catch mismatched ']'");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    j = json_pack("{}");
+    if (!json_unpack_ex(j, &error, 0, "{]"))
+        fail("json_unpack failed to catch mismatched '}'");
+    check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1,
+                2, 2);
+    json_decref(j);
+
+    /* missing close array */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, "["))
+        fail("json_unpack failed to catch missing ']'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    /* missing close object */
+    j = json_pack("{}");
+    if (!json_unpack_ex(j, &error, 0, "{"))
+        fail("json_unpack failed to catch missing '}'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    /* garbage after format string */
+    j = json_pack("[i]", 42);
+    if (!json_unpack_ex(j, &error, 0, "[i]a", &i1))
+        fail("json_unpack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                4, 4);
+    json_decref(j);
+
+    j = json_integer(12345);
+    if (!json_unpack_ex(j, &error, 0, "ia", &i1))
+        fail("json_unpack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                2, 2);
+    json_decref(j);
+
+    /* NULL format string */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, NULL))
+        fail("json_unpack failed to catch null format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+    json_decref(j);
+
+    /* NULL string pointer */
+    j = json_string("foobie");
+    if (!json_unpack_ex(j, &error, 0, "s", NULL))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_null_value, "NULL string argument", "<args>", 1, 1, 1);
+    json_decref(j);
+
+    /* invalid types */
+    j = json_integer(42);
+    j2 = json_string("foo");
+    if (!json_unpack_ex(j, &error, 0, "s"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected string, got integer", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "n"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected null, got integer", "<validation>", 1, 1,
+                1);
+
+    if (!json_unpack_ex(j, &error, 0, "b"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected true or false, got integer",
+                "<validation>", 1, 1, 1);
+
+    if (!json_unpack_ex(j2, &error, 0, "i"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j2, &error, 0, "I"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "f"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected real, got integer", "<validation>", 1, 1,
+                1);
+
+    if (!json_unpack_ex(j2, &error, 0, "F"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected real or integer, got string",
+                "<validation>", 1, 1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "[i]"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected array, got integer", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "{si}", "foo"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected object, got integer", "<validation>", 1,
+                1, 1);
+
+    json_decref(j);
+    json_decref(j2);
+
+    /* Array index out of range */
+    j = json_pack("[i]", 1);
+    if (!json_unpack_ex(j, &error, 0, "[ii]", &i1, &i2))
+        fail("json_unpack failed to catch index out of array bounds");
+    check_error(json_error_index_out_of_range, "Array index 1 out of range",
+                "<validation>", 1, 3, 3);
+    json_decref(j);
+
+    /* NULL object key */
+    j = json_pack("{si}", "foo", 42);
+    if (!json_unpack_ex(j, &error, 0, "{si}", NULL, &i1))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2);
+    json_decref(j);
+
+    /* Object key not found */
+    j = json_pack("{si}", "foo", 42);
+    if (!json_unpack_ex(j, &error, 0, "{si}", "baz", &i1))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_item_not_found, "Object item not found: baz", "<validation>",
+                1, 3, 3);
+    json_decref(j);
+
+    /*
+     * Strict validation
+     */
+
+    j = json_pack("[iii]", 1, 2, 3);
+    rv = json_unpack(j, "[iii!]", &i1, &i2, &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack array with strict validation failed");
+    json_decref(j);
+
+    j = json_pack("[iii]", 1, 2, 3);
+    if (!json_unpack_ex(j, &error, 0, "[ii!]", &i1, &i2))
+        fail("json_unpack array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 5, 5);
+    json_decref(j);
+
+    /* Like above, but with JSON_STRICT instead of '!' format */
+    j = json_pack("[iii]", 1, 2, 3);
+    if (!json_unpack_ex(j, &error, JSON_STRICT, "[ii]", &i1, &i2))
+        fail("json_unpack array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 4, 4);
+    json_decref(j);
+
+    j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42);
+    rv = json_unpack(j, "{sssi!}", "foo", &s, "baz", &i1);
+    if (rv || strcmp(s, "bar") != 0 || i1 != 42)
+        fail("json_unpack object with strict validation failed");
+    json_decref(j);
+
+    /* Unpack the same item twice */
+    j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
+    if (!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
+        fail("json_unpack object with strict validation failed");
+    {
+        const char *possible_errors[] = {"2 object item(s) left unpacked: baz, quux",
+                                         "2 object item(s) left unpacked: quux, baz"};
+        check_errors(json_error_end_of_input_expected, possible_errors, 2, "<validation>",
+                     1, 10, 10);
+    }
+    json_decref(j);
+
+    j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4);
+    if (json_unpack_ex(j, NULL, JSON_STRICT | JSON_VALIDATE_ONLY, "[i{sisn}[ii]]", "foo",
+                       "bar"))
+        fail("json_unpack complex value with strict validation failed");
+    json_decref(j);
+
+    /* ! and * must be last */
+    j = json_pack("[ii]", 1, 2);
+    if (!json_unpack_ex(j, &error, 0, "[i!i]", &i1, &i2))
+        fail("json_unpack failed to catch ! in the middle of an array");
+    check_error(json_error_invalid_format, "Expected ']' after '!', got 'i'", "<format>",
+                1, 4, 4);
+
+    if (!json_unpack_ex(j, &error, 0, "[i*i]", &i1, &i2))
+        fail("json_unpack failed to catch * in the middle of an array");
+    check_error(json_error_invalid_format, "Expected ']' after '*', got 'i'", "<format>",
+                1, 4, 4);
+    json_decref(j);
+
+    j = json_pack("{sssi}", "foo", "bar", "baz", 42);
+    if (!json_unpack_ex(j, &error, 0, "{ss!si}", "foo", &s, "baz", &i1))
+        fail("json_unpack failed to catch ! in the middle of an object");
+    check_error(json_error_invalid_format, "Expected '}' after '!', got 's'", "<format>",
+                1, 5, 5);
+
+    if (!json_unpack_ex(j, &error, 0, "{ss*si}", "foo", &s, "baz", &i1))
+        fail("json_unpack failed to catch ! in the middle of an object");
+    check_error(json_error_invalid_format, "Expected '}' after '*', got 's'", "<format>",
+                1, 5, 5);
+    json_decref(j);
+
+    /* Error in nested object */
+    j = json_pack("{s{snsn}}", "foo", "bar", "baz");
+    if (!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar"))
+        fail("json_unpack nested object with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz",
+                "<validation>", 1, 7, 7);
+    json_decref(j);
+
+    /* Error in nested array */
+    j = json_pack("[[ii]]", 1, 2);
+    if (!json_unpack_ex(j, &error, 0, "[[i!]]", &i1))
+        fail("json_unpack nested array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 5, 5);
+    json_decref(j);
+
+    /* Optional values */
+    j = json_object();
+    i1 = 0;
+    if (json_unpack(j, "{s?i}", "foo", &i1))
+        fail("json_unpack failed for optional key");
+    if (i1 != 0)
+        fail("json_unpack unpacked an optional key");
+    json_decref(j);
+
+    i1 = 0;
+    j = json_pack("{si}", "foo", 42);
+    if (json_unpack(j, "{s?i}", "foo", &i1))
+        fail("json_unpack failed for an optional value");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack an optional value");
+    json_decref(j);
+
+    j = json_object();
+    i1 = i2 = i3 = 0;
+    if (json_unpack(j, "{s?[ii]s?{s{si}}}", "foo", &i1, &i2, "bar", "baz", "quux", &i3))
+        fail("json_unpack failed for complex optional values");
+    if (i1 != 0 || i2 != 0 || i3 != 0)
+        fail("json_unpack unexpectedly unpacked something");
+    json_decref(j);
+
+    j = json_pack("{s{si}}", "foo", "bar", 42);
+    if (json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1))
+        fail("json_unpack failed for complex optional values");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack");
+    json_decref(j);
+
+    /* Combine ? and ! */
+    j = json_pack("{si}", "foo", 42);
+    i1 = i2 = 0;
+    if (json_unpack(j, "{sis?i!}", "foo", &i1, "bar", &i2))
+        fail("json_unpack failed for optional values with strict mode");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack");
+    if (i2 != 0)
+        fail("json_unpack failed to unpack");
+    json_decref(j);
+
+    /* But don't compensate a missing key with an optional one. */
+    j = json_pack("{sisi}", "foo", 42, "baz", 43);
+    i1 = i2 = i3 = 0;
+    if (!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2))
+        fail("json_unpack failed for optional values with strict mode and "
+             "compensation");
+    check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz",
+                "<validation>", 1, 8, 8);
+    json_decref(j);
+}

+ 61 - 0
jansson.mod/jansson/test/suites/api/test_version.c

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Sean Bright <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_version_str(void) {
+    if (strcmp(jansson_version_str(), JANSSON_VERSION)) {
+        fail("jansson_version_str returned invalid version string");
+    }
+}
+
+static void test_version_cmp() {
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION)) {
+        fail("jansson_version_cmp equality check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION - 1, 0, 0) <= 0) {
+        fail("jansson_version_cmp less than check failed");
+    }
+
+    if (JANSSON_MINOR_VERSION) {
+        if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION - 1,
+                                JANSSON_MICRO_VERSION) <= 0) {
+            fail("jansson_version_cmp less than check failed");
+        }
+    }
+
+    if (JANSSON_MICRO_VERSION) {
+        if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                                JANSSON_MICRO_VERSION - 1) <= 0) {
+            fail("jansson_version_cmp less than check failed");
+        }
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION + 1, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION + 1,
+                            JANSSON_MICRO_VERSION) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION + 1) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+}
+
+static void run_tests() {
+    test_version_str();
+    test_version_cmp();
+}

+ 93 - 0
jansson.mod/jansson/test/suites/api/util.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#ifdef HAVE_CONFIG_H
+#include <jansson_private_config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <jansson.h>
+
+#define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__)
+
+#define fail(msg)                                                                        \
+    do {                                                                                 \
+        failhdr;                                                                         \
+        fprintf(stderr, "%s\n", msg);                                                    \
+        exit(1);                                                                         \
+    } while (0)
+
+/* Assumes json_error_t error */
+#define check_errors(code_, texts_, num_, source_, line_, column_, position_)            \
+    do {                                                                                 \
+        int i_, found_ = 0;                                                              \
+        if (json_error_code(&error) != code_) {                                          \
+            failhdr;                                                                     \
+            fprintf(stderr, "code: %d != %d\n", json_error_code(&error), code_);         \
+            exit(1);                                                                     \
+        }                                                                                \
+        for (i_ = 0; i_ < num_; i_++) {                                                  \
+            if (strcmp(error.text, texts_[i_]) == 0) {                                   \
+                found_ = 1;                                                              \
+                break;                                                                   \
+            }                                                                            \
+        }                                                                                \
+        if (!found_) {                                                                   \
+            failhdr;                                                                     \
+            if (num_ == 1) {                                                             \
+                fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]);      \
+            } else {                                                                     \
+                fprintf(stderr, "text: \"%s\" does not match\n", error.text);            \
+            }                                                                            \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (strcmp(error.source, source_) != 0) {                                        \
+            failhdr;                                                                     \
+                                                                                         \
+            fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_);        \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.line != line_) {                                                       \
+            failhdr;                                                                     \
+            fprintf(stderr, "line: %d != %d\n", error.line, line_);                      \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.column != column_) {                                                   \
+            failhdr;                                                                     \
+            fprintf(stderr, "column: %d != %d\n", error.column, column_);                \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.position != position_) {                                               \
+            failhdr;                                                                     \
+            fprintf(stderr, "position: %d != %d\n", error.position, position_);          \
+            exit(1);                                                                     \
+        }                                                                                \
+    } while (0)
+
+/* Assumes json_error_t error */
+#define check_error(code_, text_, source_, line_, column_, position_)                    \
+    check_errors(code_, &text_, 1, source_, line_, column_, position_)
+
+static void run_tests();
+
+int main() {
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+    run_tests();
+    return 0;
+}
+
+#endif

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/array/input

@@ -0,0 +1 @@
+[1, 2]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/array/output

@@ -0,0 +1 @@
+[1, 2]

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/output

@@ -0,0 +1 @@
+[1,2]

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/output

@@ -0,0 +1 @@
+{"a":1,"b":2}

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/env

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

+ 8 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/input

@@ -0,0 +1,8 @@
+[
+    "foo",
+    "å ä ö",
+    "foo åä",
+    "åä foo",
+    "å foo ä",
+    "clef g: 𝄞"
+]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/output

@@ -0,0 +1 @@
+["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"]

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/output

@@ -0,0 +1,4 @@
+[
+    1,
+    2
+]

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/output

@@ -0,0 +1,4 @@
+[
+    1,
+    2
+]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/output

@@ -0,0 +1,4 @@
+{
+    "a":1,
+    "b":2
+}

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-object/env

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

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

Some files were not shown because too many files changed in this diff