diff --git a/deps/jansson/.gitignore b/deps/jansson/.gitignore new file mode 100644 index 000000000..9189a9312 --- /dev/null +++ b/deps/jansson/.gitignore @@ -0,0 +1,28 @@ +*~ +*.o +*.a +.libs +.deps +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +*.lo +*.la +stamp-h1 +*.pyc +*.pc +/src/jansson_config.h +*.exe diff --git a/deps/jansson/.travis.yml b/deps/jansson/.travis.yml new file mode 100644 index 000000000..1cca27456 --- /dev/null +++ b/deps/jansson/.travis.yml @@ -0,0 +1,5 @@ +language: c +compiler: + - gcc + - clang +script: autoreconf -f -i && CFLAGS=-Werror ./configure && make check diff --git a/deps/jansson/Android.mk b/deps/jansson/Android.mk new file mode 100644 index 000000000..eb4fed7f2 --- /dev/null +++ b/deps/jansson/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm + +LOCAL_SRC_FILES := \ + src/dump.c \ + src/error.c \ + src/hashtable.c \ + src/load.c \ + src/memory.c \ + src/pack_unpack.c \ + src/strbuffer.c \ + src/strconv.c \ + src/utf.c \ + src/value.c + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/android \ + $(LOCAL_PATH)/src + +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libc +LOCAL_CFLAGS += -O3 + +LOCAL_MODULE:= libjansson + +include $(BUILD_SHARED_LIBRARY) diff --git a/deps/jansson/CHANGES b/deps/jansson/CHANGES new file mode 100644 index 000000000..7807904d4 --- /dev/null +++ b/deps/jansson/CHANGES @@ -0,0 +1,586 @@ +Version 2.6 (in development) +============================ + +Released XXXX-XX-XX + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s%`` and ``+%`` + for a size_t string length. + + - `json_unpack()` and friends: Add format specifier ``s%`` for + unpacking the string length along with the string itself. + + - Add length-aware string constructors `json_stringn()` and + `json_stringn_nocheck()`, length-aware string mutators + `json_string_setn()` and `json_string_setn_nocheck()`, and a + function for getting string's length `json_string_length()`. + + - Support ``\u0000`` escapes in the decoder. The support can be + enabled by using the ``JSON_ALLOW_NUL`` decoding flag. + +* Bug fixes: + + - Some malformed ``\uNNNN`` escapes could crash the decoder with an + assertion failure. + +* Other changes: + + - ``\uNNNN`` escapes are now encoded in upper case for better + readability. + + +Version 2.5 +=========== + +Released 2013-09-19 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and + ``+#``. + + - Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers + as real in the decoder (#123). + + - Add `json_array_foreach()`, paralleling `json_object_foreach()` + (#118). + +* Bug fixes: + + - `json_dumps()` and friends: Don't crash if json is *NULL* and + ``JSON_ENCODE_ANY`` is set. + + - Fix a theoretical integer overflow in `jsonp_strdup()`. + + - Fix `l_isxdigit()` macro (#97). + + - Fix an off-by-one error in `json_array_remove()`. + +* Build: + + - Support CMake in addition to GNU Autotools (#106, #107, #112, + #115, #120, #127). + + - Support building for Android (#109). + + - Don't use ``-Werror`` by default. + + - Support building and testing with VPATH (#93). + + - Fix compilation when ``NDEBUG`` is defined (#128) + +* Tests: + + - Fix a refleak in ``test/bin/json_process.c``. + +* Documentation: + + - Clarify the return value of `json_load_callback_t`. + + - Document how to circumvent problems with separate heaps on Windows. + + - Fix memory leaks and warnings in ``github_commits.c``. + + - Use `json_decref()` properly in tutorial. + +* Other: + + - Make it possible to forward declare ``struct json_t``. + + +Version 2.4 +=========== + +Released 2012-09-23 + +* New features: + + - Add `json_boolean()` macro that returns the JSON true or false + value based on its argument (#86). + + - Add `json_load_callback()` that calls a callback function + repeatedly to read the JSON input (#57). + + - Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of + ``/`` with ``\/``. + +* Bug fixes: + + - Check for and reject NaN and Inf values for reals. Encoding these + values resulted in invalid JSON. + + - Fix `json_real_set()` to return -1 on error. + +* Build: + + - Jansson now builds on Windows with Visual Studio 2010, and + includes solution and project files in ``win32/vs2010/`` + directory. + + - Fix build warnings (#77, #78). + + - Add ``-no-undefined`` to LDFLAGS (#90). + +* Tests: + + - Fix the symbol exports test on Linux/PPC64 (#88). + +* Documentation: + + - Fix typos (#73, #84). + + +Version 2.3.1 +============= + +Released 2012-04-20 + +* Build issues: + + - Only use ``long long`` if ``strtoll()`` is also available. + +* Documentation: + + - Fix the names of library version constants in documentation. (#52) + + - Change the tutorial to use GitHub API v3. (#65) + +* Tests: + + - Make some tests locale independent. (#51) + + - Distribute the library exports test in the tarball. + + - Make test run on shells that don't support the ``export FOO=bar`` + syntax. + + +Version 2.3 +=========== + +Released 2012-01-27 + +* New features: + + - `json_unpack()` and friends: Add support for optional object keys + with the ``{s?o}`` syntax. + + - Add `json_object_update_existing()` and + `json_object_update_missing()`, for updating only existing keys or + only adding missing keys to an object. (#37) + + - Add `json_object_foreach()` for more convenient iteration over + objects. (#45, #46) + + - When decoding JSON, write the number of bytes that were read from + input to ``error.position`` also on success. This is handy with + ``JSON_DISABLE_EOF_CHECK``. + + - Add support for decoding any JSON value, not just arrays or + objects. The support is enabled with the new ``JSON_DECODE_ANY`` + flag. Patch by Andrea Marchesini. (#4) + +* Bug fixes + + - Avoid problems with object's serial number growing too big. (#40, + #41) + + - Decoding functions now return NULL if the first argument is NULL. + Patch by Andrea Marchesini. + + - Include ``jansson_config.h.win32`` in the distribution tarball. + + - Remove ``+`` and leading zeros from exponents in the encoder. + (#39) + + - Make Jansson build and work on MinGW. (#39, #38) + +* Documentation + + - Note that the same JSON values must not be encoded in parallel by + separate threads. (#42) + + - Document MinGW support. + + +Version 2.2.1 +============= + +Released 2011-10-06 + +* Bug fixes: + + - Fix real number encoding and decoding under non-C locales. (#32) + + - Fix identifier decoding under non-UTF-8 locales. (#35) + + - `json_load_file()`: Open the input file in binary mode for maximum + compatiblity. + +* Documentation: + + - Clarify the lifecycle of the result of the ``s`` fromat of + `json_unpack()`. (#31) + + - Add some portability info. (#36) + + - Little clarifications here and there. + +* Other: + + - Some style fixes, issues detected by static analyzers. + + +Version 2.2 +=========== + +Released 2011-09-03 + +* New features: + + - `json_dump_callback()`: Pass the encoder output to a callback + function in chunks. + +* Bug fixes: + + - `json_string_set()`: Check that target is a string and value is + not NULL. + +* Other: + + - Documentation typo fixes and clarifications. + + +Version 2.1 +=========== + +Released 2011-06-10 + +* New features: + + - `json_loadb()`: Decode a string with a given size, useful if the + string is not null terminated. + + - Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON + value. By default, only arrays and objects can be encoded. (#19) + + - Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding + error if any JSON object in the input contins duplicate keys. (#3) + + - Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a + valid JSON input. This allows other data after the JSON data. + +* Bug fixes: + + - Fix an additional memory leak when memory allocation fails in + `json_object_set()` and friends. + + - Clear errno before calling `strtod()` for better portability. (#27) + +* Building: + + - Avoid set-but-not-used warning/error in a test. (#20) + +* Other: + + - Minor clarifications to documentation. + + +Version 2.0.1 +============= + +Released 2011-03-31 + +* Bug fixes: + + - Replace a few `malloc()` and `free()` calls with their + counterparts that support custom memory management. + + - Fix object key hashing in json_unpack() strict checking mode. + + - Fix the parentheses in ``JANSSON_VERSION_HEX`` macro. + + - Fix `json_object_size()` return value. + + - Fix a few compilation issues. + +* Portability: + + - Enhance portability of `va_copy()`. + + - Test framework portability enhancements. + +* Documentation: + + - Distribute ``doc/upgrading.rst`` with the source tarball. + + - Build documentation in strict mode in ``make distcheck``. + + +Version 2.0 +=========== + +Released 2011-02-28 + +This release is backwards incompatible with the 1.x release series. +See the chapter "Upgrading from older versions" in documentation for +details. + +* Backwards incompatible changes: + + - Unify unsigned integer usage in the API: All occurences of + unsigned int and unsigned long have been replaced with size_t. + + - Change JSON integer's underlying type to the widest signed integer + type available, i.e. long long if it's supported, otherwise long. + Add a typedef json_int_t that defines the type. + + - Change the maximum indentation depth to 31 spaces in encoder. This + frees up bits from the flags parameter of encoding functions + `json_dumpf()`, `json_dumps()` and `json_dump_file()`. + + - For future needs, add a flags parameter to all decoding functions + `json_loadf()`, `json_loads()` and `json_load_file()`. + +* New features + + - `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON + values based on a format string. + + - `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple + value extraction and validation functionality based on a format + string. + + - Add column, position and source fields to the ``json_error_t`` + struct. + + - Enhance error reporting in the decoder. + + - ``JANSSON_VERSION`` et al.: Preprocessor constants that define the + library version. + + - `json_set_alloc_funcs()`: Set custom memory allocation functions. + +* Fix many portability issues, especially on Windows. + +* Configuration + + - Add file ``jansson_config.h`` that contains site specific + configuration. It's created automatically by the configure script, + or can be created by hand if the configure script cannot be used. + The file ``jansson_config.h.win32`` can be used without + modifications on Windows systems. + + - Add a section to documentation describing how to build Jansson on + Windows. + + - Documentation now requires Sphinx 1.0 or newer. + + +Version 1.3 +=========== + +Released 2010-06-13 + +* New functions: + + - `json_object_iter_set()`, `json_object_iter_set_new()`: Change + object contents while iterating over it. + + - `json_object_iter_at()`: Return an iterator that points to a + specific object item. + +* New encoding flags: + + - ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object + keys. + +* Bug fixes: + + - Fix an error that occured when an array or object was first + encoded as empty, then populated with some data, and then + re-encoded + + - Fix the situation like above, but when the first encoding resulted + in an error + +* Documentation: + + - Clarify the documentation on reference stealing, providing an + example usage pattern + + +Version 1.2.1 +============= + +Released 2010-04-03 + +* Bug fixes: + + - Fix reference counting on ``true``, ``false`` and ``null`` + - Estimate real number underflows in decoder with 0.0 instead of + issuing an error + +* Portability: + + - Make ``int32_t`` available on all systems + - Support compilers that don't have the ``inline`` keyword + - Require Autoconf 2.60 (for ``int32_t``) + +* Tests: + + - Print test names correctly when ``VERBOSE=1`` + - ``test/suites/api``: Fail when a test fails + - Enhance tests for iterators + - Enhance tests for decoding texts that contain null bytes + +* Documentation: + + - Don't remove ``changes.rst`` in ``make clean`` + - Add a chapter on RFC conformance + + +Version 1.2 +=========== + +Released 2010-01-21 + +* New functions: + + - `json_equal()`: Test whether two JSON values are equal + - `json_copy()` and `json_deep_copy()`: Make shallow and deep copies + of JSON values + - Add a version of all functions taking a string argument that + doesn't check for valid UTF-8: `json_string_nocheck()`, + `json_string_set_nocheck()`, `json_object_set_nocheck()`, + `json_object_set_new_nocheck()` + +* New encoding flags: + + - ``JSON_SORT_KEYS``: Sort objects by key + - ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters + - ``JSON_COMPACT``: Use a compact representation with all unneeded + whitespace stripped + +* Bug fixes: + + - Revise and unify whitespace usage in encoder: Add spaces between + array and object items, never append newline to output. + - Remove const qualifier from the ``json_t`` parameter in + `json_string_set()`, `json_integer_set()` and `json_real_set`. + - Use ``int32_t`` internally for representing Unicode code points + (int is not enough on all platforms) + +* Other changes: + + - Convert ``CHANGES`` (this file) to reStructured text and add it to + HTML documentation + - The test system has been refactored. Python is no longer required + to run the tests. + - Documentation can now be built by invoking ``make html`` + - Support for pkg-config + + +Version 1.1.3 +============= + +Released 2009-12-18 + +* Encode reals correctly, so that first encoding and then decoding a + real always produces the same value +* Don't export private symbols in ``libjansson.so`` + + +Version 1.1.2 +============= + +Released 2009-11-08 + +* Fix a bug where an error message was not produced if the input file + could not be opened in `json_load_file()` +* Fix an assertion failure in decoder caused by a minus sign without a + digit after it +* Remove an unneeded include of ``stdint.h`` in ``jansson.h`` + + +Version 1.1.1 +============= + +Released 2009-10-26 + +* All documentation files were not distributed with v1.1; build + documentation in make distcheck to prevent this in the future +* Fix v1.1 release date in ``CHANGES`` + + +Version 1.1 +=========== + +Released 2009-10-20 + +* API additions and improvements: + + - Extend array and object APIs + - Add functions to modify integer, real and string values + - Improve argument validation + - Use unsigned int instead of ``uint32_t`` for encoding flags + +* Enhance documentation + + - Add getting started guide and tutorial + - Fix some typos + - General clarifications and cleanup + +* Check for integer and real overflows and underflows in decoder +* Make singleton values thread-safe (``true``, ``false`` and ``null``) +* Enhance circular reference handling +* Don't define ``-std=c99`` in ``AM_CFLAGS`` +* Add C++ guards to ``jansson.h`` +* Minor performance and portability improvements +* Expand test coverage + + +Version 1.0.4 +============= + +Released 2009-10-11 + +* Relax Autoconf version requirement to 2.59 +* Make Jansson compile on platforms where plain ``char`` is unsigned +* Fix API tests for object + + +Version 1.0.3 +============= + +Released 2009-09-14 + +* Check for integer and real overflows and underflows in decoder +* Use the Python json module for tests, or simplejson if the json + module is not found +* Distribute changelog (this file) + + +Version 1.0.2 +============= + +Released 2009-09-08 + +* Handle EOF correctly in decoder + + +Version 1.0.1 +============= + +Released 2009-09-04 + +* Fixed broken `json_is_boolean()` + + +Version 1.0 +=========== + +Released 2009-08-25 + +* Initial release diff --git a/deps/jansson/CMakeLists.txt b/deps/jansson/CMakeLists.txt new file mode 100644 index 000000000..446ec6e96 --- /dev/null +++ b/deps/jansson/CMakeLists.txt @@ -0,0 +1,481 @@ +# Notes: +# +# Author: Paul Harris, June 2012 +# Additions: Joakim Soderberg, Febuary 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 heirachy 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 2.8) +# required for exports? cmake_minimum_required (VERSION 2.8.6) +project (jansson C) + +# Options +OPTION (BUILD_SHARED_LIBS "Build shared libraries." OFF) + +if (MSVC) + # This option must match the settings used in your program, in particular if you + # are linking statically + OPTION( STATIC_CRT "Link the static CRT libraries" OFF ) +endif () + +# Set some nicer output dirs. +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + +# Give the debug version a different postfix for windows, +# so both the debug and release version can be built in the +# same build-tree on Windows (MSVC). +if (WIN32) + SET (CMAKE_DEBUG_POSTFIX "_d") +else (WIN32) +endif (WIN32) + +# This is how I thought it should go +# set (JANSSON_VERSION "2.3.1") +# set (JANSSON_SOVERSION 2) + +set(JANSSON_DISPLAY_VERSION "2.5") + +# This is what is required to match the same numbers as automake's +set (JANSSON_VERSION "4.5.0") +set (JANSSON_SOVERSION 4) + +# for CheckFunctionKeywords +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include (CheckFunctionExists) +include (CheckFunctionKeywords) +include (CheckIncludeFiles) +include (CheckTypeSize) + + +if (MSVC) + # Turn off Microsofts "security" warnings. + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" ) + + if (STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "/MT") + set(CMAKE_C_FLAGS_DEBUG "/MTd") + endif() + +endif() + +if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_C_FLAGS "-fPIC") +endif() + + + +# Check for the int-type includes +check_include_files (sys/types.h HAVE_SYS_TYPES_H) +check_include_files (inttypes.h HAVE_INTTYPES_H) +check_include_files (stdint.h HAVE_STDINT_H) + + +# Check our 64 bit integer sizes +check_type_size (__int64 __INT64) +check_type_size (int64_t INT64_T) +check_type_size ("long long" LONG_LONG_INT) + +# Check our 32 bit integer sizes +check_type_size (int32_t INT32_T) +check_type_size (__int32 __INT32) +check_type_size ("long" LONG_INT) +check_type_size ("int" INT) + +if (HAVE_INT32_T) + set (JSON_INT32 int32_t) +elseif (HAVE___INT32) + set (JSON_INT32 __int32) +elseif (HAVE_LONG AND (${LONG_INT} EQUAL 4)) + set (JSON_INT32 long) +elseif (HAVE_INT AND (${INT} EQUAL 4)) + set (JSON_INT32 int) +else () + message (FATAL_ERROR "Could not detect a valid 32 bit integer type") +endif () + +# Check for ssize_t and SSIZE_T existance. +check_type_size(ssize_t SSIZE_T) +check_type_size(SSIZE_T UPPERCASE_SSIZE_T) +if(NOT HAVE_SSIZE_T) + if(HAVE_UPPERCASE_SSIZE_T) + set(JSON_SSIZE SSIZE_T) + else() + set(JSON_SSIZE int) + endif() +endif() +set(CMAKE_EXTRA_INCLUDE_FILES "") + +# Check for all the variants of strtoll +check_function_exists (strtoll HAVE_STRTOLL) +check_function_exists (strtoq HAVE_STRTOQ) +check_function_exists (_strtoi64 HAVE__STRTOI64) + +# Figure out what variant we should use +if (HAVE_STRTOLL) + set (JSON_STRTOINT strtoll) +elseif (HAVE_STRTOQ) + set (JSON_STRTOINT strtoq) +elseif (HAVE__STRTOI64) + set (JSON_STRTOINT _strtoi64) +else () + # fallback to strtol (32 bit) + # this will set all the required variables + set (JSON_STRTOINT strtol) + set (JSON_INT_T long) + set (JSON_INTEGER_FORMAT "\"ld\"") +endif () + +# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function. +# detect what to use for the 64 bit type. +# Note: I will prefer long long if I can get it, as that is what the automake system aimed for. +if (NOT DEFINED JSON_INT_T) + if (HAVE_LONG_LONG_INT AND (${LONG_LONG_INT} EQUAL 8)) + set (JSON_INT_T "long long") + elseif (HAVE_INT64_T) + set (JSON_INT_T int64_t) + elseif (HAVE___INT64) + set (JSON_INT_T __int64) + else () + message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent") + endif () + + # Apparently, Borland BCC and MSVC wants I64d, + # Borland BCC could also accept LD + # and gcc wants ldd, + # I am not sure what cygwin will want, so I will assume I64d + + if (WIN32) # matches both msvc and cygwin + set (JSON_INTEGER_FORMAT "\"I64d\"") + else () + set (JSON_INTEGER_FORMAT "\"lld\"") + endif () +endif () + + +# If locale.h and localeconv() are available, define to 1, otherwise to 0. +check_include_files (locale.h HAVE_LOCALE_H) +check_function_exists (localeconv HAVE_LOCALECONV) + +if (HAVE_LOCALECONV AND HAVE_LOCALE_H) + set (JSON_HAVE_LOCALECONV 1) +else () + set (JSON_HAVE_LOCALECONV 0) +endif () + + +# check if we have setlocale +check_function_exists (setlocale HAVE_SETLOCALE) + + +# Check what the inline keyword is. +# Note that the original JSON_INLINE was always set to just 'inline', so this goes further. +check_function_keywords("inline") +check_function_keywords("__inline") +check_function_keywords("__inline__") + +if (HAVE_INLINE) + set (JSON_INLINE inline) +elseif (HAVE___INLINE) + set (JSON_INLINE __inline) +elseif (HAVE___INLINE__) + set (JSON_INLINE __inline__) +else (HAVE_INLINE) + # no inline on this platform + set (JSON_INLINE) +endif (HAVE_INLINE) + +# Find our snprintf +check_function_exists (snprintf HAVE_SNPRINTF) +check_function_exists (_snprintf HAVE__SNPRINTF) + +if (HAVE_SNPRINTF) + set (JSON_SNPRINTF snprintf) +elseif (HAVE__SNPRINTF) + set (JSON_SNPRINTF _snprintf) +endif () + +# Create pkg-conf file. +# (We use the same files as ./configure does, so we +# have to defined the same variables used there). +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR lib) +endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix ${CMAKE_INSTALL_PREFIX}) +set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) +set(VERSION ${JANSSON_DISPLAY_VERSION}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY) + +# configure the public config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/config.h) + +# and tell the source code to include it +add_definitions (-DHAVE_CONFIG_H) + +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) + +# Add the lib sources. +file (GLOB C_FILES src/*.c) + +if (BUILD_SHARED_LIBS) + + add_library (jansson SHARED ${C_FILES} src/jansson.def) + + set_target_properties (jansson PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) + +else () + + add_library (jansson ${C_FILES}) + +endif () + +# LIBRARY for linux +# RUNTIME for windows (when building shared) +install (TARGETS jansson + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION bin +) + +install (FILES + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION include) + +install (FILES + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# For building Documentation (uses Sphinx) +OPTION (BUILD_DOCS "Build documentation (uses python-sphinx)." ON) +if (BUILD_DOCS) + find_package(Sphinx) + + if (NOT SPHINX_FOUND) + message(WARNING "Sphinx not found. Cannot generate documentation! + Set -DBUILD_DOCS=0 to get rid of this message.") + else() + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Your Sphinx version is too old! + This project requires Sphinx v1.0 or above to produce + proper documentation (you have v${Sphinx_VERSION_STRING}). + You will get output but it will have errors.") + endif() + + # configured documentation tools and intermediate build results + set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") + + # Sphinx cache with pickled ReST documents + set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") + + # CMake could be used to build the conf.py file too, + # eg it could automatically write the version of the program or change the theme. + # if(NOT DEFINED SPHINX_THEME) + # set(SPHINX_THEME default) + # endif() + # + # if(NOT DEFINED SPHINX_THEME_DIR) + # set(SPHINX_THEME_DIR) + # endif() + # + # configure_file( + # "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + # "${BINARY_BUILD_DIR}/conf.py" + # @ONLY) + + # TODO: Add support for all sphinx builders: http://sphinx-doc.org/builders.html + + # Add documentation targets. + set(DOC_TARGETS html) + + OPTION(BUILD_MAN "Create a target for building man pages." ON) + + if (BUILD_MAN) + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.") + else() + list(APPEND DOC_TARGETS man) + endif() + endif() + + OPTION(BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF) + + if (BUILD_LATEX) + find_package(LATEX) + + if (NOT LATEX_COMPILER) + message("Couldn't find Latex, can't build latex docs using Sphinx") + else() + message("Latex found! If you have problems building, see Sphinx documentation for required Latex packages.") + list(APPEND DOC_TARGETS latex) + endif() + endif() + + # The doc target will build all documentation targets. + add_custom_target(doc) + + foreach (DOC_TARGET ${DOC_TARGETS}) + add_custom_target(${DOC_TARGET} + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b ${DOC_TARGET} + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${CMAKE_CURRENT_BINARY_DIR}/doc/${DOC_TARGET}" + COMMENT "Building ${DOC_TARGET} documentation with Sphinx") + + add_dependencies(doc ${DOC_TARGET}) + endforeach() + + message("Building documentation enabled for: ${DOC_TARGETS}") + endif() +endif () + + +OPTION (WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF) + +if (NOT WITHOUT_TESTS) + OPTION (TEST_WITH_VALGRIND "Enable valgrind tests." OFF) + + ENABLE_TESTING() + + if (TEST_WITH_VALGRIND) + # TODO: Add FindValgrind.cmake instead of having a hardcoded path. + + # enable valgrind + set(CMAKE_MEMORYCHECK_COMMAND valgrind) + set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS + "--leak-check=full --show-reachable=yes --track-origins=yes -q") + + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") + separate_arguments(MEMCHECK_COMMAND) + endif () + + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement -Werror) + endif () + + set(api_tests + test_array + test_copy + test_dump + test_dump_callback + test_equal + test_load + test_loadb + test_number + test_object + test_pack + test_simple + test_unpack) + + # Doing arithmetic on void pointers is not allowed by Microsofts compiler + # such as secure_malloc and secure_free is doing, so exclude it for now. + if (NOT MSVC) + list(APPEND api_tests test_memory_funcs) + endif() + + # Helper macro for building and linking a test program. + macro(build_testprog name dir) + add_executable(${name} ${dir}/${name}.c) + add_dependencies(${name} jansson) + target_link_libraries(${name} jansson) + endmacro(build_testprog) + + # Create executables and tests/valgrind tests for API tests. + foreach (test ${api_tests}) + build_testprog(${test} ${PROJECT_SOURCE_DIR}/test/suites/api) + add_test(${test} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test}) + + if (TEST_WITH_VALGRIND) + add_test(memcheck_${test} ${MEMCHECK_COMMAND} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test}) + endif () + endforeach () + + # Test harness for the suites tests. + build_testprog(json_process ${PROJECT_SOURCE_DIR}/test/bin) + + set(SUITES encoding-flags valid invalid invalid-unicode) + foreach (SUITE ${SUITES}) + file(GLOB TESTDIRS ${jansson_SOURCE_DIR}/test/suites/${SUITE}/*) + foreach (TESTDIR ${TESTDIRS}) + if (IS_DIRECTORY ${TESTDIR}) + get_filename_component(TNAME ${TESTDIR} NAME) + add_test(${SUITE}__${TNAME} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process ${TESTDIR}) + if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip) + add_test(${SUITE}__${TNAME}__strip + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process --strip ${TESTDIR}) + endif () + endif () + endforeach () + endforeach () + + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS json_process ${api_tests}) +endif () + diff --git a/deps/jansson/CleanSpec.mk b/deps/jansson/CleanSpec.mk new file mode 100644 index 000000000..b84e1b65e --- /dev/null +++ b/deps/jansson/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/deps/jansson/LICENSE b/deps/jansson/LICENSE new file mode 100644 index 000000000..a8fb5b82f --- /dev/null +++ b/deps/jansson/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009-2013 Petri Lehtinen + +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. diff --git a/deps/jansson/Makefile.am b/deps/jansson/Makefile.am new file mode 100644 index 000000000..9221cd19b --- /dev/null +++ b/deps/jansson/Makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = CHANGES LICENSE README.rst win32 +SUBDIRS = doc src test + +# "make distcheck" builds the dvi target, so use it to check that the +# documentation is built correctly. +dvi: + $(MAKE) SPHINXOPTS_EXTRA=-W html + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = jansson.pc + +if GCC +# These flags are gcc specific +export AM_CFLAGS = -Wall -Wextra -Wdeclaration-after-statement +endif diff --git a/deps/jansson/README.rst b/deps/jansson/README.rst new file mode 100644 index 000000000..a01cbc02d --- /dev/null +++ b/deps/jansson/README.rst @@ -0,0 +1,63 @@ +Jansson README +============== + +.. image:: https://travis-ci.org/akheron/jansson.png + :alt: Build status + :target: https://travis-ci.org/akheron/jansson + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Comprehensive documentation + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + + +Compilation and Installation +---------------------------- + +If you obtained a source tarball, just use the standard autotools +commands:: + + $ ./configure + $ make + $ make install + +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:: + + $ autoreconf -i + + +Documentation +------------- + +Prebuilt HTML documentation is available at +http://www.digip.org/jansson/doc/. + +The documentation source is in the ``doc/`` subdirectory. To generate +HTML documentation, invoke:: + + $ make html + +Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ +1.0 or newer is required to generate the documentation. + + +.. _Jansson: http://www.digip.org/jansson/ +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Sphinx: http://sphinx.pocoo.org/ diff --git a/deps/jansson/android/jansson_config.h b/deps/jansson/android/jansson_config.h new file mode 100644 index 000000000..c76940b4e --- /dev/null +++ b/deps/jansson/android/jansson_config.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 0 + +#endif diff --git a/deps/jansson/cmake/CheckFunctionKeywords.cmake b/deps/jansson/cmake/CheckFunctionKeywords.cmake new file mode 100644 index 000000000..44601fd4e --- /dev/null +++ b/deps/jansson/cmake/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/deps/jansson/cmake/FindSphinx.cmake b/deps/jansson/cmake/FindSphinx.cmake new file mode 100644 index 000000000..55539d42c --- /dev/null +++ b/deps/jansson/cmake/FindSphinx.cmake @@ -0,0 +1,301 @@ +# +# PART B. DOWNLOADING AGREEMENT - LICENSE FROM SBIA WITH RIGHT TO SUBLICENSE ("SOFTWARE LICENSE"). +# ------------------------------------------------------------------------------------------------ +# +# 1. As used in this Software License, "you" means the individual downloading and/or +# using, reproducing, modifying, displaying and/or distributing the Software and +# the institution or entity which employs or is otherwise affiliated with such +# individual in connection therewith. The Section of Biomedical Image Analysis, +# Department of Radiology at the Universiy of Pennsylvania ("SBIA") hereby grants +# you, with right to sublicense, with respect to SBIA's rights in the software, +# and data, if any, which is the subject of this Software License (collectively, +# the "Software"), a royalty-free, non-exclusive license to use, reproduce, make +# derivative works of, display and distribute the Software, provided that: +# (a) you accept and adhere to all of the terms and conditions of this Software +# License; (b) in connection with any copy of or sublicense of all or any portion +# of the Software, all of the terms and conditions in this Software License shall +# appear in and shall apply to such copy and such sublicense, including without +# limitation all source and executable forms and on any user documentation, +# prefaced with the following words: "All or portions of this licensed product +# (such portions are the "Software") have been obtained under license from the +# Section of Biomedical Image Analysis, Department of Radiology at the University +# of Pennsylvania and are subject to the following terms and conditions:" +# (c) you preserve and maintain all applicable attributions, copyright notices +# and licenses included in or applicable to the Software; (d) modified versions +# of the Software must be clearly identified and marked as such, and must not +# be misrepresented as being the original Software; and (e) you consider making, +# but are under no obligation to make, the source code of any of your modifications +# to the Software freely available to others on an open source basis. +# +# 2. The license granted in this Software License includes without limitation the +# right to (i) incorporate the Software into proprietary programs (subject to +# any restrictions applicable to such programs), (ii) add your own copyright +# statement to your modifications of the Software, and (iii) provide additional +# or different license terms and conditions in your sublicenses of modifications +# of the Software; provided that in each case your use, reproduction or +# distribution of such modifications otherwise complies with the conditions +# stated in this Software License. +# +# 3. This Software License does not grant any rights with respect to third party +# software, except those rights that SBIA has been authorized by a third +# party to grant to you, and accordingly you are solely responsible for +# (i) obtaining any permissions from third parties that you need to use, +# reproduce, make derivative works of, display and distribute the Software, +# and (ii) informing your sublicensees, including without limitation your +# end-users, of their obligations to secure any such required permissions. +# +# 4. The Software has been designed for research purposes only and has not been +# reviewed or approved by the Food and Drug Administration or by any other +# agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL APPLICATIONS ARE NEITHER +# RECOMMENDED NOR ADVISED. Any commercialization of the Software is at the +# sole risk of the party or parties engaged in such commercialization. +# You further agree to use, reproduce, make derivative works of, display +# and distribute the Software in compliance with all applicable governmental +# laws, regulations and orders, including without limitation those relating +# to export and import control. +# +# 5. The Software is provided "AS IS" and neither SBIA nor any contributor to +# the software (each a "Contributor") shall have any obligation to provide +# maintenance, support, updates, enhancements or modifications thereto. +# SBIA AND ALL CONTRIBUTORS SPECIFICALLY DISCLAIM ALL EXPRESS AND IMPLIED +# WARRANTIES OF ANY KIND INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL SBIA OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR +# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED +# TO THE SOFTWARE, EVEN IF SBIA OR ANY CONTRIBUTOR HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT NOT PROHIBITED BY LAW OR +# REGULATION, YOU FURTHER ASSUME ALL LIABILITY FOR YOUR USE, REPRODUCTION, +# MAKING OF DERIVATIVE WORKS, DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE +# AND AGREE TO INDEMNIFY AND HOLD HARMLESS SBIA AND ALL CONTRIBUTORS FROM +# AND AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS ARISING +# THEREFROM. +# +# 6. None of the names, logos or trademarks of SBIA or any of SBIA's affiliates +# or any of the Contributors, or any funding agency, may be used to endorse +# or promote products produced in whole or in part by operation of the Software +# or derived from or based on the Software without specific prior written +# permission from the applicable party. +# +# 7. Any use, reproduction or distribution of the Software which is not in accordance +# with this Software License shall automatically revoke all rights granted to you +# under this Software License and render Paragraphs 1 and 2 of this Software +# License null and void. +# +# 8. This Software License does not grant any rights in or to any intellectual +# property owned by SBIA or any Contributor except those rights expressly +# granted hereunder. +# +# +# PART C. MISCELLANEOUS +# --------------------- +# +# This Agreement shall be governed by and construed in accordance with the laws +# of The Commonwealth of Pennsylvania without regard to principles of conflicts +# of law. This Agreement shall supercede and replace any license terms that you +# may have agreed to previously with respect to Software from SBIA. +# +############################################################################## +# @file FindSphinx.cmake +# @brief Find Sphinx documentation build tools. +# +# @par Input variables: +# +# +# @tp @b Sphinx_DIR @endtp +# +# +# +# @tp @b SPHINX_DIR @endtp +# +# +# +# @tp @b Sphinx_FIND_COMPONENTS @endtp +# +# +#
Installation directory of Sphinx tools. Can also be set as environment variable.
Alternative environment variable for @c Sphinx_DIR.
Sphinx build tools to look for, i.e., 'apidoc' and/or 'build'.
+# +# @par Output variables: +# +# +# @tp @b Sphinx_FOUND @endtp +# +# +# +# @tp @b SPHINX_FOUND @endtp +# +# +# @tp @b SPHINX_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_OPTIONS @endtp +# +# +# +# @tp @b Sphinx-build_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx-apidoc_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_VERSION_STRING @endtp +# +# +# +# @tp @b Sphinx_VERSION_MAJOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_MINOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_PATCH @endtp +# +# +#
Whether all or only the requested Sphinx build tools were found.
Alias for @c Sphinx_FOUND. +#
Non-cached alias for @c Sphinx-build_EXECUTABLE.
Python executable used to run sphinx-build. This is either the +# by default found Python interpreter or a specific version as +# specified by the shebang (#!) of the sphinx-build script.
A list of Python options extracted from the shebang (#!) of the +# sphinx-build script. The -E option is added by this module +# if the Python executable is not the system default to avoid +# problems with a differing setting of the @c PYTHONHOME.
Absolute path of the found sphinx-build tool.
Absolute path of the found sphinx-apidoc tool.
Sphinx version found e.g. 1.1.2.
Sphinx major version found e.g. 1.
Sphinx minor version found e.g. 1.
Sphinx patch version found e.g. 2.
+# +# @ingroup CMakeFindModules +############################################################################## + +set (_Sphinx_REQUIRED_VARS) + +# ---------------------------------------------------------------------------- +# initialize search +if (NOT Sphinx_DIR) + if (NOT $ENV{Sphinx_DIR} STREQUAL "") + set (Sphinx_DIR "$ENV{Sphinx_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + else () + set (Sphinx_DIR "$ENV{SPHINX_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + endif () +endif () + +# ---------------------------------------------------------------------------- +# default components to look for +if (NOT Sphinx_FIND_COMPONENTS) + set (Sphinx_FIND_COMPONENTS "build") +elseif (NOT Sphinx_FIND_COMPONENTS MATCHES "^(build|apidoc)$") + message (FATAL_ERROR "Invalid Sphinx component in: ${Sphinx_FIND_COMPONENTS}") +endif () + +# ---------------------------------------------------------------------------- +# find components, i.e., build tools +foreach (_Sphinx_TOOL IN LISTS Sphinx_FIND_COMPONENTS) + if (Sphinx_DIR) + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + HINTS "${Sphinx_DIR}" + PATH_SUFFIXES bin + DOC "The sphinx-${_Sphinx_TOOL} Python script." + NO_DEFAULT_PATH + ) + else () + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + DOC "The sphinx-${_Sphinx_TOOL} Python script." + ) + endif () + mark_as_advanced (Sphinx-${_Sphinx_TOOL}_EXECUTABLE) + list (APPEND _Sphinx_REQUIRED_VARS Sphinx-${_Sphinx_TOOL}_EXECUTABLE) +endforeach () + +# ---------------------------------------------------------------------------- +# determine Python executable used by Sphinx +if (Sphinx-build_EXECUTABLE) + # extract python executable from shebang of sphinx-build + find_package (PythonInterp QUIET) + set (Sphinx_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") + set (Sphinx_PYTHON_OPTIONS) + file (STRINGS "${Sphinx-build_EXECUTABLE}" FIRST_LINE LIMIT_COUNT 1) + if (FIRST_LINE MATCHES "^#!(.*/python.*)") # does not match "#!/usr/bin/env python" ! + string (REGEX REPLACE "^ +| +$" "" Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + if (Sphinx_PYTHON_EXECUTABLE MATCHES "([^ ]+) (.*)") + set (Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + string (REGEX REPLACE " +" ";" Sphinx_PYTHON_OPTIONS "${CMAKE_MATCH_2}") + endif () + endif () + # this is done to avoid problems with multiple Python versions being installed + # remember: CMake command if(STR EQUAL STR) is bad and may cause many troubles ! + string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" _Sphinx_PYTHON_EXECUTABLE_RE "${PYTHON_EXECUTABLE}") + list (FIND Sphinx_PYTHON_OPTIONS -E IDX) + if (IDX EQUAL -1 AND NOT Sphinx_PYTHON_EXECUTABLE MATCHES "^${_Sphinx_PYTHON_EXECUTABLE_RE}$") + list (INSERT Sphinx_PYTHON_OPTIONS 0 -E) + endif () + unset (_Sphinx_PYTHON_EXECUTABLE_RE) +endif () + +# ---------------------------------------------------------------------------- +# determine Sphinx version +if (Sphinx-build_EXECUTABLE) + # intentionally use invalid -h option here as the help that is shown then + # will include the Sphinx version information + if (Sphinx_PYTHON_EXECUTABLE) + execute_process ( + COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" -h + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + elseif (UNIX) + execute_process ( + COMMAND "${Sphinx-build_EXECUTABLE}" -h + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + endif () + + # The sphinx version can also contain a "b" instead of the last dot. + # For example "Sphinx v1.2b1" so we cannot just split on "." + if (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b)[0-9]+)") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING}) + + # v1.2.0 -> v1.2 + if (Sphinx_VERSION_PATCH EQUAL 0) + string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}") + endif () + endif() +endif () + +# ---------------------------------------------------------------------------- +# compatibility with FindPythonInterp.cmake and FindPerl.cmake +set (SPHINX_EXECUTABLE "${Sphinx-build_EXECUTABLE}") + +# ---------------------------------------------------------------------------- +# handle the QUIETLY and REQUIRED arguments and set SPHINX_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( + Sphinx + REQUIRED_VARS + ${_Sphinx_REQUIRED_VARS} +# VERSION_VAR # This isn't available until CMake 2.8.8 so don't use it. + Sphinx_VERSION_STRING +) + +# ---------------------------------------------------------------------------- +# set Sphinx_DIR +if (NOT Sphinx_DIR AND Sphinx-build_EXECUTABLE) + get_filename_component (Sphinx_DIR "${Sphinx-build_EXECUTABLE}" PATH) + string (REGEX REPLACE "/bin/?" "" Sphinx_DIR "${Sphinx_DIR}") + set (Sphinx_DIR "${Sphinx_DIR}" CACHE PATH "Installation directory of Sphinx tools." FORCE) +endif () + +unset (_Sphinx_VERSION) +unset (_Sphinx_REQUIRED_VARS) \ No newline at end of file diff --git a/deps/jansson/cmake/config.h.cmake b/deps/jansson/cmake/config.h.cmake new file mode 100644 index 000000000..bc8117848 --- /dev/null +++ b/deps/jansson/cmake/config.h.cmake @@ -0,0 +1,45 @@ +/* Reduced down to the defines that are actually used in the code */ + +/* Define to 1 if you have the (and friends) header file. */ +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* We must include this here, as in (eg) utf.h it will want to use + the integer type, which in MSVC2010 will be in stdint.h + (there is no inttypes.h in MSVC2010) */ +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if you have the 'setlocale' function. */ +#cmakedefine HAVE_SETLOCALE 1 + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#cmakedefine HAVE_INT32_T 1 + +#ifndef HAVE_INT32_T +# define int32_t @JSON_INT32@ +#endif + +#cmakedefine HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t @JSON_SSIZE@ +#endif + +#cmakedefine HAVE_SNPRINTF 1 + +#ifndef HAVE_SNPRINTF +# define snprintf @JSON_SNPRINTF@ +#endif + +#cmakedefine HAVE_VSNPRINTF diff --git a/deps/jansson/cmake/jansson_config.h.cmake b/deps/jansson/cmake/jansson_config.h.cmake new file mode 100644 index 000000000..8c500b5da --- /dev/null +++ b/deps/jansson/cmake/jansson_config.h.cmake @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#define JANSSON_USING_CMAKE + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @JSON_INLINE@ +#endif + + +#define json_int_t @JSON_INT_T@ +#define json_strtoint @JSON_STRTOINT@ +#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@ + + + +#endif diff --git a/deps/jansson/configure.ac b/deps/jansson/configure.ac new file mode 100644 index 000000000..24ba37d49 --- /dev/null +++ b/deps/jansson/configure.ac @@ -0,0 +1,57 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.5], [petri@digip.org]) + +AM_INIT_AUTOMAKE([1.10 foreign]) + +AC_CONFIG_SRCDIR([src/value.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([locale.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([strtoll localeconv]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +AC_CONFIG_FILES([ + jansson.pc + Makefile + doc/Makefile + src/Makefile + src/jansson_config.h + test/Makefile + test/bin/Makefile + test/suites/Makefile + test/suites/api/Makefile +]) +AC_OUTPUT diff --git a/deps/jansson/doc/.gitignore b/deps/jansson/doc/.gitignore new file mode 100644 index 000000000..69fa449dd --- /dev/null +++ b/deps/jansson/doc/.gitignore @@ -0,0 +1 @@ +_build/ diff --git a/deps/jansson/doc/Makefile.am b/deps/jansson/doc/Makefile.am new file mode 100644 index 000000000..5069623fa --- /dev/null +++ b/deps/jansson/doc/Makefile.am @@ -0,0 +1,20 @@ +EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \ + gettingstarted.rst github_commits.c index.rst portability.rst \ + tutorial.rst upgrading.rst ext/refcounting.py + +SPHINXBUILD = sphinx-build +SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA) + +html-local: + $(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html + +install-html-local: html + mkdir -p $(DESTDIR)$(htmldir) + cp -r _build/html $(DESTDIR)$(htmldir) + +uninstall-local: + rm -rf $(DESTDIR)$(htmldir) + +clean-local: + rm -rf _build + rm -f ext/refcounting.pyc diff --git a/deps/jansson/doc/README b/deps/jansson/doc/README new file mode 100644 index 000000000..930b3bf0c --- /dev/null +++ b/deps/jansson/doc/README @@ -0,0 +1,5 @@ +To build the documentation, invoke + + make html + +Then point your browser to _build/html/index.html. diff --git a/deps/jansson/doc/apiref.rst b/deps/jansson/doc/apiref.rst new file mode 100644 index 000000000..13b7901da --- /dev/null +++ b/deps/jansson/doc/apiref.rst @@ -0,0 +1,1555 @@ +.. _apiref: + +************* +API Reference +************* + +.. highlight:: c + +Preliminaries +============= + +All declarations are in :file:`jansson.h`, so it's enough to + +:: + + #include + +in each source file. + +All constants are prefixed with ``JSON_`` (except for those describing +the library version, prefixed with ``JANSSON_``). Other identifiers +are prefixed with ``json_``. Type names are suffixed with ``_t`` and +``typedef``\ 'd so that the ``struct`` keyword need not be used. + + +Library Version +=============== + +The Jansson version is of the form *A.B.C*, where *A* is the major +version, *B* is the minor version and *C* is the micro version. If the +micro version is zero, it's omitted from the version string, i.e. the +version string is just *A.B*. + +When a new release only fixes bugs and doesn't add new features or +functionality, the micro version is incremented. When new features are +added in a backwards compatible way, the minor version is incremented +and the micro version is set to zero. When there are backwards +incompatible changes, the major version is incremented and others are +set to zero. + +The following preprocessor constants specify the current version of +the library: + +``JANSSON_MAJOR_VERSION``, ``JANSSON_MINOR_VERSION``, ``JANSSON_MICRO_VERSION`` + Integers specifying the major, minor and micro versions, + respectively. + +``JANSSON_VERSION`` + A string representation of the current version, e.g. ``"1.2.1"`` or + ``"1.3"``. + +``JANSSON_VERSION_HEX`` + A 3-byte hexadecimal representation of the version, e.g. + ``0x010201`` for version 1.2.1 and ``0x010300`` for version 1.3. + This is useful in numeric comparisions, e.g.:: + + #if JANSSON_VERSION_HEX >= 0x010300 + /* Code specific to version 1.3 and above */ + #endif + + +Value Representation +==================== + +The JSON specification (:rfc:`4627`) defines the following data types: +*object*, *array*, *string*, *number*, *boolean*, and *null*. JSON +types are used dynamically; arrays and objects can hold any other data +type, including themselves. For this reason, Jansson's type system is +also dynamic in nature. There's one C type to represent all JSON +values, and this structure knows the type of the JSON value it holds. + +.. type:: json_t + + This data structure is used throughout the library to represent all + JSON values. It always contains the type of the JSON value it holds + and the value's reference count. The rest depends on the type of the + value. + +Objects of :type:`json_t` are always used through a pointer. There +are APIs for querying the type, manipulating the reference count, and +for constructing and manipulating values of different types. + +Unless noted otherwise, all API functions return an error value if an +error occurs. Depending on the function's signature, the error value +is either *NULL* or -1. Invalid arguments or invalid input are +apparent sources for errors. Memory allocation and I/O operations may +also cause errors. + + +Type +---- + +The type of a JSON value is queried and tested using the following +functions: + +.. type:: enum json_type + + The type of a JSON value. The following members are defined: + + +--------------------+ + | ``JSON_OBJECT`` | + +--------------------+ + | ``JSON_ARRAY`` | + +--------------------+ + | ``JSON_STRING`` | + +--------------------+ + | ``JSON_INTEGER`` | + +--------------------+ + | ``JSON_REAL`` | + +--------------------+ + | ``JSON_TRUE`` | + +--------------------+ + | ``JSON_FALSE`` | + +--------------------+ + | ``JSON_NULL`` | + +--------------------+ + + These correspond to JSON object, array, string, number, boolean and + null. A number is represented by either a value of the type + ``JSON_INTEGER`` or of the type ``JSON_REAL``. A true boolean value + is represented by a value of the type ``JSON_TRUE`` and false by a + value of the type ``JSON_FALSE``. + +.. 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 + 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) + + 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) + + 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) + + Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false + for values of other types and for *NULL*. + + +.. _apiref-reference-count: + +Reference Count +--------------- + +The reference count is used to track whether a value is still in use +or not. When a value is created, it's reference count is set to 1. If +a reference to a value is kept (e.g. a value is stored somewhere for +later use), its reference count is incremented, and when the value is +no longer needed, the reference count is decremented. When the +reference count drops to zero, there are no references left, and the +value can be destroyed. + +The following functions are used to manipulate the reference count. + +.. function:: json_t *json_incref(json_t *json) + + Increment the reference count of *json* if it's not *NULL*. + Returns *json*. + +.. function:: void json_decref(json_t *json) + + Decrement the reference count of *json*. As soon as a call to + :func:`json_decref()` drops the reference count to zero, the value + is destroyed and it can no longer be used. + +Functions creating new JSON values set the reference count to 1. These +functions are said to return a **new reference**. Other functions +returning (existing) JSON values do not normally increase the +reference count. These functions are said to return a **borrowed +reference**. So, if the user will hold a reference to a value returned +as a borrowed reference, he must call :func:`json_incref`. As soon as +the value is no longer needed, :func:`json_decref` should be called +to release the reference. + +Normally, all functions accepting a JSON value as an argument will +manage the reference, i.e. increase and decrease the reference count +as needed. However, some functions **steal** the reference, i.e. they +have the same result as if the user called :func:`json_decref()` on +the argument right after calling the function. These functions are +suffixed with ``_new`` or have ``_new_`` somewhere in their name. + +For example, the following code creates a new JSON array and appends +an integer to it:: + + json_t *array, *integer; + + array = json_array(); + integer = json_integer(42); + + json_array_append(array, integer); + json_decref(integer); + +Note how the caller has to release the reference to the integer value +by calling :func:`json_decref()`. By using a reference stealing +function :func:`json_array_append_new()` instead of +:func:`json_array_append()`, the code becomes much simpler:: + + json_t *array = json_array(); + json_array_append_new(array, json_integer(42)); + +In this case, the user doesn't have to explicitly release the +reference to the integer value, as :func:`json_array_append_new()` +steals the reference when appending the value to the array. + +In the following sections it is clearly documented whether a function +will return a new or borrowed reference or steal a reference to its +argument. + + +Circular References +------------------- + +A circular reference is created when an object or an array is, +directly or indirectly, inserted inside itself. The direct case is +simple:: + + json_t *obj = json_object(); + json_object_set(obj, "foo", obj); + +Jansson will refuse to do this, and :func:`json_object_set()` (and +all the other such functions for objects and arrays) will return with +an error status. The indirect case is the dangerous one:: + + json_t *arr1 = json_array(), *arr2 = json_array(); + json_array_append(arr1, arr2); + json_array_append(arr2, arr1); + +In this example, the array ``arr2`` is contained in the array +``arr1``, and vice versa. Jansson cannot check for this kind of +indirect circular references without a performance hit, so it's up to +the user to avoid them. + +If a circular reference is created, the memory consumed by the values +cannot be freed by :func:`json_decref()`. The reference counts never +drops to zero because the values are keeping the references to each +other. Moreover, trying to encode the values with any of the encoding +functions will fail. The encoder detects circular references and +returns an error status. + + +True, False and Null +==================== + +These three values are implemented as singletons, so the returned +pointers won't change between invocations of these functions. + +.. function:: json_t *json_true(void) + + .. refcounting:: new + + Returns the JSON true value. + +.. function:: json_t *json_false(void) + + .. refcounting:: new + + Returns the JSON false value. + +.. function:: json_t *json_boolean(val) + + .. refcounting:: new + + Returns JSON false if ``val`` is zero, and JSON true otherwise. + This is a macro, and equivalent to ``val ? json_true() : + json_false()``. + + .. versionadded:: 2.4 + + +.. function:: json_t *json_null(void) + + .. refcounting:: new + + Returns the JSON null value. + + +String +====== + +Jansson uses UTF-8 as the character encoding. All JSON strings must be +valid UTF-8 (or ASCII, as it's a subset of UTF-8). Normal null +terminated C strings are used, so JSON strings may not contain +embedded null characters. All other Unicode codepoints U+0000 through +U+10FFFF are allowed, but you must use length-aware functions if you +wish to embed NUL bytes in strings. + +.. function:: json_t *json_string(const char *value) + + .. refcounting:: new + + Returns a new JSON string, or *NULL* on error. *value* must be a + valid UTF-8 encoded Unicode string. + +.. function:: json_t *json_stringn(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string`, but with explicit length, so *value* may + contain null characters or not be null terminated. + +.. function:: json_t *json_string_nocheck(const char *value) + + .. refcounting:: new + + Like :func:`json_string`, but doesn't check that *value* is valid + UTF-8. Use this function only if you are certain that this really + is the case (e.g. you have already checked it by other means). + +.. function:: json_t *json_stringn_nocheck(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string_nocheck`, but with explicit length, so + *value* may contain null characters or not be null terminated. + +.. function:: const char *json_string_value(const json_t *string) + + Returns the associated value of *string* as a null terminated UTF-8 + encoded string, or *NULL* if *string* is not a JSON string. + + The retuned value is read-only and must not be modified or freed by + the user. It is valid as long as *string* exists, i.e. as long as + its reference count has not dropped to zero. + +.. function:: size_t json_string_length(const json_t *string) + + Returns the length of *string* in its UTF-8 presentation, or zero + if *string* is not a JSON string. + +.. function:: int json_string_set(const json_t *string, const char *value) + + Sets the associated value of *string* to *value*. *value* must be a + valid UTF-8 encoded Unicode string. Returns 0 on success and -1 on + error. + +.. function:: int json_string_setn(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set`, but with explicit length, so *value* + may contain null characters or not be null terminated. + +.. function:: int json_string_set_nocheck(const json_t *string, const char *value) + + Like :func:`json_string_set`, but doesn't check that *value* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_string_setn_nocheck(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set_nocheck`, but with explicit length, + so *value* may contain null characters or not be null terminated. + + +Number +====== + +The JSON specification only contains one numeric type, "number". The C +programming language has distinct types for integer and floating-point +numbers, so for practical reasons Jansson also has distinct types for +the two. They are called "integer" and "real", respectively. For more +information, see :ref:`rfc-conformance`. + +.. type:: json_int_t + + This is the C type that is used to store JSON integer values. It + represents the widest integer type available on your system. In + practice it's just a typedef of ``long long`` if your compiler + supports it, otherwise ``long``. + + Usually, you can safely use plain ``int`` in place of + ``json_int_t``, and the implicit C integer conversion handles the + rest. Only when you know that you need the full 64-bit range, you + should use ``json_int_t`` explicitly. + +``JSON_INTEGER_IS_LONG_LONG`` + This is a preprocessor variable that holds the value 1 if + :type:`json_int_t` is ``long long``, and 0 if it's ``long``. It + can be used as follows:: + + #if JSON_INTEGER_IS_LONG_LONG + /* Code specific for long long */ + #else + /* Code specific for long */ + #endif + +``JSON_INTEGER_FORMAT`` + This is a macro that expands to a :func:`printf()` conversion + specifier that corresponds to :type:`json_int_t`, without the + leading ``%`` sign, i.e. either ``"lld"`` or ``"ld"``. This macro + is required because the actual type of :type:`json_int_t` can be + either ``long`` or ``long long``, and :func:`printf()` reuiqres + different length modifiers for the two. + + Example:: + + json_int_t x = 123123123; + printf("x is %" JSON_INTEGER_FORMAT "\n", x); + + +.. function:: json_t *json_integer(json_int_t value) + + .. refcounting:: new + + Returns a new JSON integer, or *NULL* on error. + +.. function:: json_int_t json_integer_value(const json_t *integer) + + Returns the associated value of *integer*, or 0 if *json* is not a + JSON integer. + +.. function:: int json_integer_set(const json_t *integer, json_int_t value) + + Sets the associated value of *integer* to *value*. Returns 0 on + success and -1 if *integer* is not a JSON integer. + +.. function:: json_t *json_real(double value) + + .. refcounting:: new + + Returns a new JSON real, or *NULL* on error. + +.. function:: double json_real_value(const json_t *real) + + Returns the associated value of *real*, or 0.0 if *real* is not a + JSON real. + +.. function:: int json_real_set(const json_t *real, double value) + + Sets the associated value of *real* to *value*. Returns 0 on + success and -1 if *real* is not a JSON real. + +In addition to the functions above, there's a common query function +for integers and reals: + +.. function:: double json_number_value(const json_t *json) + + Returns the associated value of the JSON integer or JSON real + *json*, cast to double regardless of the actual type. If *json* is + neither JSON real nor JSON integer, 0.0 is returned. + + +Array +===== + +A JSON array is an ordered collection of other JSON values. + +.. function:: json_t *json_array(void) + + .. refcounting:: new + + Returns a new JSON array, or *NULL* on error. Initially, the array + is empty. + +.. function:: size_t json_array_size(const json_t *array) + + Returns the number of elements in *array*, or 0 if *array* is NULL + or not a JSON array. + +.. function:: json_t *json_array_get(const json_t *array, size_t index) + + .. refcounting:: borrow + + Returns the element in *array* at position *index*. The valid range + for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. If *array* is not a JSON array, + if *array* is *NULL*, or if *index* is out of range, *NULL* is + returned. + +.. function:: int json_array_set(json_t *array, size_t index, json_t *value) + + Replaces the element in *array* at position *index* with *value*. + The valid range for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. Returns 0 on success and -1 on + error. + +.. function:: int json_array_set_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_set()` but steals the reference to *value*. + This is useful when *value* is newly created and not used after + the call. + +.. function:: int json_array_append(json_t *array, json_t *value) + + Appends *value* to the end of *array*, growing the size of *array* + by 1. Returns 0 on success and -1 on error. + +.. function:: int json_array_append_new(json_t *array, json_t *value) + + Like :func:`json_array_append()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_insert(json_t *array, size_t index, json_t *value) + + Inserts *value* to *array* at position *index*, shifting the + elements at *index* and after it one position towards the end of + the array. Returns 0 on success and -1 on error. + +.. function:: int json_array_insert_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_insert()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_remove(json_t *array, size_t index) + + Removes the element in *array* at position *index*, shifting the + elements after *index* one position towards the start of the array. + Returns 0 on success and -1 on error. The reference count of the + removed value is decremented. + +.. function:: int json_array_clear(json_t *array) + + Removes all elements from *array*. Returns 0 on sucess and -1 on + error. The reference count of all removed values are decremented. + +.. function:: int json_array_extend(json_t *array, json_t *other_array) + + Appends all elements in *other_array* to the end of *array*. + Returns 0 on success and -1 on error. + +The following macro can be used to iterate through all elements +in an array. + +.. function:: 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:: + + /* array is a JSON array */ + size_t index; + json_t *value; + + json_array_foreach(array, index, value) { + /* block of code that uses index and value */ + } + + The items are returned in increasing index order. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written code using the array access functions. + The main advantage of this macro is that it abstracts + away the complexity, and makes for shorter, more + concise code. + + .. versionadded:: 2.5 + + +Object +====== + +A JSON object is a dictionary of key-value pairs, where the key is a +Unicode string and the value is any JSON value. + +Even though NUL bytes are allowed in string values, they are not +allowed in object keys. + +.. function:: json_t *json_object(void) + + .. refcounting:: new + + Returns a new JSON object, or *NULL* on error. Initially, the + object is empty. + +.. function:: size_t json_object_size(const json_t *object) + + Returns the number of elements in *object*, or 0 if *object* is not + a JSON object. + +.. function:: json_t *json_object_get(const json_t *object, const char *key) + + .. refcounting:: borrow + + Get a value corresponding to *key* from *object*. Returns *NULL* if + *key* is not found and on error. + +.. 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 + valid null terminated UTF-8 encoded Unicode string. If there + 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_set_nocheck(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set`, but doesn't check that *key* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. 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_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 + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. 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_clear(json_t *object) + + Remove all elements from *object*. Returns 0 on success and -1 if + *object* is not a JSON object. The reference count of all removed + values are decremented. + +.. function:: int json_object_update(json_t *object, json_t *other) + + Update *object* with the key-value pairs from *other*, overwriting + existing keys. Returns 0 on success or -1 on error. + +.. function:: int json_object_update_existing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only the values of existing + keys are updated. No new keys are created. Returns 0 on success or + -1 on error. + + .. versionadded:: 2.3 + +.. function:: int json_object_update_missing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only new keys are created. + The value of any existing key is not changed. Returns 0 on success + or -1 on error. + + .. versionadded:: 2.3 + +The following macro can be used to iterate through all key-value pairs +in an object. + +.. function:: 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:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + json_object_foreach(obj, key, value) { + /* block of code that uses key and value */ + } + + The items are not returned in any particular order. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written iteration code using the object iteration protocol + (see below). The main advantage of this macro is that it abstracts + away the complexity behind iteration, and makes for shorter, more + concise code. + + .. versionadded:: 2.3 + + +The following functions implement an iteration protocol for objects, +allowing to iterate through all key-value pairs in an object. The +items are not returned in any particular order, as this would require +sorting due to the internal hashtable implementation. + +.. function:: void *json_object_iter(json_t *object) + + Returns an opaque iterator which can be used to iterate over all + key-value pairs in *object*, or *NULL* if *object* is empty. + +.. function:: void *json_object_iter_at(json_t *object, const char *key) + + Like :func:`json_object_iter()`, but returns an iterator to the + key-value pair in *object* whose key is equal to *key*, or NULL if + *key* is not found in *object*. Iterating forward to the end of + *object* only yields all key-value pairs of the object if *key* + happens to be the first key in the underlying hash table. + +.. function:: void *json_object_iter_next(json_t *object, void *iter) + + Returns an iterator pointing to the next key-value pair in *object* + after *iter*, or *NULL* if the whole object has been iterated + through. + +.. function:: const char *json_object_iter_key(void *iter) + + Extract the associated key from *iter*. + +.. function:: json_t *json_object_iter_value(void *iter) + + .. refcounting:: borrow + + Extract the associated value from *iter*. + +.. function:: int json_object_iter_set(json_t *object, void *iter, json_t *value) + + Set the value of the key-value pair in *object*, that is pointed to + by *iter*, to *value*. + +.. function:: int json_object_iter_set_new(json_t *object, void *iter, json_t *value) + + Like :func:`json_object_iter_set()`, but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: void *json_object_key_to_iter(const char *key) + + Like :func:`json_object_iter_at()`, but much faster. Only works for + values returned by :func:`json_object_iter_key()`. Using other keys + will lead to segfaults. This function is used internally to + implement :func:`json_object_foreach`. + + .. versionadded:: 2.3 + +The iteration protocol can be used for example as follows:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + void *iter = json_object_iter(obj); + while(iter) + { + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + /* use key and value ... */ + iter = json_object_iter_next(obj, iter); + } + + +Error reporting +=============== + +Jansson uses a single struct type to pass error information to the +user. See sections :ref:`apiref-decoding`, :ref:`apiref-pack` and +:ref:`apiref-unpack` for functions that pass error information using +this struct. + +.. type:: json_error_t + + .. member:: char text[] + + The error message (in UTF-8), or an empty string if a message is + not available. + + .. member:: char source[] + + Source of the error. This can be (a part of) the file name or a + special identifier in angle brackers (e.g. ````). + + .. member:: int line + + The line number on which the error occurred. + + .. member:: int column + + The column on which the error occurred. Note that this is the + *character column*, not the byte column, i.e. a multibyte UTF-8 + character counts as one column. + + .. member:: size_t position + + The position in bytes from the start of the input. This is + useful for debugging Unicode encoding problems. + +The normal use of :type:`json_error_t` is to allocate it on the stack, +and pass a pointer to a function. Example:: + + int main() { + json_t *json; + json_error_t error; + + json = json_load_file("/path/to/file.json", 0, &error); + if(!json) { + /* the error variable contains error information */ + } + ... + } + +Also note that if the call succeeded (``json != NULL`` in the above +example), the contents of ``error`` are generally left unspecified. +The decoding functions write to the ``position`` member also on +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. + + +Encoding +======== + +This sections 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 +below). + +By default, the output has no newlines, and spaces are used between +array and object elements for a readable output. This behavior can be +altered by using the ``JSON_INDENT`` and ``JSON_COMPACT`` flags +described below. A newline is never appended to the end of the encoded +JSON data. + +Each function takes a *flags* parameter that controls some aspects of +how the data is encoded. Its default value is 0. The following macros +can be ORed together to obtain *flags*. + +``JSON_INDENT(n)`` + Pretty-print the result, using newlines between array and object + items, and indenting with *n* spaces. The valid range for *n* is + between 0 and 31 (inclusive), other values result in an undefined + output. If ``JSON_INDENT`` is not used or *n* is 0, no newlines are + inserted between array and object items. + +``JSON_COMPACT`` + This flag enables a compact representation, i.e. sets the separator + between array and object items to ``","`` and between object keys + and values to ``":"``. Without this flag, the corresponding + separators are ``", "`` and ``": "`` for more readable output. + +``JSON_ENSURE_ASCII`` + If this flag is used, the output is guaranteed to consist only of + ASCII characters. This is achived by escaping all Unicode + characters outside the ASCII range. + +``JSON_SORT_KEYS`` + If this flag is used, all the objects in output are sorted by key. + This is useful e.g. if two JSON texts are diffed or visually + compared. + +``JSON_PRESERVE_ORDER`` + If this flag is used, object keys in the output are sorted into the + same order in which they were first inserted to the object. For + example, decoding a JSON text and then encoding with this flag + preserves the order of object keys. + +``JSON_ENCODE_ANY`` + Specifying this flag makes it possible to encode any JSON value on + its own. Without it, only objects and arrays can be passed as the + *root* value to the encoding functions. + + **Note:** Encoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatiblity with + :rfc:`4627`. If you use this flag, don't expect interoperatibility + with other JSON systems. + + .. versionadded:: 2.1 + +``JSON_ESCAPE_SLASH`` + Escape the ``/`` characters in strings with ``\/``. + + .. versionadded:: 2.4 + +The following functions perform the actual JSON encoding. The result +is in UTF-8. + +.. function:: char *json_dumps(const json_t *root, size_t flags) + + Returns the JSON representation of *root* as a string, or *NULL* on + error. *flags* is described above. The return value must be freed + by the caller using :func:`free()`. + +.. function:: int json_dumpf(const json_t *root, FILE *output, size_t flags) + + Write the JSON representation of *root* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + If an error occurs, something may have already been written to + *output*. In this case, the output is undefined and most likely not + valid JSON. + +.. function:: int json_dump_file(const json_t *json, const char *path, size_t flags) + + Write the JSON representation of *root* to the file *path*. If + *path* already exists, it is overwritten. *flags* is described + above. Returns 0 on success and -1 on error. + +.. type:: json_dump_callback_t + + A typedef for a function that's called by + :func:`json_dump_callback()`:: + + typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + + *buffer* points to a buffer containing a chunk of output, *size* is + the length of the buffer, and *data* is the corresponding + :func:`json_dump_callback()` argument passed through. + + On error, the function should return -1 to stop the encoding + process. On success, it should return 0. + + .. versionadded:: 2.2 + +.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) + + Call *callback* repeatedly, passing a chunk of the JSON + representation of *root* each time. *flags* is described above. + Returns 0 on success and -1 on error. + + .. versionadded:: 2.2 + + +.. _apiref-decoding: + +Decoding +======== + +This sections 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 +functions. In other words, the top level value in the JSON text being +decoded must be either array or object. To decode any JSON value, use +the ``JSON_DECODE_ANY`` flag (see below). + +See :ref:`rfc-conformance` for a discussion on Jansson's conformance +to the JSON specification. It explains many design decisions that +affect especially the behavior of the decoder. + +Each function takes a *flags* parameter that can be used to control +the behavior of the decoder. Its default value is 0. The following +macros can be ORed together to obtain *flags*. + +``JSON_REJECT_DUPLICATES`` + Issue a decoding error if any JSON object in the input text + contains duplicate keys. Without this flag, the value of the last + occurence of each key ends up in the result. Key equivalence is + checked byte-by-byte, without special Unicode comparison + algorithms. + + .. versionadded:: 2.1 + +``JSON_DECODE_ANY`` + By default, the decoder expects an array or object as the input. + With this flag enabled, the decoder accepts any valid JSON value. + + **Note:** Decoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatiblity with + :rfc:`4627`. If you use this flag, don't expect interoperatibility + with other JSON systems. + + .. versionadded:: 2.3 + +``JSON_DISABLE_EOF_CHECK`` + By default, the decoder expects that its whole input constitutes a + valid JSON text, and issues an error if there's extra data after + the otherwise valid JSON input. With this flag enabled, the decoder + stops after decoding a valid JSON array or object, and thus allows + extra data after the JSON text. + + Normally, reading will stop when the last ``]`` or ``}`` in the + JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and + ``JSON_DECODE_ANY`` flags are used, the decoder may read one extra + UTF-8 code unit (up to 4 bytes of input). For example, decoding + ``4true`` correctly decodes the integer 4, but also reads the + ``t``. For this reason, if reading multiple consecutive values that + are not arrays or objects, they should be separated by at least one + whitespace character. + + .. versionadded:: 2.1 + +``JSON_DECODE_INT_AS_REAL`` + JSON defines only one number type. Jansson distinguishes between + ints and reals. For more information see :ref:`real-vs-integer`. + With this flag enabled the decoder interprets all numbers as real + values. Integers that do not have an exact double representation + will silently result in a loss of precision. Integers that cause + a double overflow will cause an error. + + .. versionadded:: 2.5 + +``JSON_ALLOW_NUL`` + Allow ``\u0000`` escape inside string values. This is a safety + measure; If you know your input can contain NUL bytes, use this + flag. If you don't use this flag, you don't have to worry about NUL + bytes inside strings unless you explicitly create themselves by + using e.g. :func:`json_stringn()` or ``s#`` format specifier for + :func:`json_pack()`. + + Object keys cannot have embedded NUL bytes even if this flag is + used. + + .. versionadded:: 2.6 + +Each function also takes an optional :type:`json_error_t` parameter +that is filled with error information if decoding fails. It's also +updated on success; the number of bytes of input read is written to +its ``position`` field. This is especially useful when using +``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts. + +.. versionadded:: 2.3 + Number of bytes of input read is written to the ``position`` field + of the :type:`json_error_t` structure. + +If no error or position information is needed, you can pass *NULL*. + +The following functions perform the actual JSON decoding. + +.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *input* and returns the array or object it + contains, or *NULL* on error, in which case *error* is filled with + information about the error. *flags* is described above. + +.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *buffer*, whose length is *buflen*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. This + is similar to :func:`json_loads()` except that the string doesn't + need to be null-terminated. *flags* is described above. + + .. versionadded:: 2.1 + +.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + + This function will start reading the input from whatever position + the input file was, without attempting to seek first. If an error + occurs, the file position will be left indeterminate. On success, + the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK`` + flag was used. In this case, the file position will be at the first + character after the last ``]`` or ``}`` in the JSON input. This + allows calling :func:`json_loadf()` on the same ``FILE`` object + multiple times, if the input consists of consecutive JSON texts, + possibly separated by whitespace. + +.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in file *path* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + +.. type:: json_load_callback_t + + A typedef for a function that's called by + :func:`json_load_callback()` to read a chunk of input data:: + + typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + + *buffer* points to a buffer of *buflen* bytes, and *data* is the + corresponding :func:`json_load_callback()` argument passed through. + + On success, the function should return the number of bytes read; a + returned value of 0 indicates that no data was read and that the + end of file has been reached. On error, the function should return + ``(size_t)-1`` to abort the decoding process. + + .. versionadded:: 2.4 + +.. function:: json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text produced by repeated calls to *callback*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. + *data* is passed through to *callback* on each call. *flags* is + described above. + + .. versionadded:: 2.4 + + +.. _apiref-pack: + +Building Values +=============== + +This section describes functions that help to create, or *pack*, +complex JSON values, especially nested objects and arrays. Value +building is based on a *format string* that is used to tell the +functions about the expected arguments. + +For example, the format string ``"i"`` specifies a single integer +value, while the format string ``"[ssb]"`` or the equivalent ``"[s, s, +b]"`` specifies an array value with two strings and a boolean as its +items:: + + /* Create the JSON integer 42 */ + json_pack("i", 42); + + /* Create the JSON array ["foo", "bar", true] */ + json_pack("[ssb]", "foo", "bar", 1); + +Here's the full list of format specifiers. The type in parentheses +denotes the resulting JSON type, and the type in brackets (if any) +denotes the C type that is expected as the corresponding argument or +arguments. + +``s`` (string) [const char \*] + Convert a NULL terminated UTF-8 string to a JSON string. + +``s#`` (string) [const char \*, int] + Convert a UTF-8 buffer of a given length to a JSON string. + + .. versionadded:: 2.5 + +``s%`` (string) [const char \*, size_t] + Like ``s#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``+`` [const char \*] + Like ``s``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+#`` [const char \*, int] + Like ``s#``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+%`` (string) [const char \*, size_t] + Like ``+#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``n`` (null) + Output a JSON null value. No argument is consumed. + +``b`` (boolean) [int] + Convert a C :type:`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. + +``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. + +``o`` (any value) [json_t \*] + Output any given JSON value as-is. If the value is added to an + array or object, the reference to the value passed to ``o`` is + stolen by the container. + +``O`` (any value) [json_t \*] + Like ``o``, but the argument's reference count is incremented. + This is useful if you pack into an array or object and want to + keep the reference for the JSON value consumed by ``O`` to + yourself. + +``[fmt]`` (array) + Build an array with contents from the inner format string. ``fmt`` + may contain objects and arrays, i.e. recursive value building is + supported. + +``{fmt}`` (object) + Build an object with contents from the inner format string + ``fmt``. The first, third, etc. format specifier represent a key, + and must be a string (see ``s``, ``s#``, ``+`` and ``+#`` above), + as object keys are always strings. The second, fourth, etc. format + specifier represent a value. Any value may be an object or array, + i.e. recursive value building is supported. + +Whitespace, ``:`` and ``,`` are ignored. + +The following functions compose the value building API: + +.. function:: json_t *json_pack(const char *fmt, ...) + + .. refcounting:: new + + Build a new JSON value according to the format string *fmt*. For + each format specifier (except for ``{}[]n``), one or more arguments + are consumed and used to build the corresponding value. Returns + *NULL* on error. + +.. function:: json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) + json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) + + .. refcounting:: new + + Like :func:`json_pack()`, but an in the case of an error, an error + message is written to *error*, if it's not *NULL*. The *flags* + parameter is currently unused and should be set to 0. + + As only the errors in format string (and out-of-memory errors) can + be caught by the packer, these two functions are most likely only + useful for debugging format strings. + +More examples:: + + /* Build an empty JSON object */ + json_pack("{}"); + + /* Build the JSON object {"foo": 42, "bar": 7} */ + json_pack("{sisi}", "foo", 42, "bar", 7); + + /* Like above, ':', ',' and whitespace are ignored */ + json_pack("{s:i, s:i}", "foo", 42, "bar", 7); + + /* Build the JSON array [[1, 2], {"cool": true}] */ + json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1); + + /* Build a string from a non-NUL terminated buffer */ + char buffer[4] = {'t', 'e', 's', 't'}; + json_pack("s#", buffer, 4); + + /* Concatentate strings together to build the JSON string "foobarbaz" */ + json_pack("s++", "foo", "bar", "baz"); + + +.. _apiref-unpack: + +Parsing and Validating Values +============================= + +This section describes functions that help to validate complex values +and extract, or *unpack*, data from them. Like :ref:`building values +`, this is also based on format strings. + +While a JSON value is unpacked, the type specified in the format +string is checked to match that of the JSON value. This is the +validation part of the process. In addition to this, the unpacking +functions can also check that all items of arrays and objects are +unpacked. This check be enabled with the format specifier ``!`` or by +using the flag ``JSON_STRICT``. See below for details. + +Here's the full list of format specifiers. The type in parentheses +denotes the JSON type, and the type in brackets (if any) denotes the C +type whose address should be passed. + +``s`` (string) [const char \*] + Convert a JSON string to a pointer to a NULL terminated UTF-8 + string. The resulting string is extracted by using + :func:`json_string_value()` internally, so it exists as long as + there are still references to the corresponding JSON string. + +``s%`` (string) [const char \*, size_t *] + Convert a JSON string to a pointer to a NULL terminated UTF-8 + string and its length. + + .. versionadded:: 2.6 + +``n`` (null) + Expect a JSON null value. Nothing is extracted. + +``b`` (boolean) [int] + Convert a JSON boolean value to a C :type:`int`, so that ``true`` + is converted to 1 and ``false`` to 0. + +``i`` (integer) [int] + Convert a JSON integer to C :type:`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`. + +``F`` (integer or real) [double] + Convert a JSON number (integer or real) to C :type:`double`. + +``o`` (any value) [json_t \*] + Store a JSON value with no conversion to a :type:`json_t` pointer. + +``O`` (any value) [json_t \*] + Like ``O``, but the JSON value's reference count is incremented. + +``[fmt]`` (array) + Convert each item in the JSON array according to the inner format + string. ``fmt`` may contain objects and arrays, i.e. recursive + value extraction is supporetd. + +``{fmt}`` (object) + Convert each item in the JSON object according to the inner format + string ``fmt``. The first, third, etc. format specifier represent + a key, and must be ``s``. The corresponding argument to unpack + functions is read as the object key. The second fourth, etc. + format specifier represent a value and is written to the address + given as the corresponding argument. **Note** that every other + argument is read from and every other is written to. + + ``fmt`` may contain objects and arrays as values, i.e. recursive + value extraction is supporetd. + + .. versionadded:: 2.3 + Any ``s`` representing a key may be suffixed with a ``?`` to + make the key optional. If the key is not found, nothing is + extracted. See below for an example. + +``!`` + This special format specifier is used to enable the check that + all object and array items are accessed, on a per-value basis. It + must appear inside an array or object as the last format specifier + before the closing bracket or brace. To enable the check globally, + use the ``JSON_STRICT`` unpacking flag. + +``*`` + This special format specifier is the opposite of ``!``. If the + ``JSON_STRICT`` flag is used, ``*`` can be used to disable the + strict check on a per-value basis. It must appear inside an array + or object as the last format specifier before the closing bracket + or brace. + +Whitespace, ``:`` and ``,`` are ignored. + +The following functions compose the parsing and validation API: + +.. function:: int json_unpack(json_t *root, const char *fmt, ...) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. Returns 0 on success and -1 on failure. + +.. function:: int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) + int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. If an error occurs and *error* is not *NULL*, write + error information to *error*. *flags* can be used to control the + behaviour of the unpacker, see below for the flags. Returns 0 on + success and -1 on failure. + +.. note:: + + The first argument of all unpack functions is ``json_t *root`` + instead of ``const json_t *root``, because the use of ``O`` format + specifier causes the reference count of ``root``, or some value + reachable from ``root``, to be increased. Furthermore, the ``o`` + format specifier may be used to extract a value as-is, which allows + modifying the structure or contents of a value reachable from + ``root``. + + If the ``O`` and ``o`` format specifiers are not used, it's + perfectly safe to cast a ``const json_t *`` variable to plain + ``json_t *`` when used with these functions. + +The following unpacking flags are available: + +``JSON_STRICT`` + Enable the extra validation step checking that all object and + array items are unpacked. This is equivalent to appending the + format specifier ``!`` to the end of every array and object in the + format string. + +``JSON_VALIDATE_ONLY`` + Don't extract any data, just validate the JSON value against the + given format string. Note that object keys must still be specified + after the format string. + +Examples:: + + /* root is the JSON integer 42 */ + int myint; + json_unpack(root, "i", &myint); + assert(myint == 42); + + /* root is the JSON object {"foo": "bar", "quux": true} */ + const char *str; + int boolean; + json_unpack(root, "{s:s, s:b}", "foo", &str, "quux", &boolean); + assert(strcmp(str, "bar") == 0 && boolean == 1); + + /* root is the JSON array [[1, 2], {"baz": null} */ + json_error_t error; + json_unpack_ex(root, &error, JSON_VALIDATE_ONLY, "[[i,i], {s:n}]", "baz"); + /* returns 0 for validation success, nothing is extracted */ + + /* root is the JSON array [1, 2, 3, 4, 5] */ + int myint1, myint2; + json_unpack(root, "[ii!]", &myint1, &myint2); + /* returns -1 for failed validation */ + + /* root is an empty JSON object */ + int myint = 0, myint2 = 0; + json_unpack(root, "{s?i, s?[ii]}", + "foo", &myint1, + "bar", &myint2, &myint3); + /* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */ + + +Equality +======== + +Testing for equality of two JSON values cannot, in general, be +achieved using the ``==`` operator. Equality in the terms of the +``==`` operator states that the two :type:`json_t` pointers point to +exactly the same JSON value. However, two JSON values can be equal not +only if they are exactly the same value, but also if they have equal +"contents": + +* Two integer or real values are equal if their contained numeric + values are equal. An integer value is never equal to a real value, + though. + +* Two strings are equal if their contained UTF-8 strings are equal, + byte by byte. Unicode comparison algorithms are not implemented. + +* Two arrays are equal if they have the same number of elements and + each element in the first array is equal to the corresponding + element in the second array. + +* Two objects are equal if they have exactly the same keys and the + value for each key in the first object is equal to the value of the + corresponding key in the second object. + +* Two true, false or null values have no "contents", so they are equal + if their types are equal. (Because these values are singletons, + their equality can actually be tested with ``==``.) + +The following function can be used to test whether two JSON values are +equal. + +.. function:: int json_equal(json_t *value1, json_t *value2) + + Returns 1 if *value1* and *value2* are equal, as defined above. + Returns 0 if they are inequal or one or both of the pointers are + *NULL*. + + +Copying +======= + +Because of reference counting, passing JSON values around doesn't +require copying them. But sometimes a fresh copy of a JSON value is +needed. For example, if you need to modify an array, but still want to +use the original afterwards, you should take a copy of it first. + +Jansson supports two kinds of copying: shallow and deep. There is a +difference between these methods only for arrays and objects. Shallow +copying only copies the first level value (array or object) and uses +the same child values in the copied value. Deep copying makes a fresh +copy of the child values, too. Moreover, all the child values are deep +copied in a recursive fashion. + +.. function:: json_t *json_copy(json_t *value) + + .. refcounting:: new + + Returns a shallow copy of *value*, or *NULL* on error. + +.. function:: json_t *json_deep_copy(const json_t *value) + + .. refcounting:: new + + Returns a deep copy of *value*, or *NULL* on error. + + +.. _apiref-custom-memory-allocation: + +Custom Memory Allocation +======================== + +By default, Jansson uses :func:`malloc()` and :func:`free()` for +memory allocation. These functions can be overridden if custom +behavior is needed. + +.. type:: json_malloc_t + + A typedef for a function pointer with :func:`malloc()`'s + signature:: + + typedef void *(*json_malloc_t)(size_t); + +.. type:: json_free_t + + A typedef for a function pointer with :func:`free()`'s + signature:: + + typedef void (*json_free_t)(void *); + +.. function:: void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) + + Use *malloc_fn* instead of :func:`malloc()` and *free_fn* instead + of :func:`free()`. This function has to be called before any other + Jansson's API functions to ensure that all memory operations use + the same functions. + +**Examples:** + +Circumvent problems with different CRT heaps on Windows by using +application's :func:`malloc()` and :func:`free()`:: + + json_set_alloc_funcs(malloc, free); + +Use the `Boehm's conservative garbage collector`_ for memory +operations:: + + json_set_alloc_funcs(GC_malloc, GC_free); + +.. _Boehm's conservative garbage collector: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ + +Allow storing sensitive data (e.g. passwords or encryption keys) in +JSON structures by zeroing all memory when freed:: + + 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 ptr + 8; + } + + static void secure_free(void *ptr) + { + size_t size; + + ptr -= 8; + size = *((size_t *)ptr); + + guaranteed_memset(ptr, 0, size + 8); + free(ptr); + } + + int main() + { + json_set_alloc_funcs(secure_malloc, secure_free); + /* ... */ + } + +For more information about the issues of storing sensitive data in +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. diff --git a/deps/jansson/doc/changes.rst b/deps/jansson/doc/changes.rst new file mode 100644 index 000000000..ea5684377 --- /dev/null +++ b/deps/jansson/doc/changes.rst @@ -0,0 +1,5 @@ +****************** +Changes in Jansson +****************** + +.. include:: ../CHANGES diff --git a/deps/jansson/doc/conf.py b/deps/jansson/doc/conf.py new file mode 100644 index 000000000..ddf583332 --- /dev/null +++ b/deps/jansson/doc/conf.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# +# Jansson documentation build configuration file, created by +# sphinx-quickstart on Sun Sep 5 21:47:20 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('ext')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['refcounting'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Jansson' +copyright = u'2009-2013, Petri Lehtinen' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.5' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +default_role = 'c:func' +primary_domain = 'c' + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Janssondoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Jansson.tex', u'Jansson Documentation', + u'Petri Lehtinen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'jansson', u'Jansson Documentation', + [u'Petri Lehtinen'], 1) +] diff --git a/deps/jansson/doc/conformance.rst b/deps/jansson/doc/conformance.rst new file mode 100644 index 000000000..de3947d40 --- /dev/null +++ b/deps/jansson/doc/conformance.rst @@ -0,0 +1,110 @@ +.. _rfc-conformance: + +*************** +RFC Conformance +*************** + +JSON is specified in :rfc:`4627`, *"The application/json Media Type +for JavaScript Object Notation (JSON)"*. + +Character Encoding +================== + +Jansson only supports UTF-8 encoded JSON texts. It does not support or +auto-detect any of the other encodings mentioned in the RFC, namely +UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as +it's a subset of UTF-8. + +Strings +======= + +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. + +Unicode normalization or any other transformation is never performed +on any strings (string values or object keys). When checking for +equivalence of strings or object keys, the comparison is performed +byte by byte between the original UTF-8 representations of the +strings. + +Numbers +======= + +.. _real-vs-integer: + +Real vs. Integer +---------------- + +JSON makes no distinction between real and integer numbers; Jansson +does. Real numbers are mapped to the ``double`` type and integers to +the ``json_int_t`` type, which is a typedef of ``long long`` or +``long``, depending on whether ``long long`` is supported by your +compiler or not. + +A JSON number is considered to be a real number if its lexical +representation includes one of ``e``, ``E``, or ``.``; regardless if +its actual numeric value is a true integer (e.g., all of ``1E6``, +``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but +will be treated as real values). With the ``JSON_DECODE_INT_AS_REAL`` +decoder flag set all numbers are interpreted as real. + +All other JSON numbers are considered integers. + +When encoding to JSON, real values are always represented +with a fractional part; e.g., the ``double`` value 3.0 will be +represented in JSON as ``3.0``, not ``3``. + +Overflow, Underflow & Precision +------------------------------- + +Real numbers whose absolute values are too small to be represented in +a C ``double`` will be silently estimated with 0.0. Thus, depending on +platform, JSON numbers very close to zero such as 1E-999 may result in +0.0. + +Real numbers whose absolute values are too large to be represented in +a C ``double`` will result in an overflow error (a JSON decoding +error). Thus, depending on platform, JSON numbers like 1E+999 or +-1E+999 may result in a parsing error. + +Likewise, integer numbers whose absolute values are too large to be +represented in the ``json_int_t`` type (see above) will result in an +overflow error (a JSON decoding error). Thus, depending on platform, +JSON numbers like 1000000000000000 may result in parsing error. + +Parsing JSON real numbers may result in a loss of precision. As long +as overflow does not occur (i.e. a total loss of precision), the +rounded approximate value is silently used. Thus the JSON number +1.000000000000000005 may, depending on platform, result in the +``double`` value 1.0. + +Signed zeros +------------ + +JSON makes no statement about what a number means; however Javascript +(ECMAscript) does state that +0.0 and -0.0 must be treated as being +distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the +underlying floating point library in the C environment in which it is +compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will +be distinct values. Most platforms that use the IEEE 754 +floating-point standard will support signed zeros. + +Note that this only applies to floating-point; neither JSON, C, or +IEEE support the concept of signed integer zeros. + +.. |not-equal| unicode:: U+2260 + +Types +----- + +No support is provided in Jansson for any C numeric types other than +``json_int_t`` and ``double``. This excludes things such as unsigned +types, ``long double``, etc. Obviously, shorter types like ``short``, +``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float`` +are implicitly handled via the ordinary C type coercion rules (subject +to overflow semantics). Also, no support or hooks are provided for any +supplemental "bignum" type add-on packages. diff --git a/deps/jansson/doc/ext/refcounting.py b/deps/jansson/doc/ext/refcounting.py new file mode 100644 index 000000000..4af308467 --- /dev/null +++ b/deps/jansson/doc/ext/refcounting.py @@ -0,0 +1,59 @@ +""" + refcounting + ~~~~~~~~~~~ + + Reference count annotations for C API functions. Has the same + result as the sphinx.ext.refcounting extension but works for all + functions regardless of the signature, and the reference counting + information is written inline with the documentation instead of a + separate file. + + Adds a new directive "refcounting". The directive has no content + and one required positional parameter:: "new" or "borrow". + + Example: + + .. cfunction:: json_t *json_object(void) + + .. refcounting:: new + + + + :copyright: Copyright (c) 2009-2013 Petri Lehtinen + :license: MIT, see LICENSE for details. +""" + +from docutils import nodes + +class refcounting(nodes.emphasis): pass + +def visit(self, node): + self.visit_emphasis(node) + +def depart(self, node): + self.depart_emphasis(node) + +def html_visit(self, node): + self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) + +def html_depart(self, node): + self.body.append('') + + +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') + + return [refcounting(text, text)] + +def setup(app): + app.add_node(refcounting, + html=(html_visit, html_depart), + latex=(visit, depart), + text=(visit, depart)) + app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0)) diff --git a/deps/jansson/doc/gettingstarted.rst b/deps/jansson/doc/gettingstarted.rst new file mode 100644 index 000000000..4e59e519e --- /dev/null +++ b/deps/jansson/doc/gettingstarted.rst @@ -0,0 +1,237 @@ +*************** +Getting Started +*************** + +.. highlight:: c + +Compiling and Installing Jansson +================================ + +The Jansson source is available at +http://www.digip.org/jansson/releases/. + +Unix-like systems (including MinGW) +----------------------------------- + +Unpack the source tarball and change to the source directory: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + +The source uses GNU Autotools (autoconf_, automake_, libtool_), so +compiling and installing is extremely simple:: + + ./configure + make + make check + make install + +To change the destination directory (``/usr/local`` by default), use +the ``--prefix=DIR`` argument to ``./configure``. See ``./configure +--help`` for the list of all possible installation options. (There are +no options to customize the resulting Jansson binary.) + +The command ``make check`` runs the test suite distributed with +Jansson. This step is not strictly necessary, but it may find possible +problems that Jansson has on your platform. If any problems are found, +please report them. + +If you obtained the source from a Git repository (or any other source +control system), there's no ``./configure`` script as it's not kept in +version control. To create the script, the build system needs to be +bootstrapped. There are many ways to do this, but the easiest one is +to use ``autoreconf``:: + + autoreconf -vi + +This command creates the ``./configure`` script, which can then be +used as described above. + +.. _autoconf: http://www.gnu.org/software/autoconf/ +.. _automake: http://www.gnu.org/software/automake/ +.. _libtool: http://www.gnu.org/software/libtool/ + + +.. _build-cmake: + +CMake (various platforms, including Windows) +-------------------------------------------- + +Jansson can be built using CMake_. Create a build directory for an +out-of-tree build, change to that directory, and run ``cmake`` (or ``ccmake``, +``cmake-gui``, or similar) to configure the project. + +See the examples below for more detailed information. + +.. note:: In the below examples ``..`` is used as an argument for ``cmake``. + This is simply the path to the jansson project root directory. + In the example it is assumed you've created a sub-directory ``build`` + and are using that. You could use any path you want. + +.. _build-cmake-unix: + +Unix (Make files) +^^^^^^^^^^^^^^^^^ +Generating make files on unix: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + + mkdir build + cd build + cmake .. # or `ccmake ..` for a GUI. + +Then to build:: + + make + make check + make install + +Windows (Visual Studio) +^^^^^^^^^^^^^^^^^^^^^^^ +Creating Visual Studio project files from the command line: + +.. parsed-literal:: + + + cd jansson-|release| + + md build + cd build + cmake -G "Visual Studio 10" .. + +You will now have a *Visual Studio Solution* in your build directory. +To run the unit tests build the ``RUN_TESTS`` project. + +If you prefer a GUI the ``cmake`` line in the above example can +be replaced with:: + + cmake-gui .. + +For command line help (including a list of available generators) +for CMake_ simply run:: + + cmake + +To list available CMake_ settings (and what they are currently set to) +for the project, run:: + + cmake -LH .. + +Mac OSX (Xcode) +^^^^^^^^^^^^^^^ +If you prefer using Xcode instead of make files on OSX, +do the following. (Use the same steps as +for :ref:`Unix `):: + + ... + cmake -G "Xcode" .. + +Additional CMake settings +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Shared library +"""""""""""""" +By default the CMake_ project will generate build files for building the +static library. To build the shared version use:: + + ... + cmake -DBUILD_SHARED=1 .. + +Changing install directory (same as autoconf --prefix) +"""""""""""""""""""""""""""""""""""""""""""""""""""""" +Just as with the autoconf_ project you can change the destination directory +for ``make install``. The equivalent for autoconfs ``./configure --prefix`` +in CMake_ is:: + + ... + cmake -DCMAKE_INSTALL_PREFIX:PATH=/some/other/path .. + make install + +.. _CMake: http://www.cmake.org + +Android +------- + +Jansson can be built for Android platforms. Android.mk is in the +source root directory. The configuration header file is located in the +``android`` directory in the source distribution. + + +Windows +------- + +**This method is deprecated**. Using :ref:`CMake ` is now +preferred. + +Jansson can be built with Visual Studio 2010 (and probably newer +versions, too). The solution and project files are in the +``win32/vs2010/`` directory in the source distribution. + + +Other Systems +------------- + +On non Unix-like systems, you may be unable to run the ``./configure`` +script. In this case, follow these steps. All the files mentioned can +be found in the ``src/`` directory. + +1. Create ``jansson_config.h`` (which has some platform-specific + parameters that are normally filled in by the ``./configure`` + script). Edit ``jansson_config.h.in``, replacing all ``@variable@`` + placeholders, and rename the file to ``jansson_config.h``. + +2. Make ``jansson.h`` and ``jansson_config.h`` available to the + compiler, so that they can be found when compiling programs that + use Jansson. + +3. Compile all the ``.c`` files (in the ``src/`` directory) into a + library file. Make the library available to the compiler, as in + step 2. + + +Building the Documentation +-------------------------- + +(This subsection describes how to build the HTML documentation you are +currently reading, so it can be safely skipped.) + +Documentation is in the ``doc/`` subdirectory. It's written in +reStructuredText_ with Sphinx_ annotations. To generate the HTML +documentation, invoke:: + + make html + +and point your browser to ``doc/_build/html/index.html``. Sphinx_ 1.0 +or newer is required to generate the documentation. + +.. _reStructuredText: http://docutils.sourceforge.net/rst.html +.. _Sphinx: http://sphinx.pocoo.org/ + + +Compiling Programs that Use Jansson +=================================== + +Jansson involves one C header file, :file:`jansson.h`, so it's enough +to put the line + +:: + + #include + +in the beginning of every source file that uses Jansson. + +There's also just one library to link with, ``libjansson``. Compile and +link the program as follows:: + + cc -o prog prog.c -ljansson + +Starting from version 1.2, there's also support for pkg-config_:: + + cc -o prog prog.c `pkg-config --cflags --libs jansson` + +.. _pkg-config: http://pkg-config.freedesktop.org/ diff --git a/deps/jansson/doc/github_commits.c b/deps/jansson/doc/github_commits.c new file mode 100644 index 000000000..2b39250d2 --- /dev/null +++ b/deps/jansson/doc/github_commits.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include +#include + +#define BUFFER_SIZE (256 * 1024) /* 256 KB */ + +#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" +#define URL_SIZE 256 + +/* Return the offset of the first newline in text or the length of + text if there's no newline */ +static int newline_offset(const char *text) +{ + const char *newline = strchr(text, '\n'); + if(!newline) + return strlen(text); + else + return (int)(newline - text); +} + +struct write_result +{ + char *data; + int pos; +}; + +static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) +{ + struct write_result *result = (struct write_result *)stream; + + if(result->pos + size * nmemb >= BUFFER_SIZE - 1) + { + fprintf(stderr, "error: too small buffer\n"); + return 0; + } + + memcpy(result->data + result->pos, ptr, size * nmemb); + result->pos += size * nmemb; + + return size * nmemb; +} + +static char *request(const char *url) +{ + CURL *curl = NULL; + CURLcode status; + char *data = NULL; + long code; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(!curl) + goto error; + + data = malloc(BUFFER_SIZE); + if(!data) + goto error; + + struct write_result write_result = { + .data = data, + .pos = 0 + }; + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); + + status = curl_easy_perform(curl); + if(status != 0) + { + fprintf(stderr, "error: unable to request data from %s:\n", url); + fprintf(stderr, "%s\n", curl_easy_strerror(status)); + goto error; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if(code != 200) + { + fprintf(stderr, "error: server responded with code %ld\n", code); + goto error; + } + + curl_easy_cleanup(curl); + curl_global_cleanup(); + + /* zero-terminate the result */ + data[write_result.pos] = '\0'; + + return data; + +error: + if(data) + free(data); + if(curl) + curl_easy_cleanup(curl); + curl_global_cleanup(); + return NULL; +} + +int main(int argc, char *argv[]) +{ + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if(argc != 3) + { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + + text = request(url); + if(!text) + return 1; + + root = json_loads(text, 0, &error); + free(text); + + if(!root) + { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + + if(!json_is_array(root)) + { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + + for(i = 0; i < json_array_size(root); i++) + { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if(!json_is_object(data)) + { + fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + 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)); + return 1; + } + + commit = json_object_get(data, "commit"); + if(!json_is_object(commit)) + { + fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if(!json_is_string(message)) + { + fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message_text = json_string_value(message); + printf("%.8s %.*s\n", + json_string_value(sha), + newline_offset(message_text), + message_text); + } + + json_decref(root); + return 0; +} diff --git a/deps/jansson/doc/index.rst b/deps/jansson/doc/index.rst new file mode 100644 index 000000000..1f3f8ef70 --- /dev/null +++ b/deps/jansson/doc/index.rst @@ -0,0 +1,53 @@ +Jansson Documentation +===================== + +This is the documentation for Jansson_ |release|, last updated |today|. + +Introduction +------------ + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Comprehensive documentation + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + +Jansson is used in production and its API is stable. It works on +numerous platforms, including numerous Unix like systems and Windows. +It's suitable for use on any system, including desktop, server, and +small embedded systems. + + +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Jansson: http://www.digip.org/jansson/ + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + gettingstarted + upgrading + tutorial + conformance + portability + apiref + changes + + +Indices and Tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/deps/jansson/doc/portability.rst b/deps/jansson/doc/portability.rst new file mode 100644 index 000000000..dc6c5eb53 --- /dev/null +++ b/deps/jansson/doc/portability.rst @@ -0,0 +1,52 @@ +*********** +Portability +*********** + +Thread safety +------------- + +Jansson is thread safe and has no mutable global state. The only +exception are the memory allocation functions, that should be set at +most once, and only on program startup. See +:ref:`apiref-custom-memory-allocation`. + +There's no locking performed inside Jansson's code, so a multithreaded +program must perform its own locking if JSON values are shared by +multiple threads. Jansson's reference counting semantics may make this +a bit harder than it seems, as it's possible to have a reference to a +value that's also stored inside a list or object. Modifying the +container (adding or removing values) may trigger concurrent access to +such values, as containers manage the reference count of their +contained values. Bugs involving concurrent incrementing or +decrementing of deference counts may be hard to track. + +The encoding functions (:func:`json_dumps()` and friends) track +reference loops by modifying the internal state of objects and arrays. +For this reason, encoding functions must not be run on the same JSON +values in two separate threads at the same time. As already noted +above, be especially careful if two arrays or objects share their +contained values with another array or object. + +If you want to make sure that two JSON value hierarchies do not +contain shared values, use :func:`json_deep_copy()` to make copies. + +Locale +------ + +Jansson works fine under any locale. + +However, if the host program is multithreaded and uses ``setlocale()`` +to switch the locale in one thread while Jansson is currently encoding +or decoding JSON data in another thread, the result may be wrong or +the program may even crash. + +Jansson uses locale specific functions for certain string conversions +in the encoder and decoder, and then converts the locale specific +values to/from the JSON representation. This fails if the locale +changes between the string conversion and the locale-to-JSON +conversion. This can only happen in multithreaded programs that use +``setlocale()``, because ``setlocale()`` switches the locale for all +running threads, not only the thread that calls ``setlocale()``. + +If your program uses ``setlocale()`` as described above, consider +using the thread-safe ``uselocale()`` instead. diff --git a/deps/jansson/doc/tutorial.rst b/deps/jansson/doc/tutorial.rst new file mode 100644 index 000000000..c2df081c9 --- /dev/null +++ b/deps/jansson/doc/tutorial.rst @@ -0,0 +1,286 @@ +.. _tutorial: + +******** +Tutorial +******** + +.. highlight:: c + +In this tutorial, we create a program that fetches the latest commits +of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so +the result can be parsed using Jansson. + +To stick to the the scope of this tutorial, we will only cover the the +parts of the program related to handling JSON data. For the best user +experience, the full source code is available: +:download:`github_commits.c`. To compile it (on Unix-like systems with +gcc), use the following command:: + + gcc -o github_commits github_commits.c -ljansson -lcurl + +libcurl_ is used to communicate over the web, so it is required to +compile the program. + +The command line syntax is:: + + github_commits USER REPOSITORY + +``USER`` is a GitHub user ID and ``REPOSITORY`` is the repository +name. Please note that the GitHub API is rate limited, so if you run +the program too many times within a short period of time, the sever +starts to respond with an error. + +.. _GitHub: https://github.com/ +.. _GitHub API: http://developer.github.com/ +.. _libcurl: http://curl.haxx.se/ + + +.. _tutorial-github-commits-api: + +The GitHub Repo Commits API +=========================== + +The `GitHub Repo Commits API`_ is used by sending HTTP requests to +URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``, +where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name +of the repository whose commits are to be listed, respectively. + +GitHub responds with a JSON array of the following form: + +.. code-block:: none + + [ + { + "sha": "", + "commit": { + "message": "", + + }, + + }, + { + "sha": "", + "commit": { + "message": "", + + }, + + }, + + ] + +In our program, the HTTP request is sent using the following +function:: + + static char *request(const char *url); + +It takes the URL as a parameter, preforms a HTTP GET request, and +returns a newly allocated string that contains the response body. If +the request fails, an error message is printed to stderr and the +return value is *NULL*. For full details, refer to :download:`the code +`, as the actual implementation is not important +here. + +.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/ + +.. _tutorial-the-program: + +The Program +=========== + +First the includes:: + + #include + #include + +Like all the programs using Jansson, we need to include +:file:`jansson.h`. + +The following definitions are used to build the GitHub API request +URL:: + + #define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" + #define URL_SIZE 256 + +The following function is used when formatting the result to find the +first newline in the commit message:: + + /* Return the offset of the first newline in text or the length of + text if there's no newline */ + static int newline_offset(const char *text) + { + const char *newline = strchr(text, '\n'); + if(!newline) + return strlen(text); + else + return (int)(newline - text); + } + +The main function follows. In the beginning, we first declare a bunch +of variables and check the command line parameters:: + + int main(int argc, char *argv[]) + { + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if(argc != 3) + { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + +Then we build the request URL using the user and repository names +given as command line parameters:: + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + +This uses the ``URL_SIZE`` and ``URL_FORMAT`` constants defined above. +Now we're ready to actually request the JSON data over the web:: + + text = request(url); + if(!text) + return 1; + +If an error occurs, our function ``request`` prints the error and +returns *NULL*, so it's enough to just return 1 from the main +function. + +Next we'll call :func:`json_loads()` to decode the JSON text we got +as a response:: + + root = json_loads(text, 0, &error); + free(text); + + if(!root) + { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + +We don't need the JSON text anymore, so we can free the ``text`` +variable right after decoding it. If :func:`json_loads()` fails, it +returns *NULL* and sets error information to the :type:`json_error_t` +structure given as the second parameter. In this case, our program +prints the error information out and returns 1 from the main function. + +Now we're ready to extract the data out of the decoded JSON response. +The structure of the response JSON was explained in section +:ref:`tutorial-github-commits-api`. + +We check that the returned value really is an array:: + + if(!json_is_array(root)) + { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + +Then we proceed to loop over all the commits in the array:: + + for(i = 0; i < json_array_size(root); i++) + { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if(!json_is_object(data)) + { + fprintf(stderr, "error: commit data %d is not an object\n", i + 1); + json_decref(root); + return 1; + } + ... + +The function :func:`json_array_size()` returns the size of a JSON +array. First, we again declare some variables and then extract the +i'th element of the ``root`` array using :func:`json_array_get()`. +We also check that the resulting value is a JSON object. + +Next we'll extract the commit ID (a hexadecimal SHA-1 sum), +intermediate commit info object, and the commit message from that +object. We also do proper type checks:: + + sha = json_object_get(data, "sha"); + if(!json_is_string(sha)) + { + fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1); + json_decref(root); + return 1; + } + + commit = json_object_get(data, "commit"); + if(!json_is_object(commit)) + { + fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if(!json_is_string(message)) + { + fprintf(stderr, "error: commit %d: message is not a string\n", i + 1); + json_decref(root); + return 1; + } + ... + +And finally, we'll print the first 8 characters of the commit ID and +the first line of the commit message. A C-style string is extracted +from a JSON string using :func:`json_string_value()`:: + + message_text = json_string_value(message); + printf("%.8s %.*s\n", + json_string_value(id), + newline_offset(message_text), + message_text); + } + +After sending the HTTP request, we decoded the JSON text using +:func:`json_loads()`, remember? It returns a *new reference* to the +JSON value it decodes. When we're finished with the value, we'll need +to decrease the reference count using :func:`json_decref()`. This way +Jansson can release the resources:: + + json_decref(root); + return 0; + +For a detailed explanation of reference counting in Jansson, see +:ref:`apiref-reference-count` in :ref:`apiref`. + +The program's ready, let's test it and view the latest commits in +Jansson's repository:: + + $ ./github_commits akheron jansson + 1581f26a Merge branch '2.3' + aabfd493 load: Change buffer_pos to be a size_t + bd72efbd load: Avoid unexpected behaviour in macro expansion + e8fd3e30 Document and tweak json_load_callback() + 873eddaf Merge pull request #60 from rogerz/contrib + bd2c0c73 Ignore the binary test_load_callback + 17a51a4b Merge branch '2.3' + 09c39adc Add json_load_callback to the list of exported symbols + cbb80baf Merge pull request #57 from rogerz/contrib + 040bd7b0 Add json_load_callback() + 2637faa4 Make test stripping locale independent + <...> + + +Conclusion +========== + +In this tutorial, we implemented a program that fetches the latest +commits of a GitHub repository using the GitHub Repo Commits API. +Jansson was used to decode the JSON response and to extract the commit +data. + +This tutorial only covered a small part of Jansson. For example, we +did not create or manipulate JSON values at all. Proceed to +:ref:`apiref` to explore all features of Jansson. diff --git a/deps/jansson/doc/upgrading.rst b/deps/jansson/doc/upgrading.rst new file mode 100644 index 000000000..9b4904610 --- /dev/null +++ b/deps/jansson/doc/upgrading.rst @@ -0,0 +1,76 @@ +.. highlight:: c + +****************** +Upgrading from 1.x +****************** + +This chapter lists the backwards incompatible changes introduced in +Jansson 2.0, and the steps that are needed for upgrading your code. + +**The incompatibilities are not dramatic.** The biggest change is that +all decoding functions now require and extra parameter. Most programs +can be modified to work with 2.0 by adding a ``0`` as the second +parameter to all calls of :func:`json_loads()`, :func:`json_loadf()` +and :func:`json_load_file()`. + + +Compatibility +============= + +Jansson 2.0 is backwards incompatible with the Jansson 1.x releases. +It is ABI incompatible, i.e. all programs dynamically linking to the +Jansson library need to be recompiled. It's also API incompatible, +i.e. the source code of programs using Jansson 1.x may need +modifications to make them compile against Jansson 2.0. + +All the 2.x releases are guaranteed to be backwards compatible for +both ABI and API, so no recompilation or source changes are needed +when upgrading from 2.x to 2.y. + + +List of Incompatible Changes +============================ + +**Decoding flags** + For future needs, a ``flags`` parameter was added as the second + parameter to all decoding functions, i.e. :func:`json_loads()`, + :func:`json_loadf()` and :func:`json_load_file()`. All calls to + these functions need to be changed by adding a ``0`` as the second + argument. For example:: + + /* old code */ + json_loads(input, &error); + + /* new code */ + json_loads(input, 0, &error); + + +**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 + 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 + 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. + + +**Maximum encoder indentation depth** + The maximum argument of the ``JSON_INDENT()`` macro has been + changed from 255 to 31, to free up bits from the ``flags`` + parameter of :func:`json_dumps()`, :func:`json_dumpf()` and + :func:`json_dump_file()`. If your code uses a bigger indentation + than 31, it needs to be changed. + + +**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. + This should not require source code changes, as both + :type:`unsigned int` and :type:`unsigned long` are usually + compatible with :type:`size_t`. diff --git a/deps/jansson/jansson.pc.in b/deps/jansson/jansson.pc.in new file mode 100644 index 000000000..d9bf4dade --- /dev/null +++ b/deps/jansson/jansson.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=${prefix}/include + +Name: Jansson +Description: Library for encoding, decoding and manipulating JSON data +Version: @VERSION@ +Libs: -L${libdir} -ljansson +Cflags: -I${includedir} diff --git a/deps/jansson/release.sh b/deps/jansson/release.sh new file mode 100755 index 000000000..c2551f828 --- /dev/null +++ b/deps/jansson/release.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# Use this script to easily make releases of Jansson. It configures +# the source tree, and builds and signs all tarballs. + +die() { + echo $1 >&2 + exit 1 +} + +confirm() { + local answer + read -p "$1 [yN]: " answer + [ "$answer" = "Y" -o "$answer" = "y" ] || exit 0 +} + +set -e +[ -f configure.ac ] || die "Must be run at project root directory" + +# Determine version +v=$(grep AC_INIT configure.ac | sed -r 's/.*, \[(.+?)\],.*/\1/') +[ -n "$v" ] || die "Unable to determine version" +confirm "Version is $v, proceed?" + +# Sanity checks +vi=$(grep version-info src/Makefile.am | sed 's/^[ \t]*//g' | cut -d" " -f2) +confirm "Libtool version-info is $vi, proceed?" + +r=$(grep 'Released ' CHANGES | head -n 1) +confirm "Last CHANGES entry says \"$r\", proceed??" + +dv=$(grep ^version doc/conf.py | sed -r "s/.*'(.*)'.*/\1/") +if [ "$dv" != "$v" ]; then + die "Documentation version ($dv) doesn't match library version" +fi + +[ -f Makefile ] && make distclean || true +rm -f jansson-$v.tar.* +rm -rf jansson-$v-doc +rm -f jansson-$v-doc.tar.* + +autoreconf -fi +./configure + +# Run tests and make gz source tarball +: ${VALGRIND:=1} +export VALGRIND +make distcheck + +# Make bzip2 source tarball +make dist-bzip2 + +# Sign source tarballs +for s in gz bz2; do + gpg --detach-sign --armor jansson-$v.tar.$s +done + +# Build documentation +make html +mv doc/_build/html jansson-$v-doc + +# Make and sign documentation tarballs +for s in gz bz2; do + [ $s = gz ] && compress=gzip + [ $s = bz2 ] && compress=bzip2 + tar cf - jansson-$v-doc | $compress -9 -c > jansson-$v-doc.tar.$s + gpg --detach-sign --armor jansson-$v-doc.tar.$s +done + +echo "All done" diff --git a/deps/jansson/src/Makefile.am b/deps/jansson/src/Makefile.am new file mode 100644 index 000000000..e1a549385 --- /dev/null +++ b/deps/jansson/src/Makefile.am @@ -0,0 +1,24 @@ +EXTRA_DIST = jansson.def + +include_HEADERS = jansson.h jansson_config.h + +lib_LTLIBRARIES = libjansson.la +libjansson_la_SOURCES = \ + dump.c \ + error.c \ + hashtable.c \ + hashtable.h \ + jansson_private.h \ + load.c \ + memory.c \ + pack_unpack.c \ + strbuffer.c \ + strbuffer.h \ + strconv.c \ + utf.c \ + utf.h \ + value.c +libjansson_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^json_' \ + -version-info 9:0:5 diff --git a/deps/jansson/src/dump.c b/deps/jansson/src/dump.c new file mode 100644 index 000000000..d347aae5f --- /dev/null +++ b/deps/jansson/src/dump.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include "jansson.h" +#include "jansson_private.h" +#include "strbuffer.h" +#include "utf.h" + +#define MAX_INTEGER_STR_LENGTH 100 +#define MAX_REAL_STR_LENGTH 100 + +struct object_key { + size_t serial; + const char *key; +}; + +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) +{ + return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); +} + +static int dump_to_file(const char *buffer, size_t size, void *data) +{ + FILE *dest = (FILE *)data; + if(fwrite(buffer, size, 1, dest) != 1) + return -1; + return 0; +} + +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; + +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) +{ + if(JSON_INDENT(flags) > 0) + { + int i, ws_count = JSON_INDENT(flags); + + if(dump("\n", 1, data)) + return -1; + + for(i = 0; i < depth; i++) + { + if(dump(whitespace, ws_count, data)) + return -1; + } + } + else if(space && !(flags & JSON_COMPACT)) + { + return dump(" ", 1, data); + } + return 0; +} + +static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) +{ + const char *pos, *end, *lim; + int32_t codepoint; + + if(dump("\"", 1, data)) + return -1; + + end = pos = str; + lim = str + len; + while(1) + { + const char *text; + char seq[13]; + int length; + + while(end < lim) + { + end = utf8_iterate(pos, lim - pos, &codepoint); + if(!end) + return -1; + + /* mandatory escape or control char */ + if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) + break; + + /* slash */ + if((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + + /* non-ASCII */ + if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) + break; + + pos = end; + } + + if(pos != str) { + if(dump(str, pos - str, data)) + return -1; + } + + if(end == pos) + break; + + /* handle \, /, ", and control codes */ + length = 2; + switch(codepoint) + { + case '\\': text = "\\\\"; break; + case '\"': text = "\\\""; break; + case '\b': text = "\\b"; break; + case '\f': text = "\\f"; break; + case '\n': text = "\\n"; break; + case '\r': text = "\\r"; break; + case '\t': text = "\\t"; break; + case '/': text = "\\/"; break; + default: + { + /* codepoint is in BMP */ + if(codepoint < 0x10000) + { + sprintf(seq, "\\u%04X", codepoint); + length = 6; + } + + /* not in BMP -> construct a UTF-16 surrogate pair */ + else + { + int32_t first, last; + + codepoint -= 0x10000; + first = 0xD800 | ((codepoint & 0xffc00) >> 10); + last = 0xDC00 | (codepoint & 0x003ff); + + sprintf(seq, "\\u%04X\\u%04X", first, last); + length = 12; + } + + text = seq; + break; + } + } + + if(dump(text, length, data)) + return -1; + + str = pos = end; + } + + return dump("\"", 1, data); +} + +static int object_key_compare_keys(const void *key1, const void *key2) +{ + return strcmp(((const struct object_key *)key1)->key, + ((const struct object_key *)key2)->key); +} + +static int object_key_compare_serials(const void *key1, const void *key2) +{ + size_t a = ((const struct object_key *)key1)->serial; + size_t b = ((const struct object_key *)key2)->serial; + + return a < b ? -1 : a == b ? 0 : 1; +} + +static int do_dump(const json_t *json, size_t flags, int depth, + json_dump_callback_t dump, void *data) +{ + if(!json) + return -1; + + switch(json_typeof(json)) { + case JSON_NULL: + return dump("null", 4, data); + + case JSON_TRUE: + return dump("true", 4, data); + + case JSON_FALSE: + return dump("false", 5, data); + + case JSON_INTEGER: + { + char buffer[MAX_INTEGER_STR_LENGTH]; + int size; + + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, + "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) + return -1; + + return dump(buffer, size, data); + } + + case JSON_REAL: + { + char buffer[MAX_REAL_STR_LENGTH]; + int size; + double value = json_real_value(json); + + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + if(size < 0) + return -1; + + return dump(buffer, size, data); + } + + case JSON_STRING: + return dump_string(json_string_value(json), json_string_length(json), dump, data, flags); + + case JSON_ARRAY: + { + int i; + int n; + json_array_t *array; + + /* detect circular references */ + array = json_to_array(json); + if(array->visited) + goto array_error; + array->visited = 1; + + n = json_array_size(json); + + if(dump("[", 1, data)) + goto array_error; + if(n == 0) { + array->visited = 0; + return dump("]", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + goto array_error; + + for(i = 0; i < n; ++i) { + if(do_dump(json_array_get(json, i), flags, depth + 1, + dump, data)) + goto array_error; + + if(i < n - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + goto array_error; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + goto array_error; + } + } + + array->visited = 0; + return dump("]", 1, data); + + array_error: + array->visited = 0; + return -1; + } + + case JSON_OBJECT: + { + json_object_t *object; + void *iter; + const char *separator; + int separator_length; + + if(flags & JSON_COMPACT) { + separator = ":"; + separator_length = 1; + } + else { + separator = ": "; + separator_length = 2; + } + + /* detect circular references */ + object = json_to_object(json); + if(object->visited) + goto object_error; + object->visited = 1; + + iter = json_object_iter((json_t *)json); + + if(dump("{", 1, data)) + goto object_error; + if(!iter) { + object->visited = 0; + return dump("}", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + goto object_error; + + if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) + { + struct object_key *keys; + size_t size, i; + int (*cmp_func)(const void *, const void *); + + size = json_object_size(json); + keys = jsonp_malloc(size * sizeof(struct object_key)); + if(!keys) + goto object_error; + + i = 0; + while(iter) + { + keys[i].serial = hashtable_iter_serial(iter); + keys[i].key = json_object_iter_key(iter); + iter = json_object_iter_next((json_t *)json, iter); + i++; + } + assert(i == size); + + if(flags & JSON_SORT_KEYS) + cmp_func = object_key_compare_keys; + else + cmp_func = object_key_compare_serials; + + qsort(keys, size, sizeof(struct object_key), cmp_func); + + for(i = 0; i < size; i++) + { + const char *key; + json_t *value; + + key = keys[i].key; + value = json_object_get(json, key); + assert(value); + + dump_string(key, strlen(key), dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(value, flags, depth + 1, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + + if(i < size - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + { + jsonp_free(keys); + goto object_error; + } + } + } + + jsonp_free(keys); + } + else + { + /* Don't sort keys */ + + while(iter) + { + void *next = json_object_iter_next((json_t *)json, iter); + const char *key = json_object_iter_key(iter); + + dump_string(key, strlen(key), dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(json_object_iter_value(iter), flags, depth + 1, + dump, data)) + goto object_error; + + if(next) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + goto object_error; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + goto object_error; + } + + iter = next; + } + } + + object->visited = 0; + return dump("}", 1, data); + + object_error: + object->visited = 0; + return -1; + } + + default: + /* not reached */ + return -1; + } +} + +char *json_dumps(const json_t *json, size_t flags) +{ + strbuffer_t strbuff; + char *result; + + if(strbuffer_init(&strbuff)) + return NULL; + + if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); + + strbuffer_close(&strbuff); + return result; +} + +int json_dumpf(const json_t *json, FILE *output, size_t flags) +{ + return json_dump_callback(json, dump_to_file, (void *)output, flags); +} + +int json_dump_file(const json_t *json, const char *path, size_t flags) +{ + int result; + + FILE *output = fopen(path, "w"); + if(!output) + return -1; + + result = json_dumpf(json, output, flags); + + fclose(output); + return result; +} + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) +{ + if(!(flags & JSON_ENCODE_ANY)) { + if(!json_is_array(json) && !json_is_object(json)) + return -1; + } + + return do_dump(json, flags, 0, callback, data); +} diff --git a/deps/jansson/src/error.c b/deps/jansson/src/error.c new file mode 100644 index 000000000..a544a59fb --- /dev/null +++ b/deps/jansson/src/error.c @@ -0,0 +1,63 @@ +#include +#include "jansson_private.h" + +void jsonp_error_init(json_error_t *error, const char *source) +{ + if(error) + { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if(source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) +{ + size_t length; + + if(!error || !source) + return; + + length = strlen(source); + if(length < JSON_ERROR_SOURCE_LENGTH) + strcpy(error->source, source); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + strcpy(error->source, "..."); + strcpy(error->source + 3, source + extra); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap) +{ + if(!error) + return; + + if(error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; +} diff --git a/deps/jansson/src/hashtable.c b/deps/jansson/src/hashtable.c new file mode 100644 index 000000000..a254cfa6c --- /dev/null +++ b/deps/jansson/src/hashtable.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include /* for JSON_INLINE */ +#include "jansson_private.h" /* for container_of() */ +#include "hashtable.h" + +typedef struct hashtable_list list_t; +typedef struct hashtable_pair pair_t; +typedef struct hashtable_bucket bucket_t; + +#define list_to_pair(list_) container_of(list_, pair_t, list) + +/* From http://www.cse.yorku.ca/~oz/hash.html */ +static size_t hash_str(const void *ptr) +{ + const char *str = (const char *)ptr; + + size_t hash = 5381; + size_t c; + + while((c = (size_t)*str)) + { + hash = ((hash << 5) + hash) + c; + str++; + } + + return hash; +} + +static JSON_INLINE void list_init(list_t *list) +{ + list->next = list; + list->prev = list; +} + +static JSON_INLINE void list_insert(list_t *list, list_t *node) +{ + node->next = list; + node->prev = list->prev; + list->prev->next = node; + list->prev = node; +} + +static JSON_INLINE void list_remove(list_t *list) +{ + list->prev->next = list->next; + list->next->prev = list->prev; +} + +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) +{ + return bucket->first == &hashtable->list && bucket->first == bucket->last; +} + +static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, + list_t *list) +{ + if(bucket_is_empty(hashtable, bucket)) + { + list_insert(&hashtable->list, list); + bucket->first = bucket->last = list; + } + else + { + list_insert(bucket->first, list); + bucket->first = list; + } +} + +static const size_t primes[] = { + 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, + 805306457, 1610612741 +}; + +static JSON_INLINE size_t num_buckets(hashtable_t *hashtable) +{ + return primes[hashtable->num_buckets]; +} + + +static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, + const char *key, size_t hash) +{ + list_t *list; + pair_t *pair; + + if(bucket_is_empty(hashtable, bucket)) + return NULL; + + list = bucket->first; + while(1) + { + pair = list_to_pair(list); + if(pair->hash == hash && strcmp(pair->key, key) == 0) + return pair; + + if(list == bucket->last) + break; + + list = list->next; + } + + return NULL; +} + +/* returns 0 on success, -1 if key was not found */ +static int hashtable_do_del(hashtable_t *hashtable, + const char *key, size_t hash) +{ + pair_t *pair; + bucket_t *bucket; + size_t index; + + index = hash % num_buckets(hashtable); + bucket = &hashtable->buckets[index]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return -1; + + if(&pair->list == bucket->first && &pair->list == bucket->last) + bucket->first = bucket->last = &hashtable->list; + + else if(&pair->list == bucket->first) + bucket->first = pair->list.next; + + else if(&pair->list == bucket->last) + bucket->last = pair->list.prev; + + list_remove(&pair->list); + json_decref(pair->value); + + jsonp_free(pair); + hashtable->size--; + + return 0; +} + +static void hashtable_do_clear(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + + for(list = hashtable->list.next; list != &hashtable->list; list = next) + { + next = list->next; + pair = list_to_pair(list); + json_decref(pair->value); + jsonp_free(pair); + } +} + +static int hashtable_do_rehash(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + size_t i, index, new_size; + + jsonp_free(hashtable->buckets); + + hashtable->num_buckets++; + new_size = num_buckets(hashtable); + + hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if(!hashtable->buckets) + return -1; + + for(i = 0; i < num_buckets(hashtable); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list = hashtable->list.next; + list_init(&hashtable->list); + + for(; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + index = pair->hash % new_size; + insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); + } + + return 0; +} + + +int hashtable_init(hashtable_t *hashtable) +{ + size_t i; + + hashtable->size = 0; + hashtable->num_buckets = 0; /* index to primes[] */ + hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t)); + if(!hashtable->buckets) + return -1; + + list_init(&hashtable->list); + + for(i = 0; i < num_buckets(hashtable); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + return 0; +} + +void hashtable_close(hashtable_t *hashtable) +{ + hashtable_do_clear(hashtable); + jsonp_free(hashtable->buckets); +} + +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value) +{ + pair_t *pair; + bucket_t *bucket; + size_t hash, index; + + /* rehash if the load ratio exceeds 1 */ + if(hashtable->size >= num_buckets(hashtable)) + if(hashtable_do_rehash(hashtable)) + return -1; + + hash = hash_str(key); + index = hash % num_buckets(hashtable); + bucket = &hashtable->buckets[index]; + pair = hashtable_find_pair(hashtable, bucket, key, 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 = jsonp_malloc(offsetof(pair_t, key) + len + 1); + if(!pair) + return -1; + + pair->hash = hash; + pair->serial = serial; + strcpy(pair->key, key); + pair->value = value; + list_init(&pair->list); + + insert_to_bucket(hashtable, bucket, &pair->list); + + hashtable->size++; + } + return 0; +} + +void *hashtable_get(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; + + pair = hashtable_find_pair(hashtable, bucket, key, 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); +} + +void hashtable_clear(hashtable_t *hashtable) +{ + size_t i; + + hashtable_do_clear(hashtable); + + for(i = 0; i < num_buckets(hashtable); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list_init(&hashtable->list); + hashtable->size = 0; +} + +void *hashtable_iter(hashtable_t *hashtable) +{ + return hashtable_iter_next(hashtable, &hashtable->list); +} + +void *hashtable_iter_at(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return NULL; + + return &pair->list; +} + +void *hashtable_iter_next(hashtable_t *hashtable, void *iter) +{ + list_t *list = (list_t *)iter; + if(list->next == &hashtable->list) + return NULL; + return list->next; +} + +void *hashtable_iter_key(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->key; +} + +size_t hashtable_iter_serial(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->serial; +} + +void *hashtable_iter_value(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->value; +} + +void hashtable_iter_set(void *iter, json_t *value) +{ + pair_t *pair = list_to_pair((list_t *)iter); + + json_decref(pair->value); + pair->value = value; +} diff --git a/deps/jansson/src/hashtable.h b/deps/jansson/src/hashtable.h new file mode 100644 index 000000000..4a7ce6f67 --- /dev/null +++ b/deps/jansson/src/hashtable.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef HASHTABLE_H +#define HASHTABLE_H + +struct hashtable_list { + struct hashtable_list *prev; + struct hashtable_list *next; +}; + +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ +struct hashtable_pair { + size_t hash; + struct hashtable_list list; + json_t *value; + size_t serial; + char key[1]; +}; + +struct hashtable_bucket { + struct hashtable_list *first; + struct hashtable_list *last; +}; + +typedef struct hashtable { + size_t size; + struct hashtable_bucket *buckets; + size_t num_buckets; /* index to primes[] */ + struct hashtable_list list; +} hashtable_t; + + +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->list)) + +/** + * hashtable_init - Initialize a hashtable object + * + * @hashtable: The (statically allocated) hashtable object + * + * Initializes a statically allocated hashtable object. The object + * should be cleared with hashtable_close when it's no longer used. + * + * Returns 0 on success, -1 on error (out of memory). + */ +int hashtable_init(hashtable_t *hashtable); + +/** + * hashtable_close - Release all resources used by a hashtable object + * + * @hashtable: The hashtable + * + * Destroys a statically allocated hashtable object. + */ +void hashtable_close(hashtable_t *hashtable); + +/** + * hashtable_set - Add/modify value in hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @serial: For addition order of keys + * @value: The value + * + * If a value with the given key already exists, its value is replaced + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. + * + * Returns 0 on success, -1 on failure (out of memory). + */ +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value); + +/** + * hashtable_get - Get a value associated with a key + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns value if it is found, or NULL otherwise. + */ +void *hashtable_get(hashtable_t *hashtable, const char *key); + +/** + * hashtable_del - Remove a value from the hashtable + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns 0 on success, or -1 if the key was not found. + */ +int hashtable_del(hashtable_t *hashtable, const char *key); + +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + +/** + * hashtable_iter - Iterate over hashtable + * + * @hashtable: The hashtable object + * + * Returns an opaque iterator to the first element in the hashtable. + * The iterator should be passed to hashtable_iter_* functions. + * The hashtable items are not iterated over in any particular order. + * + * There's no need to free the iterator in any way. The iterator is + * valid as long as the item that is referenced by the iterator is not + * deleted. Other values may be added or deleted. In particular, + * hashtable_iter_next() may be called on an iterator, and after that + * the key/value pair pointed by the old iterator may be deleted. + */ +void *hashtable_iter(hashtable_t *hashtable); + +/** + * hashtable_iter_at - Return an iterator at a specific key + * + * @hashtable: The hashtable object + * @key: The key that the iterator should point to + * + * Like hashtable_iter() but returns an iterator pointing to a + * specific key. + */ +void *hashtable_iter_at(hashtable_t *hashtable, const char *key); + +/** + * hashtable_iter_next - Advance an iterator + * + * @hashtable: The hashtable object + * @iter: The iterator + * + * Returns a new iterator pointing to the next element in the + * hashtable or NULL if the whole hastable has been iterated over. + */ +void *hashtable_iter_next(hashtable_t *hashtable, void *iter); + +/** + * hashtable_iter_key - Retrieve the key pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_key(void *iter); + +/** + * hashtable_iter_serial - Retrieve the serial number pointed to by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_serial(void *iter); + +/** + * hashtable_iter_value - Retrieve the value pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_value(void *iter); + +/** + * hashtable_iter_set - Set the value pointed by an iterator + * + * @iter: The iterator + * @value: The value to set + */ +void hashtable_iter_set(void *iter, json_t *value); + +#endif diff --git a/deps/jansson/src/jansson.def b/deps/jansson/src/jansson.def new file mode 100644 index 000000000..3c7d6d1be --- /dev/null +++ b/deps/jansson/src/jansson.def @@ -0,0 +1,68 @@ +EXPORTS + json_delete + json_true + json_false + json_null + json_string + json_stringn + json_string_nocheck + json_stringn_nocheck + json_string_value + json_string_length + json_string_set + json_string_setn + json_string_set_nocheck + json_string_setn_nocheck + json_integer + json_integer_value + json_integer_set + json_real + json_real_value + json_real_set + json_number_value + json_array + json_array_size + json_array_get + json_array_set_new + json_array_append_new + json_array_insert_new + json_array_remove + json_array_clear + json_array_extend + json_object + json_object_size + json_object_get + json_object_set_new + json_object_set_new_nocheck + json_object_del + json_object_clear + json_object_update + json_object_update_existing + json_object_update_missing + json_object_iter + json_object_iter_at + json_object_iter_next + json_object_iter_key + json_object_iter_value + json_object_iter_set_new + json_object_key_to_iter + json_dumps + json_dumpf + json_dump_file + json_dump_callback + json_loads + json_loadb + json_loadf + json_load_file + json_load_callback + json_equal + json_copy + json_deep_copy + json_pack + json_pack_ex + json_vpack_ex + json_unpack + json_unpack_ex + json_vunpack_ex + json_set_alloc_funcs + diff --git a/deps/jansson/src/jansson.h b/deps/jansson/src/jansson.h new file mode 100644 index 000000000..27c0c74ba --- /dev/null +++ b/deps/jansson/src/jansson.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include +#include /* for size_t */ +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 5 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.5" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct json_t { + json_type type; + size_t refcount; +} json_t; + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE) +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_stringn(const char *value, size_t len); +json_t *json_string_nocheck(const char *value); +json_t *json_stringn_nocheck(const char *value, size_t len); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +static JSON_INLINE +json_t *json_incref(json_t *json) +{ + if(json && json->refcount != (size_t)-1) + ++json->refcount; + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE +void json_decref(json_t *json) +{ + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) + json_delete(json); +} + + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + + +/* getters, setters, manipulation */ + +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_del(json_t *object, const char *key); +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); +int json_object_update_missing(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +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); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + 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)))) + +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + +static JSON_INLINE +int json_object_set(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new(object, key, 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_iter_set(json_t *object, void *iter, json_t *value) +{ + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE +int json_array_set(json_t *array, size_t ind, json_t *value) +{ + return json_array_set_new(array, ind, json_incref(value)); +} + +static JSON_INLINE +int json_array_append(json_t *array, json_t *value) +{ + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE +int json_array_insert(json_t *array, size_t ind, json_t *value) +{ + return json_array_insert_new(array, ind, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +size_t json_string_length(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_setn(json_t *string, const char *value, size_t len); +int json_string_set_nocheck(json_t *string, const char *value); +int json_string_setn_nocheck(json_t *string, const char *value, size_t len); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + + +/* equality */ + +int json_equal(json_t *value1, json_t *value2); + + +/* copying */ + +json_t *json_copy(json_t *value); +json_t *json_deep_copy(const json_t *value); + + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 +#define JSON_ALLOW_NUL 0x10 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); + + +/* encoding */ + +#define JSON_INDENT(n) (n & 0x1F) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/jansson/src/jansson_config.h.in b/deps/jansson/src/jansson_config.h.in new file mode 100644 index 000000000..785801f27 --- /dev/null +++ b/deps/jansson/src/jansson_config.h.in @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @json_inline@ +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @json_have_localeconv@ + +#endif diff --git a/deps/jansson/src/jansson_private.h b/deps/jansson/src/jansson_private.h new file mode 100644 index 000000000..eb51d0d52 --- /dev/null +++ b/deps/jansson/src/jansson_private.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_PRIVATE_H +#define JANSSON_PRIVATE_H + +#include +#include "jansson.h" +#include "hashtable.h" +#include "strbuffer.h" + +#define container_of(ptr_, type_, member_) \ + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif + +typedef struct { + json_t json; + hashtable_t hashtable; + size_t serial; + int visited; +} json_object_t; + +typedef struct { + json_t json; + size_t size; + size_t entries; + json_t **table; + int visited; +} json_array_t; + +typedef struct { + json_t json; + char *value; + size_t length; +} json_string_t; + +typedef struct { + json_t json; + double value; +} json_real_t; + +typedef struct { + json_t json; + json_int_t value; +} json_integer_t; + +#define json_to_object(json_) container_of(json_, json_object_t, json) +#define json_to_array(json_) container_of(json_, json_array_t, json) +#define json_to_string(json_) container_of(json_, json_string_t, json) +#define json_to_real(json_) container_of(json_, json_real_t, json) +#define json_to_integer(json_) container_of(json_, json_integer_t, json) + +/* Create a string by taking ownership of an existing buffer */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); + +/* Error message formatting */ +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value); + +/* Wrappers for custom memory functions */ +void* jsonp_malloc(size_t size); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length); +char *jsonp_strdup(const char *str); +char *jsonp_strndup(const char *str, size_t len); + +/* Windows compatibility */ +#ifdef _WIN32 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +#endif diff --git a/deps/jansson/src/load.c b/deps/jansson/src/load.c new file mode 100644 index 000000000..2adaee80d --- /dev/null +++ b/deps/jansson/src/load.c @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "jansson.h" +#include "jansson_private.h" +#include "strbuffer.h" +#include "utf.h" + +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + +#define TOKEN_INVALID -1 +#define TOKEN_EOF 0 +#define TOKEN_STRING 256 +#define TOKEN_INTEGER 257 +#define TOKEN_REAL 258 +#define TOKEN_TRUE 259 +#define TOKEN_FALSE 260 +#define TOKEN_NULL 261 + +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ +typedef int (*get_func)(void *data); + +typedef struct { + get_func get; + void *data; + char buffer[5]; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; +} stream_t; + +typedef struct { + stream_t stream; + strbuffer_t saved_text; + int token; + union { + struct { + char *val; + size_t len; + } string; + json_int_t integer; + double real; + } value; +} lex_t; + +#define stream_to_lex(stream) container_of(stream, lex_t, stream) + + +/*** error reporting ***/ + +static void error_set(json_error_t *error, const lex_t *lex, + const char *msg, ...) +{ + va_list ap; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; + + if(!error) + return; + + va_start(ap, msg); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + va_end(ap); + + if(lex) + { + const char *saved_text = strbuffer_value(&lex->saved_text); + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + + if(saved_text && saved_text[0]) + { + if(lex->saved_text.length <= 20) { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near '%s'", msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + else + { + if(lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } + else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near end of file", msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + } + + jsonp_error_set(error, line, col, pos, "%s", result); +} + + +/*** lexical analyzer ***/ + +static void +stream_init(stream_t *stream, get_func get, void *data) +{ + stream->get = get; + stream->data = data; + stream->buffer[0] = '\0'; + stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; +} + +static int stream_get(stream_t *stream, json_error_t *error) +{ + int c; + + if(stream->state != STREAM_STATE_OK) + return stream->state; + + if(!stream->buffer[stream->buffer_pos]) + { + c = stream->get(stream->data); + if(c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } + + stream->buffer[0] = c; + stream->buffer_pos = 0; + + if(0x80 <= c && c <= 0xFF) + { + /* multi-byte UTF-8 sequence */ + int i, count; + + count = utf8_check_first(c); + if(!count) + goto out; + + assert(count >= 2); + + for(i = 1; i < count; i++) + stream->buffer[i] = stream->get(stream->data); + + if(!utf8_check_full(stream->buffer, count, NULL)) + goto out; + + stream->buffer[count] = '\0'; + } + else + stream->buffer[1] = '\0'; + } + + c = stream->buffer[stream->buffer_pos++]; + + stream->position++; + if(c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } + else if(utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } + + return c; + +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; +} + +static void stream_unget(stream_t *stream, int c) +{ + if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if(c == '\n') { + stream->line--; + stream->column = stream->last_column; + } + else if(utf8_check_first(c)) + stream->column--; + + assert(stream->buffer_pos > 0); + stream->buffer_pos--; + assert(stream->buffer[stream->buffer_pos] == c); +} + + +static int lex_get(lex_t *lex, json_error_t *error) +{ + return stream_get(&lex->stream, error); +} + +static void lex_save(lex_t *lex, int c) +{ + strbuffer_append_byte(&lex->saved_text, c); +} + +static int lex_get_save(lex_t *lex, json_error_t *error) +{ + int c = stream_get(&lex->stream, error); + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); + return c; +} + +static void lex_unget(lex_t *lex, int c) +{ + stream_unget(&lex->stream, c); +} + +static void lex_unget_unsave(lex_t *lex, int c) +{ + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { + /* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ + #ifndef NDEBUG + char d; + #endif + stream_unget(&lex->stream, c); + #ifndef NDEBUG + d = + #endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } +} + +static void lex_save_cached(lex_t *lex) +{ + while(lex->stream.buffer[lex->stream.buffer_pos] != '\0') + { + lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); + lex->stream.buffer_pos++; + lex->stream.position++; + } +} + +static void lex_free_string(lex_t *lex) +{ + jsonp_free(lex->value.string.val); + lex->value.string.val = NULL; + lex->value.string.len = 0; +} + +/* assumes that str points to 'u' plus at least 4 valid hex digits */ +static int32_t decode_unicode_escape(const char *str) +{ + int i; + int32_t value = 0; + + assert(str[0] == 'u'); + + for(i = 1; i <= 4; i++) { + char c = str[i]; + value <<= 4; + if(l_isdigit(c)) + value += c - '0'; + else if(l_islower(c)) + value += c - 'a' + 10; + else if(l_isupper(c)) + value += c - 'A' + 10; + else + return -1; + } + + return value; +} + +static void lex_scan_string(lex_t *lex, json_error_t *error) +{ + int c; + const char *p; + char *t; + int i; + + lex->value.string.val = NULL; + lex->token = TOKEN_INVALID; + + c = lex_get_save(lex, error); + + while(c != '"') { + if(c == STREAM_STATE_ERROR) + goto out; + + else if(c == STREAM_STATE_EOF) { + error_set(error, lex, "premature end of input"); + goto out; + } + + else if(0 <= c && c <= 0x1F) { + /* control character */ + lex_unget_unsave(lex, c); + if(c == '\n') + error_set(error, lex, "unexpected newline", c); + else + error_set(error, lex, "control character 0x%x", c); + goto out; + } + + else if(c == '\\') { + c = lex_get_save(lex, error); + if(c == 'u') { + c = lex_get_save(lex, error); + for(i = 0; i < 4; i++) { + if(!l_isxdigit(c)) { + error_set(error, lex, "invalid escape"); + goto out; + } + c = lex_get_save(lex, error); + } + } + else if(c == '"' || c == '\\' || c == '/' || c == 'b' || + c == 'f' || c == 'n' || c == 'r' || c == 't') + c = lex_get_save(lex, error); + else { + error_set(error, lex, "invalid escape"); + goto out; + } + } + else + c = lex_get_save(lex, error); + } + + /* the actual value is at most of the same length as the source + string, because: + - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte + - a single \uXXXX escape (length 6) is converted to at most 3 bytes + - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair + are converted to 4 bytes + */ + t = jsonp_malloc(lex->saved_text.length + 1); + if(!t) { + /* this is not very nice, since TOKEN_INVALID is returned */ + goto out; + } + lex->value.string.val = t; + + /* + 1 to skip the " */ + p = strbuffer_value(&lex->saved_text) + 1; + + while(*p != '"') { + if(*p == '\\') { + p++; + if(*p == 'u') { + size_t length; + int32_t value; + + value = decode_unicode_escape(p); + if(value < 0) { + error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if(0xD800 <= value && value <= 0xDBFF) { + /* surrogate pair */ + if(*p == '\\' && *(p + 1) == 'u') { + int32_t value2 = decode_unicode_escape(++p); + if(value2 < 0) { + error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if(0xDC00 <= value2 && value2 <= 0xDFFF) { + /* valid second surrogate */ + value = + ((value - 0xD800) << 10) + + (value2 - 0xDC00) + + 0x10000; + } + else { + /* invalid second surrogate */ + error_set(error, lex, + "invalid Unicode '\\u%04X\\u%04X'", + value, value2); + goto out; + } + } + else { + /* no second surrogate */ + error_set(error, lex, "invalid Unicode '\\u%04X'", + value); + goto out; + } + } + else if(0xDC00 <= value && value <= 0xDFFF) { + error_set(error, lex, "invalid Unicode '\\u%04X'", value); + goto out; + } + + if(utf8_encode(value, t, &length)) + assert(0); + t += length; + } + else { + switch(*p) { + case '"': case '\\': case '/': + *t = *p; break; + case 'b': *t = '\b'; break; + case 'f': *t = '\f'; break; + case 'n': *t = '\n'; break; + case 'r': *t = '\r'; break; + case 't': *t = '\t'; break; + default: assert(0); + } + t++; + p++; + } + } + else + *(t++) = *(p++); + } + *t = '\0'; + lex->value.string.len = t - lex->value.string.val; + lex->token = TOKEN_STRING; + return; + +out: + lex_free_string(lex); +} + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) +{ + const char *saved_text; + char *end; + double value; + + lex->token = TOKEN_INVALID; + + if(c == '-') + c = lex_get_save(lex, error); + + if(c == '0') { + c = lex_get_save(lex, error); + if(l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + } + else if(l_isdigit(c)) { + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + else { + lex_unget_unsave(lex, c); + goto out; + } + + if(c != '.' && c != 'E' && c != 'e') { + json_int_t value; + + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + errno = 0; + value = json_strtoint(saved_text, &end, 10); + if(errno == ERANGE) { + if(value < 0) + error_set(error, lex, "too big negative integer"); + else + error_set(error, lex, "too big integer"); + goto out; + } + + assert(end == saved_text + lex->saved_text.length); + + lex->token = TOKEN_INTEGER; + lex->value.integer = value; + return 0; + } + + if(c == '.') { + c = lex_get(lex, error); + if(!l_isdigit(c)) { + lex_unget(lex, c); + goto out; + } + lex_save(lex, c); + + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + + if(c == 'E' || c == 'e') { + c = lex_get_save(lex, error); + if(c == '+' || c == '-') + c = lex_get_save(lex, error); + + if(!l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + + c = lex_get_save(lex, error); + while(l_isdigit(c)) + c = lex_get_save(lex, error); + } + + lex_unget_unsave(lex, c); + + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = value; + return 0; + +out: + return -1; +} + +static int lex_scan(lex_t *lex, json_error_t *error) +{ + int c; + + strbuffer_clear(&lex->saved_text); + + if(lex->token == TOKEN_STRING) + lex_free_string(lex); + + c = lex_get(lex, error); + while(c == ' ' || c == '\t' || c == '\n' || c == '\r') + c = lex_get(lex, error); + + if(c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; + } + + if(c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; + goto out; + } + + lex_save(lex, c); + + if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') + lex->token = c; + + else if(c == '"') + lex_scan_string(lex, error); + + else if(l_isdigit(c) || c == '-') { + if(lex_scan_number(lex, c, error)) + goto out; + } + + else if(l_isalpha(c)) { + /* eat up the whole identifier for clearer error messages */ + const char *saved_text; + + c = lex_get_save(lex, error); + while(l_isalpha(c)) + c = lex_get_save(lex, error); + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + if(strcmp(saved_text, "true") == 0) + lex->token = TOKEN_TRUE; + else if(strcmp(saved_text, "false") == 0) + lex->token = TOKEN_FALSE; + else if(strcmp(saved_text, "null") == 0) + lex->token = TOKEN_NULL; + else + lex->token = TOKEN_INVALID; + } + + else { + /* save the rest of the input UTF-8 sequence to get an error + message of valid UTF-8 */ + lex_save_cached(lex); + lex->token = TOKEN_INVALID; + } + +out: + return lex->token; +} + +static char *lex_steal_string(lex_t *lex, size_t *out_len) +{ + char *result = NULL; + if(lex->token == TOKEN_STRING) { + result = lex->value.string.val; + *out_len = lex->value.string.len; + lex->value.string.val = NULL; + lex->value.string.len = 0; + } + return result; +} + +static int lex_init(lex_t *lex, get_func get, void *data) +{ + stream_init(&lex->stream, get, data); + if(strbuffer_init(&lex->saved_text)) + return -1; + + lex->token = TOKEN_INVALID; + return 0; +} + +static void lex_close(lex_t *lex) +{ + if(lex->token == TOKEN_STRING) + lex_free_string(lex); + strbuffer_close(&lex->saved_text); +} + + +/*** parser ***/ + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); + +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *object = json_object(); + if(!object) + return NULL; + + lex_scan(lex, error); + if(lex->token == '}') + return object; + + while(1) { + char *key; + size_t len; + json_t *value; + + if(lex->token != TOKEN_STRING) { + error_set(error, lex, "string or '}' expected"); + goto error; + } + + key = lex_steal_string(lex, &len); + if(!key) + return NULL; + if (memchr(key, '\0', len)) { + jsonp_free(key); + error_set(error, lex, "NUL byte in object key not supported"); + goto error; + } + + if(flags & JSON_REJECT_DUPLICATES) { + if(json_object_get(object, key)) { + jsonp_free(key); + error_set(error, lex, "duplicate object key"); + goto error; + } + } + + lex_scan(lex, error); + if(lex->token != ':') { + jsonp_free(key); + error_set(error, lex, "':' expected"); + goto error; + } + + lex_scan(lex, error); + value = parse_value(lex, flags, error); + if(!value) { + jsonp_free(key); + goto error; + } + + if(json_object_set_nocheck(object, key, value)) { + jsonp_free(key); + json_decref(value); + goto error; + } + + json_decref(value); + jsonp_free(key); + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != '}') { + error_set(error, lex, "'}' expected"); + goto error; + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *array = json_array(); + if(!array) + return NULL; + + lex_scan(lex, error); + if(lex->token == ']') + return array; + + while(lex->token) { + json_t *elem = parse_value(lex, flags, error); + if(!elem) + goto error; + + if(json_array_append(array, elem)) { + json_decref(elem); + goto error; + } + json_decref(elem); + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != ']') { + error_set(error, lex, "']' expected"); + goto error; + } + + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *json; + double value; + + switch(lex->token) { + case TOKEN_STRING: { + const char *value = lex->value.string.val; + size_t len = lex->value.string.len; + + if(!(flags & JSON_ALLOW_NUL)) { + if(memchr(value, '\0', len)) { + error_set(error, lex, "\\u0000 is not allowed without JSON_ALLOW_NUL"); + return NULL; + } + } + + json = jsonp_stringn_nocheck_own(value, len); + if(json) { + lex->value.string.val = NULL; + lex->value.string.len = 0; + } + break; + } + + case TOKEN_INTEGER: { + if (flags & JSON_DECODE_INT_AS_REAL) { + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + return NULL; + } + json = json_real(value); + } else { + json = json_integer(lex->value.integer); + } + break; + } + + case TOKEN_REAL: { + json = json_real(lex->value.real); + break; + } + + case TOKEN_TRUE: + json = json_true(); + break; + + case TOKEN_FALSE: + json = json_false(); + break; + + case TOKEN_NULL: + json = json_null(); + break; + + case '{': + json = parse_object(lex, flags, error); + break; + + case '[': + json = parse_array(lex, flags, error); + break; + + case TOKEN_INVALID: + error_set(error, lex, "invalid token"); + return NULL; + + default: + error_set(error, lex, "unexpected token"); + return NULL; + } + + if(!json) + return NULL; + + return json; +} + +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *result; + + lex_scan(lex, error); + if(!(flags & JSON_DECODE_ANY)) { + if(lex->token != '[' && lex->token != '{') { + error_set(error, lex, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if(!result) + return NULL; + + if(!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if(lex->token != TOKEN_EOF) { + error_set(error, lex, "end of file expected"); + json_decref(result); + return NULL; + } + } + + if(error) { + /* Save the position even though there was no error */ + error->position = lex->stream.position; + } + + return result; +} + +typedef struct +{ + const char *data; + int pos; +} string_data_t; + +static int string_get(void *data) +{ + char c; + string_data_t *stream = (string_data_t *)data; + c = stream->data[stream->pos]; + if(c == '\0') + return EOF; + else + { + stream->pos++; + return (unsigned char)c; + } +} + +json_t *json_loads(const char *string, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if(lex_init(&lex, string_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct +{ + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) +{ + char c; + buffer_data_t *stream = data; + if(stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + buffer_data_t stream_data; + + jsonp_error_init(error, ""); + + if (buffer == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; + + if(lex_init(&lex, buffer_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) +{ + lex_t lex; + const char *source; + json_t *result; + + if(input == stdin) + source = ""; + else + source = ""; + + jsonp_error_init(error, source); + + if (input == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)fgetc, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) +{ + json_t *result; + FILE *fp; + + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + fp = fopen(path, "rb"); + if(!fp) + { + error_set(error, NULL, "unable to open %s: %s", + path, strerror(errno)); + return NULL; + } + + result = json_loadf(fp, flags, error); + + fclose(fp); + return result; +} + +#define MAX_BUF_LEN 1024 + +typedef struct +{ + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) +{ + char c; + callback_data_t *stream = data; + + if(stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if(stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)callback_get, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/deps/jansson/src/memory.c b/deps/jansson/src/memory.c new file mode 100644 index 000000000..e6da96edf --- /dev/null +++ b/deps/jansson/src/memory.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* C89 allows these to be macros */ +#undef malloc +#undef free + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) +{ + if(!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) +{ + if(!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) +{ + return jsonp_strndup(str, strlen(str)); +} + +char *jsonp_strndup(const char *str, size_t len) +{ + char *new_str; + + new_str = jsonp_malloc(len + 1); + if(!new_str) + return NULL; + + memcpy(new_str, str, len); + new_str[len] = '\0'; + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) +{ + do_malloc = malloc_fn; + do_free = free_fn; +} diff --git a/deps/jansson/src/pack_unpack.c b/deps/jansson/src/pack_unpack.c new file mode 100644 index 000000000..b19097df1 --- /dev/null +++ b/deps/jansson/src/pack_unpack.c @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { + "object", + "array", + "string", + "integer", + "real", + "true", + "false", + "null" +}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + + +static void scanner_init(scanner_t *s, json_error_t *error, + size_t flags, const char *fmt) +{ + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; +} + +static void next_token(scanner_t *s) +{ + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if(*t == '\n') { + s->line++; + s->column = 1; + } + else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + fmt, ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, + const char *purpose, size_t *out_len, int *ours) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + + next_token(s); + t = token(s); + prev_token(s); + + if(t != '#' && t != '%' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + set_error(s, "", "NULL string argument"); + return NULL; + } + + length = strlen(str); + + if(!utf8_check_string(str, length)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *out_len = length; + *ours = 0; + return (char *)str; + } + + strbuffer_init(&strbuff); + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "", "NULL string argument"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + + if(token(s) == '#') { + length = va_arg(*ap, int); + } + else if(token(s) == '%') { + length = va_arg(*ap, size_t); + } + else { + prev_token(s); + length = strlen(str); + } + + if(strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", "Out of memory"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + if(!utf8_check_string(strbuff.value, strbuff.length)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + strbuffer_close(&strbuff); + return NULL; + } + + *out_len = strbuff.length; + *ours = 1; + return strbuffer_steal_value(&strbuff); +} + +static json_t *pack_object(scanner_t *s, va_list *ap) +{ + json_t *object = json_object(); + next_token(s); + + while(token(s) != '}') { + char *key; + size_t len; + int ours; + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &len, &ours); + if(!key) + goto error; + + next_token(s); + + value = pack(s, ap); + if(!value) { + if(ours) + jsonp_free(key); + + goto error; + } + + if(json_object_set_new_nocheck(object, key, value)) { + if(ours) + jsonp_free(key); + + set_error(s, "", "Unable to add key \"%s\"", key); + goto error; + } + + if(ours) + jsonp_free(key); + + next_token(s); + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) +{ + json_t *array = json_array(); + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + value = pack(s, ap); + if(!value) + goto error; + + if(json_array_append_new(array, value)) { + set_error(s, "", "Unable to append to array"); + goto error; + } + + next_token(s); + } + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack(scanner_t *s, va_list *ap) +{ + switch(token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': /* string */ + { + char *str; + size_t len; + int ours; + + str = read_string(s, ap, "string", &len, &ours); + if(!str) + return NULL; + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + else + return json_stringn_nocheck(str, len); + } + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return json_integer(va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return json_integer(va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return json_real(va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return json_incref(va_arg(*ap, json_t *)); + + case 'o': /* a json_t object; doesn't increment refcount */ + return va_arg(*ap, json_t *); + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) +{ + int ret = -1; + int strict = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if(hashtable_init(&key_set)) { + set_error(s, "", "Out of memory"); + return -1; + } + + if(root && !json_is_object(root)) { + set_error(s, "", "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while(token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if(strict != 0) { + set_error(s, "", "Expected '}' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), token(s)); + goto out; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto out; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if(!key) { + set_error(s, "", "NULL object key"); + goto out; + } + + next_token(s); + + if(token(s) == '?') { + opt = 1; + next_token(s); + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_object_get(root, key); + if(!value && !opt) { + set_error(s, "", "Object item not found: %s", key); + goto out; + } + } + + if(unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, 0, json_null()); + next_token(s); + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && key_set.size != json_object_size(root)) { + long diff = (long)json_object_size(root) - (long)key_set.size; + set_error(s, "", "%li object item(s) left unpacked", diff); + goto out; + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) +{ + size_t i = 0; + int strict = 0; + + if(root && !json_is_array(root)) { + set_error(s, "", "Expected array, got %s", type_name(root)); + return -1; + } + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(strict != 0) { + set_error(s, "", "Expected ']' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + return -1; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(!strchr(unpack_value_starters, token(s))) { + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_array_get(root, i); + if(!value) { + set_error(s, "", "Array index %lu out of range", + (unsigned long)i); + return -1; + } + } + + if(unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) +{ + switch(token(s)) + { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if(root && !json_is_string(root)) { + set_error(s, "", "Expected string, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + const char **str_target; + size_t *len_target = NULL; + + str_target = va_arg(*ap, const char **); + if(!str_target) { + set_error(s, "", "NULL string argument"); + return -1; + } + + next_token(s); + + if(token(s) == '%') { + len_target = va_arg(*ap, size_t *); + if(!len_target) { + set_error(s, "", "NULL string length argument"); + return -1; + } + } + else + prev_token(s); + + if(root) { + *str_target = json_string_value(root); + if(len_target) + *len_target = json_string_length(root); + } + } + return 0; + + case 'i': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t*); + if(root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if(root && !json_is_boolean(root)) { + set_error(s, "", "Expected true or false, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if(root && !json_is_real(root)) { + set_error(s, "", "Expected real, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if(root && !json_is_number(root)) { + set_error(s, "", "Expected real or integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if(root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t**); + if(root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if(root && !json_is_null(root)) { + set_error(s, "", "Expected null, got %s", + type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + json_t *value; + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + if(!value) + return NULL; + + next_token(&s); + if(token(&s)) { + json_decref(value); + set_error(&s, "", "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + + if(!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL root value"); + return -1; + } + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if(unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if(token(&s)) { + set_error(&s, "", "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/deps/jansson/src/strbuffer.c b/deps/jansson/src/strbuffer.c new file mode 100644 index 000000000..2d6ff3105 --- /dev/null +++ b/deps/jansson/src/strbuffer.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +#define STRBUFFER_MIN_SIZE 16 +#define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) + +int strbuffer_init(strbuffer_t *strbuff) +{ + strbuff->size = STRBUFFER_MIN_SIZE; + strbuff->length = 0; + + strbuff->value = jsonp_malloc(strbuff->size); + if(!strbuff->value) + return -1; + + /* initialize to empty */ + strbuff->value[0] = '\0'; + return 0; +} + +void strbuffer_close(strbuffer_t *strbuff) +{ + if(strbuff->value) + jsonp_free(strbuff->value); + + strbuff->size = 0; + strbuff->length = 0; + strbuff->value = NULL; +} + +void strbuffer_clear(strbuffer_t *strbuff) +{ + strbuff->length = 0; + strbuff->value[0] = '\0'; +} + +const char *strbuffer_value(const strbuffer_t *strbuff) +{ + return strbuff->value; +} + +char *strbuffer_steal_value(strbuffer_t *strbuff) +{ + char *result = strbuff->value; + strbuff->value = NULL; + return result; +} + +int strbuffer_append(strbuffer_t *strbuff, const char *string) +{ + return strbuffer_append_bytes(strbuff, string, strlen(string)); +} + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte) +{ + return strbuffer_append_bytes(strbuff, &byte, 1); +} + +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) +{ + if(size >= strbuff->size - strbuff->length) + { + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR + || size > STRBUFFER_SIZE_MAX - 1 + || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, + strbuff->length + size + 1); + + new_value = jsonp_malloc(new_size); + if(!new_value) + return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; + } + + memcpy(strbuff->value + strbuff->length, data, size); + strbuff->length += size; + strbuff->value[strbuff->length] = '\0'; + + return 0; +} + +char strbuffer_pop(strbuffer_t *strbuff) +{ + if(strbuff->length > 0) { + char c = strbuff->value[--strbuff->length]; + strbuff->value[strbuff->length] = '\0'; + return c; + } + else + return '\0'; +} diff --git a/deps/jansson/src/strbuffer.h b/deps/jansson/src/strbuffer.h new file mode 100644 index 000000000..06fd065bb --- /dev/null +++ b/deps/jansson/src/strbuffer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STRBUFFER_H +#define STRBUFFER_H + +typedef struct { + char *value; + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ +} strbuffer_t; + +int strbuffer_init(strbuffer_t *strbuff); +void strbuffer_close(strbuffer_t *strbuff); + +void strbuffer_clear(strbuffer_t *strbuff); + +const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ +char *strbuffer_steal_value(strbuffer_t *strbuff); + +int strbuffer_append(strbuffer_t *strbuff, const char *string); +int strbuffer_append_byte(strbuffer_t *strbuff, char byte); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); + +char strbuffer_pop(strbuffer_t *strbuff); + +#endif diff --git a/deps/jansson/src/strconv.c b/deps/jansson/src/strconv.c new file mode 100644 index 000000000..3e2cb7c4c --- /dev/null +++ b/deps/jansson/src/strconv.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +/* need config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if(pos) + *pos = *point; +} + +static void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) +{ + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if(errno == ERANGE && value != 0) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value) +{ + int ret; + char *start, *end; + size_t length; + + ret = snprintf(buffer, size, "%.17g", value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(buffer, '.') == NULL && + strchr(buffer, 'e') == NULL) + { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/deps/jansson/src/utf.c b/deps/jansson/src/utf.c new file mode 100644 index 000000000..cbeeb54a1 --- /dev/null +++ b/deps/jansson/src/utf.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "utf.h" + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size) +{ + if(codepoint < 0) + return -1; + else if(codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if(codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if(codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if(codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +size_t utf8_check_first(char byte) +{ + unsigned char u = (unsigned char)byte; + + if(u < 0x80) + return 1; + + if(0x80 <= u && u <= 0xBF) { + /* second, third or fourth byte of a multi-byte + sequence, i.e. a "continuation byte" */ + return 0; + } + else if(u == 0xC0 || u == 0xC1) { + /* overlong encoding of an ASCII byte */ + return 0; + } + else if(0xC2 <= u && u <= 0xDF) { + /* 2-byte sequence */ + return 2; + } + + else if(0xE0 <= u && u <= 0xEF) { + /* 3-byte sequence */ + return 3; + } + else if(0xF0 <= u && u <= 0xF4) { + /* 4-byte sequence */ + return 4; + } + else { /* u >= 0xF5 */ + /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid + UTF-8 */ + return 0; + } +} + +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) +{ + size_t i; + int32_t value = 0; + unsigned char u = (unsigned char)buffer[0]; + + if(size == 2) + { + value = u & 0x1F; + } + else if(size == 3) + { + value = u & 0xF; + } + else if(size == 4) + { + value = u & 0x7; + } + else + return 0; + + for(i = 1; i < size; i++) + { + u = (unsigned char)buffer[i]; + + if(u < 0x80 || u > 0xBF) { + /* not a continuation byte */ + return 0; + } + + value = (value << 6) + (u & 0x3F); + } + + if(value > 0x10FFFF) { + /* not in Unicode range */ + return 0; + } + + else if(0xD800 <= value && value <= 0xDFFF) { + /* invalid code point (UTF-16 surrogate halves) */ + return 0; + } + + else if((size == 2 && value < 0x80) || + (size == 3 && value < 0x800) || + (size == 4 && value < 0x10000)) { + /* overlong encoding */ + return 0; + } + + if(codepoint) + *codepoint = value; + + return 1; +} + +const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) +{ + size_t count; + int32_t value; + + if(!bufsize) + return buffer; + + count = utf8_check_first(buffer[0]); + if(count <= 0) + return NULL; + + if(count == 1) + value = (unsigned char)buffer[0]; + else + { + if(count > bufsize || !utf8_check_full(buffer, count, &value)) + return NULL; + } + + if(codepoint) + *codepoint = value; + + return buffer + count; +} + +int utf8_check_string(const char *string, size_t length) +{ + size_t i; + + for(i = 0; i < length; i++) + { + size_t count = utf8_check_first(string[i]); + if(count == 0) + return 0; + else if(count > 1) + { + if(count > length - i) + return 0; + + if(!utf8_check_full(&string[i], count, NULL)) + return 0; + + i += count - 1; + } + } + + return 1; +} diff --git a/deps/jansson/src/utf.h b/deps/jansson/src/utf.h new file mode 100644 index 000000000..81f85ab8c --- /dev/null +++ b/deps/jansson/src/utf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTF_H +#define UTF_H + +#ifdef HAVE_CONFIG_H +#include + +#ifdef HAVE_INTTYPES_H +/* inttypes.h includes stdint.h in a standard environment, so there's +no need to include stdint.h separately. If inttypes.h doesn't define +int32_t, it's defined in config.h. */ +#include +#endif /* HAVE_INTTYPES_H */ + +#else /* !HAVE_CONFIG_H */ +#ifdef _WIN32 +typedef int int32_t; +#else /* !_WIN32 */ +/* Assume a standard environment */ +#include +#endif /* _WIN32 */ + +#endif /* HAVE_CONFIG_H */ + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size); + +size_t utf8_check_first(char byte); +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint); +const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint); + +int utf8_check_string(const char *string, size_t length); + +#endif diff --git a/deps/jansson/src/value.c b/deps/jansson/src/value.c new file mode 100644 index 000000000..417ea85b8 --- /dev/null +++ b/deps/jansson/src/value.c @@ -0,0 +1,1023 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +#include "jansson.h" +#include "hashtable.h" +#include "jansson_private.h" +#include "utf.h" + +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif + +static JSON_INLINE void json_init(json_t *json, json_type type) +{ + json->type = type; + json->refcount = 1; +} + + +/*** object ***/ + +json_t *json_object(void) +{ + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); + if(!object) + return NULL; + json_init(&object->json, JSON_OBJECT); + + if(hashtable_init(&object->hashtable)) + { + jsonp_free(object); + return NULL; + } + + object->serial = 0; + object->visited = 0; + + return &object->json; +} + +static void json_delete_object(json_object_t *object) +{ + hashtable_close(&object->hashtable); + jsonp_free(object); +} + +size_t json_object_size(const json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return 0; + + object = json_to_object(json); + return object->hashtable.size; +} + +json_t *json_object_get(const json_t *json, const char *key) +{ + json_object_t *object; + + if(!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_get(&object->hashtable, key); +} + +int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) +{ + json_object_t *object; + + if(!value) + return -1; + + if(!key || !json_is_object(json) || json == value) + { + json_decref(value); + return -1; + } + object = json_to_object(json); + + if(hashtable_set(&object->hashtable, key, object->serial++, value)) + { + json_decref(value); + return -1; + } + + return 0; +} + +int json_object_set_new(json_t *json, const char *key, json_t *value) +{ + if(!key || !utf8_check_string(key, strlen(key))) + { + json_decref(value); + return -1; + } + + return json_object_set_new_nocheck(json, key, value); +} + +int json_object_del(json_t *json, const char *key) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + return hashtable_del(&object->hashtable, key); +} + +int json_object_clear(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + + hashtable_clear(&object->hashtable); + object->serial = 0; + + return 0; +} + +int json_object_update(json_t *object, json_t *other) +{ + const char *key; + 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)) + return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) +{ + const char *key; + 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); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) +{ + const char *key; + 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); + } + + return 0; +} + +void *json_object_iter(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter(&object->hashtable); +} + +void *json_object_iter_at(json_t *json, const char *key) +{ + json_object_t *object; + + if(!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter_at(&object->hashtable, key); +} + +void *json_object_iter_next(json_t *json, void *iter) +{ + json_object_t *object; + + if(!json_is_object(json) || iter == NULL) + return NULL; + + object = json_to_object(json); + return hashtable_iter_next(&object->hashtable, iter); +} + +const char *json_object_iter_key(void *iter) +{ + if(!iter) + return NULL; + + return hashtable_iter_key(iter); +} + +json_t *json_object_iter_value(void *iter) +{ + if(!iter) + return NULL; + + return (json_t *)hashtable_iter_value(iter); +} + +int json_object_iter_set_new(json_t *json, void *iter, json_t *value) +{ + if(!json_is_object(json) || !iter || !value) + return -1; + + hashtable_iter_set(iter, value); + return 0; +} + +void *json_object_key_to_iter(const char *key) +{ + if(!key) + return NULL; + + return hashtable_key_to_iter(key); +} + +static int json_object_equal(json_t *object1, json_t *object2) +{ + const char *key; + json_t *value1, *value2; + + if(json_object_size(object1) != json_object_size(object2)) + return 0; + + json_object_foreach(object1, key, value1) { + value2 = json_object_get(object2, key); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_object_copy(json_t *object) +{ + json_t *result; + + const char *key; + json_t *value; + + result = json_object(); + if(!result) + return NULL; + + json_object_foreach(object, key, value) + json_object_set_nocheck(result, key, value); + + return result; +} + +static json_t *json_object_deep_copy(const json_t *object) +{ + json_t *result; + void *iter; + + result = json_object(); + if(!result) + return NULL; + + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { + const char *key; + const json_t *value; + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); + } + + return result; +} + + +/*** array ***/ + +json_t *json_array(void) +{ + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); + if(!array) + return NULL; + json_init(&array->json, JSON_ARRAY); + + array->entries = 0; + array->size = 8; + + array->table = jsonp_malloc(array->size * sizeof(json_t *)); + if(!array->table) { + jsonp_free(array); + return NULL; + } + + array->visited = 0; + + return &array->json; +} + +static void json_delete_array(json_array_t *array) +{ + size_t i; + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + jsonp_free(array->table); + jsonp_free(array); +} + +size_t json_array_size(const json_t *json) +{ + if(!json_is_array(json)) + return 0; + + return json_to_array(json)->entries; +} + +json_t *json_array_get(const json_t *json, size_t index) +{ + json_array_t *array; + if(!json_is_array(json)) + return NULL; + array = json_to_array(json); + + if(index >= array->entries) + return NULL; + + return array->table[index]; +} + +int json_array_set_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index >= array->entries) + { + json_decref(value); + return -1; + } + + json_decref(array->table[index]); + array->table[index] = value; + + return 0; +} + +static void array_move(json_array_t *array, size_t dest, + size_t src, size_t count) +{ + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, size_t dpos, + json_t **src, size_t spos, + size_t count) +{ + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, + size_t amount, + int copy) +{ + size_t new_size; + json_t **old_table, **new_table; + + if(array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); + if(!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if(copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + jsonp_free(old_table); + return array->table; + } + + return old_table; +} + +int json_array_append_new(json_t *json, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; + } + + array->table[array->entries] = value; + array->entries++; + + return 0; +} + +int json_array_insert_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + json_t **old_table; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if(!old_table) { + json_decref(value); + return -1; + } + + if(old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, + array->entries - index); + jsonp_free(old_table); + } + else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, size_t index) +{ + json_array_t *array; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + if(index >= array->entries) + return -1; + + json_decref(array->table[index]); + + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) +{ + json_array_t *array; + size_t i; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) +{ + json_array_t *array, *other; + size_t i; + + if(!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if(!json_array_grow(array, other->entries, 1)) + return -1; + + for(i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + +static int json_array_equal(json_t *array1, json_t *array2) +{ + size_t i, size; + + size = json_array_size(array1); + if(size != json_array_size(array2)) + return 0; + + for(i = 0; i < size; i++) + { + json_t *value1, *value2; + + value1 = json_array_get(array1, i); + value2 = json_array_get(array2, i); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_array_copy(json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append(result, json_array_get(array, i)); + + return result; +} + +static json_t *json_array_deep_copy(const json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append_new(result, json_deep_copy(json_array_get(array, i))); + + return result; +} + +/*** string ***/ + +static json_t *string_create(const char *value, size_t len, int own) +{ + char *v; + json_string_t *string; + + if(!value) + return NULL; + + if(own) + v = (char *)value; + else { + v = jsonp_strndup(value, len); + if(!v) + return NULL; + } + + string = jsonp_malloc(sizeof(json_string_t)); + if(!string) { + if(!own) + jsonp_free(v); + return NULL; + } + json_init(&string->json, JSON_STRING); + string->value = v; + string->length = len; + + return &string->json; +} + +json_t *json_string_nocheck(const char *value) +{ + if(!value) + return NULL; + + return string_create(value, strlen(value), 0); +} + +json_t *json_stringn_nocheck(const char *value, size_t len) +{ + return string_create(value, len, 0); +} + +/* this is private; "steal" is not a public API concept */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len) +{ + return string_create(value, len, 1); +} + +json_t *json_string(const char *value) +{ + if(!value) + return NULL; + + return json_stringn(value, strlen(value)); +} + +json_t *json_stringn(const char *value, size_t len) +{ + if(!value || !utf8_check_string(value, len)) + return NULL; + + return json_stringn_nocheck(value, len); +} + +const char *json_string_value(const json_t *json) +{ + if(!json_is_string(json)) + return NULL; + + return json_to_string(json)->value; +} + +size_t json_string_length(const json_t *json) +{ + if(!json_is_string(json)) + return 0; + + return json_to_string(json)->length; +} + +int json_string_set_nocheck(json_t *json, const char *value) +{ + if(!value) + return -1; + + return json_string_setn_nocheck(json, value, strlen(value)); +} + +int json_string_setn_nocheck(json_t *json, const char *value, size_t len) +{ + char *dup; + json_string_t *string; + + if(!json_is_string(json) || !value) + return -1; + + dup = jsonp_strndup(value, len); + if(!dup) + return -1; + + string = json_to_string(json); + jsonp_free(string->value); + string->value = dup; + string->length = len; + + return 0; +} + +int json_string_set(json_t *json, const char *value) +{ + if(!value) + return -1; + + return json_string_setn(json, value, strlen(value)); +} + +int json_string_setn(json_t *json, const char *value, size_t len) +{ + if(!value || !utf8_check_string(value, len)) + return -1; + + return json_string_setn_nocheck(json, value, len); +} + +static void json_delete_string(json_string_t *string) +{ + jsonp_free(string->value); + jsonp_free(string); +} + +static int json_string_equal(json_t *string1, json_t *string2) +{ + json_string_t *s1, *s2; + + if(!json_is_string(string1) || !json_is_string(string2)) + return 0; + + s1 = json_to_string(string1); + s2 = json_to_string(string2); + return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); +} + +static json_t *json_string_copy(const json_t *string) +{ + json_string_t *s; + + if(!json_is_string(string)) + return NULL; + + s = json_to_string(string); + return json_stringn_nocheck(s->value, s->length); +} + + +/*** integer ***/ + +json_t *json_integer(json_int_t value) +{ + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); + if(!integer) + return NULL; + json_init(&integer->json, JSON_INTEGER); + + integer->value = value; + return &integer->json; +} + +json_int_t json_integer_value(const json_t *json) +{ + if(!json_is_integer(json)) + return 0; + + return json_to_integer(json)->value; +} + +int json_integer_set(json_t *json, json_int_t value) +{ + if(!json_is_integer(json)) + return -1; + + json_to_integer(json)->value = value; + + return 0; +} + +static void json_delete_integer(json_integer_t *integer) +{ + jsonp_free(integer); +} + +static int json_integer_equal(json_t *integer1, json_t *integer2) +{ + return json_integer_value(integer1) == json_integer_value(integer2); +} + +static json_t *json_integer_copy(const json_t *integer) +{ + return json_integer(json_integer_value(integer)); +} + + +/*** real ***/ + +json_t *json_real(double value) +{ + json_real_t *real; + + if(isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); + if(!real) + return NULL; + json_init(&real->json, JSON_REAL); + + real->value = value; + return &real->json; +} + +double json_real_value(const json_t *json) +{ + if(!json_is_real(json)) + return 0; + + return json_to_real(json)->value; +} + +int json_real_set(json_t *json, double value) +{ + if(!json_is_real(json) || isnan(value) || isinf(value)) + return -1; + + json_to_real(json)->value = value; + + return 0; +} + +static void json_delete_real(json_real_t *real) +{ + jsonp_free(real); +} + +static int json_real_equal(json_t *real1, json_t *real2) +{ + return json_real_value(real1) == json_real_value(real2); +} + +static json_t *json_real_copy(const json_t *real) +{ + return json_real(json_real_value(real)); +} + + +/*** number ***/ + +double json_number_value(const json_t *json) +{ + if(json_is_integer(json)) + return (double)json_integer_value(json); + else if(json_is_real(json)) + return json_real_value(json); + else + return 0.0; +} + + +/*** simple values ***/ + +json_t *json_true(void) +{ + static json_t the_true = {JSON_TRUE, (size_t)-1}; + return &the_true; +} + + +json_t *json_false(void) +{ + static json_t the_false = {JSON_FALSE, (size_t)-1}; + return &the_false; +} + + +json_t *json_null(void) +{ + static json_t the_null = {JSON_NULL, (size_t)-1}; + return &the_null; +} + + +/*** deletion ***/ + +void json_delete(json_t *json) +{ + if(json_is_object(json)) + json_delete_object(json_to_object(json)); + + else if(json_is_array(json)) + json_delete_array(json_to_array(json)); + + else if(json_is_string(json)) + json_delete_string(json_to_string(json)); + + else if(json_is_integer(json)) + json_delete_integer(json_to_integer(json)); + + else if(json_is_real(json)) + json_delete_real(json_to_real(json)); + + /* json_delete is not called for true, false or null */ +} + + +/*** equality ***/ + +int json_equal(json_t *json1, json_t *json2) +{ + if(!json1 || !json2) + return 0; + + if(json_typeof(json1) != json_typeof(json2)) + return 0; + + /* this covers true, false and null as they are singletons */ + if(json1 == json2) + return 1; + + if(json_is_object(json1)) + return json_object_equal(json1, json2); + + if(json_is_array(json1)) + return json_array_equal(json1, json2); + + if(json_is_string(json1)) + return json_string_equal(json1, json2); + + if(json_is_integer(json1)) + return json_integer_equal(json1, json2); + + if(json_is_real(json1)) + return json_real_equal(json1, json2); + + return 0; +} + + +/*** copying ***/ + +json_t *json_copy(json_t *json) +{ + if(!json) + return NULL; + + if(json_is_object(json)) + return json_object_copy(json); + + if(json_is_array(json)) + return json_array_copy(json); + + if(json_is_string(json)) + return json_string_copy(json); + + if(json_is_integer(json)) + return json_integer_copy(json); + + if(json_is_real(json)) + return json_real_copy(json); + + if(json_is_true(json) || json_is_false(json) || json_is_null(json)) + return json; + + return NULL; +} + +json_t *json_deep_copy(const json_t *json) +{ + if(!json) + return NULL; + + if(json_is_object(json)) + return json_object_deep_copy(json); + + if(json_is_array(json)) + return json_array_deep_copy(json); + + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + + if(json_is_string(json)) + return json_string_copy(json); + + if(json_is_integer(json)) + return json_integer_copy(json); + + if(json_is_real(json)) + return json_real_copy(json); + + if(json_is_true(json) || json_is_false(json) || json_is_null(json)) + return (json_t *)json; + + return NULL; +} diff --git a/deps/jansson/test/.gitignore b/deps/jansson/test/.gitignore new file mode 100644 index 000000000..ae6c8f926 --- /dev/null +++ b/deps/jansson/test/.gitignore @@ -0,0 +1,17 @@ +logs +bin/json_process +suites/api/test_array +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_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_unpack +suites/api/test_load_callback diff --git a/deps/jansson/test/Makefile.am b/deps/jansson/test/Makefile.am new file mode 100644 index 000000000..86d1614e0 --- /dev/null +++ b/deps/jansson/test/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = bin suites +EXTRA_DIST = scripts run-suites + +TESTS = run-suites +TESTS_ENVIRONMENT = \ + top_srcdir=$(top_srcdir) \ + top_builddir=$(top_builddir) + +clean-local: + rm -rf logs diff --git a/deps/jansson/test/bin/Makefile.am b/deps/jansson/test/bin/Makefile.am new file mode 100644 index 000000000..63b6dce7e --- /dev/null +++ b/deps/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 diff --git a/deps/jansson/test/bin/json_process.c b/deps/jansson/test/bin/json_process.c new file mode 100644 index 000000000..23afefec0 --- /dev/null +++ b/deps/jansson/test/bin/json_process.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * 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 +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include + #endif + +#if _WIN32 +#include /* for _setmode() */ +#include /* for _O_BINARY */ + +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; +} 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) +{ + long 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, "STRIP")) + conf.strip = atoi(val); + } + + 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 > 255) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent); + 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.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; + 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 > 255) { + 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; + + if(getenv_int("STRIP")) { + /* Load to memory, strip leading and trailing whitespace */ + size_t size = 0, used = 0; + char *buffer = NULL; + + while(1) { + size_t count; + + size = (size == 0 ? 128 : size * 2); + buffer = realloc(buffer, size); + if(!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); + return 1; + } + + 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; +} diff --git a/deps/jansson/test/run-suites b/deps/jansson/test/run-suites new file mode 100755 index 000000000..4cbaa8b14 --- /dev/null +++ b/deps/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=$(($passed+1)) + else + failed=$(($failed+1)) + [ $STOP -eq 1 ] && break + fi +done + +if [ $failed -gt 0 ]; then + echo "$failed of $((passed+failed)) test suites failed" + exit 1 +else + echo "$passed test suites passed" + rm -rf $logdir +fi diff --git a/deps/jansson/test/scripts/run-tests.sh b/deps/jansson/test/scripts/run-tests.sh new file mode 100644 index 000000000..5ed3b9f73 --- /dev/null +++ b/deps/jansson/test/scripts/run-tests.sh @@ -0,0 +1,100 @@ +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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 diff --git a/deps/jansson/test/scripts/valgrind.sh b/deps/jansson/test/scripts/valgrind.sh new file mode 100644 index 000000000..9b0043885 --- /dev/null +++ b/deps/jansson/test/scripts/valgrind.sh @@ -0,0 +1,35 @@ +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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 +} diff --git a/deps/jansson/test/suites/.gitattributes b/deps/jansson/test/suites/.gitattributes new file mode 100644 index 000000000..68d88612c --- /dev/null +++ b/deps/jansson/test/suites/.gitattributes @@ -0,0 +1,2 @@ +api/ text=auto +* text eol=lf \ No newline at end of file diff --git a/deps/jansson/test/suites/Makefile.am b/deps/jansson/test/suites/Makefile.am new file mode 100644 index 000000000..a53eb07f1 --- /dev/null +++ b/deps/jansson/test/suites/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = api +EXTRA_DIST = invalid invalid-unicode valid diff --git a/deps/jansson/test/suites/api/Makefile.am b/deps/jansson/test/suites/api/Makefile.am new file mode 100644 index 000000000..1dbdd2b89 --- /dev/null +++ b/deps/jansson/test/suites/api/Makefile.am @@ -0,0 +1,34 @@ +EXTRA_DIST = run check-exports + +check_PROGRAMS = \ + test_array \ + test_copy \ + test_dump \ + test_dump_callback \ + test_equal \ + test_load \ + test_loadb \ + test_load_callback \ + test_memory_funcs \ + test_number \ + test_object \ + test_pack \ + test_simple \ + test_unpack + +test_array_SOURCES = test_array.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_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_unpack_SOURCES = test_unpack.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 diff --git a/deps/jansson/test/suites/api/check-exports b/deps/jansson/test/suites/api/check-exports new file mode 100755 index 000000000..9adca7d39 --- /dev/null +++ b/deps/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_' $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 '^_' | 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 diff --git a/deps/jansson/test/suites/api/run b/deps/jansson/test/suites/api/run new file mode 100755 index 000000000..5f8e95939 --- /dev/null +++ b/deps/jansson/test/suites/api/run @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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 diff --git a/deps/jansson/test/suites/api/test_array.c b/deps/jansson/test/suites/api/test_array.c new file mode 100644 index 000000000..0a9447fc8 --- /dev/null +++ b/deps/jansson/test/suites/api/test_array.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "util.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 begining 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 run_tests() +{ + test_misc(); + test_insert(); + test_remove(); + test_clear(); + test_extend(); + test_circular(); + test_array_foreach(); +} diff --git a/deps/jansson/test/suites/api/test_copy.c b/deps/jansson/test/suites/api/test_copy.c new file mode 100644 index 000000000..580488d82 --- /dev/null +++ b/deps/jansson/test/suites/api/test_copy.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.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]}"; + + 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"); + + 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 modifies its items"); + + iter = json_object_iter_next(object, iter); + } + + 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]}"; + + 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"); + + 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"); + + iter = json_object_iter_next(object, iter); + } + + json_decref(object); + json_decref(copy); +} + +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(); +} diff --git a/deps/jansson/test/suites/api/test_dump.c b/deps/jansson/test/suites/api/test_dump.c new file mode 100644 index 000000000..89e73a7a2 --- /dev/null +++ b/deps/jansson/test/suites/api/test_dump.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +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_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1) + fail("json_dumpf didn't fail for NULL"); + + /* 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": }}} + 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; + FILE *fp = NULL; + char *result; + + json = json_string("foo"); + if(json_dumps(json, 0) != NULL) + fail("json_dumps encoded a string!"); + if(json_dumpf(json, fp, 0) == 0) + fail("json_dumpf 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, fp, 0) == 0) + fail("json_dumpf 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 run_tests() +{ + encode_null(); + encode_twice(); + circular_references(); + encode_other_than_array_or_object(); + escape_slashes(); + encode_nul_byte(); +} diff --git a/deps/jansson/test/suites/api/test_dump_callback.c b/deps/jansson/test/suites/api/test_dump_callback.c new file mode 100644 index 000000000..4536d5608 --- /dev/null +++ b/deps/jansson/test/suites/api/test_dump_callback.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.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); +} diff --git a/deps/jansson/test/suites/api/test_equal.c b/deps/jansson/test/suites/api/test_equal.c new file mode 100644 index 000000000..354e5c9ea --- /dev/null +++ b/deps/jansson/test/suites/api/test_equal.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "util.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(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; + + 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); + if(!value1 || !value2) + fail("unable to parse JSON"); + if(!json_equal(value1, value2)) + fail("json_equal fails for two inequal strings"); + + json_decref(value1); + json_decref(value2); + + /* TODO: There's no negative test case here */ +} + +static void run_tests() +{ + test_equal_simple(); + test_equal_array(); + test_equal_object(); + test_equal_complex(); +} diff --git a/deps/jansson/test/suites/api/test_load.c b/deps/jansson/test/suites/api/test_load.c new file mode 100644 index 000000000..eb52323e4 --- /dev/null +++ b/deps/jansson/test/suites/api/test_load.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.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"); +} + +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("duplicate object key near '\"foo\"'", "", 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("end of file expected near 'garbage'", "", 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 + + 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 +} + +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_load_file(NULL, 0, &error); + if (json) + fail("json_loadf 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 run_tests() +{ + file_not_found(); + reject_duplicates(); + disable_eof_check(); + decode_any(); + decode_int_as_real(); + allow_nul(); + load_wrong_args(); + position(); +} diff --git a/deps/jansson/test/suites/api/test_load_callback.c b/deps/jansson/test/suites/api/test_load_callback.c new file mode 100644 index 000000000..944952816 --- /dev/null +++ b/deps/jansson/test/suites/api/test_load_callback.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009-2011 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.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, "") != 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"); + } +} diff --git a/deps/jansson/test/suites/api/test_loadb.c b/deps/jansson/test/suites/api/test_loadb.c new file mode 100644 index 000000000..fa5e96762 --- /dev/null +++ b/deps/jansson/test/suites/api/test_loadb.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.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"); + } +} diff --git a/deps/jansson/test/suites/api/test_memory_funcs.c b/deps/jansson/test/suites/api/test_memory_funcs.c new file mode 100644 index 000000000..8737389b8 --- /dev/null +++ b/deps/jansson/test/suites/api/test_memory_funcs.c @@ -0,0 +1,82 @@ +#include +#include + +#include "util.h" + +static int malloc_called = 0; +static int free_called = 0; + +/* helper */ +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 *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_set_alloc_funcs(my_malloc, my_free); + create_and_free_complex_object(); + + if(malloc_called != 20 || free_called != 20) + fail("Custom allocation 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 run_tests() +{ + test_simple(); + test_secure_funcs(); +} diff --git a/deps/jansson/test/suites/api/test_number.c b/deps/jansson/test/suites/api/test_number.c new file mode 100644 index 000000000..b506a2bcf --- /dev/null +++ b/deps/jansson/test/suites/api/test_number.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +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 + 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); +#endif +} diff --git a/deps/jansson/test/suites/api/test_object.c b/deps/jansson/test/suites/api/test_object.c new file mode 100644 index 000000000..ba428e196 --- /dev/null +++ b/deps/jansson/test/suites/api/test_object.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.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 emtpy 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"); + + json_decref(nine); + json_decref(ten); + json_decref(other); + json_decref(object); +} + +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); + + 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_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 || !bar) + 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")) + fail("iterating failed: wrong key"); + if(json_object_iter_value(iter) != foo) + fail("iterating failed: wrong value"); + + iter = json_object_iter_next(object, iter); + if(!iter) + fail("unable to increment iterator"); + 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"); + + iter = json_object_iter_next(object, iter); + if(!iter) + fail("unable to increment iterator"); + if(strcmp(json_object_iter_key(iter), "c")) + fail("iterating failed: wrong key"); + if(json_object_iter_value(iter) != baz) + fail("iterating failed: wrong value"); + + 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"); + + iter = json_object_iter_next(object, iter); + if(!iter) + fail("unable to increment iterator"); + if(strcmp(json_object_iter_key(iter), "c")) + fail("iterating failed: wrong key"); + if(json_object_iter_value(iter) != baz) + fail("iterating failed: wrong value"); + + if(json_object_iter_set(object, iter, bar)) + fail("unable to set value at iterator"); + + if(strcmp(json_object_iter_key(iter), "c")) + fail("json_object_iter_key() fails after json_object_iter_set()"); + if(json_object_iter_value(iter) != bar) + fail("json_object_iter_value() fails after json_object_iter_set()"); + if(json_object_get(object, "c") != bar) + 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_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 run_tests() +{ + test_misc(); + test_clear(); + test_update(); + test_conditional_updates(); + test_circular(); + test_set_nocheck(); + test_iterators(); + test_preserve_order(); + test_object_foreach(); +} diff --git a/deps/jansson/test/suites/api/test_pack.c b/deps/jansson/test/suites/api/test_pack.c new file mode 100644 index 000000000..348d8b2cc --- /dev/null +++ b/deps/jansson/test/suites/api/test_pack.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2010-2012 Graeme Smecher + * + * 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 +#endif + +#include + +#include +#include +#include +#include "util.h" + +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); + + /* 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 */ + 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); + + /* 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); + + /* 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); + + /* 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); + + /* Whitespace; regular string */ + value = json_pack(" s ", "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("Expected format 's', got '1'", "", 3, 1, 4); + + /* mismatched open/close array/object */ + if(json_pack_ex(&error, 0, "[}")) + fail("json_pack failed to catch mismatched '}'"); + check_error("Unexpected format character '}'", "", 1, 2, 2); + + if(json_pack_ex(&error, 0, "{]")) + fail("json_pack failed to catch mismatched ']'"); + check_error("Expected format 's', got ']'", "", 1, 2, 2); + + /* missing close array */ + if(json_pack_ex(&error, 0, "[")) + fail("json_pack failed to catch missing ']'"); + check_error("Unexpected end of format string", "", 1, 2, 2); + + /* missing close object */ + if(json_pack_ex(&error, 0, "{")) + fail("json_pack failed to catch missing '}'"); + check_error("Unexpected end of format string", "", 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("Garbage after format string", "", 1, 4, 4); + + if(json_pack_ex(&error, 0, "ia", 42)) + fail("json_pack failed to catch garbage after format string"); + check_error("Garbage after format string", "", 1, 2, 2); + + /* NULL string */ + if(json_pack_ex(&error, 0, "s", NULL)) + fail("json_pack failed to catch null argument string"); + check_error("NULL string argument", "", 1, 1, 1); + + /* + on its own */ + if(json_pack_ex(&error, 0, "+", NULL)) + fail("json_pack failed to a lone +"); + check_error("Unexpected format character '+'", "", 1, 1, 1); + + /* NULL format */ + if(json_pack_ex(&error, 0, NULL)) + fail("json_pack failed to catch NULL format string"); + check_error("NULL or empty format string", "", -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("NULL string argument", "", 1, 2, 2); + + /* 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("Expected format 's', got '{'", "", 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("Unexpected format character '}'", "", 1, 19, 19); + + /* Complex array */ + if(json_pack_ex(&error, 0, "[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]")) + fail("json_pack failed to catch extra }"); + check_error("Unexpected format character '}'", "", 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("Invalid UTF-8 object key", "", 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("Invalid UTF-8 string", "", 1, 4, 4); +} diff --git a/deps/jansson/test/suites/api/test_simple.c b/deps/jansson/test/suites/api/test_simple.c new file mode 100644 index 000000000..ca97a7d1b --- /dev/null +++ b/deps/jansson/test/suites/api/test_simple.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +/* 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"); + 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() 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"); +} diff --git a/deps/jansson/test/suites/api/test_unpack.c b/deps/jansson/test/suites/api/test_unpack.c new file mode 100644 index 000000000..7f049ddc1 --- /dev/null +++ b/deps/jansson/test/suites/api/test_unpack.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2010-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.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("Unexpected format character 'z'", "", 1, 1, 1); + + if(!json_unpack_ex(NULL, &error, 0, "[i]")) + fail("json_unpack succeeded with NULL root"); + check_error("NULL root value", "", -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("Unexpected format character '}'", "", 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("Expected format 's', got ']'", "", 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("Unexpected end of format string", "", 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("Unexpected end of format string", "", 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("Garbage after format string", "", 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("Garbage after format string", "", 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("NULL or empty format string", "", -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("NULL string argument", "", 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("Expected string, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "n")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected null, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "b")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected true or false, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "i")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "I")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "f")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected real, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "F")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected real or integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "[i]")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected array, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "{si}", "foo")) + fail("json_unpack failed to catch invalid type"); + check_error("Expected object, got integer", "", 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("Array index 1 out of range", "", 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("NULL object key", "", 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("Object item not found: baz", "", 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("1 array item(s) left unpacked", "", 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("1 array item(s) left unpacked", "", 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}", "foo", "bar", "baz", 42); + if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) + fail("json_unpack object with strict validation failed"); + check_error("1 object item(s) left unpacked", "", 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("Expected ']' after '!', got 'i'", "", 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("Expected ']' after '*', got 'i'", "", 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("Expected '}' after '!', got 's'", "", 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("Expected '}' after '*', got 's'", "", 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("1 object item(s) left unpacked", "", 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("1 array item(s) left unpacked", "", 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); +} diff --git a/deps/jansson/test/suites/api/util.h b/deps/jansson/test/suites/api/util.h new file mode 100644 index 000000000..b86a5463d --- /dev/null +++ b/deps/jansson/test/suites/api/util.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * + * 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 +#endif + +#include +#include +#if HAVE_LOCALE_H +#include +#endif + +#include + +#define failhdr fprintf(stderr, "%s:%s:%d: ", __FILE__, __FUNCTION__, __LINE__) + +#define fail(msg) \ + do { \ + failhdr; \ + fprintf(stderr, "%s\n", msg); \ + exit(1); \ + } while(0) + +/* Assumes json_error_t error */ +#define check_error(text_, source_, line_, column_, position_) \ + do { \ + if(strcmp(error.text, text_) != 0) { \ + failhdr; \ + fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, 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) + + +static void run_tests(); + +int main() { +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + run_tests(); + return 0; +} + +#endif diff --git a/deps/jansson/test/suites/encoding-flags/array/input b/deps/jansson/test/suites/encoding-flags/array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/deps/jansson/test/suites/encoding-flags/array/output b/deps/jansson/test/suites/encoding-flags/array/output new file mode 100644 index 000000000..fd8ef0957 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/array/output @@ -0,0 +1 @@ +[1, 2] \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/compact-array/env b/deps/jansson/test/suites/encoding-flags/compact-array/env new file mode 100644 index 000000000..4474aaf14 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-array/env @@ -0,0 +1,2 @@ +JSON_COMPACT=1 +export JSON_COMPACT diff --git a/deps/jansson/test/suites/encoding-flags/compact-array/input b/deps/jansson/test/suites/encoding-flags/compact-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/deps/jansson/test/suites/encoding-flags/compact-array/output b/deps/jansson/test/suites/encoding-flags/compact-array/output new file mode 100644 index 000000000..3169929f6 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-array/output @@ -0,0 +1 @@ +[1,2] \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/compact-object/env b/deps/jansson/test/suites/encoding-flags/compact-object/env new file mode 100644 index 000000000..4474aaf14 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-object/env @@ -0,0 +1,2 @@ +JSON_COMPACT=1 +export JSON_COMPACT diff --git a/deps/jansson/test/suites/encoding-flags/compact-object/input b/deps/jansson/test/suites/encoding-flags/compact-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/deps/jansson/test/suites/encoding-flags/compact-object/output b/deps/jansson/test/suites/encoding-flags/compact-object/output new file mode 100644 index 000000000..73a5d70e3 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/compact-object/output @@ -0,0 +1 @@ +{"a":1,"b":2} \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/ensure-ascii/env b/deps/jansson/test/suites/encoding-flags/ensure-ascii/env new file mode 100644 index 000000000..1b7b3e3f9 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/ensure-ascii/env @@ -0,0 +1,2 @@ +JSON_ENSURE_ASCII=1 +export JSON_ENSURE_ASCII diff --git a/deps/jansson/test/suites/encoding-flags/ensure-ascii/input b/deps/jansson/test/suites/encoding-flags/ensure-ascii/input new file mode 100644 index 000000000..69469cef5 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/ensure-ascii/input @@ -0,0 +1,8 @@ +[ + "foo", + "å ä ö", + "foo åä", + "åä foo", + "å foo ä", + "clef g: 𝄞" +] diff --git a/deps/jansson/test/suites/encoding-flags/ensure-ascii/output b/deps/jansson/test/suites/encoding-flags/ensure-ascii/output new file mode 100644 index 000000000..94fa79d2d --- /dev/null +++ b/deps/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"] \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/indent-array/env b/deps/jansson/test/suites/encoding-flags/indent-array/env new file mode 100644 index 000000000..d220f837c --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-array/env @@ -0,0 +1,2 @@ +JSON_INDENT=4 +export JSON_INDENT diff --git a/deps/jansson/test/suites/encoding-flags/indent-array/input b/deps/jansson/test/suites/encoding-flags/indent-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/deps/jansson/test/suites/encoding-flags/indent-array/output b/deps/jansson/test/suites/encoding-flags/indent-array/output new file mode 100644 index 000000000..c57d705ba --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-array/env b/deps/jansson/test/suites/encoding-flags/indent-compact-array/env new file mode 100644 index 000000000..78fbfcc2e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-array/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +export JSON_INDENT JSON_COMPACT diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-array/input b/deps/jansson/test/suites/encoding-flags/indent-compact-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-array/output b/deps/jansson/test/suites/encoding-flags/indent-compact-array/output new file mode 100644 index 000000000..c57d705ba --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-object/env b/deps/jansson/test/suites/encoding-flags/indent-compact-object/env new file mode 100644 index 000000000..78fbfcc2e --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-object/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +export JSON_INDENT JSON_COMPACT diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-object/input b/deps/jansson/test/suites/encoding-flags/indent-compact-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/deps/jansson/test/suites/encoding-flags/indent-compact-object/output b/deps/jansson/test/suites/encoding-flags/indent-compact-object/output new file mode 100644 index 000000000..9cc42948d --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-compact-object/output @@ -0,0 +1,4 @@ +{ + "a":1, + "b":2 +} \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/indent-object/env b/deps/jansson/test/suites/encoding-flags/indent-object/env new file mode 100644 index 000000000..d220f837c --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-object/env @@ -0,0 +1,2 @@ +JSON_INDENT=4 +export JSON_INDENT diff --git a/deps/jansson/test/suites/encoding-flags/indent-object/input b/deps/jansson/test/suites/encoding-flags/indent-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/deps/jansson/test/suites/encoding-flags/indent-object/output b/deps/jansson/test/suites/encoding-flags/indent-object/output new file mode 100644 index 000000000..0fbddba44 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/indent-object/output @@ -0,0 +1,4 @@ +{ + "a": 1, + "b": 2 +} \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/object/input b/deps/jansson/test/suites/encoding-flags/object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/deps/jansson/test/suites/encoding-flags/object/output b/deps/jansson/test/suites/encoding-flags/object/output new file mode 100644 index 000000000..ecd219f72 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/object/output @@ -0,0 +1 @@ +{"a": 1, "b": 2} \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/preserve-order/env b/deps/jansson/test/suites/encoding-flags/preserve-order/env new file mode 100644 index 000000000..4d9d20659 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/preserve-order/env @@ -0,0 +1,2 @@ +JSON_PRESERVE_ORDER=1 +export JSON_PRESERVE_ORDER diff --git a/deps/jansson/test/suites/encoding-flags/preserve-order/input b/deps/jansson/test/suites/encoding-flags/preserve-order/input new file mode 100644 index 000000000..27bcf18a0 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/preserve-order/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} diff --git a/deps/jansson/test/suites/encoding-flags/preserve-order/output b/deps/jansson/test/suites/encoding-flags/preserve-order/output new file mode 100644 index 000000000..7a443f684 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/preserve-order/output @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} \ No newline at end of file diff --git a/deps/jansson/test/suites/encoding-flags/run b/deps/jansson/test/suites/encoding-flags/run new file mode 100755 index 000000000..1920f7fc6 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/run @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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() { + test -d $test_path +} + +run_test() { + ( + if [ -f $test_path/env ]; then + . $test_path/env + fi + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + ) + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/output $test_log/stdout +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED OUTPUT:" + nl -bn $test_path/output + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/deps/jansson/test/suites/encoding-flags/sort-keys/env b/deps/jansson/test/suites/encoding-flags/sort-keys/env new file mode 100644 index 000000000..3ef24cb7b --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/sort-keys/env @@ -0,0 +1,2 @@ +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS diff --git a/deps/jansson/test/suites/encoding-flags/sort-keys/input b/deps/jansson/test/suites/encoding-flags/sort-keys/input new file mode 100644 index 000000000..66951d6b0 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/sort-keys/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "baz": 3, "quux": 4} diff --git a/deps/jansson/test/suites/encoding-flags/sort-keys/output b/deps/jansson/test/suites/encoding-flags/sort-keys/output new file mode 100644 index 000000000..132d9df31 --- /dev/null +++ b/deps/jansson/test/suites/encoding-flags/sort-keys/output @@ -0,0 +1 @@ +{"bar": 2, "baz": 3, "foo": 1, "quux": 4} \ No newline at end of file diff --git a/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error b/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error new file mode 100644 index 000000000..762d2c4b1 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xed near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input b/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input new file mode 100644 index 000000000..515dd933c --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input @@ -0,0 +1 @@ +[" <-- encoded surrogate half"] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error new file mode 100644 index 000000000..b16dc171e --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '"\' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input new file mode 100644 index 000000000..57c8beef6 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input @@ -0,0 +1 @@ +["\"] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error new file mode 100644 index 000000000..be15386df --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error @@ -0,0 +1,2 @@ +1 1 1 +unable to decode byte 0xe5 diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input new file mode 100644 index 000000000..ebefcd6f8 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input @@ -0,0 +1 @@ +[] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error new file mode 100644 index 000000000..01b447639 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '123' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input new file mode 100644 index 000000000..e512f9ae0 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input @@ -0,0 +1 @@ +[123] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error new file mode 100644 index 000000000..c13583dd8 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '"\u' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input new file mode 100644 index 000000000..2b271b82f --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input @@ -0,0 +1 @@ +["\u"] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error new file mode 100644 index 000000000..c7b20b7a2 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '1e1' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input new file mode 100644 index 000000000..d8e83c595 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input @@ -0,0 +1 @@ +[1e1] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error new file mode 100644 index 000000000..33dfc2324 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near 'a' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input new file mode 100644 index 000000000..ef038514a --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input @@ -0,0 +1 @@ +[a] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error new file mode 100644 index 000000000..8f08970c1 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '0' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input new file mode 100644 index 000000000..371226e4c --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input @@ -0,0 +1 @@ +[0] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error new file mode 100644 index 000000000..b7660e327 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '1e' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input new file mode 100644 index 000000000..17fc29c90 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input @@ -0,0 +1 @@ +[1e] diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error new file mode 100644 index 000000000..0b7039a52 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input new file mode 100644 index 000000000..00b79c0af --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input @@ -0,0 +1 @@ +[" <-- invalid UTF-8"] diff --git a/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error b/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error new file mode 100644 index 000000000..8e9a51119 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error @@ -0,0 +1,2 @@ +1 0 0 +unable to decode byte 0xe5 diff --git a/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input b/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input new file mode 100644 index 000000000..eb8079699 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input @@ -0,0 +1 @@ + diff --git a/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error b/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error new file mode 100644 index 000000000..86bbad3c8 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0x81 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input b/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input new file mode 100644 index 000000000..62a26b6fb --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input @@ -0,0 +1 @@ +[""] diff --git a/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/error b/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/error new file mode 100644 index 000000000..d07ccb3e5 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf4 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/input b/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/input new file mode 100644 index 000000000..1216186a7 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/not-in-unicode-range/input @@ -0,0 +1 @@ +[""] diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error b/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error new file mode 100644 index 000000000..8a05abaed --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input b/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input new file mode 100644 index 000000000..0bf909f7b --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input @@ -0,0 +1 @@ +[" <-- overlong encoding"] diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error b/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error new file mode 100644 index 000000000..7e19c5fe4 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf0 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input b/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input new file mode 100644 index 000000000..c6b631350 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input @@ -0,0 +1 @@ +[" <-- overlong encoding"] diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error b/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error new file mode 100644 index 000000000..1d382edd7 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xc1 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input b/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input new file mode 100644 index 000000000..ef6e10a34 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input @@ -0,0 +1 @@ +[""] diff --git a/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/error b/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/error new file mode 100644 index 000000000..d018f5ff3 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xfd near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/input b/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/input new file mode 100644 index 000000000..ba6017002 --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/restricted-utf-8/input @@ -0,0 +1 @@ +[""] diff --git a/deps/jansson/test/suites/invalid-unicode/run b/deps/jansson/test/suites/invalid-unicode/run new file mode 100755 index 000000000..ac584f6fd --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/run @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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() { + test -d $test_path +} + +run_test() { + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/error $test_log/stderr +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED ERROR:" + nl -bn $test_path/error + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/error b/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/error new file mode 100644 index 000000000..8a05abaed --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/input b/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/input new file mode 100644 index 000000000..bce9e18bf --- /dev/null +++ b/deps/jansson/test/suites/invalid-unicode/truncated-utf-8/input @@ -0,0 +1 @@ +[" <-- truncated UTF-8"] diff --git a/deps/jansson/test/suites/invalid/apostrophe/error b/deps/jansson/test/suites/invalid/apostrophe/error new file mode 100644 index 000000000..79bb2a0eb --- /dev/null +++ b/deps/jansson/test/suites/invalid/apostrophe/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near ''' diff --git a/deps/jansson/test/suites/invalid/apostrophe/input b/deps/jansson/test/suites/invalid/apostrophe/input new file mode 100644 index 000000000..f2dd4d224 --- /dev/null +++ b/deps/jansson/test/suites/invalid/apostrophe/input @@ -0,0 +1 @@ +[' diff --git a/deps/jansson/test/suites/invalid/ascii-unicode-identifier/error b/deps/jansson/test/suites/invalid/ascii-unicode-identifier/error new file mode 100644 index 000000000..a4d814280 --- /dev/null +++ b/deps/jansson/test/suites/invalid/ascii-unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 1 +'[' or '{' expected near 'a' diff --git a/deps/jansson/test/suites/invalid/ascii-unicode-identifier/input b/deps/jansson/test/suites/invalid/ascii-unicode-identifier/input new file mode 100644 index 000000000..c2c0208ed --- /dev/null +++ b/deps/jansson/test/suites/invalid/ascii-unicode-identifier/input @@ -0,0 +1 @@ +aå diff --git a/deps/jansson/test/suites/invalid/brace-comma/error b/deps/jansson/test/suites/invalid/brace-comma/error new file mode 100644 index 000000000..ce046213c --- /dev/null +++ b/deps/jansson/test/suites/invalid/brace-comma/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ',' diff --git a/deps/jansson/test/suites/invalid/brace-comma/input b/deps/jansson/test/suites/invalid/brace-comma/input new file mode 100644 index 000000000..74a6628d4 --- /dev/null +++ b/deps/jansson/test/suites/invalid/brace-comma/input @@ -0,0 +1 @@ +{, diff --git a/deps/jansson/test/suites/invalid/bracket-comma/error b/deps/jansson/test/suites/invalid/bracket-comma/error new file mode 100644 index 000000000..ce0a912bf --- /dev/null +++ b/deps/jansson/test/suites/invalid/bracket-comma/error @@ -0,0 +1,2 @@ +1 2 2 +unexpected token near ',' diff --git a/deps/jansson/test/suites/invalid/bracket-comma/input b/deps/jansson/test/suites/invalid/bracket-comma/input new file mode 100644 index 000000000..5b911f11d --- /dev/null +++ b/deps/jansson/test/suites/invalid/bracket-comma/input @@ -0,0 +1 @@ +[, diff --git a/deps/jansson/test/suites/invalid/bracket-one-comma/error.normal b/deps/jansson/test/suites/invalid/bracket-one-comma/error.normal new file mode 100644 index 000000000..0248b114a --- /dev/null +++ b/deps/jansson/test/suites/invalid/bracket-one-comma/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/bracket-one-comma/error.strip b/deps/jansson/test/suites/invalid/bracket-one-comma/error.strip new file mode 100644 index 000000000..f89b38fcb --- /dev/null +++ b/deps/jansson/test/suites/invalid/bracket-one-comma/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/bracket-one-comma/input b/deps/jansson/test/suites/invalid/bracket-one-comma/input new file mode 100644 index 000000000..874691b1d --- /dev/null +++ b/deps/jansson/test/suites/invalid/bracket-one-comma/input @@ -0,0 +1 @@ +[1, diff --git a/deps/jansson/test/suites/invalid/empty/error b/deps/jansson/test/suites/invalid/empty/error new file mode 100644 index 000000000..f45da6f82 --- /dev/null +++ b/deps/jansson/test/suites/invalid/empty/error @@ -0,0 +1,2 @@ +1 0 0 +'[' or '{' expected near end of file diff --git a/deps/jansson/test/suites/invalid/empty/input b/deps/jansson/test/suites/invalid/empty/input new file mode 100644 index 000000000..e69de29bb diff --git a/deps/jansson/test/suites/invalid/extra-comma-in-array/error b/deps/jansson/test/suites/invalid/extra-comma-in-array/error new file mode 100644 index 000000000..cae86c246 --- /dev/null +++ b/deps/jansson/test/suites/invalid/extra-comma-in-array/error @@ -0,0 +1,2 @@ +1 4 4 +unexpected token near ']' diff --git a/deps/jansson/test/suites/invalid/extra-comma-in-array/input b/deps/jansson/test/suites/invalid/extra-comma-in-array/input new file mode 100644 index 000000000..e8b1a170f --- /dev/null +++ b/deps/jansson/test/suites/invalid/extra-comma-in-array/input @@ -0,0 +1 @@ +[1,] diff --git a/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/error b/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/error new file mode 100644 index 000000000..5baeea447 --- /dev/null +++ b/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/error @@ -0,0 +1,2 @@ +6 1 17 +unexpected token near ']' diff --git a/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/input b/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/input new file mode 100644 index 000000000..bcb2a7526 --- /dev/null +++ b/deps/jansson/test/suites/invalid/extra-comma-in-multiline-array/input @@ -0,0 +1,6 @@ +[1, +2, +3, +4, +5, +] diff --git a/deps/jansson/test/suites/invalid/garbage-after-newline/error b/deps/jansson/test/suites/invalid/garbage-after-newline/error new file mode 100644 index 000000000..5d2dec374 --- /dev/null +++ b/deps/jansson/test/suites/invalid/garbage-after-newline/error @@ -0,0 +1,2 @@ +2 3 11 +end of file expected near 'foo' diff --git a/deps/jansson/test/suites/invalid/garbage-after-newline/input b/deps/jansson/test/suites/invalid/garbage-after-newline/input new file mode 100644 index 000000000..3614ac78f --- /dev/null +++ b/deps/jansson/test/suites/invalid/garbage-after-newline/input @@ -0,0 +1,2 @@ +[1,2,3] +foo diff --git a/deps/jansson/test/suites/invalid/garbage-at-the-end/error b/deps/jansson/test/suites/invalid/garbage-at-the-end/error new file mode 100644 index 000000000..cdd817572 --- /dev/null +++ b/deps/jansson/test/suites/invalid/garbage-at-the-end/error @@ -0,0 +1,2 @@ +1 10 10 +end of file expected near 'foo' diff --git a/deps/jansson/test/suites/invalid/garbage-at-the-end/input b/deps/jansson/test/suites/invalid/garbage-at-the-end/input new file mode 100644 index 000000000..55aee53d2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/garbage-at-the-end/input @@ -0,0 +1 @@ +[1,2,3]foo diff --git a/deps/jansson/test/suites/invalid/integer-starting-with-zero/error b/deps/jansson/test/suites/invalid/integer-starting-with-zero/error new file mode 100644 index 000000000..64e0536aa --- /dev/null +++ b/deps/jansson/test/suites/invalid/integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '0' diff --git a/deps/jansson/test/suites/invalid/integer-starting-with-zero/input b/deps/jansson/test/suites/invalid/integer-starting-with-zero/input new file mode 100644 index 000000000..12f67e2c2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/integer-starting-with-zero/input @@ -0,0 +1 @@ +[012] diff --git a/deps/jansson/test/suites/invalid/invalid-escape/error b/deps/jansson/test/suites/invalid/invalid-escape/error new file mode 100644 index 000000000..d9863f73b --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-escape/error @@ -0,0 +1,2 @@ +1 4 4 +invalid escape near '"\a' diff --git a/deps/jansson/test/suites/invalid/invalid-escape/input b/deps/jansson/test/suites/invalid/invalid-escape/input new file mode 100644 index 000000000..64c7b70d9 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-escape/input @@ -0,0 +1 @@ +["\a <-- invalid escape"] diff --git a/deps/jansson/test/suites/invalid/invalid-identifier/error b/deps/jansson/test/suites/invalid/invalid-identifier/error new file mode 100644 index 000000000..496c6aba2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-identifier/error @@ -0,0 +1,2 @@ +1 5 5 +invalid token near 'troo' diff --git a/deps/jansson/test/suites/invalid/invalid-identifier/input b/deps/jansson/test/suites/invalid/invalid-identifier/input new file mode 100644 index 000000000..3d2860da1 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-identifier/input @@ -0,0 +1 @@ +[troo diff --git a/deps/jansson/test/suites/invalid/invalid-negative-integer/error b/deps/jansson/test/suites/invalid/invalid-negative-integer/error new file mode 100644 index 000000000..f2526c51e --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-negative-integer/error @@ -0,0 +1,2 @@ +1 8 8 +']' expected near 'foo' diff --git a/deps/jansson/test/suites/invalid/invalid-negative-integer/input b/deps/jansson/test/suites/invalid/invalid-negative-integer/input new file mode 100644 index 000000000..6196980ec --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-negative-integer/input @@ -0,0 +1 @@ +[-123foo] diff --git a/deps/jansson/test/suites/invalid/invalid-negative-real/error b/deps/jansson/test/suites/invalid/invalid-negative-real/error new file mode 100644 index 000000000..933158ae5 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-negative-real/error @@ -0,0 +1,2 @@ +1 12 12 +']' expected near 'foo' diff --git a/deps/jansson/test/suites/invalid/invalid-negative-real/input b/deps/jansson/test/suites/invalid/invalid-negative-real/input new file mode 100644 index 000000000..3c763d334 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-negative-real/input @@ -0,0 +1 @@ +[-123.123foo] diff --git a/deps/jansson/test/suites/invalid/invalid-second-surrogate/error b/deps/jansson/test/suites/invalid/invalid-second-surrogate/error new file mode 100644 index 000000000..e5a2359e6 --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-second-surrogate/error @@ -0,0 +1,2 @@ +1 62 62 +invalid Unicode '\uD888\u3210' diff --git a/deps/jansson/test/suites/invalid/invalid-second-surrogate/input b/deps/jansson/test/suites/invalid/invalid-second-surrogate/input new file mode 100644 index 000000000..b21453f6f --- /dev/null +++ b/deps/jansson/test/suites/invalid/invalid-second-surrogate/input @@ -0,0 +1 @@ +["\uD888\u3210 (first surrogate and invalid second surrogate)"] diff --git a/deps/jansson/test/suites/invalid/lone-open-brace/error.normal b/deps/jansson/test/suites/invalid/lone-open-brace/error.normal new file mode 100644 index 000000000..00dc765b9 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-brace/error.normal @@ -0,0 +1,2 @@ +2 0 2 +string or '}' expected near end of file diff --git a/deps/jansson/test/suites/invalid/lone-open-brace/error.strip b/deps/jansson/test/suites/invalid/lone-open-brace/error.strip new file mode 100644 index 000000000..bb1c04745 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-brace/error.strip @@ -0,0 +1,2 @@ +1 1 1 +string or '}' expected near end of file diff --git a/deps/jansson/test/suites/invalid/lone-open-brace/input b/deps/jansson/test/suites/invalid/lone-open-brace/input new file mode 100644 index 000000000..98232c64f --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-brace/input @@ -0,0 +1 @@ +{ diff --git a/deps/jansson/test/suites/invalid/lone-open-bracket/error.normal b/deps/jansson/test/suites/invalid/lone-open-bracket/error.normal new file mode 100644 index 000000000..f463928f8 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-bracket/error.normal @@ -0,0 +1,2 @@ +2 0 2 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/lone-open-bracket/error.strip b/deps/jansson/test/suites/invalid/lone-open-bracket/error.strip new file mode 100644 index 000000000..2bc07ea0c --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-bracket/error.strip @@ -0,0 +1,2 @@ +1 1 1 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/lone-open-bracket/input b/deps/jansson/test/suites/invalid/lone-open-bracket/input new file mode 100644 index 000000000..558ed37d9 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-open-bracket/input @@ -0,0 +1 @@ +[ diff --git a/deps/jansson/test/suites/invalid/lone-second-surrogate/error b/deps/jansson/test/suites/invalid/lone-second-surrogate/error new file mode 100644 index 000000000..bc5f34e11 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-second-surrogate/error @@ -0,0 +1,2 @@ +1 40 40 +invalid Unicode '\uDFAA' diff --git a/deps/jansson/test/suites/invalid/lone-second-surrogate/input b/deps/jansson/test/suites/invalid/lone-second-surrogate/input new file mode 100644 index 000000000..328e35c82 --- /dev/null +++ b/deps/jansson/test/suites/invalid/lone-second-surrogate/input @@ -0,0 +1 @@ +["\uDFAA (second surrogate on it's own)"] diff --git a/deps/jansson/test/suites/invalid/minus-sign-without-number/error b/deps/jansson/test/suites/invalid/minus-sign-without-number/error new file mode 100644 index 000000000..b3a78b978 --- /dev/null +++ b/deps/jansson/test/suites/invalid/minus-sign-without-number/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '-' diff --git a/deps/jansson/test/suites/invalid/minus-sign-without-number/input b/deps/jansson/test/suites/invalid/minus-sign-without-number/input new file mode 100644 index 000000000..033788355 --- /dev/null +++ b/deps/jansson/test/suites/invalid/minus-sign-without-number/input @@ -0,0 +1 @@ +[-foo] diff --git a/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/error b/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/error new file mode 100644 index 000000000..36adc34b4 --- /dev/null +++ b/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '-0' diff --git a/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/input b/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/input new file mode 100644 index 000000000..6fbb7a2f8 --- /dev/null +++ b/deps/jansson/test/suites/invalid/negative-integer-starting-with-zero/input @@ -0,0 +1 @@ +[-012] diff --git a/deps/jansson/test/suites/invalid/null-byte-in-object-key/error b/deps/jansson/test/suites/invalid/null-byte-in-object-key/error new file mode 100644 index 000000000..3ec685b5d --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-in-object-key/error @@ -0,0 +1,2 @@ +1 15 15 +NUL byte in object key not supported near '"foo\u0000bar"' diff --git a/deps/jansson/test/suites/invalid/null-byte-in-object-key/input b/deps/jansson/test/suites/invalid/null-byte-in-object-key/input new file mode 100644 index 000000000..593f0f67f --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-in-object-key/input @@ -0,0 +1 @@ +{"foo\u0000bar": 42} \ No newline at end of file diff --git a/deps/jansson/test/suites/invalid/null-byte-in-string/error b/deps/jansson/test/suites/invalid/null-byte-in-string/error new file mode 100644 index 000000000..45f9bd817 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-in-string/error @@ -0,0 +1,2 @@ +1 12 12 +control character 0x0 near '"null byte ' diff --git a/deps/jansson/test/suites/invalid/null-byte-in-string/input b/deps/jansson/test/suites/invalid/null-byte-in-string/input new file mode 100644 index 000000000..268d1f194 Binary files /dev/null and b/deps/jansson/test/suites/invalid/null-byte-in-string/input differ diff --git a/deps/jansson/test/suites/invalid/null-byte-in-string/nostrip b/deps/jansson/test/suites/invalid/null-byte-in-string/nostrip new file mode 100644 index 000000000..80f4bf761 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-in-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/deps/jansson/test/suites/invalid/null-byte-outside-string/error b/deps/jansson/test/suites/invalid/null-byte-outside-string/error new file mode 100644 index 000000000..44d4def92 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-outside-string/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near end of file diff --git a/deps/jansson/test/suites/invalid/null-byte-outside-string/input b/deps/jansson/test/suites/invalid/null-byte-outside-string/input new file mode 100644 index 000000000..aa550eb0c Binary files /dev/null and b/deps/jansson/test/suites/invalid/null-byte-outside-string/input differ diff --git a/deps/jansson/test/suites/invalid/null-byte-outside-string/nostrip b/deps/jansson/test/suites/invalid/null-byte-outside-string/nostrip new file mode 100644 index 000000000..80f4bf761 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null-byte-outside-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/deps/jansson/test/suites/invalid/null/error b/deps/jansson/test/suites/invalid/null/error new file mode 100644 index 000000000..1f5d46490 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null/error @@ -0,0 +1,2 @@ +1 4 4 +'[' or '{' expected near 'null' diff --git a/deps/jansson/test/suites/invalid/null/input b/deps/jansson/test/suites/invalid/null/input new file mode 100644 index 000000000..19765bd50 --- /dev/null +++ b/deps/jansson/test/suites/invalid/null/input @@ -0,0 +1 @@ +null diff --git a/deps/jansson/test/suites/invalid/object-apostrophes/error b/deps/jansson/test/suites/invalid/object-apostrophes/error new file mode 100644 index 000000000..23fab01f6 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-apostrophes/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ''' diff --git a/deps/jansson/test/suites/invalid/object-apostrophes/input b/deps/jansson/test/suites/invalid/object-apostrophes/input new file mode 100644 index 000000000..52b290574 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-apostrophes/input @@ -0,0 +1 @@ +{'a' diff --git a/deps/jansson/test/suites/invalid/object-garbage-at-end/error b/deps/jansson/test/suites/invalid/object-garbage-at-end/error new file mode 100644 index 000000000..06c4ec1c2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-garbage-at-end/error @@ -0,0 +1,2 @@ +1 12 12 +'}' expected near '123' diff --git a/deps/jansson/test/suites/invalid/object-garbage-at-end/input b/deps/jansson/test/suites/invalid/object-garbage-at-end/input new file mode 100644 index 000000000..62c19d742 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-garbage-at-end/input @@ -0,0 +1 @@ +{"a":"a" 123} diff --git a/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.normal b/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.normal new file mode 100644 index 000000000..0248b114a --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.strip b/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.strip new file mode 100644 index 000000000..f89b38fcb --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-in-unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/object-in-unterminated-array/input b/deps/jansson/test/suites/invalid/object-in-unterminated-array/input new file mode 100644 index 000000000..ca9ec378e --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-in-unterminated-array/input @@ -0,0 +1 @@ +[{} diff --git a/deps/jansson/test/suites/invalid/object-no-colon/error.normal b/deps/jansson/test/suites/invalid/object-no-colon/error.normal new file mode 100644 index 000000000..78d84f7b7 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-colon/error.normal @@ -0,0 +1,2 @@ +2 0 5 +':' expected near end of file diff --git a/deps/jansson/test/suites/invalid/object-no-colon/error.strip b/deps/jansson/test/suites/invalid/object-no-colon/error.strip new file mode 100644 index 000000000..528e266d2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-colon/error.strip @@ -0,0 +1,2 @@ +1 4 4 +':' expected near end of file diff --git a/deps/jansson/test/suites/invalid/object-no-colon/input b/deps/jansson/test/suites/invalid/object-no-colon/input new file mode 100644 index 000000000..107e6265c --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-colon/input @@ -0,0 +1 @@ +{"a" diff --git a/deps/jansson/test/suites/invalid/object-no-value/error.normal b/deps/jansson/test/suites/invalid/object-no-value/error.normal new file mode 100644 index 000000000..47ad902dd --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-value/error.normal @@ -0,0 +1,2 @@ +2 0 6 +unexpected token near end of file diff --git a/deps/jansson/test/suites/invalid/object-no-value/error.strip b/deps/jansson/test/suites/invalid/object-no-value/error.strip new file mode 100644 index 000000000..b36c5e2bc --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-value/error.strip @@ -0,0 +1,2 @@ +1 5 5 +unexpected token near end of file diff --git a/deps/jansson/test/suites/invalid/object-no-value/input b/deps/jansson/test/suites/invalid/object-no-value/input new file mode 100644 index 000000000..f68f26269 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-no-value/input @@ -0,0 +1 @@ +{"a": diff --git a/deps/jansson/test/suites/invalid/object-unterminated-value/error.normal b/deps/jansson/test/suites/invalid/object-unterminated-value/error.normal new file mode 100644 index 000000000..2ad76d473 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-unterminated-value/error.normal @@ -0,0 +1,2 @@ +1 7 7 +unexpected newline near '"a' diff --git a/deps/jansson/test/suites/invalid/object-unterminated-value/error.strip b/deps/jansson/test/suites/invalid/object-unterminated-value/error.strip new file mode 100644 index 000000000..385afb534 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-unterminated-value/error.strip @@ -0,0 +1,2 @@ +1 7 7 +premature end of input near '"a' diff --git a/deps/jansson/test/suites/invalid/object-unterminated-value/input b/deps/jansson/test/suites/invalid/object-unterminated-value/input new file mode 100644 index 000000000..b854d7e18 --- /dev/null +++ b/deps/jansson/test/suites/invalid/object-unterminated-value/input @@ -0,0 +1 @@ +{"a":"a diff --git a/deps/jansson/test/suites/invalid/real-garbage-after-e/error b/deps/jansson/test/suites/invalid/real-garbage-after-e/error new file mode 100644 index 000000000..b40ffa9b5 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-garbage-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/deps/jansson/test/suites/invalid/real-garbage-after-e/input b/deps/jansson/test/suites/invalid/real-garbage-after-e/input new file mode 100644 index 000000000..6a945ac0f --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-garbage-after-e/input @@ -0,0 +1 @@ +[1ea] diff --git a/deps/jansson/test/suites/invalid/real-negative-overflow/error b/deps/jansson/test/suites/invalid/real-negative-overflow/error new file mode 100644 index 000000000..d7f8e412d --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-negative-overflow/error @@ -0,0 +1,2 @@ +1 15 15 +real number overflow near '-123123e100000' diff --git a/deps/jansson/test/suites/invalid/real-negative-overflow/input b/deps/jansson/test/suites/invalid/real-negative-overflow/input new file mode 100644 index 000000000..b5bd21c46 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-negative-overflow/input @@ -0,0 +1 @@ +[-123123e100000] diff --git a/deps/jansson/test/suites/invalid/real-positive-overflow/error b/deps/jansson/test/suites/invalid/real-positive-overflow/error new file mode 100644 index 000000000..55883c981 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-positive-overflow/error @@ -0,0 +1,2 @@ +1 14 14 +real number overflow near '123123e100000' diff --git a/deps/jansson/test/suites/invalid/real-positive-overflow/input b/deps/jansson/test/suites/invalid/real-positive-overflow/input new file mode 100644 index 000000000..524e53b31 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-positive-overflow/input @@ -0,0 +1 @@ +[123123e100000] diff --git a/deps/jansson/test/suites/invalid/real-truncated-at-e/error b/deps/jansson/test/suites/invalid/real-truncated-at-e/error new file mode 100644 index 000000000..b40ffa9b5 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-truncated-at-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/deps/jansson/test/suites/invalid/real-truncated-at-e/input b/deps/jansson/test/suites/invalid/real-truncated-at-e/input new file mode 100644 index 000000000..1d67b7b82 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-truncated-at-e/input @@ -0,0 +1 @@ +[1e] diff --git a/deps/jansson/test/suites/invalid/real-truncated-at-point/error b/deps/jansson/test/suites/invalid/real-truncated-at-point/error new file mode 100644 index 000000000..db972e8e1 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-truncated-at-point/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1.' diff --git a/deps/jansson/test/suites/invalid/real-truncated-at-point/input b/deps/jansson/test/suites/invalid/real-truncated-at-point/input new file mode 100644 index 000000000..b652b3fe0 --- /dev/null +++ b/deps/jansson/test/suites/invalid/real-truncated-at-point/input @@ -0,0 +1 @@ +[1.] diff --git a/deps/jansson/test/suites/invalid/run b/deps/jansson/test/suites/invalid/run new file mode 100755 index 000000000..a640ea0ea --- /dev/null +++ b/deps/jansson/test/suites/invalid/run @@ -0,0 +1,57 @@ +#!/bin/sh +# +# Copyright (c) 2009-2013 Petri Lehtinen +# +# 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() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + if [ "$variant" = "strip" ]; then + # This test should not be stripped + [ -f $test_path/nostrip ] && return + strip=1 + fi + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=error + [ -f $test_path/error$s ] && ref=error$s + + if ! cmp -s $test_path/$ref $test_log/stderr$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED ERROR:" + ref=error + [ -f $test_path/error$s ] && ref=error$s + nl -bn $test_path/$ref + + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/deps/jansson/test/suites/invalid/tab-character-in-string/error b/deps/jansson/test/suites/invalid/tab-character-in-string/error new file mode 100644 index 000000000..9e2f76ed2 --- /dev/null +++ b/deps/jansson/test/suites/invalid/tab-character-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +control character 0x9 near '"' diff --git a/deps/jansson/test/suites/invalid/tab-character-in-string/input b/deps/jansson/test/suites/invalid/tab-character-in-string/input new file mode 100644 index 000000000..3ebae0953 --- /dev/null +++ b/deps/jansson/test/suites/invalid/tab-character-in-string/input @@ -0,0 +1 @@ +[" <-- tab character"] diff --git a/deps/jansson/test/suites/invalid/too-big-negative-integer/error b/deps/jansson/test/suites/invalid/too-big-negative-integer/error new file mode 100644 index 000000000..a0640b9a9 --- /dev/null +++ b/deps/jansson/test/suites/invalid/too-big-negative-integer/error @@ -0,0 +1,2 @@ +1 32 32 +too big negative integer diff --git a/deps/jansson/test/suites/invalid/too-big-negative-integer/input b/deps/jansson/test/suites/invalid/too-big-negative-integer/input new file mode 100644 index 000000000..d6c26f1cf --- /dev/null +++ b/deps/jansson/test/suites/invalid/too-big-negative-integer/input @@ -0,0 +1 @@ +[-123123123123123123123123123123] diff --git a/deps/jansson/test/suites/invalid/too-big-positive-integer/error b/deps/jansson/test/suites/invalid/too-big-positive-integer/error new file mode 100644 index 000000000..3bdbefd53 --- /dev/null +++ b/deps/jansson/test/suites/invalid/too-big-positive-integer/error @@ -0,0 +1,2 @@ +1 31 31 +too big integer diff --git a/deps/jansson/test/suites/invalid/too-big-positive-integer/input b/deps/jansson/test/suites/invalid/too-big-positive-integer/input new file mode 100644 index 000000000..27c855399 --- /dev/null +++ b/deps/jansson/test/suites/invalid/too-big-positive-integer/input @@ -0,0 +1 @@ +[123123123123123123123123123123] diff --git a/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/error b/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/error new file mode 100644 index 000000000..1b99f061a --- /dev/null +++ b/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/error @@ -0,0 +1,2 @@ +1 46 46 +invalid Unicode '\uDADA' diff --git a/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/input b/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/input new file mode 100644 index 000000000..2b340f4ad --- /dev/null +++ b/deps/jansson/test/suites/invalid/truncated-unicode-surrogate/input @@ -0,0 +1 @@ +["\uDADA (first surrogate without the second)"] diff --git a/deps/jansson/test/suites/invalid/unicode-identifier/error b/deps/jansson/test/suites/invalid/unicode-identifier/error new file mode 100644 index 000000000..178b0dd4d --- /dev/null +++ b/deps/jansson/test/suites/invalid/unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 2 +'[' or '{' expected near 'å' diff --git a/deps/jansson/test/suites/invalid/unicode-identifier/input b/deps/jansson/test/suites/invalid/unicode-identifier/input new file mode 100644 index 000000000..aad321caf --- /dev/null +++ b/deps/jansson/test/suites/invalid/unicode-identifier/input @@ -0,0 +1 @@ +å diff --git a/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.normal b/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.normal new file mode 100644 index 000000000..5b19804bc --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.normal @@ -0,0 +1,2 @@ +2 0 3 +string or '}' expected near end of file diff --git a/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.strip b/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.strip new file mode 100644 index 000000000..da2bb22f1 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array-and-object/error.strip @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near end of file diff --git a/deps/jansson/test/suites/invalid/unterminated-array-and-object/input b/deps/jansson/test/suites/invalid/unterminated-array-and-object/input new file mode 100644 index 000000000..cd9dc6482 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array-and-object/input @@ -0,0 +1 @@ +[{ diff --git a/deps/jansson/test/suites/invalid/unterminated-array/error.normal b/deps/jansson/test/suites/invalid/unterminated-array/error.normal new file mode 100644 index 000000000..8025ed1b0 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 5 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/unterminated-array/error.strip b/deps/jansson/test/suites/invalid/unterminated-array/error.strip new file mode 100644 index 000000000..495d0f7c4 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 4 4 +']' expected near end of file diff --git a/deps/jansson/test/suites/invalid/unterminated-array/input b/deps/jansson/test/suites/invalid/unterminated-array/input new file mode 100644 index 000000000..727ee8106 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-array/input @@ -0,0 +1 @@ +["a" diff --git a/deps/jansson/test/suites/invalid/unterminated-empty-key/error.normal b/deps/jansson/test/suites/invalid/unterminated-empty-key/error.normal new file mode 100644 index 000000000..3d646abda --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-empty-key/error.normal @@ -0,0 +1,2 @@ +1 2 2 +unexpected newline near '"' diff --git a/deps/jansson/test/suites/invalid/unterminated-empty-key/error.strip b/deps/jansson/test/suites/invalid/unterminated-empty-key/error.strip new file mode 100644 index 000000000..94f194715 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-empty-key/error.strip @@ -0,0 +1,2 @@ +1 2 2 +premature end of input near '"' diff --git a/deps/jansson/test/suites/invalid/unterminated-empty-key/input b/deps/jansson/test/suites/invalid/unterminated-empty-key/input new file mode 100644 index 000000000..4117452de --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-empty-key/input @@ -0,0 +1 @@ +{" diff --git a/deps/jansson/test/suites/invalid/unterminated-key/error.normal b/deps/jansson/test/suites/invalid/unterminated-key/error.normal new file mode 100644 index 000000000..5f09b77da --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-key/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/deps/jansson/test/suites/invalid/unterminated-key/error.strip b/deps/jansson/test/suites/invalid/unterminated-key/error.strip new file mode 100644 index 000000000..8b6bec430 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-key/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/deps/jansson/test/suites/invalid/unterminated-key/input b/deps/jansson/test/suites/invalid/unterminated-key/input new file mode 100644 index 000000000..705948c64 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-key/input @@ -0,0 +1 @@ +{"a diff --git a/deps/jansson/test/suites/invalid/unterminated-object-and-array/error b/deps/jansson/test/suites/invalid/unterminated-object-and-array/error new file mode 100644 index 000000000..ed97be73e --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-object-and-array/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near '[' diff --git a/deps/jansson/test/suites/invalid/unterminated-object-and-array/input b/deps/jansson/test/suites/invalid/unterminated-object-and-array/input new file mode 100644 index 000000000..da35a8620 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-object-and-array/input @@ -0,0 +1 @@ +{[ diff --git a/deps/jansson/test/suites/invalid/unterminated-string/error.normal b/deps/jansson/test/suites/invalid/unterminated-string/error.normal new file mode 100644 index 000000000..5f09b77da --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-string/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/deps/jansson/test/suites/invalid/unterminated-string/error.strip b/deps/jansson/test/suites/invalid/unterminated-string/error.strip new file mode 100644 index 000000000..8b6bec430 --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-string/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/deps/jansson/test/suites/invalid/unterminated-string/input b/deps/jansson/test/suites/invalid/unterminated-string/input new file mode 100644 index 000000000..38ab6b04c --- /dev/null +++ b/deps/jansson/test/suites/invalid/unterminated-string/input @@ -0,0 +1 @@ +["a diff --git a/deps/jansson/test/suites/valid/complex-array/env b/deps/jansson/test/suites/valid/complex-array/env new file mode 100644 index 000000000..bd89eff9d --- /dev/null +++ b/deps/jansson/test/suites/valid/complex-array/env @@ -0,0 +1 @@ +JSON_SORT_KEYS=1 \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/complex-array/input b/deps/jansson/test/suites/valid/complex-array/input new file mode 100644 index 000000000..1b9bbb949 --- /dev/null +++ b/deps/jansson/test/suites/valid/complex-array/input @@ -0,0 +1,5 @@ +[1,2,3,4, +"a", "b", "c", +{"foo": "bar", "core": "dump"}, +true, false, true, true, null, false +] diff --git a/deps/jansson/test/suites/valid/complex-array/output b/deps/jansson/test/suites/valid/complex-array/output new file mode 100644 index 000000000..7aefe5642 --- /dev/null +++ b/deps/jansson/test/suites/valid/complex-array/output @@ -0,0 +1 @@ +[1, 2, 3, 4, "a", "b", "c", {"core": "dump", "foo": "bar"}, true, false, true, true, null, false] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/empty-array/input b/deps/jansson/test/suites/valid/empty-array/input new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-array/input @@ -0,0 +1 @@ +[] diff --git a/deps/jansson/test/suites/valid/empty-array/output b/deps/jansson/test/suites/valid/empty-array/output new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-array/output @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/empty-object-in-array/input b/deps/jansson/test/suites/valid/empty-object-in-array/input new file mode 100644 index 000000000..93d51406d --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-object-in-array/input @@ -0,0 +1 @@ +[{}] diff --git a/deps/jansson/test/suites/valid/empty-object-in-array/output b/deps/jansson/test/suites/valid/empty-object-in-array/output new file mode 100644 index 000000000..ee1aac42b --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-object-in-array/output @@ -0,0 +1 @@ +[{}] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/empty-object/input b/deps/jansson/test/suites/valid/empty-object/input new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-object/input @@ -0,0 +1 @@ +{} diff --git a/deps/jansson/test/suites/valid/empty-object/output b/deps/jansson/test/suites/valid/empty-object/output new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-object/output @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/empty-string/input b/deps/jansson/test/suites/valid/empty-string/input new file mode 100644 index 000000000..66a1e1856 --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-string/input @@ -0,0 +1 @@ +[""] diff --git a/deps/jansson/test/suites/valid/empty-string/output b/deps/jansson/test/suites/valid/empty-string/output new file mode 100644 index 000000000..93b6be2bc --- /dev/null +++ b/deps/jansson/test/suites/valid/empty-string/output @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/escaped-utf-control-char/input b/deps/jansson/test/suites/valid/escaped-utf-control-char/input new file mode 100644 index 000000000..9a98545c0 --- /dev/null +++ b/deps/jansson/test/suites/valid/escaped-utf-control-char/input @@ -0,0 +1 @@ +["\u0012 escaped control character"] diff --git a/deps/jansson/test/suites/valid/escaped-utf-control-char/output b/deps/jansson/test/suites/valid/escaped-utf-control-char/output new file mode 100644 index 000000000..07221b78d --- /dev/null +++ b/deps/jansson/test/suites/valid/escaped-utf-control-char/output @@ -0,0 +1 @@ +["\u0012 escaped control character"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/false/input b/deps/jansson/test/suites/valid/false/input new file mode 100644 index 000000000..434365202 --- /dev/null +++ b/deps/jansson/test/suites/valid/false/input @@ -0,0 +1 @@ +[false] diff --git a/deps/jansson/test/suites/valid/false/output b/deps/jansson/test/suites/valid/false/output new file mode 100644 index 000000000..67b2f0760 --- /dev/null +++ b/deps/jansson/test/suites/valid/false/output @@ -0,0 +1 @@ +[false] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/negative-int/input b/deps/jansson/test/suites/valid/negative-int/input new file mode 100644 index 000000000..a96d5cdb3 --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-int/input @@ -0,0 +1 @@ +[-123] diff --git a/deps/jansson/test/suites/valid/negative-int/output b/deps/jansson/test/suites/valid/negative-int/output new file mode 100644 index 000000000..8e30f8bd9 --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-int/output @@ -0,0 +1 @@ +[-123] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/negative-one/input b/deps/jansson/test/suites/valid/negative-one/input new file mode 100644 index 000000000..2363a1ac0 --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-one/input @@ -0,0 +1 @@ +[-1] diff --git a/deps/jansson/test/suites/valid/negative-one/output b/deps/jansson/test/suites/valid/negative-one/output new file mode 100644 index 000000000..99d21a2a0 --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-one/output @@ -0,0 +1 @@ +[-1] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/negative-zero/input b/deps/jansson/test/suites/valid/negative-zero/input new file mode 100644 index 000000000..40fc49c71 --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-zero/input @@ -0,0 +1 @@ +[-0] diff --git a/deps/jansson/test/suites/valid/negative-zero/output b/deps/jansson/test/suites/valid/negative-zero/output new file mode 100644 index 000000000..6e7ea636e --- /dev/null +++ b/deps/jansson/test/suites/valid/negative-zero/output @@ -0,0 +1 @@ +[0] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/null/input b/deps/jansson/test/suites/valid/null/input new file mode 100644 index 000000000..62864b313 --- /dev/null +++ b/deps/jansson/test/suites/valid/null/input @@ -0,0 +1 @@ +[null] diff --git a/deps/jansson/test/suites/valid/null/output b/deps/jansson/test/suites/valid/null/output new file mode 100644 index 000000000..500db4a86 --- /dev/null +++ b/deps/jansson/test/suites/valid/null/output @@ -0,0 +1 @@ +[null] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/one-byte-utf-8/input b/deps/jansson/test/suites/valid/one-byte-utf-8/input new file mode 100644 index 000000000..8bda4685d --- /dev/null +++ b/deps/jansson/test/suites/valid/one-byte-utf-8/input @@ -0,0 +1 @@ +["\u002c one-byte UTF-8"] diff --git a/deps/jansson/test/suites/valid/one-byte-utf-8/output b/deps/jansson/test/suites/valid/one-byte-utf-8/output new file mode 100644 index 000000000..c33d250ff --- /dev/null +++ b/deps/jansson/test/suites/valid/one-byte-utf-8/output @@ -0,0 +1 @@ +[", one-byte UTF-8"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/input b/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/input new file mode 100644 index 000000000..1e9fa5153 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/input @@ -0,0 +1 @@ +[1E-2] diff --git a/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/output b/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/output new file mode 100644 index 000000000..75b9ef92c --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e-negative-exponent/output @@ -0,0 +1 @@ +[0.01] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/input b/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/input new file mode 100644 index 000000000..6a6ab9337 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/input @@ -0,0 +1 @@ +[1E+2] diff --git a/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/output b/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/output new file mode 100644 index 000000000..d8ff702a1 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e-positive-exponent/output @@ -0,0 +1 @@ +[100.0] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-capital-e/input b/deps/jansson/test/suites/valid/real-capital-e/input new file mode 100644 index 000000000..e70322356 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e/input @@ -0,0 +1 @@ +[1E22] diff --git a/deps/jansson/test/suites/valid/real-capital-e/output b/deps/jansson/test/suites/valid/real-capital-e/output new file mode 100644 index 000000000..9a739f21f --- /dev/null +++ b/deps/jansson/test/suites/valid/real-capital-e/output @@ -0,0 +1 @@ +[1e22] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-exponent/input b/deps/jansson/test/suites/valid/real-exponent/input new file mode 100644 index 000000000..b2a69b9a3 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-exponent/input @@ -0,0 +1 @@ +[123e45] diff --git a/deps/jansson/test/suites/valid/real-exponent/output b/deps/jansson/test/suites/valid/real-exponent/output new file mode 100644 index 000000000..5ffc7196d --- /dev/null +++ b/deps/jansson/test/suites/valid/real-exponent/output @@ -0,0 +1 @@ +[1.2299999999999999e47] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-fraction-exponent/input b/deps/jansson/test/suites/valid/real-fraction-exponent/input new file mode 100644 index 000000000..0c1660d1e --- /dev/null +++ b/deps/jansson/test/suites/valid/real-fraction-exponent/input @@ -0,0 +1 @@ +[123.456e78] diff --git a/deps/jansson/test/suites/valid/real-fraction-exponent/output b/deps/jansson/test/suites/valid/real-fraction-exponent/output new file mode 100644 index 000000000..66a3c8186 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-fraction-exponent/output @@ -0,0 +1 @@ +[1.23456e80] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-negative-exponent/input b/deps/jansson/test/suites/valid/real-negative-exponent/input new file mode 100644 index 000000000..daa4af932 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-negative-exponent/input @@ -0,0 +1 @@ +[1e-2] diff --git a/deps/jansson/test/suites/valid/real-negative-exponent/output b/deps/jansson/test/suites/valid/real-negative-exponent/output new file mode 100644 index 000000000..75b9ef92c --- /dev/null +++ b/deps/jansson/test/suites/valid/real-negative-exponent/output @@ -0,0 +1 @@ +[0.01] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-positive-exponent/input b/deps/jansson/test/suites/valid/real-positive-exponent/input new file mode 100644 index 000000000..f3780773a --- /dev/null +++ b/deps/jansson/test/suites/valid/real-positive-exponent/input @@ -0,0 +1 @@ +[1e+2] diff --git a/deps/jansson/test/suites/valid/real-positive-exponent/output b/deps/jansson/test/suites/valid/real-positive-exponent/output new file mode 100644 index 000000000..d8ff702a1 --- /dev/null +++ b/deps/jansson/test/suites/valid/real-positive-exponent/output @@ -0,0 +1 @@ +[100.0] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/real-underflow/input b/deps/jansson/test/suites/valid/real-underflow/input new file mode 100644 index 000000000..dc709960a --- /dev/null +++ b/deps/jansson/test/suites/valid/real-underflow/input @@ -0,0 +1 @@ +[123e-10000000] diff --git a/deps/jansson/test/suites/valid/real-underflow/output b/deps/jansson/test/suites/valid/real-underflow/output new file mode 100644 index 000000000..92df1df1d --- /dev/null +++ b/deps/jansson/test/suites/valid/real-underflow/output @@ -0,0 +1 @@ +[0.0] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/run b/deps/jansson/test/suites/valid/run new file mode 100755 index 000000000..c30d94a73 --- /dev/null +++ b/deps/jansson/test/suites/valid/run @@ -0,0 +1,56 @@ +#!/bin/sh +# +# Copyright (c) 2009-2013 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS + +is_test() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + [ "$variant" = "strip" ] && strip=1 + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=output + [ -f $test_path/output$s ] && ref=output$s + + if ! cmp -s $test_path/$ref $test_log/stdout$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED OUTPUT:" + ref=output + [ -f $test_path/output$s ] && ref=output$s + nl -bn $test_path/$ref + + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/deps/jansson/test/suites/valid/short-string/input b/deps/jansson/test/suites/valid/short-string/input new file mode 100644 index 000000000..0c3426d4c --- /dev/null +++ b/deps/jansson/test/suites/valid/short-string/input @@ -0,0 +1 @@ +["a"] diff --git a/deps/jansson/test/suites/valid/short-string/output b/deps/jansson/test/suites/valid/short-string/output new file mode 100644 index 000000000..eac5f7b46 --- /dev/null +++ b/deps/jansson/test/suites/valid/short-string/output @@ -0,0 +1 @@ +["a"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-ascii-string/input b/deps/jansson/test/suites/valid/simple-ascii-string/input new file mode 100644 index 000000000..929b215c1 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-ascii-string/input @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "] diff --git a/deps/jansson/test/suites/valid/simple-ascii-string/output b/deps/jansson/test/suites/valid/simple-ascii-string/output new file mode 100644 index 000000000..90358ab70 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-ascii-string/output @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-int-0/input b/deps/jansson/test/suites/valid/simple-int-0/input new file mode 100644 index 000000000..111bb8686 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-0/input @@ -0,0 +1 @@ +[0] diff --git a/deps/jansson/test/suites/valid/simple-int-0/output b/deps/jansson/test/suites/valid/simple-int-0/output new file mode 100644 index 000000000..6e7ea636e --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-0/output @@ -0,0 +1 @@ +[0] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-int-1/input b/deps/jansson/test/suites/valid/simple-int-1/input new file mode 100644 index 000000000..7660873d1 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-1/input @@ -0,0 +1 @@ +[1] diff --git a/deps/jansson/test/suites/valid/simple-int-1/output b/deps/jansson/test/suites/valid/simple-int-1/output new file mode 100644 index 000000000..bace2a0be --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-1/output @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-int-123/input b/deps/jansson/test/suites/valid/simple-int-123/input new file mode 100644 index 000000000..3214bfe58 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-123/input @@ -0,0 +1 @@ +[123] diff --git a/deps/jansson/test/suites/valid/simple-int-123/output b/deps/jansson/test/suites/valid/simple-int-123/output new file mode 100644 index 000000000..e47f69afc --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-int-123/output @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-object/input b/deps/jansson/test/suites/valid/simple-object/input new file mode 100644 index 000000000..a34fb4907 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-object/input @@ -0,0 +1 @@ +{"a":[]} diff --git a/deps/jansson/test/suites/valid/simple-object/output b/deps/jansson/test/suites/valid/simple-object/output new file mode 100644 index 000000000..982abe826 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-object/output @@ -0,0 +1 @@ +{"a": []} \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/simple-real/input b/deps/jansson/test/suites/valid/simple-real/input new file mode 100644 index 000000000..0fed7df36 --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-real/input @@ -0,0 +1 @@ +[123.456789] diff --git a/deps/jansson/test/suites/valid/simple-real/output b/deps/jansson/test/suites/valid/simple-real/output new file mode 100644 index 000000000..b02878e5f --- /dev/null +++ b/deps/jansson/test/suites/valid/simple-real/output @@ -0,0 +1 @@ +[123.456789] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/string-escapes/input b/deps/jansson/test/suites/valid/string-escapes/input new file mode 100644 index 000000000..d994564d3 --- /dev/null +++ b/deps/jansson/test/suites/valid/string-escapes/input @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] diff --git a/deps/jansson/test/suites/valid/string-escapes/output b/deps/jansson/test/suites/valid/string-escapes/output new file mode 100644 index 000000000..ca5c1c658 --- /dev/null +++ b/deps/jansson/test/suites/valid/string-escapes/output @@ -0,0 +1 @@ +["\"\\/\b\f\n\r\t"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/three-byte-utf-8/input b/deps/jansson/test/suites/valid/three-byte-utf-8/input new file mode 100644 index 000000000..ccc0bfa57 --- /dev/null +++ b/deps/jansson/test/suites/valid/three-byte-utf-8/input @@ -0,0 +1 @@ +["\u0821 three-byte UTF-8"] diff --git a/deps/jansson/test/suites/valid/three-byte-utf-8/output b/deps/jansson/test/suites/valid/three-byte-utf-8/output new file mode 100644 index 000000000..c44d124e7 --- /dev/null +++ b/deps/jansson/test/suites/valid/three-byte-utf-8/output @@ -0,0 +1 @@ +["ࠡ three-byte UTF-8"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/true/input b/deps/jansson/test/suites/valid/true/input new file mode 100644 index 000000000..29513c491 --- /dev/null +++ b/deps/jansson/test/suites/valid/true/input @@ -0,0 +1 @@ +[true] diff --git a/deps/jansson/test/suites/valid/true/output b/deps/jansson/test/suites/valid/true/output new file mode 100644 index 000000000..de601e305 --- /dev/null +++ b/deps/jansson/test/suites/valid/true/output @@ -0,0 +1 @@ +[true] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/two-byte-utf-8/input b/deps/jansson/test/suites/valid/two-byte-utf-8/input new file mode 100644 index 000000000..05ae854b5 --- /dev/null +++ b/deps/jansson/test/suites/valid/two-byte-utf-8/input @@ -0,0 +1 @@ +["\u0123 two-byte UTF-8"] diff --git a/deps/jansson/test/suites/valid/two-byte-utf-8/output b/deps/jansson/test/suites/valid/two-byte-utf-8/output new file mode 100644 index 000000000..1f0988d94 --- /dev/null +++ b/deps/jansson/test/suites/valid/two-byte-utf-8/output @@ -0,0 +1 @@ +["ģ two-byte UTF-8"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/utf-8-string/input b/deps/jansson/test/suites/valid/utf-8-string/input new file mode 100644 index 000000000..20dc64a45 --- /dev/null +++ b/deps/jansson/test/suites/valid/utf-8-string/input @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"] diff --git a/deps/jansson/test/suites/valid/utf-8-string/output b/deps/jansson/test/suites/valid/utf-8-string/output new file mode 100644 index 000000000..53728650d --- /dev/null +++ b/deps/jansson/test/suites/valid/utf-8-string/output @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"] \ No newline at end of file diff --git a/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input b/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input new file mode 100644 index 000000000..c598b4172 --- /dev/null +++ b/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input @@ -0,0 +1 @@ +["\uD834\uDD1E surrogate, four-byte UTF-8"] diff --git a/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output b/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output new file mode 100644 index 000000000..fa806d254 --- /dev/null +++ b/deps/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output @@ -0,0 +1 @@ +["𝄞 surrogate, four-byte UTF-8"] \ No newline at end of file diff --git a/deps/jansson/win32/jansson_config.h b/deps/jansson/win32/jansson_config.h new file mode 100644 index 000000000..ab1da5dd3 --- /dev/null +++ b/deps/jansson/win32/jansson_config.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE __inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +#endif diff --git a/deps/jansson/win32/vs2010/jansson.sln b/deps/jansson/win32/vs2010/jansson.sln new file mode 100644 index 000000000..58f911ba8 --- /dev/null +++ b/deps/jansson/win32/vs2010/jansson.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jansson", "jansson.vcxproj", "{76226D20-1972-4789-A595-EDACC7A76DC3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.ActiveCfg = Debug|Win32 + {76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.Build.0 = Debug|Win32 + {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.ActiveCfg = Release|Win32 + {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/deps/jansson/win32/vs2010/jansson.vcxproj b/deps/jansson/win32/vs2010/jansson.vcxproj new file mode 100644 index 000000000..d5b2a8796 --- /dev/null +++ b/deps/jansson/win32/vs2010/jansson.vcxproj @@ -0,0 +1,108 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + {76226D20-1972-4789-A595-EDACC7A76DC3} + Win32Proj + jansson_dll + jansson + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + true + Output\$(Configuration)\ + Build\$(Configuration)\ + + + false + Output\$(Configuration)\ + Build\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions) + .. + 4996 + + + Windows + true + ../../src/jansson.def + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions) + .. + 4996 + + + Windows + true + true + true + ../../src/jansson.def + + + + + + \ No newline at end of file diff --git a/deps/jansson/win32/vs2010/jansson.vcxproj.filters b/deps/jansson/win32/vs2010/jansson.vcxproj.filters new file mode 100644 index 000000000..f8eee304a --- /dev/null +++ b/deps/jansson/win32/vs2010/jansson.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/deps/jansson/win32/vs2010/jansson.vcxproj.user b/deps/jansson/win32/vs2010/jansson.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/deps/jansson/win32/vs2010/jansson.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file