Import ubus tools.
This commit is contained in:
14
3P/CMakeLists.txt
Normal file
14
3P/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# CMakeLists files in this project can
|
||||||
|
# refer to the root source directory of the project as ${HELLO_SOURCE_DIR} and
|
||||||
|
# to the root binary directory of the project as ${HELLO_BINARY_DIR}.
|
||||||
|
cmake_minimum_required (VERSION 2.8.11)
|
||||||
|
|
||||||
|
#add_subdirectory (wolfssl/builders/cmake)
|
||||||
|
add_subdirectory (json/builders/cmake)
|
||||||
|
#add_subdirectory (jsoncpp/builders/cmake)
|
||||||
|
add_subdirectory (libubox/builders/cmake)
|
||||||
|
add_subdirectory (ubus/libubus/builders/cmake)
|
||||||
|
add_subdirectory (ubus/ubus/builders/cmake)
|
||||||
|
add_subdirectory (ubus/ubusd/builders/cmake)
|
||||||
|
#add_subdirectory (civetweb/builders/cmake)
|
||||||
|
#add_subdirectory (wiringPi/)
|
||||||
49
3P/json/.gitignore
vendored
Normal file
49
3P/json/.gitignore
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
/INSTALL
|
||||||
|
.deps/
|
||||||
|
.libs/
|
||||||
|
/aclocal.m4
|
||||||
|
/autom4te.cache
|
||||||
|
/config.guess
|
||||||
|
/json_config.h
|
||||||
|
/config.h
|
||||||
|
/config.log
|
||||||
|
/config.status
|
||||||
|
/config.sub
|
||||||
|
/configure
|
||||||
|
/depcomp
|
||||||
|
/doc
|
||||||
|
/install-sh
|
||||||
|
/json.pc
|
||||||
|
/json-c.pc
|
||||||
|
/json-c-uninstalled.pc
|
||||||
|
/libtool
|
||||||
|
/ltmain.sh
|
||||||
|
/Makefile
|
||||||
|
/Makefile.in
|
||||||
|
/missing
|
||||||
|
/stamp-h1
|
||||||
|
/stamp-h2
|
||||||
|
/tests/Makefile
|
||||||
|
/tests/Makefile.in
|
||||||
|
/tests/test1
|
||||||
|
/tests/test1Formatted
|
||||||
|
/tests/test2
|
||||||
|
/tests/test2Formatted
|
||||||
|
/tests/test4
|
||||||
|
/tests/testReplaceExisting
|
||||||
|
/tests/testSubDir
|
||||||
|
/tests/test_parse_int64
|
||||||
|
/tests/test_parse
|
||||||
|
/tests/test_cast
|
||||||
|
/tests/test_null
|
||||||
|
/tests/test_printbuf
|
||||||
|
/tests/test_set_serializer
|
||||||
|
/tests/*.vg.out
|
||||||
|
/Debug
|
||||||
|
/Release
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
/libjson-c.la
|
||||||
|
/libjson.la
|
||||||
0
3P/json/0.11
Normal file
0
3P/json/0.11
Normal file
5
3P/json/AUTHORS
Normal file
5
3P/json/AUTHORS
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
Jehiah Czebotar <jehiah@gmail.com>
|
||||||
|
Eric Haszlakiewicz <hawicz+json-c@gmail.com>
|
||||||
|
C. Watford (christopher.watford@gmail.com)
|
||||||
|
|
||||||
39
3P/json/Android.configure.mk
Normal file
39
3P/json/Android.configure.mk
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# This file is the top android makefile for all sub-modules.
|
||||||
|
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
json_c_TOP := $(LOCAL_PATH)
|
||||||
|
|
||||||
|
JSON_C_BUILT_SOURCES := Android.mk
|
||||||
|
|
||||||
|
JSON_C_BUILT_SOURCES := $(patsubst %, $(abspath $(json_c_TOP))/%, $(JSON_C_BUILT_SOURCES))
|
||||||
|
|
||||||
|
.PHONY: json-c-configure json-c-configure-real
|
||||||
|
json-c-configure-real:
|
||||||
|
echo $(JSON_C_BUILT_SOURCES)
|
||||||
|
cd $(json_c_TOP) ; \
|
||||||
|
$(abspath $(json_c_TOP))/autogen.sh && \
|
||||||
|
CC="$(CONFIGURE_CC)" \
|
||||||
|
CFLAGS="$(CONFIGURE_CFLAGS)" \
|
||||||
|
LD=$(TARGET_LD) \
|
||||||
|
LDFLAGS="$(CONFIGURE_LDFLAGS)" \
|
||||||
|
CPP=$(CONFIGURE_CPP) \
|
||||||
|
CPPFLAGS="$(CONFIGURE_CPPFLAGS)" \
|
||||||
|
PKG_CONFIG_LIBDIR=$(CONFIGURE_PKG_CONFIG_LIBDIR) \
|
||||||
|
PKG_CONFIG_TOP_BUILD_DIR=/ \
|
||||||
|
ac_cv_func_malloc_0_nonnull=yes \
|
||||||
|
ac_cv_func_realloc_0_nonnull=yes \
|
||||||
|
$(abspath $(json_c_TOP))/$(CONFIGURE) --host=$(CONFIGURE_HOST) \
|
||||||
|
--prefix=/system \
|
||||||
|
&& \
|
||||||
|
for file in $(JSON_C_BUILT_SOURCES); do \
|
||||||
|
rm -f $$file && \
|
||||||
|
make -C $$(dirname $$file) $$(basename $$file) ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
json-c-configure: json-c-configure-real
|
||||||
|
|
||||||
|
PA_CONFIGURE_TARGETS += json-c-configure
|
||||||
|
|
||||||
|
-include $(json_c_TOP)/Android.mk
|
||||||
42
3P/json/COPYING
Normal file
42
3P/json/COPYING
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Copyright (c) 2009-2012 Eric Haszlakiewicz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004, 2005 Metaparadigm Pte Ltd
|
||||||
|
|
||||||
|
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.
|
||||||
175
3P/json/ChangeLog
Normal file
175
3P/json/ChangeLog
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
|
||||||
|
0.11
|
||||||
|
|
||||||
|
* IMPORTANT: the name of the library has changed to libjson-c.so and
|
||||||
|
the header files are now in include/json-c.
|
||||||
|
The pkgconfig name has also changed from json to json-c.
|
||||||
|
You should change your build to use appropriate -I and -l options.
|
||||||
|
A compatibility shim is in place so builds using the old name will
|
||||||
|
continue to work, but that will be removed in the next release.
|
||||||
|
* Maximum recursion depth is now a runtime option.
|
||||||
|
json_tokener_new() is provided for compatibility.
|
||||||
|
json_tokener_new_ex(depth)
|
||||||
|
* Include json_object_iterator.h in the installed headers.
|
||||||
|
* Add support for building on Android.
|
||||||
|
* Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid.
|
||||||
|
* Make it safe to delete keys while iterating with the json_object_object_foreach macro.
|
||||||
|
* Add a json_set_serializer() function to allow the string output of a json_object to be customized.
|
||||||
|
* Make float parsing locale independent.
|
||||||
|
* Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag.
|
||||||
|
* Enable -Werror when building.
|
||||||
|
* speed improvements to parsing 64-bit integers on systems with working sscanf
|
||||||
|
* Add a json_object_object_length function.
|
||||||
|
* Fix a bug (buffer overrun) when expanding arrays to more than 64 entries.
|
||||||
|
|
||||||
|
0.10
|
||||||
|
|
||||||
|
* Add a json_object_to_json_string_ext() function to allow output to be
|
||||||
|
formatted in a more human readable form.
|
||||||
|
* Add json_object_object_get_ex(), a NULL-safe get object method, to be able
|
||||||
|
to distinguish between a key not present and the value being NULL.
|
||||||
|
* Add an alternative iterator implementation, see json_object_iterator.h
|
||||||
|
* Make json_object_iter public to enable external use of the
|
||||||
|
json_object_object_foreachC macro.
|
||||||
|
* Add a printbuf_memset() function to provide an effecient way to set and
|
||||||
|
append things like whitespace indentation.
|
||||||
|
* Adjust json_object_is_type and json_object_get_type so they return
|
||||||
|
json_type_null for NULL objects and handle NULL passed to
|
||||||
|
json_objct_object_get().
|
||||||
|
* Rename boolean type to json_bool.
|
||||||
|
* Fix various compile issues for Visual Studio and MinGW.
|
||||||
|
* Allow json_tokener_parse_ex() to be re-used to parse multiple object.
|
||||||
|
Also, fix some parsing issues with capitalized hexadecimal numbers and
|
||||||
|
number in E notation.
|
||||||
|
* Add json_tokener_get_error() and json_tokener_error_desc() to better
|
||||||
|
encapsulate the process of retrieving errors while parsing.
|
||||||
|
* Various improvements to the documentation of many functions.
|
||||||
|
* Add new json_object_array_sort() function.
|
||||||
|
* Fix a bug in json_object_get_int(), which would incorrectly return 0
|
||||||
|
when called on a string type object.
|
||||||
|
Eric Haszlakiewicz
|
||||||
|
* Add a json_type_to_name() function.
|
||||||
|
Eric Haszlakiewicz
|
||||||
|
* Add a json_tokener_parse_verbose() function.
|
||||||
|
Jehiah Czebotar
|
||||||
|
* Improve support for null bytes within JSON strings.
|
||||||
|
Jehiah Czebotar
|
||||||
|
* Fix file descriptor leak if memory allocation fails in json_util
|
||||||
|
Zachary Blair, zack_blair at hotmail dot com
|
||||||
|
* Add int64 support. Two new functions json_object_net_int64 and
|
||||||
|
json_object_get_int64. Binary compatibility preserved.
|
||||||
|
Eric Haszlakiewicz, EHASZLA at transunion com
|
||||||
|
Rui Miguel Silva Seabra, rms at 1407 dot org
|
||||||
|
* Fix subtle bug in linkhash where lookup could hang after all slots
|
||||||
|
were filled then successively freed.
|
||||||
|
Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com
|
||||||
|
* Make json_object_from_file take const char *filename
|
||||||
|
Spotted by Vikram Raj V, vsagar at attinteractive dot com
|
||||||
|
* Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am)
|
||||||
|
Brent Miller, bdmiller at yahoo dash inc dot com
|
||||||
|
* Correction to comment describing printbuf_memappend in printbuf.h
|
||||||
|
Brent Miller, bdmiller at yahoo dash inc dot com
|
||||||
|
|
||||||
|
0.9
|
||||||
|
* Add README.html README-WIN32.html config.h.win32 to Makefile.am
|
||||||
|
Michael Clark, <michael@metaparadigm.com>
|
||||||
|
* Add const qualifier to the json_tokener_parse functions
|
||||||
|
Eric Haszlakiewicz, EHASZLA at transunion dot com
|
||||||
|
* Rename min and max so we can never clash with C or C++ std library
|
||||||
|
Ian Atha, thatha at yahoo dash inc dot com
|
||||||
|
* Fix any noticeable spelling or grammar errors.
|
||||||
|
* Make sure every va_start has a va_end.
|
||||||
|
* Check all pointers for validity.
|
||||||
|
Erik Hovland, erik at hovland dot org
|
||||||
|
* Fix json_object_get_boolean to return false for empty string
|
||||||
|
Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com
|
||||||
|
* optimizations to json_tokener_parse_ex(), printbuf_memappend()
|
||||||
|
Brent Miller, bdmiller at yahoo dash inc dot com
|
||||||
|
* Disable REFCOUNT_DEBUG by default in json_object.c
|
||||||
|
* Don't use this as a variable, so we can compile with a C++ compiler
|
||||||
|
* Add casts from void* to type of assignment when using malloc
|
||||||
|
* Add #ifdef __cplusplus guards to all of the headers
|
||||||
|
* Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table
|
||||||
|
Michael Clark, <michael@metaparadigm.com>
|
||||||
|
* Null pointer dereference fix. Fix json_object_get_boolean strlen test
|
||||||
|
to not return TRUE for zero length string. Remove redundant includes.
|
||||||
|
Erik Hovland, erik at hovland dot org
|
||||||
|
* Fixed warning reported by adding -Wstrict-prototypes
|
||||||
|
-Wold-style-definition to the compilatin flags.
|
||||||
|
Dotan Barak, dotanba at gmail dot com
|
||||||
|
* Add const correctness to public interfaces
|
||||||
|
Gerard Krol, g dot c dot krol at student dot tudelft dot nl
|
||||||
|
|
||||||
|
0.8
|
||||||
|
* Add va_end for every va_start
|
||||||
|
Dotan Barak, dotanba at gmail dot com
|
||||||
|
* Add macros to enable compiling out debug code
|
||||||
|
Geoffrey Young, geoff at modperlcookbook dot org
|
||||||
|
* Fix bug with use of capital E in numbers with exponents
|
||||||
|
Mateusz Loskot, mateusz at loskot dot net
|
||||||
|
* Add stddef.h include
|
||||||
|
* Patch allows for json-c compile with -Werror and not fail due to
|
||||||
|
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
|
||||||
|
Geoffrey Young, geoff at modperlcookbook dot org
|
||||||
|
|
||||||
|
0.7
|
||||||
|
* Add escaping of backslash to json output
|
||||||
|
* Add escaping of foward slash on tokenizing and output
|
||||||
|
* Changes to internal tokenizer from using recursion to
|
||||||
|
using a depth state structure to allow incremental parsing
|
||||||
|
|
||||||
|
0.6
|
||||||
|
* Fix bug in escaping of control characters
|
||||||
|
Johan Björklund, johbjo09 at kth dot se
|
||||||
|
* Remove include "config.h" from headers (should only
|
||||||
|
be included from .c files)
|
||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
|
||||||
|
0.5
|
||||||
|
* Make headers C++ compatible by change *this to *obj
|
||||||
|
* Add ifdef C++ extern "C" to headers
|
||||||
|
* Use simpler definition of min and max in bits.h
|
||||||
|
Larry Lansing, llansing at fuzzynerd dot com
|
||||||
|
|
||||||
|
* Remove automake 1.6 requirement
|
||||||
|
* Move autogen commands into autogen.sh. Update README
|
||||||
|
* Remove error pointer special case for Windows
|
||||||
|
* Change license from LGPL to MIT
|
||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
|
||||||
|
0.4
|
||||||
|
* Fix additional error case in object parsing
|
||||||
|
* Add back sign reversal in nested object parse as error pointer
|
||||||
|
value is negative, while error value is positive.
|
||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
|
||||||
|
0.3
|
||||||
|
* fix pointer arithmetic bug for error pointer check in is_error() macro
|
||||||
|
* fix type passed to printbuf_memappend in json_tokener
|
||||||
|
* update autotools bootstrap instructions in README
|
||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
|
||||||
|
0.2
|
||||||
|
* printbuf.c - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Added a Win32/Win64 compliant implementation of vasprintf
|
||||||
|
* debug.c - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Removed usage of vsyslog on Win32/Win64 systems, needs to be handled
|
||||||
|
by a configure script
|
||||||
|
* json_object.c - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Added scope operator to wrap usage of json_object_object_foreach, this
|
||||||
|
needs to be rethought to be more ANSI C friendly
|
||||||
|
* json_object.h - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Added Microsoft C friendly version of json_object_object_foreach
|
||||||
|
* json_tokener.c - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Added a Win32/Win64 compliant implementation of strndup
|
||||||
|
* json_util.c - C. Watford (christopher.watford@gmail.com)
|
||||||
|
Added cast and mask to suffice size_t v. unsigned int conversion
|
||||||
|
correctness
|
||||||
|
* json_tokener.c - sign reversal issue on error info for nested object parse
|
||||||
|
spotted by Johan Björklund (johbjo09 at kth.se)
|
||||||
|
* json_object.c - escape " in json_escape_str
|
||||||
|
* Change to automake and libtool to build shared and static library
|
||||||
|
Michael Clark <michael@metaparadigm.com>
|
||||||
|
|
||||||
|
0.1
|
||||||
|
* initial release
|
||||||
1153
3P/json/Doxyfile
Normal file
1153
3P/json/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
92
3P/json/Makefile.am
Normal file
92
3P/json/Makefile.am
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
include Makefile.am.inc
|
||||||
|
|
||||||
|
EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj
|
||||||
|
SUBDIRS = . tests
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libjson-c.la
|
||||||
|
if ENABLE_OLDNAME_COMPAT
|
||||||
|
lib_LTLIBRARIES+=libjson.la
|
||||||
|
endif
|
||||||
|
|
||||||
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
|
pkgconfig_DATA = json-c.pc
|
||||||
|
if ENABLE_OLDNAME_COMPAT
|
||||||
|
pkgconfig_DATA += json.pc
|
||||||
|
endif
|
||||||
|
|
||||||
|
libjson_cincludedir = $(includedir)/json-c
|
||||||
|
libjson_cinclude_HEADERS = \
|
||||||
|
arraylist.h \
|
||||||
|
bits.h \
|
||||||
|
debug.h \
|
||||||
|
json.h \
|
||||||
|
json_config.h \
|
||||||
|
json_c_version.h \
|
||||||
|
json_inttypes.h \
|
||||||
|
json_object.h \
|
||||||
|
json_object_iterator.h \
|
||||||
|
json_object_private.h \
|
||||||
|
json_tokener.h \
|
||||||
|
json_util.h \
|
||||||
|
linkhash.h \
|
||||||
|
printbuf.h
|
||||||
|
|
||||||
|
#libjsonx_includedir = $(libdir)/json-c-@VERSION@
|
||||||
|
#
|
||||||
|
#libjsonx_include_HEADERS = \
|
||||||
|
# json_config.h
|
||||||
|
|
||||||
|
libjson_c_la_LDFLAGS = -version-info 2:1:0 -no-undefined
|
||||||
|
|
||||||
|
if ENABLE_OLDNAME_COMPAT
|
||||||
|
libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c
|
||||||
|
|
||||||
|
# Temporary libjson library. This will be removed after one release.
|
||||||
|
libjson_la_LIBADD = -ljson-c
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
libjson_c_la_SOURCES = \
|
||||||
|
arraylist.c \
|
||||||
|
debug.c \
|
||||||
|
json_c_version.c \
|
||||||
|
json_object.c \
|
||||||
|
json_object_iterator.c \
|
||||||
|
json_tokener.c \
|
||||||
|
json_util.c \
|
||||||
|
linkhash.c \
|
||||||
|
printbuf.c
|
||||||
|
|
||||||
|
|
||||||
|
distclean-local:
|
||||||
|
-rm -rf $(testsubdir)
|
||||||
|
-rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub depcomp install-sh ltmain.sh missing
|
||||||
|
|
||||||
|
maintainer-clean-local:
|
||||||
|
-rm -rf configure
|
||||||
|
|
||||||
|
if ENABLE_OLDNAME_COMPAT
|
||||||
|
install-data-hook:
|
||||||
|
test \! -e "$(DESTDIR)@includedir@/json" || rm "$(DESTDIR)@includedir@/json"
|
||||||
|
$(LN_S) json-c "$(DESTDIR)@includedir@/json"
|
||||||
|
|
||||||
|
uninstall-local:
|
||||||
|
rm -f "$(DESTDIR)@includedir@/json"
|
||||||
|
rm -rf "$(DESTDIR)@includedir@/json-c"
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H
|
||||||
|
|
||||||
|
Android.mk: Makefile.am
|
||||||
|
androgenizer -:PROJECT json-c \
|
||||||
|
-:SHARED libjson-c \
|
||||||
|
-:TAGS eng debug \
|
||||||
|
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
|
||||||
|
-:SOURCES $(libjson_c_la_SOURCES) $(nodist_libjson_c_la_SOURCES) \
|
||||||
|
-:CFLAGS $(DEFS) $(ANDROID_CFLAGS) $(libjson_c_la_CFLAGS) \
|
||||||
|
-:LDFLAGS $(libjson_c_la_LDFLAGS) $(libjson_c_la_LIBADD) \
|
||||||
|
-:HEADER_TARGET json-c \
|
||||||
|
-:HEADERS $(libjson_cinclude_HEADERS) \
|
||||||
|
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
||||||
|
> $@
|
||||||
2
3P/json/Makefile.am.inc
Normal file
2
3P/json/Makefile.am.inc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
AM_CFLAGS = -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT
|
||||||
|
|
||||||
0
3P/json/NEWS
Normal file
0
3P/json/NEWS
Normal file
44
3P/json/README
Normal file
44
3P/json/README
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
Building on Unix with git, gcc and autotools
|
||||||
|
|
||||||
|
Home page for json-c:
|
||||||
|
https://github.com/json-c/json-c/wiki
|
||||||
|
|
||||||
|
Caution: do NOT use sources from svn.metaparadigm.com, they are old.
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
gcc (or another C compiler)
|
||||||
|
libtool
|
||||||
|
|
||||||
|
If you're not using a release tarball, you'll also need:
|
||||||
|
autoconf (autoreconf)
|
||||||
|
automake
|
||||||
|
|
||||||
|
Github repo for json-c:
|
||||||
|
https://github.com/json-c/json-c
|
||||||
|
|
||||||
|
$ git clone https://github.com/json-c/json-c.git
|
||||||
|
$ cd json-c
|
||||||
|
$ sh autogen.sh
|
||||||
|
|
||||||
|
Then
|
||||||
|
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
$ make install
|
||||||
|
|
||||||
|
To build and run the test programs run
|
||||||
|
|
||||||
|
$ make check
|
||||||
|
|
||||||
|
Linking to libjson-c
|
||||||
|
|
||||||
|
If your system has pkgconfig then you can just add this to your makefile
|
||||||
|
|
||||||
|
CFLAGS += $(shell pkg-config --cflags json-c)
|
||||||
|
LDFLAGS += $(shell pkg-config --libs json-c)
|
||||||
|
|
||||||
|
Without pkgconfig, you would do something like this:
|
||||||
|
|
||||||
|
JSON_C_DIR=/path/to/json_c/install
|
||||||
|
CFLAGS += -I$(JSON_C_DIR)/include/json-c
|
||||||
|
LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c
|
||||||
50
3P/json/README-WIN32.html
Normal file
50
3P/json/README-WIN32.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<title>JSON-C - A JSON implementation in C - Win32 specific notes</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Windows specific notes for JSON-C</h2>
|
||||||
|
<p>Please send Win32 bug reports to <a href="mailto:christopher.watford@gmail.com">christopher.watford@gmail.com</a></p>
|
||||||
|
<p><b>Win32 Specific Changes:</b></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Various functions have been redefined to their Win32 version (i.e. <tt>open</tt>
|
||||||
|
on win32 is <tt>_open</tt>)</li>
|
||||||
|
<li>
|
||||||
|
Implemented missing functions from MS's libc (i.e. <tt>vasprintf</tt> and <tt>strndup</tt>)</li>
|
||||||
|
<li>
|
||||||
|
Added code to allow Win64 support without integer resizing issues, this
|
||||||
|
probably makes it much nicer on 64bit machines everywhere (i.e. using <tt>ptrdiff_t</tt>
|
||||||
|
for pointer math)</li>
|
||||||
|
</ul>
|
||||||
|
<p><b>Porting Changelog:</b></p>
|
||||||
|
<dl>
|
||||||
|
<dt><tt>printbuf.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Added a Win32/Win64 compliant implementation of <tt>vasprintf</tt></dd>
|
||||||
|
<dt><tt>debug.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Removed usage of <tt>vsyslog</tt> on Win32/Win64 systems, needs to be handled
|
||||||
|
by a configure script</dd>
|
||||||
|
<dt><tt>json_object.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Added scope operator to wrap usage of <tt>json_object_object_foreach</tt>, this needs to be
|
||||||
|
rethought to be more ANSI C friendly</dd>
|
||||||
|
<dt><tt>json_object.h</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Added Microsoft C friendly version of <tt>json_object_object_foreach</tt></dd>
|
||||||
|
<dt><tt>json_tokener.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Added a Win32/Win64 compliant implementation of <tt>strndup</tt></dd>
|
||||||
|
<dt><tt>json_util.c</tt> - C. Watford (christopher.watford@gmail.com)</dt>
|
||||||
|
<dd>
|
||||||
|
Added cast and mask to suffice <tt>size_t</tt> v. <tt>unsigned int</tt>
|
||||||
|
conversion correctness</dd>
|
||||||
|
</dl>
|
||||||
|
<p>This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the MIT License. See COPYING for details.</p>
|
||||||
|
<hr />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
3P/json/README.html
Normal file
34
3P/json/README.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<title>JSON-C - A JSON implementation in C</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>JSON-C - A JSON implementation in C</h2>
|
||||||
|
|
||||||
|
<h3>Overview</h3>
|
||||||
|
<p>JSON-C implements a reference counting object model that allows you to easily
|
||||||
|
construct JSON objects in C, output them as JSON formatted strings and parse
|
||||||
|
JSON formatted strings back into the C representation of JSON objects.</p>
|
||||||
|
|
||||||
|
<h3>Building</h3>
|
||||||
|
<p>To setup JSON-C to build on your system please run <tt>configure</tt> and <tt>make</tt>.</p>
|
||||||
|
<p>If you are on Win32 and are not using the VS project file, be sure
|
||||||
|
to rename <tt>config.h.win32</tt> to <tt>config.h</tt> before building.</p>
|
||||||
|
|
||||||
|
<h3>Documentation</h3>
|
||||||
|
<P>Doxygen generated documentation exists <a href="doc/html/json__object_8h.html">here</a>
|
||||||
|
and Win32 specific notes can be found <a href="README-WIN32.html">here</a>.</P>
|
||||||
|
|
||||||
|
<h3><a href="https://github.com/json-c/json-c">GIT Reposository</a></h3>
|
||||||
|
<p><strong><code>git clone https://github.com/json-c/json-c.git</code></strong></p>
|
||||||
|
|
||||||
|
<h3><a href="http://groups.google.com/group/json-c">Mailing List</a></h3>
|
||||||
|
<pi>Send email to <strong><code>json-c <i><at></i> googlegroups <i><dot></i> com</code></strong></p>
|
||||||
|
|
||||||
|
<h3><a href="COPYING">License</a></h3>
|
||||||
|
<p>This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..</p>
|
||||||
|
<hr/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
61
3P/json/RELEASE_CHECKLIST.txt
Normal file
61
3P/json/RELEASE_CHECKLIST.txt
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
Release checklist:
|
||||||
|
|
||||||
|
release=0.11
|
||||||
|
git clone https://github.com/json-c/json-c json-c-${release}
|
||||||
|
cd json-c-${release}
|
||||||
|
|
||||||
|
Check that the compile works on Linux
|
||||||
|
Check that the compile works on NetBSD
|
||||||
|
Check that the compile works on Windows
|
||||||
|
Check ChangeLog to see if anything should be added.
|
||||||
|
|
||||||
|
git branch json-c-${release}
|
||||||
|
git checkout json-c-${release}
|
||||||
|
|
||||||
|
Generate the configure script and other files:
|
||||||
|
sh autogen.sh
|
||||||
|
git add -f Makefile.in aclocal.m4 config.guess \
|
||||||
|
config.sub configure depcomp install-sh \
|
||||||
|
ltmain.sh missing tests/Makefile.in \
|
||||||
|
INSTALL
|
||||||
|
|
||||||
|
# check for anything else to be added:
|
||||||
|
git status --ignored
|
||||||
|
git commit
|
||||||
|
|
||||||
|
Generate the doxygen documentation:
|
||||||
|
doxygen
|
||||||
|
git add -f doc
|
||||||
|
git commit doc
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
echo .git > excludes
|
||||||
|
echo autom4te.cache >> excludes
|
||||||
|
tar -czf json-c-${release}.tar.gz -X excludes json-c-${release}
|
||||||
|
|
||||||
|
echo doc >> excludes
|
||||||
|
tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release}
|
||||||
|
|
||||||
|
Tag the branch:
|
||||||
|
cd json-c-${release}
|
||||||
|
git tag -a json-c-${release}-$(date +%Y%m%d)
|
||||||
|
git push
|
||||||
|
git push --tags
|
||||||
|
|
||||||
|
Go to https://github.com/json-c/json-c/downloads
|
||||||
|
Upload the two tarballs.
|
||||||
|
|
||||||
|
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Post-release checklist:
|
||||||
|
|
||||||
|
git branch master
|
||||||
|
Add new section to CHANGES
|
||||||
|
Update the version in json_c_version.h
|
||||||
|
Update the version in Doxyfile
|
||||||
|
Update the version in configure.in
|
||||||
|
Update the libjson_la_LDFLAGS line in Makefile.am to the new version.
|
||||||
|
http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
|
|
||||||
101
3P/json/arraylist.c
Normal file
101
3P/json/arraylist.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
|
||||||
|
#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
|
||||||
|
# include <strings.h>
|
||||||
|
#endif /* HAVE_STRINGS_H */
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "arraylist.h"
|
||||||
|
|
||||||
|
struct array_list*
|
||||||
|
array_list_new(array_list_free_fn *free_fn)
|
||||||
|
{
|
||||||
|
struct array_list *arr;
|
||||||
|
|
||||||
|
arr = (struct array_list*)calloc(1, sizeof(struct array_list));
|
||||||
|
if(!arr) return NULL;
|
||||||
|
arr->size = ARRAY_LIST_DEFAULT_SIZE;
|
||||||
|
arr->length = 0;
|
||||||
|
arr->free_fn = free_fn;
|
||||||
|
if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {
|
||||||
|
free(arr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void
|
||||||
|
array_list_free(struct array_list *arr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < arr->length; i++)
|
||||||
|
if(arr->array[i]) arr->free_fn(arr->array[i]);
|
||||||
|
free(arr->array);
|
||||||
|
free(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
array_list_get_idx(struct array_list *arr, int i)
|
||||||
|
{
|
||||||
|
if(i >= arr->length) return NULL;
|
||||||
|
return arr->array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int array_list_expand_internal(struct array_list *arr, int max)
|
||||||
|
{
|
||||||
|
void *t;
|
||||||
|
int new_size;
|
||||||
|
|
||||||
|
if(max < arr->size) return 0;
|
||||||
|
new_size = json_max(arr->size << 1, max);
|
||||||
|
if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1;
|
||||||
|
arr->array = (void**)t;
|
||||||
|
(void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));
|
||||||
|
arr->size = new_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
array_list_put_idx(struct array_list *arr, int idx, void *data)
|
||||||
|
{
|
||||||
|
if(array_list_expand_internal(arr, idx+1)) return -1;
|
||||||
|
if(arr->array[idx]) arr->free_fn(arr->array[idx]);
|
||||||
|
arr->array[idx] = data;
|
||||||
|
if(arr->length <= idx) arr->length = idx + 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
array_list_add(struct array_list *arr, void *data)
|
||||||
|
{
|
||||||
|
return array_list_put_idx(arr, arr->length, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
|
||||||
|
{
|
||||||
|
qsort(arr->array, arr->length, sizeof(arr->array[0]),
|
||||||
|
(int (*)(const void *, const void *))sort_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
array_list_length(struct array_list *arr)
|
||||||
|
{
|
||||||
|
return arr->length;
|
||||||
|
}
|
||||||
56
3P/json/arraylist.h
Normal file
56
3P/json/arraylist.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _arraylist_h_
|
||||||
|
#define _arraylist_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_LIST_DEFAULT_SIZE 32
|
||||||
|
|
||||||
|
typedef void (array_list_free_fn) (void *data);
|
||||||
|
|
||||||
|
struct array_list
|
||||||
|
{
|
||||||
|
void **array;
|
||||||
|
int length;
|
||||||
|
int size;
|
||||||
|
array_list_free_fn *free_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct array_list*
|
||||||
|
array_list_new(array_list_free_fn *free_fn);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
array_list_free(struct array_list *al);
|
||||||
|
|
||||||
|
extern void*
|
||||||
|
array_list_get_idx(struct array_list *al, int i);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
array_list_put_idx(struct array_list *al, int i, void *data);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
array_list_add(struct array_list *al, void *data);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
array_list_length(struct array_list *al);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
13
3P/json/autogen.sh
Executable file
13
3P/json/autogen.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
autoreconf -v --install || exit 1
|
||||||
|
|
||||||
|
# If there are any options, assume the user wants to run configure.
|
||||||
|
# To run configure w/o any options, use ./autogen.sh --configure
|
||||||
|
if [ $# -gt 0 ] ; then
|
||||||
|
case "$1" in
|
||||||
|
--conf*)
|
||||||
|
shift 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exec ./configure "$@"
|
||||||
|
fi
|
||||||
28
3P/json/bits.h
Normal file
28
3P/json/bits.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _bits_h_
|
||||||
|
#define _bits_h_
|
||||||
|
|
||||||
|
#ifndef json_min
|
||||||
|
#define json_min(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef json_max
|
||||||
|
#define json_max(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
|
||||||
|
#define error_ptr(error) ((void*)error)
|
||||||
|
#define error_description(error) (json_tokener_errors[error])
|
||||||
|
#define is_error(ptr) (ptr == NULL)
|
||||||
|
|
||||||
|
#endif
|
||||||
29
3P/json/builders/cmake/CMakeLists.txt
Normal file
29
3P/json/builders/cmake/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
|
||||||
|
include (libjson-c)
|
||||||
|
|
||||||
|
project(json-c)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB
|
||||||
|
source_files
|
||||||
|
../../arraylist.c
|
||||||
|
../../debug.c
|
||||||
|
../../json_c_version.c
|
||||||
|
../../json_object.c
|
||||||
|
../../json_object_iterator.c
|
||||||
|
../../json_tokener.c
|
||||||
|
../../json_util.c
|
||||||
|
../../linkhash.c
|
||||||
|
../../printbuf.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT")
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
json-c
|
||||||
|
SHARED
|
||||||
|
${source_files}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories (json-c PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
31
3P/json/builders/linux-gcc/Makefile
Normal file
31
3P/json/builders/linux-gcc/Makefile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
ifeq (,$(filter _%,$(notdir $(CURDIR))))
|
||||||
|
include $(AWOXCVS)/AwoxSoftware/builders/linux-gcc/target.mk
|
||||||
|
else
|
||||||
|
|
||||||
|
|
||||||
|
include $(BUILDERS)/main.mk
|
||||||
|
include $(AUDIOBUILDERS)/use-libjson-c.mk
|
||||||
|
|
||||||
|
VPATH = ../../..
|
||||||
|
|
||||||
|
OBJS += arraylist.o
|
||||||
|
OBJS += debug.o
|
||||||
|
OBJS += json_c_version.o
|
||||||
|
OBJS += json_object.o
|
||||||
|
OBJS += json_object_iterator.o
|
||||||
|
OBJS += json_tokener.o
|
||||||
|
OBJS += json_util.o
|
||||||
|
OBJS += linkhash.o
|
||||||
|
OBJS += printbuf.o
|
||||||
|
|
||||||
|
AWOX_CFLAGS += -I../../../
|
||||||
|
|
||||||
|
AWOX_CFLAGS += -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT
|
||||||
|
|
||||||
|
MAKELIB_TARGET=json-c
|
||||||
|
|
||||||
|
LIB_DEPS=$(AWOX_LIB_DEPS)
|
||||||
|
|
||||||
|
include $(BUILDERS)/make-lib.mk
|
||||||
|
|
||||||
|
endif
|
||||||
148
3P/json/config.h.in
Normal file
148
3P/json/config.h.in
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/* config.h.in. Generated from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* Define if .gnu.warning accepts long strings. */
|
||||||
|
#undef HAS_GNU_WARNING_LONG
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
|
#undef HAVE_DLFCN_H
|
||||||
|
|
||||||
|
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||||
|
#undef HAVE_DOPRNT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#undef HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <limits.h> header file. */
|
||||||
|
#undef HAVE_LIMITS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <locale.h> header file. */
|
||||||
|
#undef HAVE_LOCALE_H
|
||||||
|
|
||||||
|
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||||
|
to 0 otherwise. */
|
||||||
|
#undef HAVE_MALLOC
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `open' function. */
|
||||||
|
#undef HAVE_OPEN
|
||||||
|
|
||||||
|
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||||
|
and to 0 otherwise. */
|
||||||
|
#undef HAVE_REALLOC
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `setlocale' function. */
|
||||||
|
#undef HAVE_SETLOCALE
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
|
#undef HAVE_SNPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||||
|
#undef HAVE_STDARG_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strcasecmp' function. */
|
||||||
|
#undef HAVE_STRCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strdup' function. */
|
||||||
|
#undef HAVE_STRDUP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strerror' function. */
|
||||||
|
#undef HAVE_STRERROR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#undef HAVE_STRING_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strncasecmp' function. */
|
||||||
|
#undef HAVE_STRNCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strndup' function. */
|
||||||
|
#undef HAVE_STRNDUP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <syslog.h> header file. */
|
||||||
|
#undef HAVE_SYSLOG_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||||
|
#undef HAVE_SYS_CDEFS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||||
|
#undef HAVE_SYS_PARAM_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vasprintf' function. */
|
||||||
|
#undef HAVE_VASPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vprintf' function. */
|
||||||
|
#undef HAVE_VPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vsnprintf' function. */
|
||||||
|
#undef HAVE_VSNPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vsyslog' function. */
|
||||||
|
#undef HAVE_VSYSLOG
|
||||||
|
|
||||||
|
/* Public define for json_inttypes.h */
|
||||||
|
#undef JSON_C_HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||||
|
*/
|
||||||
|
#undef LT_OBJDIR
|
||||||
|
|
||||||
|
/* Name of package */
|
||||||
|
#undef PACKAGE
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#undef PACKAGE_BUGREPORT
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#undef PACKAGE_NAME
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#undef PACKAGE_STRING
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#undef PACKAGE_TARNAME
|
||||||
|
|
||||||
|
/* Define to the home page for this package. */
|
||||||
|
#undef PACKAGE_URL
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#undef PACKAGE_VERSION
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Version number of package */
|
||||||
|
#undef VERSION
|
||||||
|
|
||||||
|
/* Define to empty if `const' does not conform to ANSI C. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
/* Define to rpl_malloc if the replacement function should be used. */
|
||||||
|
#undef malloc
|
||||||
|
|
||||||
|
/* Define to rpl_realloc if the replacement function should be used. */
|
||||||
|
#undef realloc
|
||||||
|
|
||||||
|
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||||
|
#undef size_t
|
||||||
94
3P/json/config.h.win32
Normal file
94
3P/json/config.h.win32
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* $Id: config.h.win32,v 1.2 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* config.h.win32 Generated by configure. */
|
||||||
|
|
||||||
|
#define PACKAGE_STRING "JSON C Library 0.2"
|
||||||
|
#define PACKAGE_BUGREPORT "json-c@googlegroups.com"
|
||||||
|
#define PACKAGE_NAME "JSON C Library"
|
||||||
|
#define PACKAGE_TARNAME "json-c"
|
||||||
|
#define PACKAGE_VERSION "0.2"
|
||||||
|
|
||||||
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
|
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||||
|
/* #undef HAVE_DOPRNT */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
|
#define HAVE_FCNTL_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#define HAVE_INTTYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <limits.h> header file. */
|
||||||
|
#define HAVE_LIMITS_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||||
|
to 0 otherwise. */
|
||||||
|
#define HAVE_MALLOC 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `open' function. */
|
||||||
|
#undef HAVE_OPEN
|
||||||
|
|
||||||
|
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||||
|
and to 0 otherwise. */
|
||||||
|
#define HAVE_REALLOC 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strdup' function. */
|
||||||
|
#undef HAVE_STRNDUP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||||
|
#define HAVE_STDARG_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strerror' function. */
|
||||||
|
#define HAVE_STRERROR 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#define HAVE_STRING_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <syslog.h> header file. */
|
||||||
|
#undef HAVE_SYSLOG_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||||
|
#undef HAVE_SYS_PARAM_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#define HAVE_SYS_TYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vprintf' function. */
|
||||||
|
#undef HAVE_VPRINTF
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vsyslog' function. */
|
||||||
|
#undef HAVE_VSYSLOG
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strncasecmp' function. */
|
||||||
|
#undef HAVE_STRNCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
69
3P/json/configure.in
Normal file
69
3P/json/configure.in
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
AC_PREREQ(2.52)
|
||||||
|
|
||||||
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
AC_INIT([json-c], 0.11, [json-c@googlegroups.com])
|
||||||
|
|
||||||
|
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
|
||||||
|
|
||||||
|
AC_PROG_MAKE_SET
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(oldname-compat,
|
||||||
|
AS_HELP_STRING([--disable-oldname-compat],
|
||||||
|
[Don't include the old libjson.so library and include/json directory.]),
|
||||||
|
[],
|
||||||
|
[enable_oldname_compat=yes]
|
||||||
|
)
|
||||||
|
AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno"])
|
||||||
|
|
||||||
|
# Checks for programs.
|
||||||
|
|
||||||
|
# Checks for libraries.
|
||||||
|
|
||||||
|
# Checks for header files.
|
||||||
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
AC_CONFIG_HEADER(json_config.h)
|
||||||
|
AC_HEADER_STDC
|
||||||
|
AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h)
|
||||||
|
AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public define for json_inttypes.h])])
|
||||||
|
|
||||||
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
AC_C_CONST
|
||||||
|
AC_TYPE_SIZE_T
|
||||||
|
|
||||||
|
# Checks for library functions.
|
||||||
|
AC_FUNC_VPRINTF
|
||||||
|
AC_FUNC_MEMCMP
|
||||||
|
AC_FUNC_MALLOC
|
||||||
|
AC_FUNC_REALLOC
|
||||||
|
AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
|
||||||
|
|
||||||
|
#check if .section.gnu.warning accepts long strings (for __warn_references)
|
||||||
|
AC_LANG_PUSH([C])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([if .gnu.warning accepts long strings])
|
||||||
|
AC_LINK_IFELSE([[
|
||||||
|
extern void json_object_get();
|
||||||
|
__asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libjson-c instead of libjson\"\n\t.text");
|
||||||
|
|
||||||
|
int main(int c,char* v) {return 0;}
|
||||||
|
]], [
|
||||||
|
AC_DEFINE(HAS_GNU_WARNING_LONG, 1, [Define if .gnu.warning accepts long strings.])
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
], [
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_LANG_POP([C])
|
||||||
|
|
||||||
|
AM_PROG_LIBTOOL
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
json.pc
|
||||||
|
json-c.pc
|
||||||
|
tests/Makefile
|
||||||
|
json-c-uninstalled.pc
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_OUTPUT
|
||||||
|
|
||||||
98
3P/json/debug.c
Normal file
98
3P/json/debug.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if HAVE_SYSLOG_H
|
||||||
|
# include <syslog.h>
|
||||||
|
#endif /* HAVE_SYSLOG_H */
|
||||||
|
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
|
||||||
|
#if HAVE_SYS_PARAM_H
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif /* HAVE_SYS_PARAM_H */
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
static int _syslog = 0;
|
||||||
|
static int _debug = 0;
|
||||||
|
|
||||||
|
void mc_set_debug(int debug) { _debug = debug; }
|
||||||
|
int mc_get_debug(void) { return _debug; }
|
||||||
|
|
||||||
|
extern void mc_set_syslog(int syslog)
|
||||||
|
{
|
||||||
|
_syslog = syslog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_abort(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
#if HAVE_VSYSLOG
|
||||||
|
if(_syslog) {
|
||||||
|
vsyslog(LOG_ERR, msg, ap);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
vprintf(msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mc_debug(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
if(_debug) {
|
||||||
|
va_start(ap, msg);
|
||||||
|
#if HAVE_VSYSLOG
|
||||||
|
if(_syslog) {
|
||||||
|
vsyslog(LOG_DEBUG, msg, ap);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
vprintf(msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_error(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
#if HAVE_VSYSLOG
|
||||||
|
if(_syslog) {
|
||||||
|
vsyslog(LOG_ERR, msg, ap);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
vfprintf(stderr, msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mc_info(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
#if HAVE_VSYSLOG
|
||||||
|
if(_syslog) {
|
||||||
|
vsyslog(LOG_INFO, msg, ap);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
vfprintf(stderr, msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
72
3P/json/debug.h
Normal file
72
3P/json/debug.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DEBUG_H_
|
||||||
|
#define _DEBUG_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void mc_set_debug(int debug);
|
||||||
|
extern int mc_get_debug(void);
|
||||||
|
|
||||||
|
extern void mc_set_syslog(int syslog);
|
||||||
|
extern void mc_abort(const char *msg, ...);
|
||||||
|
extern void mc_debug(const char *msg, ...);
|
||||||
|
extern void mc_error(const char *msg, ...);
|
||||||
|
extern void mc_info(const char *msg, ...);
|
||||||
|
|
||||||
|
#ifndef __STRING
|
||||||
|
#define __STRING(x) #x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PARSER_BROKEN_FIXED
|
||||||
|
|
||||||
|
#define JASSERT(cond) do {} while(0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define JASSERT(cond) do { \
|
||||||
|
if (!(cond)) { \
|
||||||
|
mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \
|
||||||
|
*(int *)0 = 1;\
|
||||||
|
abort(); \
|
||||||
|
}\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__)
|
||||||
|
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef MC_MAINTAINER_MODE
|
||||||
|
#define MC_SET_DEBUG(x) mc_set_debug(x)
|
||||||
|
#define MC_GET_DEBUG() mc_get_debug()
|
||||||
|
#define MC_SET_SYSLOG(x) mc_set_syslog(x)
|
||||||
|
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
|
||||||
|
#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
|
||||||
|
#define MC_GET_DEBUG() (0)
|
||||||
|
#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
|
||||||
|
#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
|
||||||
|
#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
11
3P/json/json-c-uninstalled.pc.in
Normal file
11
3P/json/json-c-uninstalled.pc.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
prefix=
|
||||||
|
exec_prefix=
|
||||||
|
libdir=@abs_top_builddir@
|
||||||
|
includedir=@abs_top_srcdir@
|
||||||
|
|
||||||
|
Name: json
|
||||||
|
Description: JSON implementation in C
|
||||||
|
Version: @VERSION@
|
||||||
|
Requires:
|
||||||
|
Libs: -L@abs_top_builddir@ -ljson-c
|
||||||
|
Cflags: -I@abs_top_srcdir@
|
||||||
11
3P/json/json-c.pc.in
Normal file
11
3P/json/json-c.pc.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: json-c
|
||||||
|
Description: JSON implementation in C
|
||||||
|
Version: @VERSION@
|
||||||
|
Requires:
|
||||||
|
Libs: -L${libdir} -ljson-c
|
||||||
|
Cflags: -I${includedir}/json-c
|
||||||
179
3P/json/json-c.vcproj
Normal file
179
3P/json/json-c.vcproj
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="7.10"
|
||||||
|
Name="json-c"
|
||||||
|
ProjectGUID="{04D8CDBE-FB3E-4362-87E6-07DC3C0083B2}"
|
||||||
|
Keyword="Win32Proj">
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"/>
|
||||||
|
</Platforms>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="Debug"
|
||||||
|
IntermediateDirectory="Debug"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||||
|
MinimalRebuild="TRUE"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="5"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
|
DebugInformationFormat="4"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
OutputFile="$(OutDir)/jsonD.lib"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
CommandLine="copy config.h.win32 config.h"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="Release"
|
||||||
|
IntermediateDirectory="Release"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||||
|
RuntimeLibrary="4"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
|
DebugInformationFormat="3"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
OutputFile="$(OutDir)/json.lib"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="Source Files"
|
||||||
|
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||||
|
<File
|
||||||
|
RelativePath=".\arraylist.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\debug.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_object.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_tokener.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_util.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\linkhash.c">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\printbuf.c">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Header Files"
|
||||||
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||||
|
<File
|
||||||
|
RelativePath=".\arraylist.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\bits.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\debug.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_object.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_object_private.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_tokener.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\json_util.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\linkhash.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\printbuf.h">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Resource Files"
|
||||||
|
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||||
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Documentation"
|
||||||
|
Filter="">
|
||||||
|
<File
|
||||||
|
RelativePath=".\Doxyfile">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<File
|
||||||
|
RelativePath=".\config.h.win32">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\README-WIN32.html">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\README.html">
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
||||||
34
3P/json/json.h
Normal file
34
3P/json/json.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_h_
|
||||||
|
#define _json_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "linkhash.h"
|
||||||
|
#include "arraylist.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
#include "json_object_iterator.h"
|
||||||
|
#include "json_c_version.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
11
3P/json/json.pc.in
Normal file
11
3P/json/json.pc.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: json-c
|
||||||
|
Description: JSON implementation in C, compat shim. Use json-c instead.
|
||||||
|
Version: @VERSION@
|
||||||
|
Requires: json-c
|
||||||
|
Libs:
|
||||||
|
Cflags:
|
||||||
20
3P/json/json_c_version.c
Normal file
20
3P/json/json_c_version.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Eric Haszlakiewicz
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "json_c_version.h"
|
||||||
|
|
||||||
|
const char *json_c_version(void)
|
||||||
|
{
|
||||||
|
return JSON_C_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_c_version_num(void)
|
||||||
|
{
|
||||||
|
return JSON_C_VERSION_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
22
3P/json/json_c_version.h
Normal file
22
3P/json/json_c_version.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Eric Haszlakiewicz
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_c_version_h_
|
||||||
|
#define _json_c_version_h_
|
||||||
|
|
||||||
|
#define JSON_C_MAJOR_VERSION 0
|
||||||
|
#define JSON_C_MINOR_VERSION 11
|
||||||
|
#define JSON_C_MICRO_VERSION 0
|
||||||
|
#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \
|
||||||
|
(JSON_C_MINOR_VERSION << 8) | \
|
||||||
|
JSON_C_MICRO_VERSION)
|
||||||
|
#define JSON_C_VERSION "0.11"
|
||||||
|
|
||||||
|
const char *json_c_version(void); /* Returns JSON_C_VERSION */
|
||||||
|
int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */
|
||||||
|
|
||||||
|
#endif
|
||||||
3
3P/json/json_config.h.in
Normal file
3
3P/json/json_config.h.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#undef JSON_C_HAVE_INTTYPES_H
|
||||||
28
3P/json/json_inttypes.h
Normal file
28
3P/json/json_inttypes.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#ifndef _json_inttypes_h_
|
||||||
|
#define _json_inttypes_h_
|
||||||
|
|
||||||
|
#include "json_config.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||||
|
|
||||||
|
/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */
|
||||||
|
typedef __int32 int32_t;
|
||||||
|
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||||
|
#define INT32_MAX ((int32_t)_I32_MAX)
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||||
|
#define INT64_MAX ((int64_t)_I64_MAX)
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define SCNd64 "I64d"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef JSON_C_HAVE_INTTYPES_H
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
/* inttypes.h includes stdint.h */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
782
3P/json/json_object.c
Normal file
782
3P/json/json_object.c
Normal file
@@ -0,0 +1,782 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
#include "linkhash.h"
|
||||||
|
#include "arraylist.h"
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_object_private.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
#if !defined(HAVE_STRDUP) && defined(_MSC_VER)
|
||||||
|
/* MSC has the version as _strdup */
|
||||||
|
# define strdup _strdup
|
||||||
|
#elif !defined(HAVE_STRDUP)
|
||||||
|
# error You do not have strdup on your system.
|
||||||
|
#endif /* HAVE_STRDUP */
|
||||||
|
|
||||||
|
#if !defined(HAVE_STRNDUP)
|
||||||
|
char* strndup(const char* str, size_t n);
|
||||||
|
#endif /* !HAVE_STRNDUP */
|
||||||
|
|
||||||
|
// Don't define this. It's not thread-safe.
|
||||||
|
/* #define REFCOUNT_DEBUG 1 */
|
||||||
|
|
||||||
|
const char *json_number_chars = "0123456789.+-eE";
|
||||||
|
const char *json_hex_chars = "0123456789abcdefABCDEF";
|
||||||
|
|
||||||
|
static void json_object_generic_delete(struct json_object* jso);
|
||||||
|
static struct json_object* json_object_new(enum json_type o_type);
|
||||||
|
|
||||||
|
static json_object_to_json_string_fn json_object_object_to_json_string;
|
||||||
|
static json_object_to_json_string_fn json_object_boolean_to_json_string;
|
||||||
|
static json_object_to_json_string_fn json_object_int_to_json_string;
|
||||||
|
static json_object_to_json_string_fn json_object_double_to_json_string;
|
||||||
|
static json_object_to_json_string_fn json_object_string_to_json_string;
|
||||||
|
static json_object_to_json_string_fn json_object_array_to_json_string;
|
||||||
|
|
||||||
|
|
||||||
|
/* ref count debugging */
|
||||||
|
|
||||||
|
#ifdef REFCOUNT_DEBUG
|
||||||
|
|
||||||
|
static struct lh_table *json_object_table;
|
||||||
|
|
||||||
|
static void json_object_init(void) __attribute__ ((constructor));
|
||||||
|
static void json_object_init(void) {
|
||||||
|
MC_DEBUG("json_object_init: creating object table\n");
|
||||||
|
json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_object_fini(void) __attribute__ ((destructor));
|
||||||
|
static void json_object_fini(void) {
|
||||||
|
struct lh_entry *ent;
|
||||||
|
if(MC_GET_DEBUG()) {
|
||||||
|
if (json_object_table->count) {
|
||||||
|
MC_DEBUG("json_object_fini: %d referenced objects at exit\n",
|
||||||
|
json_object_table->count);
|
||||||
|
lh_foreach(json_object_table, ent) {
|
||||||
|
struct json_object* obj = (struct json_object*)ent->v;
|
||||||
|
MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MC_DEBUG("json_object_fini: freeing object table\n");
|
||||||
|
lh_table_free(json_object_table);
|
||||||
|
}
|
||||||
|
#endif /* REFCOUNT_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
|
/* string escaping */
|
||||||
|
|
||||||
|
static int json_escape_str(struct printbuf *pb, char *str, int len)
|
||||||
|
{
|
||||||
|
int pos = 0, start_offset = 0;
|
||||||
|
unsigned char c;
|
||||||
|
while (len--) {
|
||||||
|
c = str[pos];
|
||||||
|
switch(c) {
|
||||||
|
case '\b':
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
case '\f':
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
if(pos - start_offset > 0)
|
||||||
|
printbuf_memappend(pb, str + start_offset, pos - start_offset);
|
||||||
|
if(c == '\b') printbuf_memappend(pb, "\\b", 2);
|
||||||
|
else if(c == '\n') printbuf_memappend(pb, "\\n", 2);
|
||||||
|
else if(c == '\r') printbuf_memappend(pb, "\\r", 2);
|
||||||
|
else if(c == '\t') printbuf_memappend(pb, "\\t", 2);
|
||||||
|
else if(c == '\f') printbuf_memappend(pb, "\\f", 2);
|
||||||
|
else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
|
||||||
|
else if(c == '\\') printbuf_memappend(pb, "\\\\", 2);
|
||||||
|
else if(c == '/') printbuf_memappend(pb, "\\/", 2);
|
||||||
|
start_offset = ++pos;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(c < ' ') {
|
||||||
|
if(pos - start_offset > 0)
|
||||||
|
printbuf_memappend(pb, str + start_offset, pos - start_offset);
|
||||||
|
sprintbuf(pb, "\\u00%c%c",
|
||||||
|
json_hex_chars[c >> 4],
|
||||||
|
json_hex_chars[c & 0xf]);
|
||||||
|
start_offset = ++pos;
|
||||||
|
} else pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pos - start_offset > 0)
|
||||||
|
printbuf_memappend(pb, str + start_offset, pos - start_offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* reference counting */
|
||||||
|
|
||||||
|
extern struct json_object* json_object_get(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(jso) {
|
||||||
|
jso->_ref_count++;
|
||||||
|
}
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_put(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(jso)
|
||||||
|
{
|
||||||
|
jso->_ref_count--;
|
||||||
|
if(!jso->_ref_count)
|
||||||
|
{
|
||||||
|
if (jso->_user_delete)
|
||||||
|
jso->_user_delete(jso, jso->_userdata);
|
||||||
|
jso->_delete(jso);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* generic object construction and destruction parts */
|
||||||
|
|
||||||
|
static void json_object_generic_delete(struct json_object* jso)
|
||||||
|
{
|
||||||
|
#ifdef REFCOUNT_DEBUG
|
||||||
|
MC_DEBUG("json_object_delete_%s: %p\n",
|
||||||
|
json_type_to_name(jso->o_type), jso);
|
||||||
|
lh_table_delete(json_object_table, jso);
|
||||||
|
#endif /* REFCOUNT_DEBUG */
|
||||||
|
printbuf_free(jso->_pb);
|
||||||
|
free(jso);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct json_object* json_object_new(enum json_type o_type)
|
||||||
|
{
|
||||||
|
struct json_object *jso;
|
||||||
|
|
||||||
|
jso = (struct json_object*)calloc(sizeof(struct json_object), 1);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->o_type = o_type;
|
||||||
|
jso->_ref_count = 1;
|
||||||
|
jso->_delete = &json_object_generic_delete;
|
||||||
|
#ifdef REFCOUNT_DEBUG
|
||||||
|
lh_table_insert(json_object_table, jso, jso);
|
||||||
|
MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso);
|
||||||
|
#endif /* REFCOUNT_DEBUG */
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* type checking functions */
|
||||||
|
|
||||||
|
int json_object_is_type(struct json_object *jso, enum json_type type)
|
||||||
|
{
|
||||||
|
if (!jso)
|
||||||
|
return (type == json_type_null);
|
||||||
|
return (jso->o_type == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum json_type json_object_get_type(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if (!jso)
|
||||||
|
return json_type_null;
|
||||||
|
return jso->o_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set a custom conversion to string */
|
||||||
|
|
||||||
|
void json_object_set_serializer(json_object *jso,
|
||||||
|
json_object_to_json_string_fn to_string_func,
|
||||||
|
void *userdata,
|
||||||
|
json_object_delete_fn *user_delete)
|
||||||
|
{
|
||||||
|
// First, clean up any previously existing user info
|
||||||
|
if (jso->_user_delete)
|
||||||
|
{
|
||||||
|
jso->_user_delete(jso, jso->_userdata);
|
||||||
|
}
|
||||||
|
jso->_userdata = NULL;
|
||||||
|
jso->_user_delete = NULL;
|
||||||
|
|
||||||
|
if (to_string_func == NULL)
|
||||||
|
{
|
||||||
|
// Reset to the standard serialization function
|
||||||
|
switch(jso->o_type)
|
||||||
|
{
|
||||||
|
case json_type_null:
|
||||||
|
jso->_to_json_string = NULL;
|
||||||
|
break;
|
||||||
|
case json_type_boolean:
|
||||||
|
jso->_to_json_string = &json_object_boolean_to_json_string;
|
||||||
|
break;
|
||||||
|
case json_type_double:
|
||||||
|
jso->_to_json_string = &json_object_double_to_json_string;
|
||||||
|
break;
|
||||||
|
case json_type_int:
|
||||||
|
jso->_to_json_string = &json_object_int_to_json_string;
|
||||||
|
break;
|
||||||
|
case json_type_object:
|
||||||
|
jso->_to_json_string = &json_object_object_to_json_string;
|
||||||
|
break;
|
||||||
|
case json_type_array:
|
||||||
|
jso->_to_json_string = &json_object_array_to_json_string;
|
||||||
|
break;
|
||||||
|
case json_type_string:
|
||||||
|
jso->_to_json_string = &json_object_string_to_json_string;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jso->_to_json_string = to_string_func;
|
||||||
|
jso->_userdata = userdata;
|
||||||
|
jso->_user_delete = user_delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* extended conversion to string */
|
||||||
|
|
||||||
|
const char* json_object_to_json_string_ext(struct json_object *jso, int flags)
|
||||||
|
{
|
||||||
|
if (!jso)
|
||||||
|
return "null";
|
||||||
|
|
||||||
|
if ((!jso->_pb) && !(jso->_pb = printbuf_new()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
printbuf_reset(jso->_pb);
|
||||||
|
|
||||||
|
if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return jso->_pb->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* backwards-compatible conversion to string */
|
||||||
|
|
||||||
|
const char* json_object_to_json_string(struct json_object *jso)
|
||||||
|
{
|
||||||
|
return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indent(struct printbuf *pb, int level, int flags)
|
||||||
|
{
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
{
|
||||||
|
printbuf_memset(pb, -1, ' ', level * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* json_object_object */
|
||||||
|
|
||||||
|
static int json_object_object_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
int had_children = 0;
|
||||||
|
struct json_object_iter iter;
|
||||||
|
|
||||||
|
sprintbuf(pb, "{" /*}*/);
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
json_object_object_foreachC(jso, iter)
|
||||||
|
{
|
||||||
|
if (had_children)
|
||||||
|
{
|
||||||
|
sprintbuf(pb, ",");
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
}
|
||||||
|
had_children = 1;
|
||||||
|
if (flags & JSON_C_TO_STRING_SPACED)
|
||||||
|
sprintbuf(pb, " ");
|
||||||
|
indent(pb, level+1, flags);
|
||||||
|
sprintbuf(pb, "\"");
|
||||||
|
json_escape_str(pb, iter.key, strlen(iter.key));
|
||||||
|
if (flags & JSON_C_TO_STRING_SPACED)
|
||||||
|
sprintbuf(pb, "\": ");
|
||||||
|
else
|
||||||
|
sprintbuf(pb, "\":");
|
||||||
|
if(iter.val == NULL)
|
||||||
|
sprintbuf(pb, "null");
|
||||||
|
else
|
||||||
|
iter.val->_to_json_string(iter.val, pb, level+1,flags);
|
||||||
|
}
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
{
|
||||||
|
if (had_children)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
indent(pb,level,flags);
|
||||||
|
}
|
||||||
|
if (flags & JSON_C_TO_STRING_SPACED)
|
||||||
|
return sprintbuf(pb, /*{*/ " }");
|
||||||
|
else
|
||||||
|
return sprintbuf(pb, /*{*/ "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void json_object_lh_entry_free(struct lh_entry *ent)
|
||||||
|
{
|
||||||
|
free(ent->k);
|
||||||
|
json_object_put((struct json_object*)ent->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_object_object_delete(struct json_object* jso)
|
||||||
|
{
|
||||||
|
lh_table_free(jso->o.c_object);
|
||||||
|
json_object_generic_delete(jso);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_object(void)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_object);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_delete = &json_object_object_delete;
|
||||||
|
jso->_to_json_string = &json_object_object_to_json_string;
|
||||||
|
jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES,
|
||||||
|
NULL, &json_object_lh_entry_free);
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lh_table* json_object_get_object(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(!jso) return NULL;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_object:
|
||||||
|
return jso->o.c_object;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_object_object_add(struct json_object* jso, const char *key,
|
||||||
|
struct json_object *val)
|
||||||
|
{
|
||||||
|
// We lookup the entry and replace the value, rather than just deleting
|
||||||
|
// and re-adding it, so the existing key remains valid.
|
||||||
|
json_object *existing_value = NULL;
|
||||||
|
struct lh_entry *existing_entry;
|
||||||
|
existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key);
|
||||||
|
if (!existing_entry)
|
||||||
|
{
|
||||||
|
lh_table_insert(jso->o.c_object, strdup(key), val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
existing_value = (void *)existing_entry->v;
|
||||||
|
if (existing_value)
|
||||||
|
json_object_put(existing_value);
|
||||||
|
existing_entry->v = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_object_length(struct json_object *jso)
|
||||||
|
{
|
||||||
|
return lh_table_length(jso->o.c_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_object_get(struct json_object* jso, const char *key)
|
||||||
|
{
|
||||||
|
struct json_object *result = NULL;
|
||||||
|
json_object_object_get_ex(jso, key, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value)
|
||||||
|
{
|
||||||
|
if (value != NULL)
|
||||||
|
*value = NULL;
|
||||||
|
|
||||||
|
if (NULL == jso)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch(jso->o_type)
|
||||||
|
{
|
||||||
|
case json_type_object:
|
||||||
|
return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value);
|
||||||
|
default:
|
||||||
|
if (value != NULL)
|
||||||
|
*value = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_object_object_del(struct json_object* jso, const char *key)
|
||||||
|
{
|
||||||
|
lh_table_delete(jso->o.c_object, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* json_object_boolean */
|
||||||
|
|
||||||
|
static int json_object_boolean_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if(jso->o.c_boolean) return sprintbuf(pb, "true");
|
||||||
|
else return sprintbuf(pb, "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_boolean(json_bool b)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_boolean);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_to_json_string = &json_object_boolean_to_json_string;
|
||||||
|
jso->o.c_boolean = b;
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_bool json_object_get_boolean(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(!jso) return FALSE;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_boolean:
|
||||||
|
return jso->o.c_boolean;
|
||||||
|
case json_type_int:
|
||||||
|
return (jso->o.c_int64 != 0);
|
||||||
|
case json_type_double:
|
||||||
|
return (jso->o.c_double != 0);
|
||||||
|
case json_type_string:
|
||||||
|
return (jso->o.c_string.len != 0);
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* json_object_int */
|
||||||
|
|
||||||
|
static int json_object_int_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
return sprintbuf(pb, "%"PRId64, jso->o.c_int64);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_int(int32_t i)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_int);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_to_json_string = &json_object_int_to_json_string;
|
||||||
|
jso->o.c_int64 = i;
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t json_object_get_int(struct json_object *jso)
|
||||||
|
{
|
||||||
|
int64_t cint64;
|
||||||
|
enum json_type o_type;
|
||||||
|
|
||||||
|
if(!jso) return 0;
|
||||||
|
|
||||||
|
o_type = jso->o_type;
|
||||||
|
cint64 = jso->o.c_int64;
|
||||||
|
|
||||||
|
if (o_type == json_type_string)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Parse strings into 64-bit numbers, then use the
|
||||||
|
* 64-to-32-bit number handling below.
|
||||||
|
*/
|
||||||
|
if (json_parse_int64(jso->o.c_string.str, &cint64) != 0)
|
||||||
|
return 0; /* whoops, it didn't work. */
|
||||||
|
o_type = json_type_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(o_type) {
|
||||||
|
case json_type_int:
|
||||||
|
/* Make sure we return the correct values for out of range numbers. */
|
||||||
|
if (cint64 <= INT32_MIN)
|
||||||
|
return INT32_MIN;
|
||||||
|
else if (cint64 >= INT32_MAX)
|
||||||
|
return INT32_MAX;
|
||||||
|
else
|
||||||
|
return (int32_t)cint64;
|
||||||
|
case json_type_double:
|
||||||
|
return (int32_t)jso->o.c_double;
|
||||||
|
case json_type_boolean:
|
||||||
|
return jso->o.c_boolean;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_int64(int64_t i)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_int);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_to_json_string = &json_object_int_to_json_string;
|
||||||
|
jso->o.c_int64 = i;
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t json_object_get_int64(struct json_object *jso)
|
||||||
|
{
|
||||||
|
int64_t cint;
|
||||||
|
|
||||||
|
if(!jso) return 0;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_int:
|
||||||
|
return jso->o.c_int64;
|
||||||
|
case json_type_double:
|
||||||
|
return (int64_t)jso->o.c_double;
|
||||||
|
case json_type_boolean:
|
||||||
|
return jso->o.c_boolean;
|
||||||
|
case json_type_string:
|
||||||
|
if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* json_object_double */
|
||||||
|
|
||||||
|
static int json_object_double_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
char buf[128], *p, *q;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = snprintf(buf, 128, "%f", jso->o.c_double);
|
||||||
|
p = strchr(buf, ',');
|
||||||
|
if (p) {
|
||||||
|
*p = '.';
|
||||||
|
} else {
|
||||||
|
p = strchr(buf, '.');
|
||||||
|
}
|
||||||
|
if (p && (flags & JSON_C_TO_STRING_NOZERO)) {
|
||||||
|
/* last useful digit, always keep 1 zero */
|
||||||
|
p++;
|
||||||
|
for (q=p ; *q ; q++) {
|
||||||
|
if (*q!='0') p=q;
|
||||||
|
}
|
||||||
|
/* drop trailing zeroes */
|
||||||
|
*(++p) = 0;
|
||||||
|
size = p-buf;
|
||||||
|
}
|
||||||
|
printbuf_memappend(pb, buf, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_double(double d)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_double);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_to_json_string = &json_object_double_to_json_string;
|
||||||
|
jso->o.c_double = d;
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
double json_object_get_double(struct json_object *jso)
|
||||||
|
{
|
||||||
|
double cdouble;
|
||||||
|
|
||||||
|
if(!jso) return 0.0;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_double:
|
||||||
|
return jso->o.c_double;
|
||||||
|
case json_type_int:
|
||||||
|
return jso->o.c_int64;
|
||||||
|
case json_type_boolean:
|
||||||
|
return jso->o.c_boolean;
|
||||||
|
case json_type_string:
|
||||||
|
if(sscanf(jso->o.c_string.str, "%lf", &cdouble) == 1) return cdouble;
|
||||||
|
default:
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* json_object_string */
|
||||||
|
|
||||||
|
static int json_object_string_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
sprintbuf(pb, "\"");
|
||||||
|
json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len);
|
||||||
|
sprintbuf(pb, "\"");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_object_string_delete(struct json_object* jso)
|
||||||
|
{
|
||||||
|
free(jso->o.c_string.str);
|
||||||
|
json_object_generic_delete(jso);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_string(const char *s)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_string);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_delete = &json_object_string_delete;
|
||||||
|
jso->_to_json_string = &json_object_string_to_json_string;
|
||||||
|
jso->o.c_string.str = strdup(s);
|
||||||
|
jso->o.c_string.len = strlen(s);
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_string_len(const char *s, int len)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_string);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_delete = &json_object_string_delete;
|
||||||
|
jso->_to_json_string = &json_object_string_to_json_string;
|
||||||
|
jso->o.c_string.str = (char*)malloc(len + 1);
|
||||||
|
memcpy(jso->o.c_string.str, (void *)s, len);
|
||||||
|
jso->o.c_string.str[len] = '\0';
|
||||||
|
jso->o.c_string.len = len;
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* json_object_get_string(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(!jso) return NULL;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_string:
|
||||||
|
return jso->o.c_string.str;
|
||||||
|
default:
|
||||||
|
return json_object_to_json_string(jso);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_get_string_len(struct json_object *jso) {
|
||||||
|
if(!jso) return 0;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_string:
|
||||||
|
return jso->o.c_string.len;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* json_object_array */
|
||||||
|
|
||||||
|
static int json_object_array_to_json_string(struct json_object* jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
int had_children = 0;
|
||||||
|
int ii;
|
||||||
|
sprintbuf(pb, "[");
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
for(ii=0; ii < json_object_array_length(jso); ii++)
|
||||||
|
{
|
||||||
|
struct json_object *val;
|
||||||
|
if (had_children)
|
||||||
|
{
|
||||||
|
sprintbuf(pb, ",");
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
}
|
||||||
|
had_children = 1;
|
||||||
|
if (flags & JSON_C_TO_STRING_SPACED)
|
||||||
|
sprintbuf(pb, " ");
|
||||||
|
indent(pb, level + 1, flags);
|
||||||
|
val = json_object_array_get_idx(jso, ii);
|
||||||
|
if(val == NULL)
|
||||||
|
sprintbuf(pb, "null");
|
||||||
|
else
|
||||||
|
val->_to_json_string(val, pb, level+1, flags);
|
||||||
|
}
|
||||||
|
if (flags & JSON_C_TO_STRING_PRETTY)
|
||||||
|
{
|
||||||
|
if (had_children)
|
||||||
|
sprintbuf(pb, "\n");
|
||||||
|
indent(pb,level,flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & JSON_C_TO_STRING_SPACED)
|
||||||
|
return sprintbuf(pb, " ]");
|
||||||
|
else
|
||||||
|
return sprintbuf(pb, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_object_array_entry_free(void *data)
|
||||||
|
{
|
||||||
|
json_object_put((struct json_object*)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_object_array_delete(struct json_object* jso)
|
||||||
|
{
|
||||||
|
array_list_free(jso->o.c_array);
|
||||||
|
json_object_generic_delete(jso);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_new_array(void)
|
||||||
|
{
|
||||||
|
struct json_object *jso = json_object_new(json_type_array);
|
||||||
|
if(!jso) return NULL;
|
||||||
|
jso->_delete = &json_object_array_delete;
|
||||||
|
jso->_to_json_string = &json_object_array_to_json_string;
|
||||||
|
jso->o.c_array = array_list_new(&json_object_array_entry_free);
|
||||||
|
return jso;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct array_list* json_object_get_array(struct json_object *jso)
|
||||||
|
{
|
||||||
|
if(!jso) return NULL;
|
||||||
|
switch(jso->o_type) {
|
||||||
|
case json_type_array:
|
||||||
|
return jso->o.c_array;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *))
|
||||||
|
{
|
||||||
|
array_list_sort(jso->o.c_array, sort_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_array_length(struct json_object *jso)
|
||||||
|
{
|
||||||
|
return array_list_length(jso->o.c_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_array_add(struct json_object *jso,struct json_object *val)
|
||||||
|
{
|
||||||
|
return array_list_add(jso->o.c_array, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_array_put_idx(struct json_object *jso, int idx,
|
||||||
|
struct json_object *val)
|
||||||
|
{
|
||||||
|
return array_list_put_idx(jso->o.c_array, idx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_object_array_get_idx(struct json_object *jso,
|
||||||
|
int idx)
|
||||||
|
{
|
||||||
|
return (struct json_object*)array_list_get_idx(jso->o.c_array, idx);
|
||||||
|
}
|
||||||
|
|
||||||
562
3P/json/json_object.h
Normal file
562
3P/json/json_object.h
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_object_h_
|
||||||
|
#define _json_object_h_
|
||||||
|
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSON_OBJECT_DEF_HASH_ENTRIES 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag for the json_object_to_json_string_ext() and
|
||||||
|
* json_object_to_file_ext() functions which causes the output
|
||||||
|
* to have no extra whitespace or formatting applied.
|
||||||
|
*/
|
||||||
|
#define JSON_C_TO_STRING_PLAIN 0
|
||||||
|
/**
|
||||||
|
* A flag for the json_object_to_json_string_ext() and
|
||||||
|
* json_object_to_file_ext() functions which causes the output to have
|
||||||
|
* minimal whitespace inserted to make things slightly more readable.
|
||||||
|
*/
|
||||||
|
#define JSON_C_TO_STRING_SPACED (1<<0)
|
||||||
|
/**
|
||||||
|
* A flag for the json_object_to_json_string_ext() and
|
||||||
|
* json_object_to_file_ext() functions which causes
|
||||||
|
* the output to be formatted.
|
||||||
|
*
|
||||||
|
* See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/
|
||||||
|
* for an example of the format.
|
||||||
|
*/
|
||||||
|
#define JSON_C_TO_STRING_PRETTY (1<<1)
|
||||||
|
/**
|
||||||
|
* A flag to drop trailing zero for float values
|
||||||
|
*/
|
||||||
|
#define JSON_C_TO_STRING_NOZERO (1<<2)
|
||||||
|
|
||||||
|
#undef FALSE
|
||||||
|
#define FALSE ((json_bool)0)
|
||||||
|
|
||||||
|
#undef TRUE
|
||||||
|
#define TRUE ((json_bool)1)
|
||||||
|
|
||||||
|
extern const char *json_number_chars;
|
||||||
|
extern const char *json_hex_chars;
|
||||||
|
|
||||||
|
/* CAW: added for ANSI C iteration correctness */
|
||||||
|
struct json_object_iter
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
struct json_object *val;
|
||||||
|
struct lh_entry *entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* forward structure definitions */
|
||||||
|
|
||||||
|
typedef int json_bool;
|
||||||
|
typedef struct printbuf printbuf;
|
||||||
|
typedef struct lh_table lh_table;
|
||||||
|
typedef struct array_list array_list;
|
||||||
|
typedef struct json_object json_object;
|
||||||
|
typedef struct json_object_iter json_object_iter;
|
||||||
|
typedef struct json_tokener json_tokener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of custom user delete functions. See json_object_set_serializer.
|
||||||
|
*/
|
||||||
|
typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of a custom serialization function. See json_object_set_serializer.
|
||||||
|
*/
|
||||||
|
typedef int (json_object_to_json_string_fn)(struct json_object *jso,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags);
|
||||||
|
|
||||||
|
/* supported object types */
|
||||||
|
|
||||||
|
typedef enum json_type {
|
||||||
|
/* If you change this, be sure to update json_type_to_name() too */
|
||||||
|
json_type_null,
|
||||||
|
json_type_boolean,
|
||||||
|
json_type_double,
|
||||||
|
json_type_int,
|
||||||
|
json_type_object,
|
||||||
|
json_type_array,
|
||||||
|
json_type_string,
|
||||||
|
} json_type;
|
||||||
|
|
||||||
|
/* reference counting functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the reference count of json_object, thereby grabbing shared
|
||||||
|
* ownership of obj.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_get(struct json_object *obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement the reference count of json_object and free if it reaches zero.
|
||||||
|
* You must have ownership of obj prior to doing this or you will cause an
|
||||||
|
* imbalance in the reference count.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns 1 if the object was freed.
|
||||||
|
*/
|
||||||
|
int json_object_put(struct json_object *obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the json_object is of a given type
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param type one of:
|
||||||
|
json_type_null (i.e. obj == NULL),
|
||||||
|
json_type_boolean,
|
||||||
|
json_type_double,
|
||||||
|
json_type_int,
|
||||||
|
json_type_object,
|
||||||
|
json_type_array,
|
||||||
|
json_type_string,
|
||||||
|
*/
|
||||||
|
extern int json_object_is_type(struct json_object *obj, enum json_type type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of the json_object. See also json_type_to_name() to turn this
|
||||||
|
* into a string suitable, for instance, for logging.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns type being one of:
|
||||||
|
json_type_null (i.e. obj == NULL),
|
||||||
|
json_type_boolean,
|
||||||
|
json_type_double,
|
||||||
|
json_type_int,
|
||||||
|
json_type_object,
|
||||||
|
json_type_array,
|
||||||
|
json_type_string,
|
||||||
|
*/
|
||||||
|
extern enum json_type json_object_get_type(struct json_object *obj);
|
||||||
|
|
||||||
|
|
||||||
|
/** Stringify object to json format.
|
||||||
|
* Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED)
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns a string in JSON format
|
||||||
|
*/
|
||||||
|
extern const char* json_object_to_json_string(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Stringify object to json format
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants
|
||||||
|
* @returns a string in JSON format
|
||||||
|
*/
|
||||||
|
extern const char* json_object_to_json_string_ext(struct json_object *obj, int
|
||||||
|
flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a custom serialization function to be used when this particular object
|
||||||
|
* is converted to a string by json_object_to_json_string.
|
||||||
|
*
|
||||||
|
* If a custom serializer is already set on this object, any existing
|
||||||
|
* user_delete function is called before the new one is set.
|
||||||
|
*
|
||||||
|
* If to_string_func is NULL, the other parameters are ignored
|
||||||
|
* and the default behaviour is reset.
|
||||||
|
*
|
||||||
|
* The userdata parameter is optional and may be passed as NULL. If provided,
|
||||||
|
* it is passed to to_string_func as-is. This parameter may be NULL even
|
||||||
|
* if user_delete is non-NULL.
|
||||||
|
*
|
||||||
|
* The user_delete parameter is optional and may be passed as NULL, even if
|
||||||
|
* the userdata parameter is non-NULL. It will be called just before the
|
||||||
|
* json_object is deleted, after it's reference count goes to zero
|
||||||
|
* (see json_object_put()).
|
||||||
|
* If this is not provided, it is up to the caller to free the userdata at
|
||||||
|
* an appropriate time. (i.e. after the json_object is deleted)
|
||||||
|
*
|
||||||
|
* @param jso the object to customize
|
||||||
|
* @param to_string_func the custom serialization function
|
||||||
|
* @param userdata an optional opaque cookie
|
||||||
|
* @param user_delete an optional function from freeing userdata
|
||||||
|
*/
|
||||||
|
void json_object_set_serializer(json_object *jso,
|
||||||
|
json_object_to_json_string_fn to_string_func,
|
||||||
|
void *userdata,
|
||||||
|
json_object_delete_fn *user_delete);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* object type methods */
|
||||||
|
|
||||||
|
/** Create a new empty object with a reference count of 1. The caller of
|
||||||
|
* this object initially has sole ownership. Remember, when using
|
||||||
|
* json_object_object_add or json_object_array_put_idx, ownership will
|
||||||
|
* transfer to the object/array. Call json_object_get if you want to maintain
|
||||||
|
* shared ownership or also add this object as a child of multiple objects or
|
||||||
|
* arrays. Any ownerships you acquired but did not transfer must be released
|
||||||
|
* through json_object_put.
|
||||||
|
*
|
||||||
|
* @returns a json_object of type json_type_object
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_object(void);
|
||||||
|
|
||||||
|
/** Get the hashtable of a json_object of type json_type_object
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns a linkhash
|
||||||
|
*/
|
||||||
|
extern struct lh_table* json_object_get_object(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Get the size of an object in terms of the number of fields it has.
|
||||||
|
* @param obj the json_object whose length to return
|
||||||
|
*/
|
||||||
|
extern int json_object_object_length(struct json_object* obj);
|
||||||
|
|
||||||
|
/** Add an object field to a json_object of type json_type_object
|
||||||
|
*
|
||||||
|
* The reference count will *not* be incremented. This is to make adding
|
||||||
|
* fields to objects in code more compact. If you want to retain a reference
|
||||||
|
* to an added object, independent of the lifetime of obj, you must wrap the
|
||||||
|
* passed object with json_object_get.
|
||||||
|
*
|
||||||
|
* Upon calling this, the ownership of val transfers to obj. Thus you must
|
||||||
|
* make sure that you do in fact have ownership over this object. For instance,
|
||||||
|
* json_object_new_object will give you ownership until you transfer it,
|
||||||
|
* whereas json_object_object_get does not.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param key the object field name (a private copy will be duplicated)
|
||||||
|
* @param val a json_object or NULL member to associate with the given field
|
||||||
|
*/
|
||||||
|
extern void json_object_object_add(struct json_object* obj, const char *key,
|
||||||
|
struct json_object *val);
|
||||||
|
|
||||||
|
/** Get the json_object associate with a given object field
|
||||||
|
*
|
||||||
|
* *No* reference counts will be changed. There is no need to manually adjust
|
||||||
|
* reference counts through the json_object_put/json_object_get methods unless
|
||||||
|
* you need to have the child (value) reference maintain a different lifetime
|
||||||
|
* than the owning parent (obj). Ownership of the returned value is retained
|
||||||
|
* by obj (do not do json_object_put unless you have done a json_object_get).
|
||||||
|
* If you delete the value from obj (json_object_object_del) and wish to access
|
||||||
|
* the returned reference afterwards, make sure you have first gotten shared
|
||||||
|
* ownership through json_object_get (& don't forget to do a json_object_put
|
||||||
|
* or transfer ownership to prevent a memory leak).
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param key the object field name
|
||||||
|
* @returns the json_object associated with the given field name
|
||||||
|
* @deprecated Please use json_object_object_get_ex
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_object_get(struct json_object* obj,
|
||||||
|
const char *key);
|
||||||
|
|
||||||
|
/** Get the json_object associated with a given object field.
|
||||||
|
*
|
||||||
|
* This returns true if the key is found, false in all other cases (including
|
||||||
|
* if obj isn't a json_type_object).
|
||||||
|
*
|
||||||
|
* *No* reference counts will be changed. There is no need to manually adjust
|
||||||
|
* reference counts through the json_object_put/json_object_get methods unless
|
||||||
|
* you need to have the child (value) reference maintain a different lifetime
|
||||||
|
* than the owning parent (obj). Ownership of value is retained by obj.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param key the object field name
|
||||||
|
* @param value a pointer where to store a reference to the json_object
|
||||||
|
* associated with the given field name.
|
||||||
|
*
|
||||||
|
* It is safe to pass a NULL value.
|
||||||
|
* @returns whether or not the key exists
|
||||||
|
*/
|
||||||
|
extern json_bool json_object_object_get_ex(struct json_object* obj,
|
||||||
|
const char *key,
|
||||||
|
struct json_object **value);
|
||||||
|
|
||||||
|
/** Delete the given json_object field
|
||||||
|
*
|
||||||
|
* The reference count will be decremented for the deleted object. If there
|
||||||
|
* are no more owners of the value represented by this key, then the value is
|
||||||
|
* freed. Otherwise, the reference to the value will remain in memory.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param key the object field name
|
||||||
|
*/
|
||||||
|
extern void json_object_object_del(struct json_object* obj, const char *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate through all keys and values of an object.
|
||||||
|
*
|
||||||
|
* Adding keys to the object while iterating is NOT allowed.
|
||||||
|
*
|
||||||
|
* Deleting an existing key, or replacing an existing key with a
|
||||||
|
* new value IS allowed.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param key the local name for the char* key variable defined in the body
|
||||||
|
* @param val the local name for the json_object* object variable defined in
|
||||||
|
* the body
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||||
|
|
||||||
|
# define json_object_object_foreach(obj,key,val) \
|
||||||
|
char *key; \
|
||||||
|
struct json_object *val __attribute__((__unused__)); \
|
||||||
|
for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \
|
||||||
|
({ if(entry ## key) { \
|
||||||
|
key = (char*)entry ## key->k; \
|
||||||
|
val = (struct json_object*)entry ## key->v; \
|
||||||
|
entry_next ## key = entry ## key->next; \
|
||||||
|
} ; entry ## key; }); \
|
||||||
|
entry ## key = entry_next ## key )
|
||||||
|
|
||||||
|
#else /* ANSI C or MSC */
|
||||||
|
|
||||||
|
# define json_object_object_foreach(obj,key,val) \
|
||||||
|
char *key;\
|
||||||
|
struct json_object *val; \
|
||||||
|
struct lh_entry *entry ## key; \
|
||||||
|
struct lh_entry *entry_next ## key = NULL; \
|
||||||
|
for(entry ## key = json_object_get_object(obj)->head; \
|
||||||
|
(entry ## key ? ( \
|
||||||
|
key = (char*)entry ## key->k, \
|
||||||
|
val = (struct json_object*)entry ## key->v, \
|
||||||
|
entry_next ## key = entry ## key->next, \
|
||||||
|
entry ## key) : 0); \
|
||||||
|
entry ## key = entry_next ## key)
|
||||||
|
|
||||||
|
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */
|
||||||
|
|
||||||
|
/** Iterate through all keys and values of an object (ANSI C Safe)
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param iter the object iterator
|
||||||
|
*/
|
||||||
|
#define json_object_object_foreachC(obj,iter) \
|
||||||
|
for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next)
|
||||||
|
|
||||||
|
/* Array type methods */
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_array
|
||||||
|
* @returns a json_object of type json_type_array
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_array(void);
|
||||||
|
|
||||||
|
/** Get the arraylist of a json_object of type json_type_array
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns an arraylist
|
||||||
|
*/
|
||||||
|
extern struct array_list* json_object_get_array(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Get the length of a json_object of type json_type_array
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns an int
|
||||||
|
*/
|
||||||
|
extern int json_object_array_length(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Sorts the elements of jso of type json_type_array
|
||||||
|
*
|
||||||
|
* Pointers to the json_object pointers will be passed as the two arguments
|
||||||
|
* to @sort_fn
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param sort_fn a sorting function
|
||||||
|
*/
|
||||||
|
extern void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *));
|
||||||
|
|
||||||
|
/** Add an element to the end of a json_object of type json_type_array
|
||||||
|
*
|
||||||
|
* The reference count will *not* be incremented. This is to make adding
|
||||||
|
* fields to objects in code more compact. If you want to retain a reference
|
||||||
|
* to an added object you must wrap the passed object with json_object_get
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param val the json_object to be added
|
||||||
|
*/
|
||||||
|
extern int json_object_array_add(struct json_object *obj,
|
||||||
|
struct json_object *val);
|
||||||
|
|
||||||
|
/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array)
|
||||||
|
*
|
||||||
|
* The reference count will *not* be incremented. This is to make adding
|
||||||
|
* fields to objects in code more compact. If you want to retain a reference
|
||||||
|
* to an added object you must wrap the passed object with json_object_get
|
||||||
|
*
|
||||||
|
* The reference count of a replaced object will be decremented.
|
||||||
|
*
|
||||||
|
* The array size will be automatically be expanded to the size of the
|
||||||
|
* index if the index is larger than the current size.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param idx the index to insert the element at
|
||||||
|
* @param val the json_object to be added
|
||||||
|
*/
|
||||||
|
extern int json_object_array_put_idx(struct json_object *obj, int idx,
|
||||||
|
struct json_object *val);
|
||||||
|
|
||||||
|
/** Get the element at specificed index of the array (a json_object of type json_type_array)
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @param idx the index to get the element at
|
||||||
|
* @returns the json_object at the specified index (or NULL)
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_array_get_idx(struct json_object *obj,
|
||||||
|
int idx);
|
||||||
|
|
||||||
|
/* json_bool type methods */
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_boolean
|
||||||
|
* @param b a json_bool TRUE or FALSE (0 or 1)
|
||||||
|
* @returns a json_object of type json_type_boolean
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_boolean(json_bool b);
|
||||||
|
|
||||||
|
/** Get the json_bool value of a json_object
|
||||||
|
*
|
||||||
|
* The type is coerced to a json_bool if the passed object is not a json_bool.
|
||||||
|
* integer and double objects will return FALSE if there value is zero
|
||||||
|
* or TRUE otherwise. If the passed object is a string it will return
|
||||||
|
* TRUE if it has a non zero length. If any other object type is passed
|
||||||
|
* TRUE will be returned if the object is not NULL.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns a json_bool
|
||||||
|
*/
|
||||||
|
extern json_bool json_object_get_boolean(struct json_object *obj);
|
||||||
|
|
||||||
|
|
||||||
|
/* int type methods */
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_int
|
||||||
|
* Note that values are stored as 64-bit values internally.
|
||||||
|
* To ensure the full range is maintained, use json_object_new_int64 instead.
|
||||||
|
* @param i the integer
|
||||||
|
* @returns a json_object of type json_type_int
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_int(int32_t i);
|
||||||
|
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_int
|
||||||
|
* @param i the integer
|
||||||
|
* @returns a json_object of type json_type_int
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_int64(int64_t i);
|
||||||
|
|
||||||
|
|
||||||
|
/** Get the int value of a json_object
|
||||||
|
*
|
||||||
|
* The type is coerced to a int if the passed object is not a int.
|
||||||
|
* double objects will return their integer conversion. Strings will be
|
||||||
|
* parsed as an integer. If no conversion exists then 0 is returned
|
||||||
|
* and errno is set to EINVAL. null is equivalent to 0 (no error values set)
|
||||||
|
*
|
||||||
|
* Note that integers are stored internally as 64-bit values.
|
||||||
|
* If the value of too big or too small to fit into 32-bit, INT32_MAX or
|
||||||
|
* INT32_MIN are returned, respectively.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns an int
|
||||||
|
*/
|
||||||
|
extern int32_t json_object_get_int(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Get the int value of a json_object
|
||||||
|
*
|
||||||
|
* The type is coerced to a int64 if the passed object is not a int64.
|
||||||
|
* double objects will return their int64 conversion. Strings will be
|
||||||
|
* parsed as an int64. If no conversion exists then 0 is returned.
|
||||||
|
*
|
||||||
|
* NOTE: Set errno to 0 directly before a call to this function to determine
|
||||||
|
* whether or not conversion was successful (it does not clear the value for
|
||||||
|
* you).
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns an int64
|
||||||
|
*/
|
||||||
|
extern int64_t json_object_get_int64(struct json_object *obj);
|
||||||
|
|
||||||
|
|
||||||
|
/* double type methods */
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_double
|
||||||
|
* @param d the double
|
||||||
|
* @returns a json_object of type json_type_double
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_double(double d);
|
||||||
|
|
||||||
|
/** Get the double floating point value of a json_object
|
||||||
|
*
|
||||||
|
* The type is coerced to a double if the passed object is not a double.
|
||||||
|
* integer objects will return their double conversion. Strings will be
|
||||||
|
* parsed as a double. If no conversion exists then 0.0 is returned and
|
||||||
|
* errno is set to EINVAL. null is equivalent to 0 (no error values set)
|
||||||
|
*
|
||||||
|
* If the value is too big to fit in a double, then the value is set to
|
||||||
|
* the closest infinity with errno set to ERANGE. If strings cannot be
|
||||||
|
* converted to their double value, then EINVAL is set & NaN is returned.
|
||||||
|
*
|
||||||
|
* Arrays of length 0 are interpreted as 0 (with no error flags set).
|
||||||
|
* Arrays of length 1 are effectively cast to the equivalent object and
|
||||||
|
* converted using the above rules. All other arrays set the error to
|
||||||
|
* EINVAL & return NaN.
|
||||||
|
*
|
||||||
|
* NOTE: Set errno to 0 directly before a call to this function to
|
||||||
|
* determine whether or not conversion was successful (it does not clear
|
||||||
|
* the value for you).
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns a double floating point number
|
||||||
|
*/
|
||||||
|
extern double json_object_get_double(struct json_object *obj);
|
||||||
|
|
||||||
|
|
||||||
|
/* string type methods */
|
||||||
|
|
||||||
|
/** Create a new empty json_object of type json_type_string
|
||||||
|
*
|
||||||
|
* A copy of the string is made and the memory is managed by the json_object
|
||||||
|
*
|
||||||
|
* @param s the string
|
||||||
|
* @returns a json_object of type json_type_string
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_object_new_string(const char *s);
|
||||||
|
|
||||||
|
extern struct json_object* json_object_new_string_len(const char *s, int len);
|
||||||
|
|
||||||
|
/** Get the string value of a json_object
|
||||||
|
*
|
||||||
|
* If the passed object is not of type json_type_string then the JSON
|
||||||
|
* representation of the object is returned.
|
||||||
|
*
|
||||||
|
* The returned string memory is managed by the json_object and will
|
||||||
|
* be freed when the reference count of the json_object drops to zero.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns a string
|
||||||
|
*/
|
||||||
|
extern const char* json_object_get_string(struct json_object *obj);
|
||||||
|
|
||||||
|
/** Get the string length of a json_object
|
||||||
|
*
|
||||||
|
* If the passed object is not of type json_type_string then zero
|
||||||
|
* will be returned.
|
||||||
|
*
|
||||||
|
* @param obj the json_object instance
|
||||||
|
* @returns int
|
||||||
|
*/
|
||||||
|
extern int json_object_get_string_len(struct json_object *obj);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
168
3P/json/json_object_iterator.c
Normal file
168
3P/json/json_object_iterator.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/**
|
||||||
|
*******************************************************************************
|
||||||
|
* @file json_object_iterator.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
* @brief json-c forces clients to use its private data
|
||||||
|
* structures for JSON Object iteration. This API
|
||||||
|
* implementation corrects that by abstracting the
|
||||||
|
* private json-c details.
|
||||||
|
*
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "json_object_private.h"
|
||||||
|
|
||||||
|
#include "json_object_iterator.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How It Works
|
||||||
|
*
|
||||||
|
* For each JSON Object, json-c maintains a linked list of zero
|
||||||
|
* or more lh_entry (link-hash entry) structures inside the
|
||||||
|
* Object's link-hash table (lh_table).
|
||||||
|
*
|
||||||
|
* Each lh_entry structure on the JSON Object's linked list
|
||||||
|
* represents a single name/value pair. The "next" field of the
|
||||||
|
* last lh_entry in the list is set to NULL, which terminates
|
||||||
|
* the list.
|
||||||
|
*
|
||||||
|
* We represent a valid iterator that refers to an actual
|
||||||
|
* name/value pair via a pointer to the pair's lh_entry
|
||||||
|
* structure set as the iterator's opaque_ field.
|
||||||
|
*
|
||||||
|
* We follow json-c's current pair list representation by
|
||||||
|
* representing a valid "end" iterator (one that refers past the
|
||||||
|
* last pair) with a NULL value in the iterator's opaque_ field.
|
||||||
|
*
|
||||||
|
* A JSON Object without any pairs in it will have the "head"
|
||||||
|
* field of its lh_table structure set to NULL. For such an
|
||||||
|
* object, json_object_iter_begin will return an iterator with
|
||||||
|
* the opaque_ field set to NULL, which is equivalent to the
|
||||||
|
* "end" iterator.
|
||||||
|
*
|
||||||
|
* When iterating, we simply update the iterator's opaque_ field
|
||||||
|
* to point to the next lh_entry structure in the linked list.
|
||||||
|
* opaque_ will become NULL once we iterate past the last pair
|
||||||
|
* in the list, which makes the iterator equivalent to the "end"
|
||||||
|
* iterator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Our current representation of the "end" iterator;
|
||||||
|
///
|
||||||
|
/// @note May not always be NULL
|
||||||
|
static const void* kObjectEndIterValue = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_begin(struct json_object* obj)
|
||||||
|
{
|
||||||
|
struct json_object_iterator iter;
|
||||||
|
struct lh_table* pTable;
|
||||||
|
|
||||||
|
/// @note json_object_get_object will return NULL if passed NULL
|
||||||
|
/// or a non-json_type_object instance
|
||||||
|
pTable = json_object_get_object(obj);
|
||||||
|
JASSERT(NULL != pTable);
|
||||||
|
|
||||||
|
/// @note For a pair-less Object, head is NULL, which matches our
|
||||||
|
/// definition of the "end" iterator
|
||||||
|
iter.opaque_ = pTable->head;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_end(const struct json_object* obj)
|
||||||
|
{
|
||||||
|
struct json_object_iterator iter;
|
||||||
|
|
||||||
|
JASSERT(NULL != obj);
|
||||||
|
JASSERT(json_object_is_type(obj, json_type_object));
|
||||||
|
|
||||||
|
iter.opaque_ = kObjectEndIterValue;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
json_object_iter_next(struct json_object_iterator* iter)
|
||||||
|
{
|
||||||
|
JASSERT(NULL != iter);
|
||||||
|
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||||
|
|
||||||
|
iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
const char*
|
||||||
|
json_object_iter_peek_name(const struct json_object_iterator* iter)
|
||||||
|
{
|
||||||
|
JASSERT(NULL != iter);
|
||||||
|
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||||
|
|
||||||
|
return (const char*)(((struct lh_entry *)iter->opaque_)->k);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
struct json_object*
|
||||||
|
json_object_iter_peek_value(const struct json_object_iterator* iter)
|
||||||
|
{
|
||||||
|
JASSERT(NULL != iter);
|
||||||
|
JASSERT(kObjectEndIterValue != iter->opaque_);
|
||||||
|
|
||||||
|
return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
json_bool
|
||||||
|
json_object_iter_equal(const struct json_object_iterator* iter1,
|
||||||
|
const struct json_object_iterator* iter2)
|
||||||
|
{
|
||||||
|
JASSERT(NULL != iter1);
|
||||||
|
JASSERT(NULL != iter2);
|
||||||
|
|
||||||
|
return (iter1->opaque_ == iter2->opaque_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_init_default(void)
|
||||||
|
{
|
||||||
|
struct json_object_iterator iter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Make this a negative, invalid value, such that
|
||||||
|
* accidental access to it would likely be trapped by the
|
||||||
|
* hardware as an invalid address.
|
||||||
|
*/
|
||||||
|
iter.opaque_ = NULL;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
239
3P/json/json_object_iterator.h
Normal file
239
3P/json/json_object_iterator.h
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
/**
|
||||||
|
*******************************************************************************
|
||||||
|
* @file json_object_iterator.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
* @brief json-c forces clients to use its private data
|
||||||
|
* structures for JSON Object iteration. This API
|
||||||
|
* corrects that by abstracting the private json-c
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* API attributes: <br>
|
||||||
|
* * Thread-safe: NO<br>
|
||||||
|
* * Reentrant: NO
|
||||||
|
*
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef JSON_OBJECT_ITERATOR_H
|
||||||
|
#define JSON_OBJECT_ITERATOR_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward declaration for the opaque iterator information.
|
||||||
|
*/
|
||||||
|
struct json_object_iter_info_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opaque iterator that references a name/value pair within
|
||||||
|
* a JSON Object instance or the "end" iterator value.
|
||||||
|
*/
|
||||||
|
struct json_object_iterator {
|
||||||
|
const void* opaque_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* forward declaration of json-c's JSON value instance structure
|
||||||
|
*/
|
||||||
|
struct json_object;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an iterator structure to a "default" value that
|
||||||
|
* is convenient for initializing an iterator variable to a
|
||||||
|
* default state (e.g., initialization list in a class'
|
||||||
|
* constructor).
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct json_object_iterator iter = json_object_iter_init_default();
|
||||||
|
* MyClass() : iter_(json_object_iter_init_default())
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @note The initialized value doesn't reference any specific
|
||||||
|
* pair, is considered an invalid iterator, and MUST NOT
|
||||||
|
* be passed to any json-c API that expects a valid
|
||||||
|
* iterator.
|
||||||
|
*
|
||||||
|
* @note User and internal code MUST NOT make any assumptions
|
||||||
|
* about and dependencies on the value of the "default"
|
||||||
|
* iterator value.
|
||||||
|
*
|
||||||
|
* @return json_object_iterator
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_init_default(void);
|
||||||
|
|
||||||
|
/** Retrieves an iterator to the first pair of the JSON Object.
|
||||||
|
*
|
||||||
|
* @warning Any modification of the underlying pair invalidates all
|
||||||
|
* iterators to that pair.
|
||||||
|
*
|
||||||
|
* @param obj JSON Object instance (MUST be of type json_object)
|
||||||
|
*
|
||||||
|
* @return json_object_iterator If the JSON Object has at
|
||||||
|
* least one pair, on return, the iterator refers
|
||||||
|
* to the first pair. If the JSON Object doesn't
|
||||||
|
* have any pairs, the returned iterator is
|
||||||
|
* equivalent to the "end" iterator for the same
|
||||||
|
* JSON Object instance.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct json_object_iterator it;
|
||||||
|
* struct json_object_iterator itEnd;
|
||||||
|
* struct json_object* obj;
|
||||||
|
*
|
||||||
|
* obj = json_tokener_parse("{'first':'george', 'age':100}");
|
||||||
|
* it = json_object_iter_begin(obj);
|
||||||
|
* itEnd = json_object_iter_end(obj);
|
||||||
|
*
|
||||||
|
* while (!json_object_iter_equal(&it, &itEnd)) {
|
||||||
|
* printf("%s\n",
|
||||||
|
* json_object_iter_peek_name(&it));
|
||||||
|
* json_object_iter_next(&it);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_begin(struct json_object* obj);
|
||||||
|
|
||||||
|
/** Retrieves the iterator that represents the position beyond the
|
||||||
|
* last pair of the given JSON Object instance.
|
||||||
|
*
|
||||||
|
* @warning Do NOT write code that assumes that the "end"
|
||||||
|
* iterator value is NULL, even if it is so in a
|
||||||
|
* particular instance of the implementation.
|
||||||
|
*
|
||||||
|
* @note The reason we do not (and MUST NOT) provide
|
||||||
|
* "json_object_iter_is_end(json_object_iterator* iter)"
|
||||||
|
* type of API is because it would limit the underlying
|
||||||
|
* representation of name/value containment (or force us
|
||||||
|
* to add additional, otherwise unnecessary, fields to
|
||||||
|
* the iterator structure). The "end" iterator and the
|
||||||
|
* equality test method, on the other hand, permit us to
|
||||||
|
* cleanly abstract pretty much any reasonable underlying
|
||||||
|
* representation without burdening the iterator
|
||||||
|
* structure with unnecessary data.
|
||||||
|
*
|
||||||
|
* @note For performance reasons, memorize the "end" iterator prior
|
||||||
|
* to any loop.
|
||||||
|
*
|
||||||
|
* @param obj JSON Object instance (MUST be of type json_object)
|
||||||
|
*
|
||||||
|
* @return json_object_iterator On return, the iterator refers
|
||||||
|
* to the "end" of the Object instance's pairs
|
||||||
|
* (i.e., NOT the last pair, but "beyond the last
|
||||||
|
* pair" value)
|
||||||
|
*/
|
||||||
|
struct json_object_iterator
|
||||||
|
json_object_iter_end(const struct json_object* obj);
|
||||||
|
|
||||||
|
/** Returns an iterator to the next pair, if any
|
||||||
|
*
|
||||||
|
* @warning Any modification of the underlying pair
|
||||||
|
* invalidates all iterators to that pair.
|
||||||
|
*
|
||||||
|
* @param iter [IN/OUT] Pointer to iterator that references a
|
||||||
|
* name/value pair; MUST be a valid, non-end iterator.
|
||||||
|
* WARNING: bad things will happen if invalid or "end"
|
||||||
|
* iterator is passed. Upon return will contain the
|
||||||
|
* reference to the next pair if there is one; if there
|
||||||
|
* are no more pairs, will contain the "end" iterator
|
||||||
|
* value, which may be compared against the return value
|
||||||
|
* of json_object_iter_end() for the same JSON Object
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
json_object_iter_next(struct json_object_iterator* iter);
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns a const pointer to the name of the pair referenced
|
||||||
|
* by the given iterator.
|
||||||
|
*
|
||||||
|
* @param iter pointer to iterator that references a name/value
|
||||||
|
* pair; MUST be a valid, non-end iterator.
|
||||||
|
*
|
||||||
|
* @warning bad things will happen if an invalid or
|
||||||
|
* "end" iterator is passed.
|
||||||
|
*
|
||||||
|
* @return const char* Pointer to the name of the referenced
|
||||||
|
* name/value pair. The name memory belongs to the
|
||||||
|
* name/value pair, will be freed when the pair is
|
||||||
|
* deleted or modified, and MUST NOT be modified or
|
||||||
|
* freed by the user.
|
||||||
|
*/
|
||||||
|
const char*
|
||||||
|
json_object_iter_peek_name(const struct json_object_iterator* iter);
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns a pointer to the json-c instance representing the
|
||||||
|
* value of the referenced name/value pair, without altering
|
||||||
|
* the instance's reference count.
|
||||||
|
*
|
||||||
|
* @param iter pointer to iterator that references a name/value
|
||||||
|
* pair; MUST be a valid, non-end iterator.
|
||||||
|
*
|
||||||
|
* @warning bad things will happen if invalid or
|
||||||
|
* "end" iterator is passed.
|
||||||
|
*
|
||||||
|
* @return struct json_object* Pointer to the json-c value
|
||||||
|
* instance of the referenced name/value pair; the
|
||||||
|
* value's reference count is not changed by this
|
||||||
|
* function: if you plan to hold on to this json-c node,
|
||||||
|
* take a look at json_object_get() and
|
||||||
|
* json_object_put(). IMPORTANT: json-c API represents
|
||||||
|
* the JSON Null value as a NULL json_object instance
|
||||||
|
* pointer.
|
||||||
|
*/
|
||||||
|
struct json_object*
|
||||||
|
json_object_iter_peek_value(const struct json_object_iterator* iter);
|
||||||
|
|
||||||
|
|
||||||
|
/** Tests two iterators for equality. Typically used to test
|
||||||
|
* for end of iteration by comparing an iterator to the
|
||||||
|
* corresponding "end" iterator (that was derived from the same
|
||||||
|
* JSON Object instance).
|
||||||
|
*
|
||||||
|
* @note The reason we do not (and MUST NOT) provide
|
||||||
|
* "json_object_iter_is_end(json_object_iterator* iter)"
|
||||||
|
* type of API is because it would limit the underlying
|
||||||
|
* representation of name/value containment (or force us
|
||||||
|
* to add additional, otherwise unnecessary, fields to
|
||||||
|
* the iterator structure). The equality test method, on
|
||||||
|
* the other hand, permits us to cleanly abstract pretty
|
||||||
|
* much any reasonable underlying representation.
|
||||||
|
*
|
||||||
|
* @param iter1 Pointer to first valid, non-NULL iterator
|
||||||
|
* @param iter2 POinter to second valid, non-NULL iterator
|
||||||
|
*
|
||||||
|
* @warning if a NULL iterator pointer or an uninitialized
|
||||||
|
* or invalid iterator, or iterators derived from
|
||||||
|
* different JSON Object instances are passed, bad things
|
||||||
|
* will happen!
|
||||||
|
*
|
||||||
|
* @return json_bool non-zero if iterators are equal (i.e., both
|
||||||
|
* reference the same name/value pair or are both at
|
||||||
|
* "end"); zero if they are not equal.
|
||||||
|
*/
|
||||||
|
json_bool
|
||||||
|
json_object_iter_equal(const struct json_object_iterator* iter1,
|
||||||
|
const struct json_object_iterator* iter2);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JSON_OBJECT_ITERATOR_H
|
||||||
47
3P/json/json_object_private.h
Normal file
47
3P/json/json_object_private.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_object_private_h_
|
||||||
|
#define _json_object_private_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (json_object_private_delete_fn)(struct json_object *o);
|
||||||
|
|
||||||
|
struct json_object
|
||||||
|
{
|
||||||
|
enum json_type o_type;
|
||||||
|
json_object_private_delete_fn *_delete;
|
||||||
|
json_object_to_json_string_fn *_to_json_string;
|
||||||
|
int _ref_count;
|
||||||
|
struct printbuf *_pb;
|
||||||
|
union data {
|
||||||
|
json_bool c_boolean;
|
||||||
|
double c_double;
|
||||||
|
int64_t c_int64;
|
||||||
|
struct lh_table *c_object;
|
||||||
|
struct array_list *c_array;
|
||||||
|
struct {
|
||||||
|
char *str;
|
||||||
|
int len;
|
||||||
|
} c_string;
|
||||||
|
} o;
|
||||||
|
json_object_delete_fn *_user_delete;
|
||||||
|
void *_userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
792
3P/json/json_tokener.c
Normal file
792
3P/json/json_tokener.c
Normal file
@@ -0,0 +1,792 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||||
|
* The copyrights to the contents of this file are licensed under the MIT License
|
||||||
|
* (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
#include "arraylist.h"
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LOCALE_H
|
||||||
|
#include <locale.h>
|
||||||
|
#endif /* HAVE_LOCALE_H */
|
||||||
|
|
||||||
|
#if !HAVE_STRDUP && defined(_MSC_VER)
|
||||||
|
/* MSC has the version as _strdup */
|
||||||
|
# define strdup _strdup
|
||||||
|
#elif !HAVE_STRDUP
|
||||||
|
# error You do not have strdup on your system.
|
||||||
|
#endif /* HAVE_STRDUP */
|
||||||
|
|
||||||
|
#if !HAVE_STRNCASECMP && defined(_MSC_VER)
|
||||||
|
/* MSC has the version as _strnicmp */
|
||||||
|
# define strncasecmp _strnicmp
|
||||||
|
#elif !HAVE_STRNCASECMP
|
||||||
|
# error You do not have strncasecmp on your system.
|
||||||
|
#endif /* HAVE_STRNCASECMP */
|
||||||
|
|
||||||
|
static const char* json_null_str = "null";
|
||||||
|
static const char* json_true_str = "true";
|
||||||
|
static const char* json_false_str = "false";
|
||||||
|
|
||||||
|
// XXX after v0.10 this array will become static:
|
||||||
|
const char* json_tokener_errors[] = {
|
||||||
|
"success",
|
||||||
|
"continue",
|
||||||
|
"nesting too deep",
|
||||||
|
"unexpected end of data",
|
||||||
|
"unexpected character",
|
||||||
|
"null expected",
|
||||||
|
"boolean expected",
|
||||||
|
"number expected",
|
||||||
|
"array value separator ',' expected",
|
||||||
|
"quoted object property name expected",
|
||||||
|
"object property name separator ':' expected",
|
||||||
|
"object value separator ',' expected",
|
||||||
|
"invalid string sequence",
|
||||||
|
"expected comment",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *json_tokener_error_desc(enum json_tokener_error jerr)
|
||||||
|
{
|
||||||
|
int jerr_int = (int)jerr;
|
||||||
|
if (jerr_int < 0 || jerr_int > (int)sizeof(json_tokener_errors))
|
||||||
|
return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()";
|
||||||
|
return json_tokener_errors[jerr];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum json_tokener_error json_tokener_get_error(json_tokener *tok)
|
||||||
|
{
|
||||||
|
return tok->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stuff for decoding unicode sequences */
|
||||||
|
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
|
||||||
|
#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00)
|
||||||
|
#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
|
||||||
|
static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };
|
||||||
|
|
||||||
|
struct json_tokener* json_tokener_new_ex(int depth)
|
||||||
|
{
|
||||||
|
struct json_tokener *tok;
|
||||||
|
|
||||||
|
tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
|
||||||
|
if (!tok) return NULL;
|
||||||
|
tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec));
|
||||||
|
if (!tok->stack) {
|
||||||
|
free(tok);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tok->pb = printbuf_new();
|
||||||
|
tok->max_depth = depth;
|
||||||
|
json_tokener_reset(tok);
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_tokener* json_tokener_new(void)
|
||||||
|
{
|
||||||
|
return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_tokener_free(struct json_tokener *tok)
|
||||||
|
{
|
||||||
|
json_tokener_reset(tok);
|
||||||
|
if (tok->pb) printbuf_free(tok->pb);
|
||||||
|
if (tok->stack) free(tok->stack);
|
||||||
|
free(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_tokener_reset_level(struct json_tokener *tok, int depth)
|
||||||
|
{
|
||||||
|
tok->stack[depth].state = json_tokener_state_eatws;
|
||||||
|
tok->stack[depth].saved_state = json_tokener_state_start;
|
||||||
|
json_object_put(tok->stack[depth].current);
|
||||||
|
tok->stack[depth].current = NULL;
|
||||||
|
free(tok->stack[depth].obj_field_name);
|
||||||
|
tok->stack[depth].obj_field_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_tokener_reset(struct json_tokener *tok)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!tok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(i = tok->depth; i >= 0; i--)
|
||||||
|
json_tokener_reset_level(tok, i);
|
||||||
|
tok->depth = 0;
|
||||||
|
tok->err = json_tokener_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_tokener_parse(const char *str)
|
||||||
|
{
|
||||||
|
enum json_tokener_error jerr_ignored;
|
||||||
|
struct json_object* obj;
|
||||||
|
obj = json_tokener_parse_verbose(str, &jerr_ignored);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error)
|
||||||
|
{
|
||||||
|
struct json_tokener* tok;
|
||||||
|
struct json_object* obj;
|
||||||
|
|
||||||
|
tok = json_tokener_new();
|
||||||
|
if (!tok)
|
||||||
|
return NULL;
|
||||||
|
obj = json_tokener_parse_ex(tok, str, -1);
|
||||||
|
*error = tok->err;
|
||||||
|
if(tok->err != json_tokener_success) {
|
||||||
|
if (obj != NULL)
|
||||||
|
json_object_put(obj);
|
||||||
|
obj = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_tokener_free(tok);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !HAVE_STRNDUP
|
||||||
|
/* CAW: compliant version of strndup() */
|
||||||
|
char* strndup(const char* str, size_t n)
|
||||||
|
{
|
||||||
|
if(str) {
|
||||||
|
size_t len = strlen(str);
|
||||||
|
size_t nn = json_min(len,n);
|
||||||
|
char* s = (char*)malloc(sizeof(char) * (nn + 1));
|
||||||
|
|
||||||
|
if(s) {
|
||||||
|
memcpy(s, str, nn);
|
||||||
|
s[nn] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define state tok->stack[tok->depth].state
|
||||||
|
#define saved_state tok->stack[tok->depth].saved_state
|
||||||
|
#define current tok->stack[tok->depth].current
|
||||||
|
#define obj_field_name tok->stack[tok->depth].obj_field_name
|
||||||
|
|
||||||
|
/* Optimization:
|
||||||
|
* json_tokener_parse_ex() consumed a lot of CPU in its main loop,
|
||||||
|
* iterating character-by character. A large performance boost is
|
||||||
|
* achieved by using tighter loops to locally handle units such as
|
||||||
|
* comments and strings. Loops that handle an entire token within
|
||||||
|
* their scope also gather entire strings and pass them to
|
||||||
|
* printbuf_memappend() in a single call, rather than calling
|
||||||
|
* printbuf_memappend() one char at a time.
|
||||||
|
*
|
||||||
|
* PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is
|
||||||
|
* common to both the main loop and the tighter loops.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* PEEK_CHAR(dest, tok) macro:
|
||||||
|
* Peeks at the current char and stores it in dest.
|
||||||
|
* Returns 1 on success, sets tok->err and returns 0 if no more chars.
|
||||||
|
* Implicit inputs: str, len vars
|
||||||
|
*/
|
||||||
|
#define PEEK_CHAR(dest, tok) \
|
||||||
|
(((tok)->char_offset == len) ? \
|
||||||
|
(((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \
|
||||||
|
(((tok)->err = json_tokener_success), 0) \
|
||||||
|
: \
|
||||||
|
(((tok)->err = json_tokener_continue), 0) \
|
||||||
|
) : \
|
||||||
|
(((dest) = *str), 1) \
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ADVANCE_CHAR() macro:
|
||||||
|
* Incrementes str & tok->char_offset.
|
||||||
|
* For convenience of existing conditionals, returns the old value of c (0 on eof)
|
||||||
|
* Implicit inputs: c var
|
||||||
|
*/
|
||||||
|
#define ADVANCE_CHAR(str, tok) \
|
||||||
|
( ++(str), ((tok)->char_offset)++, c)
|
||||||
|
|
||||||
|
|
||||||
|
/* End optimization macro defs */
|
||||||
|
|
||||||
|
|
||||||
|
struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
|
||||||
|
const char *str, int len)
|
||||||
|
{
|
||||||
|
struct json_object *obj = NULL;
|
||||||
|
char c = '\1';
|
||||||
|
#ifdef HAVE_SETLOCALE
|
||||||
|
char *oldlocale=NULL, *tmplocale;
|
||||||
|
|
||||||
|
tmplocale = setlocale(LC_NUMERIC, NULL);
|
||||||
|
if (tmplocale) oldlocale = strdup(tmplocale);
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tok->char_offset = 0;
|
||||||
|
tok->err = json_tokener_success;
|
||||||
|
|
||||||
|
while (PEEK_CHAR(c, tok)) {
|
||||||
|
|
||||||
|
redo_char:
|
||||||
|
switch(state) {
|
||||||
|
|
||||||
|
case json_tokener_state_eatws:
|
||||||
|
/* Advance until we change state */
|
||||||
|
while (isspace((int)c)) {
|
||||||
|
if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(c == '/') {
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
state = json_tokener_state_comment_start;
|
||||||
|
} else {
|
||||||
|
state = saved_state;
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_start:
|
||||||
|
switch(c) {
|
||||||
|
case '{':
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
saved_state = json_tokener_state_object_field_start;
|
||||||
|
current = json_object_new_object();
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
saved_state = json_tokener_state_array;
|
||||||
|
current = json_object_new_array();
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
case 'n':
|
||||||
|
state = json_tokener_state_null;
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
tok->st_pos = 0;
|
||||||
|
goto redo_char;
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
state = json_tokener_state_string;
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
tok->quote_char = c;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
case 't':
|
||||||
|
case 'F':
|
||||||
|
case 'f':
|
||||||
|
state = json_tokener_state_boolean;
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
tok->st_pos = 0;
|
||||||
|
goto redo_char;
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
case '0' ... '9':
|
||||||
|
#else
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
#endif
|
||||||
|
case '-':
|
||||||
|
state = json_tokener_state_number;
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
tok->is_double = 0;
|
||||||
|
goto redo_char;
|
||||||
|
default:
|
||||||
|
tok->err = json_tokener_error_parse_unexpected;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_finish:
|
||||||
|
if(tok->depth == 0) goto out;
|
||||||
|
obj = json_object_get(current);
|
||||||
|
json_tokener_reset_level(tok, tok->depth);
|
||||||
|
tok->depth--;
|
||||||
|
goto redo_char;
|
||||||
|
|
||||||
|
case json_tokener_state_null:
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
if(strncasecmp(json_null_str, tok->pb->buf,
|
||||||
|
json_min(tok->st_pos+1, (int)strlen(json_null_str))) == 0) {
|
||||||
|
if(tok->st_pos == (int)strlen(json_null_str)) {
|
||||||
|
current = NULL;
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_null;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
tok->st_pos++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_comment_start:
|
||||||
|
if(c == '*') {
|
||||||
|
state = json_tokener_state_comment;
|
||||||
|
} else if(c == '/') {
|
||||||
|
state = json_tokener_state_comment_eol;
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_comment;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_comment:
|
||||||
|
{
|
||||||
|
/* Advance until we change state */
|
||||||
|
const char *case_start = str;
|
||||||
|
while(c != '*') {
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start);
|
||||||
|
state = json_tokener_state_comment_end;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_comment_eol:
|
||||||
|
{
|
||||||
|
/* Advance until we change state */
|
||||||
|
const char *case_start = str;
|
||||||
|
while(c != '\n') {
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_comment_end:
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
if(c == '/') {
|
||||||
|
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else {
|
||||||
|
state = json_tokener_state_comment;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_string:
|
||||||
|
{
|
||||||
|
/* Advance until we change state */
|
||||||
|
const char *case_start = str;
|
||||||
|
while(1) {
|
||||||
|
if(c == tok->quote_char) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
break;
|
||||||
|
} else if(c == '\\') {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
saved_state = json_tokener_state_string;
|
||||||
|
state = json_tokener_state_string_escape;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_string_escape:
|
||||||
|
switch(c) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
state = saved_state;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'n':
|
||||||
|
case 'r':
|
||||||
|
case 't':
|
||||||
|
case 'f':
|
||||||
|
if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1);
|
||||||
|
else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1);
|
||||||
|
else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1);
|
||||||
|
else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1);
|
||||||
|
else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1);
|
||||||
|
state = saved_state;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
tok->ucs_char = 0;
|
||||||
|
tok->st_pos = 0;
|
||||||
|
state = json_tokener_state_escape_unicode;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tok->err = json_tokener_error_parse_string;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_escape_unicode:
|
||||||
|
{
|
||||||
|
unsigned int got_hi_surrogate = 0;
|
||||||
|
|
||||||
|
/* Handle a 4-byte sequence, or two sequences if a surrogate pair */
|
||||||
|
while(1) {
|
||||||
|
if(strchr(json_hex_chars, c)) {
|
||||||
|
tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));
|
||||||
|
if(tok->st_pos == 4) {
|
||||||
|
unsigned char unescaped_utf[4];
|
||||||
|
|
||||||
|
if (got_hi_surrogate) {
|
||||||
|
if (IS_LOW_SURROGATE(tok->ucs_char)) {
|
||||||
|
/* Recalculate the ucs_char, then fall thru to process normally */
|
||||||
|
tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char);
|
||||||
|
} else {
|
||||||
|
/* Hi surrogate was not followed by a low surrogate */
|
||||||
|
/* Replace the hi and process the rest normally */
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
}
|
||||||
|
got_hi_surrogate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok->ucs_char < 0x80) {
|
||||||
|
unescaped_utf[0] = tok->ucs_char;
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1);
|
||||||
|
} else if (tok->ucs_char < 0x800) {
|
||||||
|
unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
|
||||||
|
unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2);
|
||||||
|
} else if (IS_HIGH_SURROGATE(tok->ucs_char)) {
|
||||||
|
/* Got a high surrogate. Remember it and look for the
|
||||||
|
* the beginning of another sequence, which should be the
|
||||||
|
* low surrogate.
|
||||||
|
*/
|
||||||
|
got_hi_surrogate = tok->ucs_char;
|
||||||
|
/* Not at end, and the next two chars should be "\u" */
|
||||||
|
if ((tok->char_offset+1 != len) &&
|
||||||
|
(tok->char_offset+2 != len) &&
|
||||||
|
(str[1] == '\\') &&
|
||||||
|
(str[2] == 'u'))
|
||||||
|
{
|
||||||
|
/* Advance through the 16 bit surrogate, and move on to the
|
||||||
|
* next sequence. The next step is to process the following
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) {
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
}
|
||||||
|
/* Advance to the first char of the next sequence and
|
||||||
|
* continue processing with the next sequence.
|
||||||
|
*/
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
tok->ucs_char = 0;
|
||||||
|
tok->st_pos = 0;
|
||||||
|
continue; /* other json_tokener_state_escape_unicode */
|
||||||
|
} else {
|
||||||
|
/* Got a high surrogate without another sequence following
|
||||||
|
* it. Put a replacement char in for the hi surrogate
|
||||||
|
* and pretend we finished.
|
||||||
|
*/
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
}
|
||||||
|
} else if (IS_LOW_SURROGATE(tok->ucs_char)) {
|
||||||
|
/* Got a low surrogate not preceded by a high */
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
} else if (tok->ucs_char < 0x10000) {
|
||||||
|
unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
|
||||||
|
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
|
||||||
|
unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3);
|
||||||
|
} else if (tok->ucs_char < 0x110000) {
|
||||||
|
unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07);
|
||||||
|
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);
|
||||||
|
unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
|
||||||
|
unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4);
|
||||||
|
} else {
|
||||||
|
/* Don't know what we got--insert the replacement char */
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
}
|
||||||
|
state = saved_state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_string;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
if (got_hi_surrogate) /* Clean up any pending chars */
|
||||||
|
printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_boolean:
|
||||||
|
printbuf_memappend_fast(tok->pb, &c, 1);
|
||||||
|
if(strncasecmp(json_true_str, tok->pb->buf,
|
||||||
|
json_min(tok->st_pos+1, (int)strlen(json_true_str))) == 0) {
|
||||||
|
if(tok->st_pos == (int)strlen(json_true_str)) {
|
||||||
|
current = json_object_new_boolean(1);
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
} else if(strncasecmp(json_false_str, tok->pb->buf,
|
||||||
|
json_min(tok->st_pos+1, (int)strlen(json_false_str))) == 0) {
|
||||||
|
if(tok->st_pos == (int)strlen(json_false_str)) {
|
||||||
|
current = json_object_new_boolean(0);
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_boolean;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
tok->st_pos++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_number:
|
||||||
|
{
|
||||||
|
/* Advance until we change state */
|
||||||
|
const char *case_start = str;
|
||||||
|
int case_len=0;
|
||||||
|
while(c && strchr(json_number_chars, c)) {
|
||||||
|
++case_len;
|
||||||
|
if(c == '.' || c == 'e' || c == 'E')
|
||||||
|
tok->is_double = 1;
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, case_len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (case_len>0)
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, case_len);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int64_t num64;
|
||||||
|
double numd;
|
||||||
|
if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
|
||||||
|
current = json_object_new_int64(num64);
|
||||||
|
} else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) {
|
||||||
|
current = json_object_new_double(numd);
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_number;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_array_after_sep:
|
||||||
|
case json_tokener_state_array:
|
||||||
|
if(c == ']') {
|
||||||
|
if (state == json_tokener_state_array_after_sep &&
|
||||||
|
(tok->flags & JSON_TOKENER_STRICT))
|
||||||
|
{
|
||||||
|
tok->err = json_tokener_error_parse_unexpected;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else {
|
||||||
|
if(tok->depth >= tok->max_depth-1) {
|
||||||
|
tok->err = json_tokener_error_depth;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
state = json_tokener_state_array_add;
|
||||||
|
tok->depth++;
|
||||||
|
json_tokener_reset_level(tok, tok->depth);
|
||||||
|
goto redo_char;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_array_add:
|
||||||
|
json_object_array_add(current, obj);
|
||||||
|
saved_state = json_tokener_state_array_sep;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
|
||||||
|
case json_tokener_state_array_sep:
|
||||||
|
if(c == ']') {
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else if(c == ',') {
|
||||||
|
saved_state = json_tokener_state_array_after_sep;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_array;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_object_field_start:
|
||||||
|
case json_tokener_state_object_field_start_after_sep:
|
||||||
|
if(c == '}') {
|
||||||
|
if (state == json_tokener_state_object_field_start_after_sep &&
|
||||||
|
(tok->flags & JSON_TOKENER_STRICT))
|
||||||
|
{
|
||||||
|
tok->err = json_tokener_error_parse_unexpected;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else if (c == '"' || c == '\'') {
|
||||||
|
tok->quote_char = c;
|
||||||
|
printbuf_reset(tok->pb);
|
||||||
|
state = json_tokener_state_object_field;
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_object_key_name;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_object_field:
|
||||||
|
{
|
||||||
|
/* Advance until we change state */
|
||||||
|
const char *case_start = str;
|
||||||
|
while(1) {
|
||||||
|
if(c == tok->quote_char) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
obj_field_name = strdup(tok->pb->buf);
|
||||||
|
saved_state = json_tokener_state_object_field_end;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
break;
|
||||||
|
} else if(c == '\\') {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
saved_state = json_tokener_state_object_field;
|
||||||
|
state = json_tokener_state_string_escape;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
|
||||||
|
printbuf_memappend_fast(tok->pb, case_start, str-case_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_object_field_end:
|
||||||
|
if(c == ':') {
|
||||||
|
saved_state = json_tokener_state_object_value;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_object_key_sep;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_tokener_state_object_value:
|
||||||
|
if(tok->depth >= tok->max_depth-1) {
|
||||||
|
tok->err = json_tokener_error_depth;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
state = json_tokener_state_object_value_add;
|
||||||
|
tok->depth++;
|
||||||
|
json_tokener_reset_level(tok, tok->depth);
|
||||||
|
goto redo_char;
|
||||||
|
|
||||||
|
case json_tokener_state_object_value_add:
|
||||||
|
json_object_object_add(current, obj_field_name, obj);
|
||||||
|
free(obj_field_name);
|
||||||
|
obj_field_name = NULL;
|
||||||
|
saved_state = json_tokener_state_object_sep;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
goto redo_char;
|
||||||
|
|
||||||
|
case json_tokener_state_object_sep:
|
||||||
|
if(c == '}') {
|
||||||
|
saved_state = json_tokener_state_finish;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else if(c == ',') {
|
||||||
|
saved_state = json_tokener_state_object_field_start_after_sep;
|
||||||
|
state = json_tokener_state_eatws;
|
||||||
|
} else {
|
||||||
|
tok->err = json_tokener_error_parse_object_value_sep;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!ADVANCE_CHAR(str, tok))
|
||||||
|
goto out;
|
||||||
|
} /* while(POP_CHAR) */
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!c) { /* We hit an eof char (0) */
|
||||||
|
if(state != json_tokener_state_finish &&
|
||||||
|
saved_state != json_tokener_state_finish)
|
||||||
|
tok->err = json_tokener_error_parse_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SETLOCALE
|
||||||
|
setlocale(LC_NUMERIC, oldlocale);
|
||||||
|
if (oldlocale) free(oldlocale);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (tok->err == json_tokener_success)
|
||||||
|
{
|
||||||
|
json_object *ret = json_object_get(current);
|
||||||
|
int ii;
|
||||||
|
|
||||||
|
/* Partially reset, so we parse additional objects on subsequent calls. */
|
||||||
|
for(ii = tok->depth; ii >= 0; ii--)
|
||||||
|
json_tokener_reset_level(tok, ii);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n",
|
||||||
|
json_tokener_errors[tok->err], tok->char_offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_tokener_set_flags(struct json_tokener *tok, int flags)
|
||||||
|
{
|
||||||
|
tok->flags = flags;
|
||||||
|
}
|
||||||
209
3P/json/json_tokener.h
Normal file
209
3P/json/json_tokener.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_tokener_h_
|
||||||
|
#define _json_tokener_h_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "json_object.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum json_tokener_error {
|
||||||
|
json_tokener_success,
|
||||||
|
json_tokener_continue,
|
||||||
|
json_tokener_error_depth,
|
||||||
|
json_tokener_error_parse_eof,
|
||||||
|
json_tokener_error_parse_unexpected,
|
||||||
|
json_tokener_error_parse_null,
|
||||||
|
json_tokener_error_parse_boolean,
|
||||||
|
json_tokener_error_parse_number,
|
||||||
|
json_tokener_error_parse_array,
|
||||||
|
json_tokener_error_parse_object_key_name,
|
||||||
|
json_tokener_error_parse_object_key_sep,
|
||||||
|
json_tokener_error_parse_object_value_sep,
|
||||||
|
json_tokener_error_parse_string,
|
||||||
|
json_tokener_error_parse_comment
|
||||||
|
};
|
||||||
|
|
||||||
|
enum json_tokener_state {
|
||||||
|
json_tokener_state_eatws,
|
||||||
|
json_tokener_state_start,
|
||||||
|
json_tokener_state_finish,
|
||||||
|
json_tokener_state_null,
|
||||||
|
json_tokener_state_comment_start,
|
||||||
|
json_tokener_state_comment,
|
||||||
|
json_tokener_state_comment_eol,
|
||||||
|
json_tokener_state_comment_end,
|
||||||
|
json_tokener_state_string,
|
||||||
|
json_tokener_state_string_escape,
|
||||||
|
json_tokener_state_escape_unicode,
|
||||||
|
json_tokener_state_boolean,
|
||||||
|
json_tokener_state_number,
|
||||||
|
json_tokener_state_array,
|
||||||
|
json_tokener_state_array_add,
|
||||||
|
json_tokener_state_array_sep,
|
||||||
|
json_tokener_state_object_field_start,
|
||||||
|
json_tokener_state_object_field,
|
||||||
|
json_tokener_state_object_field_end,
|
||||||
|
json_tokener_state_object_value,
|
||||||
|
json_tokener_state_object_value_add,
|
||||||
|
json_tokener_state_object_sep,
|
||||||
|
json_tokener_state_array_after_sep,
|
||||||
|
json_tokener_state_object_field_start_after_sep
|
||||||
|
};
|
||||||
|
|
||||||
|
struct json_tokener_srec
|
||||||
|
{
|
||||||
|
enum json_tokener_state state, saved_state;
|
||||||
|
struct json_object *obj;
|
||||||
|
struct json_object *current;
|
||||||
|
char *obj_field_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define JSON_TOKENER_DEFAULT_DEPTH 32
|
||||||
|
|
||||||
|
struct json_tokener
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
struct printbuf *pb;
|
||||||
|
int max_depth, depth, is_double, st_pos, char_offset;
|
||||||
|
enum json_tokener_error err;
|
||||||
|
unsigned int ucs_char;
|
||||||
|
char quote_char;
|
||||||
|
struct json_tokener_srec *stack;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Be strict when parsing JSON input. Use caution with
|
||||||
|
* this flag as what is considered valid may become more
|
||||||
|
* restrictive from one release to the next, causing your
|
||||||
|
* code to fail on previously working input.
|
||||||
|
*
|
||||||
|
* This flag is not set by default.
|
||||||
|
*
|
||||||
|
* @see json_tokener_set_flags()
|
||||||
|
*/
|
||||||
|
#define JSON_TOKENER_STRICT 0x01
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an error previously returned by json_tokener_get_error(),
|
||||||
|
* return a human readable description of the error.
|
||||||
|
*
|
||||||
|
* @return a generic error message is returned if an invalid error value is provided.
|
||||||
|
*/
|
||||||
|
const char *json_tokener_error_desc(enum json_tokener_error jerr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @b XXX do not use json_tokener_errors directly.
|
||||||
|
* After v0.10 this will be removed.
|
||||||
|
*
|
||||||
|
* See json_tokener_error_desc() instead.
|
||||||
|
*/
|
||||||
|
extern const char* json_tokener_errors[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the error caused by the last call to json_tokener_parse_ex(),
|
||||||
|
* or json_tokener_success if there is no error.
|
||||||
|
*
|
||||||
|
* When parsing a JSON string in pieces, if the tokener is in the middle
|
||||||
|
* of parsing this will return json_tokener_continue.
|
||||||
|
*
|
||||||
|
* See also json_tokener_error_desc().
|
||||||
|
*/
|
||||||
|
enum json_tokener_error json_tokener_get_error(struct json_tokener *tok);
|
||||||
|
|
||||||
|
extern struct json_tokener* json_tokener_new(void);
|
||||||
|
extern struct json_tokener* json_tokener_new_ex(int depth);
|
||||||
|
extern void json_tokener_free(struct json_tokener *tok);
|
||||||
|
extern void json_tokener_reset(struct json_tokener *tok);
|
||||||
|
extern struct json_object* json_tokener_parse(const char *str);
|
||||||
|
extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set flags that control how parsing will be done.
|
||||||
|
*/
|
||||||
|
extern void json_tokener_set_flags(struct json_tokener *tok, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string and return a non-NULL json_object if a valid JSON value
|
||||||
|
* is found. The string does not need to be a JSON object or array;
|
||||||
|
* it can also be a string, number or boolean value.
|
||||||
|
*
|
||||||
|
* A partial JSON string can be parsed. If the parsing is incomplete,
|
||||||
|
* NULL will be returned and json_tokener_get_error() will be return
|
||||||
|
* json_tokener_continue.
|
||||||
|
* json_tokener_parse_ex() can then be called with additional bytes in str
|
||||||
|
* to continue the parsing.
|
||||||
|
*
|
||||||
|
* If json_tokener_parse_ex() returns NULL and the error anything other than
|
||||||
|
* json_tokener_continue, a fatal error has occurred and parsing must be
|
||||||
|
* halted. Then tok object must not be re-used until json_tokener_reset() is
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* When a valid JSON value is parsed, a non-NULL json_object will be
|
||||||
|
* returned. Also, json_tokener_get_error() will return json_tokener_success.
|
||||||
|
* Be sure to check the type with json_object_is_type() or
|
||||||
|
* json_object_get_type() before using the object.
|
||||||
|
*
|
||||||
|
* @b XXX this shouldn't use internal fields:
|
||||||
|
* Trailing characters after the parsed value do not automatically cause an
|
||||||
|
* error. It is up to the caller to decide whether to treat this as an
|
||||||
|
* error or to handle the additional characters, perhaps by parsing another
|
||||||
|
* json value starting from that point.
|
||||||
|
*
|
||||||
|
* Extra characters can be detected by comparing the tok->char_offset against
|
||||||
|
* the length of the last len parameter passed in.
|
||||||
|
*
|
||||||
|
* The tokener does \b not maintain an internal buffer so the caller is
|
||||||
|
* responsible for calling json_tokener_parse_ex with an appropriate str
|
||||||
|
* parameter starting with the extra characters.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
json_object *jobj = NULL;
|
||||||
|
const char *mystring = NULL;
|
||||||
|
int stringlen = 0;
|
||||||
|
enum json_tokener_error jerr;
|
||||||
|
do {
|
||||||
|
mystring = ... // get JSON string, e.g. read from file, etc...
|
||||||
|
stringlen = strlen(mystring);
|
||||||
|
jobj = json_tokener_parse_ex(tok, mystring, stringlen);
|
||||||
|
} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
|
||||||
|
if (jerr != json_tokener_success)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
|
||||||
|
// Handle errors, as appropriate for your application.
|
||||||
|
}
|
||||||
|
if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
|
||||||
|
{
|
||||||
|
// Handle extra characters after parsed object as desired.
|
||||||
|
// e.g. issue an error, parse another object from that point, etc...
|
||||||
|
}
|
||||||
|
// Success, use jobj here.
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
*
|
||||||
|
* @param tok a json_tokener previously allocated with json_tokener_new()
|
||||||
|
* @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated.
|
||||||
|
* @param len the length of str
|
||||||
|
*/
|
||||||
|
extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
|
||||||
|
const char *str, int len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
299
3P/json/json_util.c
Normal file
299
3P/json/json_util.c
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#undef realloc
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif /* HAVE_SYS_TYPES_H */
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif /* HAVE_SYS_STAT_H */
|
||||||
|
|
||||||
|
#ifdef HAVE_FCNTL_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif /* HAVE_FCNTL_H */
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <io.h>
|
||||||
|
#endif /* defined(WIN32) */
|
||||||
|
|
||||||
|
#if !defined(HAVE_OPEN) && defined(WIN32)
|
||||||
|
# define open _open
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
|
||||||
|
/* MSC has the version as _snprintf */
|
||||||
|
# define snprintf _snprintf
|
||||||
|
#elif !defined(HAVE_SNPRINTF)
|
||||||
|
# error You do not have snprintf on your system.
|
||||||
|
#endif /* HAVE_SNPRINTF */
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
static int sscanf_is_broken = 0;
|
||||||
|
static int sscanf_is_broken_testdone = 0;
|
||||||
|
static void sscanf_is_broken_test(void);
|
||||||
|
|
||||||
|
struct json_object* json_object_from_file(const char *filename)
|
||||||
|
{
|
||||||
|
struct printbuf *pb;
|
||||||
|
struct json_object *obj;
|
||||||
|
char buf[JSON_FILE_BUF_SIZE];
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
if((fd = open(filename, O_RDONLY)) < 0) {
|
||||||
|
MC_ERROR("json_object_from_file: error reading file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!(pb = printbuf_new())) {
|
||||||
|
close(fd);
|
||||||
|
MC_ERROR("json_object_from_file: printbuf_new failed\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
|
||||||
|
printbuf_memappend(pb, buf, ret);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
if(ret < 0) {
|
||||||
|
MC_ABORT("json_object_from_file: error reading file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
printbuf_free(pb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
obj = json_tokener_parse(pb->buf);
|
||||||
|
printbuf_free(pb);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extended "format and write to file" function */
|
||||||
|
|
||||||
|
int json_object_to_file_ext(char *filename, struct json_object *obj, int flags)
|
||||||
|
{
|
||||||
|
const char *json_str;
|
||||||
|
int fd, ret;
|
||||||
|
unsigned int wpos, wsize;
|
||||||
|
|
||||||
|
if(!obj) {
|
||||||
|
MC_ERROR("json_object_to_file: object is null\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
|
||||||
|
MC_ERROR("json_object_to_file: error opening file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(json_str = json_object_to_json_string_ext(obj,flags))) {
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
|
||||||
|
wpos = 0;
|
||||||
|
while(wpos < wsize) {
|
||||||
|
if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
|
||||||
|
close(fd);
|
||||||
|
MC_ERROR("json_object_to_file: error writing file %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* because of the above check for ret < 0, we can safely cast and add */
|
||||||
|
wpos += (unsigned int)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// backwards compatible "format and write to file" function
|
||||||
|
|
||||||
|
int json_object_to_file(char *filename, struct json_object *obj)
|
||||||
|
{
|
||||||
|
return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_parse_double(const char *buf, double *retval)
|
||||||
|
{
|
||||||
|
return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not all implementations of sscanf actually work properly.
|
||||||
|
* Check whether the one we're currently using does, and if
|
||||||
|
* it's broken, enable the workaround code.
|
||||||
|
*/
|
||||||
|
static void sscanf_is_broken_test()
|
||||||
|
{
|
||||||
|
int64_t num64;
|
||||||
|
|
||||||
|
(void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64);
|
||||||
|
int ret_errno = errno;
|
||||||
|
int is_int64_min = (num64 == INT64_MIN);
|
||||||
|
|
||||||
|
(void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64);
|
||||||
|
int ret_errno2 = errno;
|
||||||
|
int is_int64_max = (num64 == INT64_MAX);
|
||||||
|
|
||||||
|
if (ret_errno != ERANGE || !is_int64_min ||
|
||||||
|
ret_errno2 != ERANGE || !is_int64_max)
|
||||||
|
{
|
||||||
|
MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n");
|
||||||
|
sscanf_is_broken = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_parse_int64(const char *buf, int64_t *retval)
|
||||||
|
{
|
||||||
|
int64_t num64;
|
||||||
|
const char *buf_sig_digits;
|
||||||
|
int orig_has_neg;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
if (!sscanf_is_broken_testdone)
|
||||||
|
{
|
||||||
|
sscanf_is_broken_test();
|
||||||
|
sscanf_is_broken_testdone = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip leading spaces
|
||||||
|
while (isspace((int)*buf) && *buf)
|
||||||
|
buf++;
|
||||||
|
|
||||||
|
errno = 0; // sscanf won't always set errno, so initialize
|
||||||
|
if (sscanf(buf, "%" SCNd64, &num64) != 1)
|
||||||
|
{
|
||||||
|
MC_DEBUG("Failed to parse, sscanf != 1\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
saved_errno = errno;
|
||||||
|
buf_sig_digits = buf;
|
||||||
|
orig_has_neg = 0;
|
||||||
|
if (*buf_sig_digits == '-')
|
||||||
|
{
|
||||||
|
buf_sig_digits++;
|
||||||
|
orig_has_neg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not all sscanf implementations actually work
|
||||||
|
if (sscanf_is_broken && saved_errno != ERANGE)
|
||||||
|
{
|
||||||
|
char buf_cmp[100];
|
||||||
|
char *buf_cmp_start = buf_cmp;
|
||||||
|
int recheck_has_neg = 0;
|
||||||
|
int buf_cmp_len;
|
||||||
|
|
||||||
|
// Skip leading zeros, but keep at least one digit
|
||||||
|
while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0')
|
||||||
|
buf_sig_digits++;
|
||||||
|
if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
|
||||||
|
orig_has_neg = 0; // "-0" is the same as just plain "0"
|
||||||
|
|
||||||
|
snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
|
||||||
|
if (*buf_cmp_start == '-')
|
||||||
|
{
|
||||||
|
recheck_has_neg = 1;
|
||||||
|
buf_cmp_start++;
|
||||||
|
}
|
||||||
|
// No need to skip leading spaces or zeros here.
|
||||||
|
|
||||||
|
buf_cmp_len = strlen(buf_cmp_start);
|
||||||
|
/**
|
||||||
|
* If the sign is different, or
|
||||||
|
* some of the digits are different, or
|
||||||
|
* there is another digit present in the original string
|
||||||
|
* then we have NOT successfully parsed the value.
|
||||||
|
*/
|
||||||
|
if (orig_has_neg != recheck_has_neg ||
|
||||||
|
strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
|
||||||
|
((int)strlen(buf_sig_digits) != buf_cmp_len &&
|
||||||
|
isdigit((int)buf_sig_digits[buf_cmp_len])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
saved_errno = ERANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not all sscanf impl's set the value properly when out of range.
|
||||||
|
// Always do this, even for properly functioning implementations,
|
||||||
|
// since it shouldn't slow things down much.
|
||||||
|
if (saved_errno == ERANGE)
|
||||||
|
{
|
||||||
|
if (orig_has_neg)
|
||||||
|
num64 = INT64_MIN;
|
||||||
|
else
|
||||||
|
num64 = INT64_MAX;
|
||||||
|
}
|
||||||
|
*retval = num64;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_REALLOC
|
||||||
|
void* rpl_realloc(void* p, size_t n)
|
||||||
|
{
|
||||||
|
if (n == 0)
|
||||||
|
n = 1;
|
||||||
|
if (p == 0)
|
||||||
|
return malloc(n);
|
||||||
|
return realloc(p, n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NELEM(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
static const char* json_type_name[] = {
|
||||||
|
/* If you change this, be sure to update the enum json_type definition too */
|
||||||
|
"null",
|
||||||
|
"boolean",
|
||||||
|
"double",
|
||||||
|
"int",
|
||||||
|
"object",
|
||||||
|
"array",
|
||||||
|
"string",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *json_type_to_name(enum json_type o_type)
|
||||||
|
{
|
||||||
|
int o_type_int = (int)o_type;
|
||||||
|
if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
|
||||||
|
{
|
||||||
|
MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return json_type_name[o_type];
|
||||||
|
}
|
||||||
|
|
||||||
41
3P/json/json_util.h
Normal file
41
3P/json/json_util.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _json_util_h_
|
||||||
|
#define _json_util_h_
|
||||||
|
|
||||||
|
#include "json_object.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSON_FILE_BUF_SIZE 4096
|
||||||
|
|
||||||
|
/* utility functions */
|
||||||
|
extern struct json_object* json_object_from_file(const char *filename);
|
||||||
|
extern int json_object_to_file(char *filename, struct json_object *obj);
|
||||||
|
extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags);
|
||||||
|
extern int json_parse_int64(const char *buf, int64_t *retval);
|
||||||
|
extern int json_parse_double(const char *buf, double *retval);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string describing the type of the object.
|
||||||
|
* e.g. "int", or "object", etc...
|
||||||
|
*/
|
||||||
|
extern const char *json_type_to_name(enum json_type o_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
26
3P/json/libjson.c
Normal file
26
3P/json/libjson.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
/* dummy source file for compatibility purposes */
|
||||||
|
|
||||||
|
#if defined(HAVE_CDEFS_H)
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __warn_references
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG)
|
||||||
|
|
||||||
|
#define __warn_references(sym,msg) \
|
||||||
|
__asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text");
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define __warn_references(sym,msg) /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "json_object.h"
|
||||||
|
|
||||||
|
__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson");
|
||||||
|
|
||||||
|
/* __asm__(".section .gnu.warning." __STRING(sym) \
|
||||||
|
" ; .ascii \"" msg "\" ; .text") */
|
||||||
233
3P/json/linkhash.c
Normal file
233
3P/json/linkhash.c
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "linkhash.h"
|
||||||
|
|
||||||
|
void lh_abort(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, msg);
|
||||||
|
vprintf(msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long lh_ptr_hash(const void *k)
|
||||||
|
{
|
||||||
|
/* CAW: refactored to be 64bit nice */
|
||||||
|
return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lh_ptr_equal(const void *k1, const void *k2)
|
||||||
|
{
|
||||||
|
return (k1 == k2);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long lh_char_hash(const void *k)
|
||||||
|
{
|
||||||
|
unsigned int h = 0;
|
||||||
|
const char* data = (const char*)k;
|
||||||
|
|
||||||
|
while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lh_char_equal(const void *k1, const void *k2)
|
||||||
|
{
|
||||||
|
return (strcmp((const char*)k1, (const char*)k2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lh_table* lh_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn,
|
||||||
|
lh_hash_fn *hash_fn,
|
||||||
|
lh_equal_fn *equal_fn)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct lh_table *t;
|
||||||
|
|
||||||
|
t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
|
||||||
|
if(!t) lh_abort("lh_table_new: calloc failed\n");
|
||||||
|
t->count = 0;
|
||||||
|
t->size = size;
|
||||||
|
t->name = name;
|
||||||
|
t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry));
|
||||||
|
if(!t->table) lh_abort("lh_table_new: calloc failed\n");
|
||||||
|
t->free_fn = free_fn;
|
||||||
|
t->hash_fn = hash_fn;
|
||||||
|
t->equal_fn = equal_fn;
|
||||||
|
for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lh_table* lh_kchar_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn)
|
||||||
|
{
|
||||||
|
return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lh_table* lh_kptr_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn)
|
||||||
|
{
|
||||||
|
return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lh_table_resize(struct lh_table *t, int new_size)
|
||||||
|
{
|
||||||
|
struct lh_table *new_t;
|
||||||
|
struct lh_entry *ent;
|
||||||
|
|
||||||
|
new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn);
|
||||||
|
ent = t->head;
|
||||||
|
while(ent) {
|
||||||
|
lh_table_insert(new_t, ent->k, ent->v);
|
||||||
|
ent = ent->next;
|
||||||
|
}
|
||||||
|
free(t->table);
|
||||||
|
t->table = new_t->table;
|
||||||
|
t->size = new_size;
|
||||||
|
t->head = new_t->head;
|
||||||
|
t->tail = new_t->tail;
|
||||||
|
t->resizes++;
|
||||||
|
free(new_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lh_table_free(struct lh_table *t)
|
||||||
|
{
|
||||||
|
struct lh_entry *c;
|
||||||
|
for(c = t->head; c != NULL; c = c->next) {
|
||||||
|
if(t->free_fn) {
|
||||||
|
t->free_fn(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(t->table);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int lh_table_insert(struct lh_table *t, void *k, const void *v)
|
||||||
|
{
|
||||||
|
unsigned long h, n;
|
||||||
|
|
||||||
|
t->inserts++;
|
||||||
|
if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2);
|
||||||
|
|
||||||
|
h = t->hash_fn(k);
|
||||||
|
n = h % t->size;
|
||||||
|
|
||||||
|
while( 1 ) {
|
||||||
|
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break;
|
||||||
|
t->collisions++;
|
||||||
|
if ((int)++n == t->size) n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->table[n].k = k;
|
||||||
|
t->table[n].v = v;
|
||||||
|
t->count++;
|
||||||
|
|
||||||
|
if(t->head == NULL) {
|
||||||
|
t->head = t->tail = &t->table[n];
|
||||||
|
t->table[n].next = t->table[n].prev = NULL;
|
||||||
|
} else {
|
||||||
|
t->tail->next = &t->table[n];
|
||||||
|
t->table[n].prev = t->tail;
|
||||||
|
t->table[n].next = NULL;
|
||||||
|
t->tail = &t->table[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k)
|
||||||
|
{
|
||||||
|
unsigned long h = t->hash_fn(k);
|
||||||
|
unsigned long n = h % t->size;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
t->lookups++;
|
||||||
|
while( count < t->size ) {
|
||||||
|
if(t->table[n].k == LH_EMPTY) return NULL;
|
||||||
|
if(t->table[n].k != LH_FREED &&
|
||||||
|
t->equal_fn(t->table[n].k, k)) return &t->table[n];
|
||||||
|
if ((int)++n == t->size) n = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const void* lh_table_lookup(struct lh_table *t, const void *k)
|
||||||
|
{
|
||||||
|
void *result;
|
||||||
|
lh_table_lookup_ex(t, k, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v)
|
||||||
|
{
|
||||||
|
struct lh_entry *e = lh_table_lookup_entry(t, k);
|
||||||
|
if (e != NULL) {
|
||||||
|
if (v != NULL) *v = (void *)e->v;
|
||||||
|
return TRUE; /* key found */
|
||||||
|
}
|
||||||
|
if (v != NULL) *v = NULL;
|
||||||
|
return FALSE; /* key not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e)
|
||||||
|
{
|
||||||
|
ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */
|
||||||
|
|
||||||
|
/* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */
|
||||||
|
if(n < 0) { return -2; }
|
||||||
|
|
||||||
|
if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1;
|
||||||
|
t->count--;
|
||||||
|
if(t->free_fn) t->free_fn(e);
|
||||||
|
t->table[n].v = NULL;
|
||||||
|
t->table[n].k = LH_FREED;
|
||||||
|
if(t->tail == &t->table[n] && t->head == &t->table[n]) {
|
||||||
|
t->head = t->tail = NULL;
|
||||||
|
} else if (t->head == &t->table[n]) {
|
||||||
|
t->head->next->prev = NULL;
|
||||||
|
t->head = t->head->next;
|
||||||
|
} else if (t->tail == &t->table[n]) {
|
||||||
|
t->tail->prev->next = NULL;
|
||||||
|
t->tail = t->tail->prev;
|
||||||
|
} else {
|
||||||
|
t->table[n].prev->next = t->table[n].next;
|
||||||
|
t->table[n].next->prev = t->table[n].prev;
|
||||||
|
}
|
||||||
|
t->table[n].next = t->table[n].prev = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int lh_table_delete(struct lh_table *t, const void *k)
|
||||||
|
{
|
||||||
|
struct lh_entry *e = lh_table_lookup_entry(t, k);
|
||||||
|
if(!e) return -1;
|
||||||
|
return lh_table_delete_entry(t, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lh_table_length(struct lh_table *t)
|
||||||
|
{
|
||||||
|
return t->count;
|
||||||
|
}
|
||||||
292
3P/json/linkhash.h
Normal file
292
3P/json/linkhash.h
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
* $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _linkhash_h_
|
||||||
|
#define _linkhash_h_
|
||||||
|
|
||||||
|
#include "json_object.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* golden prime used in hash functions
|
||||||
|
*/
|
||||||
|
#define LH_PRIME 0x9e370001UL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fraction of filled hash buckets until an insert will cause the table
|
||||||
|
* to be resized.
|
||||||
|
* This can range from just above 0 up to 1.0.
|
||||||
|
*/
|
||||||
|
#define LH_LOAD_FACTOR 0.66
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sentinel pointer value for empty slots
|
||||||
|
*/
|
||||||
|
#define LH_EMPTY (void*)-1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sentinel pointer value for freed slots
|
||||||
|
*/
|
||||||
|
#define LH_FREED (void*)-2
|
||||||
|
|
||||||
|
struct lh_entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback function prototypes
|
||||||
|
*/
|
||||||
|
typedef void (lh_entry_free_fn) (struct lh_entry *e);
|
||||||
|
/**
|
||||||
|
* callback function prototypes
|
||||||
|
*/
|
||||||
|
typedef unsigned long (lh_hash_fn) (const void *k);
|
||||||
|
/**
|
||||||
|
* callback function prototypes
|
||||||
|
*/
|
||||||
|
typedef int (lh_equal_fn) (const void *k1, const void *k2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry in the hash table
|
||||||
|
*/
|
||||||
|
struct lh_entry {
|
||||||
|
/**
|
||||||
|
* The key.
|
||||||
|
*/
|
||||||
|
void *k;
|
||||||
|
/**
|
||||||
|
* The value.
|
||||||
|
*/
|
||||||
|
const void *v;
|
||||||
|
/**
|
||||||
|
* The next entry
|
||||||
|
*/
|
||||||
|
struct lh_entry *next;
|
||||||
|
/**
|
||||||
|
* The previous entry.
|
||||||
|
*/
|
||||||
|
struct lh_entry *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hash table structure.
|
||||||
|
*/
|
||||||
|
struct lh_table {
|
||||||
|
/**
|
||||||
|
* Size of our hash.
|
||||||
|
*/
|
||||||
|
int size;
|
||||||
|
/**
|
||||||
|
* Numbers of entries.
|
||||||
|
*/
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of collisions.
|
||||||
|
*/
|
||||||
|
int collisions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of resizes.
|
||||||
|
*/
|
||||||
|
int resizes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of lookups.
|
||||||
|
*/
|
||||||
|
int lookups;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of inserts.
|
||||||
|
*/
|
||||||
|
int inserts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of deletes.
|
||||||
|
*/
|
||||||
|
int deletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the hash table.
|
||||||
|
*/
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first entry.
|
||||||
|
*/
|
||||||
|
struct lh_entry *head;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last entry.
|
||||||
|
*/
|
||||||
|
struct lh_entry *tail;
|
||||||
|
|
||||||
|
struct lh_entry *table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pointer onto the function responsible for freeing an entry.
|
||||||
|
*/
|
||||||
|
lh_entry_free_fn *free_fn;
|
||||||
|
lh_hash_fn *hash_fn;
|
||||||
|
lh_equal_fn *equal_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-defined hash and equality functions
|
||||||
|
*/
|
||||||
|
extern unsigned long lh_ptr_hash(const void *k);
|
||||||
|
extern int lh_ptr_equal(const void *k1, const void *k2);
|
||||||
|
|
||||||
|
extern unsigned long lh_char_hash(const void *k);
|
||||||
|
extern int lh_char_equal(const void *k1, const void *k2);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience list iterator.
|
||||||
|
*/
|
||||||
|
#define lh_foreach(table, entry) \
|
||||||
|
for(entry = table->head; entry; entry = entry->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lh_foreach_safe allows calling of deletion routine while iterating.
|
||||||
|
*/
|
||||||
|
#define lh_foreach_safe(table, entry, tmp) \
|
||||||
|
for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new linkhash table.
|
||||||
|
* @param size initial table size. The table is automatically resized
|
||||||
|
* although this incurs a performance penalty.
|
||||||
|
* @param name the table name.
|
||||||
|
* @param free_fn callback function used to free memory for entries
|
||||||
|
* when lh_table_free or lh_table_delete is called.
|
||||||
|
* If NULL is provided, then memory for keys and values
|
||||||
|
* must be freed by the caller.
|
||||||
|
* @param hash_fn function used to hash keys. 2 standard ones are defined:
|
||||||
|
* lh_ptr_hash and lh_char_hash for hashing pointer values
|
||||||
|
* and C strings respectively.
|
||||||
|
* @param equal_fn comparison function to compare keys. 2 standard ones defined:
|
||||||
|
* lh_ptr_hash and lh_char_hash for comparing pointer values
|
||||||
|
* and C strings respectively.
|
||||||
|
* @return a pointer onto the linkhash table.
|
||||||
|
*/
|
||||||
|
extern struct lh_table* lh_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn,
|
||||||
|
lh_hash_fn *hash_fn,
|
||||||
|
lh_equal_fn *equal_fn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to create a new linkhash
|
||||||
|
* table with char keys.
|
||||||
|
* @param size initial table size.
|
||||||
|
* @param name table name.
|
||||||
|
* @param free_fn callback function used to free memory for entries.
|
||||||
|
* @return a pointer onto the linkhash table.
|
||||||
|
*/
|
||||||
|
extern struct lh_table* lh_kchar_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to create a new linkhash
|
||||||
|
* table with ptr keys.
|
||||||
|
* @param size initial table size.
|
||||||
|
* @param name table name.
|
||||||
|
* @param free_fn callback function used to free memory for entries.
|
||||||
|
* @return a pointer onto the linkhash table.
|
||||||
|
*/
|
||||||
|
extern struct lh_table* lh_kptr_table_new(int size, const char *name,
|
||||||
|
lh_entry_free_fn *free_fn);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a linkhash table.
|
||||||
|
* If a callback free function is provided then it is called for all
|
||||||
|
* entries in the table.
|
||||||
|
* @param t table to free.
|
||||||
|
*/
|
||||||
|
extern void lh_table_free(struct lh_table *t);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a record into the table.
|
||||||
|
* @param t the table to insert into.
|
||||||
|
* @param k a pointer to the key to insert.
|
||||||
|
* @param v a pointer to the value to insert.
|
||||||
|
*/
|
||||||
|
extern int lh_table_insert(struct lh_table *t, void *k, const void *v);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a record into the table.
|
||||||
|
* @param t the table to lookup
|
||||||
|
* @param k a pointer to the key to lookup
|
||||||
|
* @return a pointer to the record structure of the value or NULL if it does not exist.
|
||||||
|
*/
|
||||||
|
extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a record into the table
|
||||||
|
* @param t the table to lookup
|
||||||
|
* @param k a pointer to the key to lookup
|
||||||
|
* @return a pointer to the found value or NULL if it does not exist.
|
||||||
|
* @deprecated Use lh_table_lookup_ex instead.
|
||||||
|
*/
|
||||||
|
extern const void* lh_table_lookup(struct lh_table *t, const void *k);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a record in the table
|
||||||
|
* @param t the table to lookup
|
||||||
|
* @param k a pointer to the key to lookup
|
||||||
|
* @param v a pointer to a where to store the found value (set to NULL if it doesn't exist).
|
||||||
|
* @return whether or not the key was found
|
||||||
|
*/
|
||||||
|
extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a record from the table.
|
||||||
|
* If a callback free function is provided then it is called for the
|
||||||
|
* for the item being deleted.
|
||||||
|
* @param t the table to delete from.
|
||||||
|
* @param e a pointer to the entry to delete.
|
||||||
|
* @return 0 if the item was deleted.
|
||||||
|
* @return -1 if it was not found.
|
||||||
|
*/
|
||||||
|
extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a record from the table.
|
||||||
|
* If a callback free function is provided then it is called for the
|
||||||
|
* for the item being deleted.
|
||||||
|
* @param t the table to delete from.
|
||||||
|
* @param k a pointer to the key to delete.
|
||||||
|
* @return 0 if the item was deleted.
|
||||||
|
* @return -1 if it was not found.
|
||||||
|
*/
|
||||||
|
extern int lh_table_delete(struct lh_table *t, const void *k);
|
||||||
|
|
||||||
|
extern int lh_table_length(struct lh_table *t);
|
||||||
|
|
||||||
|
void lh_abort(const char *msg, ...);
|
||||||
|
void lh_table_resize(struct lh_table *t, int new_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
192
3P/json/printbuf.c
Normal file
192
3P/json/printbuf.c
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||||
|
* The copyrights to the contents of this file are licensed under the MIT License
|
||||||
|
* (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STDARG_H
|
||||||
|
# include <stdarg.h>
|
||||||
|
#else /* !HAVE_STDARG_H */
|
||||||
|
# error Not enough var arg support!
|
||||||
|
#endif /* HAVE_STDARG_H */
|
||||||
|
|
||||||
|
#include "bits.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
|
||||||
|
static int printbuf_extend(struct printbuf *p, int min_size);
|
||||||
|
|
||||||
|
struct printbuf* printbuf_new(void)
|
||||||
|
{
|
||||||
|
struct printbuf *p;
|
||||||
|
|
||||||
|
p = (struct printbuf*)calloc(1, sizeof(struct printbuf));
|
||||||
|
if(!p) return NULL;
|
||||||
|
p->size = 32;
|
||||||
|
p->bpos = 0;
|
||||||
|
if(!(p->buf = (char*)malloc(p->size))) {
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend the buffer p so it has a size of at least min_size.
|
||||||
|
*
|
||||||
|
* If the current size is large enough, nothing is changed.
|
||||||
|
*
|
||||||
|
* Note: this does not check the available space! The caller
|
||||||
|
* is responsible for performing those calculations.
|
||||||
|
*/
|
||||||
|
static int printbuf_extend(struct printbuf *p, int min_size)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
int new_size;
|
||||||
|
|
||||||
|
if (p->size >= min_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
new_size = json_max(p->size * 2, min_size + 8);
|
||||||
|
#ifdef PRINTBUF_DEBUG
|
||||||
|
MC_DEBUG("printbuf_memappend: realloc "
|
||||||
|
"bpos=%d min_size=%d old_size=%d new_size=%d\n",
|
||||||
|
p->bpos, min_size, p->size, new_size);
|
||||||
|
#endif /* PRINTBUF_DEBUG */
|
||||||
|
if(!(t = (char*)realloc(p->buf, new_size)))
|
||||||
|
return -1;
|
||||||
|
p->size = new_size;
|
||||||
|
p->buf = t;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
|
||||||
|
{
|
||||||
|
if (p->size <= p->bpos + size + 1) {
|
||||||
|
if (printbuf_extend(p, p->bpos + size + 1) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(p->buf + p->bpos, buf, size);
|
||||||
|
p->bpos += size;
|
||||||
|
p->buf[p->bpos]= '\0';
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
|
||||||
|
{
|
||||||
|
int size_needed;
|
||||||
|
|
||||||
|
if (offset == -1)
|
||||||
|
offset = pb->bpos;
|
||||||
|
size_needed = offset + len;
|
||||||
|
if (pb->size < size_needed)
|
||||||
|
{
|
||||||
|
if (printbuf_extend(pb, size_needed) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(pb->buf + offset, charvalue, len);
|
||||||
|
if (pb->bpos < size_needed)
|
||||||
|
pb->bpos = size_needed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER)
|
||||||
|
# define vsnprintf _vsnprintf
|
||||||
|
#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */
|
||||||
|
# error Need vsnprintf!
|
||||||
|
#endif /* !HAVE_VSNPRINTF && defined(WIN32) */
|
||||||
|
|
||||||
|
#if !defined(HAVE_VASPRINTF)
|
||||||
|
/* CAW: compliant version of vasprintf */
|
||||||
|
static int vasprintf(char **buf, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
#ifndef WIN32
|
||||||
|
static char _T_emptybuffer = '\0';
|
||||||
|
#endif /* !defined(WIN32) */
|
||||||
|
int chars;
|
||||||
|
char *b;
|
||||||
|
|
||||||
|
if(!buf) { return -1; }
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
chars = _vscprintf(fmt, ap)+1;
|
||||||
|
#else /* !defined(WIN32) */
|
||||||
|
/* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
|
||||||
|
our buffer like on some 64bit sun systems.... but hey, its time to move on */
|
||||||
|
chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
|
||||||
|
if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
|
||||||
|
#endif /* defined(WIN32) */
|
||||||
|
|
||||||
|
b = (char*)malloc(sizeof(char)*chars);
|
||||||
|
if(!b) { return -1; }
|
||||||
|
|
||||||
|
if((chars = vsprintf(b, fmt, ap)) < 0)
|
||||||
|
{
|
||||||
|
free(b);
|
||||||
|
} else {
|
||||||
|
*buf = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_VASPRINTF */
|
||||||
|
|
||||||
|
int sprintbuf(struct printbuf *p, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *t;
|
||||||
|
int size;
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
/* user stack buffer first */
|
||||||
|
va_start(ap, msg);
|
||||||
|
size = vsnprintf(buf, 128, msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
/* if string is greater than stack buffer, then use dynamic string
|
||||||
|
with vasprintf. Note: some implementation of vsnprintf return -1
|
||||||
|
if output is truncated whereas some return the number of bytes that
|
||||||
|
would have been written - this code handles both cases. */
|
||||||
|
if(size == -1 || size > 127) {
|
||||||
|
va_start(ap, msg);
|
||||||
|
if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
|
||||||
|
va_end(ap);
|
||||||
|
printbuf_memappend(p, t, size);
|
||||||
|
free(t);
|
||||||
|
return size;
|
||||||
|
} else {
|
||||||
|
printbuf_memappend(p, buf, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printbuf_reset(struct printbuf *p)
|
||||||
|
{
|
||||||
|
p->buf[0] = '\0';
|
||||||
|
p->bpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printbuf_free(struct printbuf *p)
|
||||||
|
{
|
||||||
|
if(p) {
|
||||||
|
free(p->buf);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
3P/json/printbuf.h
Normal file
77
3P/json/printbuf.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
|
||||||
|
* Michael Clark <michael@metaparadigm.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See COPYING for details.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
|
||||||
|
* The copyrights to the contents of this file are licensed under the MIT License
|
||||||
|
* (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _printbuf_h_
|
||||||
|
#define _printbuf_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct printbuf {
|
||||||
|
char *buf;
|
||||||
|
int bpos;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct printbuf*
|
||||||
|
printbuf_new(void);
|
||||||
|
|
||||||
|
/* As an optimization, printbuf_memappend_fast is defined as a macro
|
||||||
|
* that handles copying data if the buffer is large enough; otherwise
|
||||||
|
* it invokes printbuf_memappend_real() which performs the heavy
|
||||||
|
* lifting of realloc()ing the buffer and copying data.
|
||||||
|
* Your code should not use printbuf_memappend directly--use
|
||||||
|
* printbuf_memappend_fast instead.
|
||||||
|
*/
|
||||||
|
extern int
|
||||||
|
printbuf_memappend(struct printbuf *p, const char *buf, int size);
|
||||||
|
|
||||||
|
#define printbuf_memappend_fast(p, bufptr, bufsize) \
|
||||||
|
do { \
|
||||||
|
if ((p->size - p->bpos) > bufsize) { \
|
||||||
|
memcpy(p->buf + p->bpos, (bufptr), bufsize); \
|
||||||
|
p->bpos += bufsize; \
|
||||||
|
p->buf[p->bpos]= '\0'; \
|
||||||
|
} else { printbuf_memappend(p, (bufptr), bufsize); } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define printbuf_length(p) ((p)->bpos)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set len bytes of the buffer to charvalue, starting at offset offset.
|
||||||
|
* Similar to calling memset(x, charvalue, len);
|
||||||
|
*
|
||||||
|
* The memory allocated for the buffer is extended as necessary.
|
||||||
|
*
|
||||||
|
* If offset is -1, this starts at the end of the current data in the buffer.
|
||||||
|
*/
|
||||||
|
extern int
|
||||||
|
printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
sprintbuf(struct printbuf *p, const char *msg, ...);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
printbuf_reset(struct printbuf *p);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
printbuf_free(struct printbuf *p);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
59
3P/json/tests/Makefile.am
Normal file
59
3P/json/tests/Makefile.am
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
include ../Makefile.am.inc
|
||||||
|
|
||||||
|
LIBJSON_LA=$(top_builddir)/libjson-c.la
|
||||||
|
|
||||||
|
check_PROGRAMS = test1 test1Formatted
|
||||||
|
check_PROGRAMS += test2 test2Formatted
|
||||||
|
check_PROGRAMS += test4
|
||||||
|
check_PROGRAMS += testReplaceExisting
|
||||||
|
check_PROGRAMS += test_parse_int64
|
||||||
|
check_PROGRAMS += test_null
|
||||||
|
check_PROGRAMS += test_cast
|
||||||
|
check_PROGRAMS += test_parse
|
||||||
|
check_PROGRAMS += test_locale
|
||||||
|
|
||||||
|
test1_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test1Formatted_LDADD= $(LIBJSON_LA)
|
||||||
|
test1Formatted_SOURCES = test1.c parse_flags.c
|
||||||
|
test1Formatted_CPPFLAGS = -DTEST_FORMATTED
|
||||||
|
|
||||||
|
test2_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test2Formatted_LDADD= $(LIBJSON_LA)
|
||||||
|
test2Formatted_SOURCES = test2.c parse_flags.c
|
||||||
|
test2Formatted_CPPFLAGS = -DTEST_FORMATTED
|
||||||
|
|
||||||
|
test4_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
testReplaceExisting_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test_parse_int64_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test_null_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test_cast_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test_parse_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
test_locale_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test
|
||||||
|
|
||||||
|
TESTS+= test_printbuf.test
|
||||||
|
check_PROGRAMS+=test_printbuf
|
||||||
|
test_printbuf_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
TESTS+= test_set_serializer.test
|
||||||
|
check_PROGRAMS += test_set_serializer
|
||||||
|
test_set_serializer_LDADD = $(LIBJSON_LA)
|
||||||
|
|
||||||
|
EXTRA_DIST=
|
||||||
|
EXTRA_DIST += $(TESTS)
|
||||||
|
|
||||||
|
testsubdir=testSubDir
|
||||||
|
TESTS_ENVIRONMENT = top_builddir=$(top_builddir)
|
||||||
|
|
||||||
|
distclean-local:
|
||||||
|
-rm -rf $(testsubdir)
|
||||||
50
3P/json/tests/parse_flags.c
Normal file
50
3P/json/tests/parse_flags.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "parse_flags.h"
|
||||||
|
|
||||||
|
#if !defined(HAVE_STRCASECMP) && defined(_MSC_VER)
|
||||||
|
# define strcasecmp _stricmp
|
||||||
|
#elif !defined(HAVE_STRCASECMP)
|
||||||
|
# error You do not have strcasecmp on your system.
|
||||||
|
#endif /* HAVE_STRNCASECMP */
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *arg;
|
||||||
|
int flag;
|
||||||
|
} format_args[] = {
|
||||||
|
{ "plain", JSON_C_TO_STRING_PLAIN },
|
||||||
|
{ "spaced", JSON_C_TO_STRING_SPACED },
|
||||||
|
{ "pretty", JSON_C_TO_STRING_PRETTY },
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NELEM
|
||||||
|
#define NELEM(x) (sizeof(x) / sizeof(&x[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int parse_flags(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int arg_idx;
|
||||||
|
int sflags = 0;
|
||||||
|
for (arg_idx = 1; arg_idx < argc ; arg_idx++)
|
||||||
|
{
|
||||||
|
int jj;
|
||||||
|
for (jj = 0; jj < (int)NELEM(format_args); jj++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(argv[arg_idx], format_args[jj].arg) == 0)
|
||||||
|
{
|
||||||
|
sflags |= format_args[jj].flag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jj == NELEM(format_args))
|
||||||
|
{
|
||||||
|
printf("Unknown arg: %s\n", argv[arg_idx]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sflags;
|
||||||
|
}
|
||||||
4
3P/json/tests/parse_flags.h
Normal file
4
3P/json/tests/parse_flags.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#ifndef __parse_flags_h
|
||||||
|
#define __parse_flags_h
|
||||||
|
int parse_flags(int argc, char **argv);
|
||||||
|
#endif
|
||||||
12
3P/json/tests/parse_int64.test
Executable file
12
3P/json/tests/parse_int64.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_parse_int64
|
||||||
|
exit $?
|
||||||
128
3P/json/tests/test-defs.sh
Executable file
128
3P/json/tests/test-defs.sh
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Make sure srcdir is an absolute path. Supply the variable
|
||||||
|
# if it does not exist. We want to be able to run the tests
|
||||||
|
# stand-alone!!
|
||||||
|
#
|
||||||
|
srcdir=${srcdir-.}
|
||||||
|
if test ! -d $srcdir ; then
|
||||||
|
echo "test-defs.sh: installation error" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use absolute paths
|
||||||
|
case "$srcdir" in
|
||||||
|
/* | [A-Za-z]:\\*) ;;
|
||||||
|
*) srcdir=`\cd $srcdir && pwd` ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$top_builddir" in
|
||||||
|
/* | [A-Za-z]:\\*) ;;
|
||||||
|
*) top_builddir=`\cd ${top_builddir-..} && pwd` ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
top_builddir=${top_builddir}/tests
|
||||||
|
|
||||||
|
progname=`echo "$0" | sed 's,^.*/,,'`
|
||||||
|
testname=`echo "$progname" | sed 's,-.*$,,'`
|
||||||
|
testsubdir=${testsubdir-testSubDir}
|
||||||
|
testsubdir=${testsubdir}/${progname}
|
||||||
|
|
||||||
|
# User can set VERBOSE to cause output redirection
|
||||||
|
case "$VERBOSE" in
|
||||||
|
[Nn]|[Nn][Oo]|0|"")
|
||||||
|
VERBOSE=0
|
||||||
|
exec > /dev/null
|
||||||
|
;;
|
||||||
|
[Yy]|[Yy][Ee][Ss])
|
||||||
|
VERBOSE=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
rm -rf "$testsubdir" > /dev/null 2>&1
|
||||||
|
mkdir -p "$testsubdir"
|
||||||
|
CURDIR=$(pwd)
|
||||||
|
cd "$testsubdir" \
|
||||||
|
|| { echo "Cannot make or change into $testsubdir"; exit 1; }
|
||||||
|
|
||||||
|
echo "=== Running test $progname"
|
||||||
|
|
||||||
|
CMP="${CMP-cmp}"
|
||||||
|
|
||||||
|
use_valgrind=${USE_VALGRIND-1}
|
||||||
|
valgrind_path=$(which valgrind 2> /dev/null)
|
||||||
|
if [ -z "${valgrind_path}" -o ! -x "${valgrind_path}" ] ; then
|
||||||
|
use_valgrind=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# This is a common function to check the results of a test program
|
||||||
|
# that is intended to generate consistent output across runs.
|
||||||
|
#
|
||||||
|
# ${top_builddir} must be set to the top level build directory.
|
||||||
|
#
|
||||||
|
# Output will be written to the current directory.
|
||||||
|
#
|
||||||
|
# It must be passed the name of the test command to run, which must be present
|
||||||
|
# in the ${top_builddir} directory.
|
||||||
|
#
|
||||||
|
# It will compare the output of running that against <name of command>.expected
|
||||||
|
#
|
||||||
|
run_output_test()
|
||||||
|
{
|
||||||
|
if [ "$1" = "-o" ] ; then
|
||||||
|
TEST_OUTPUT="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
TEST_COMMAND="$1"
|
||||||
|
shift
|
||||||
|
if [ -z "${TEST_OUTPUT}" ] ; then
|
||||||
|
TEST_OUTPUT=${TEST_COMMAND}
|
||||||
|
fi
|
||||||
|
|
||||||
|
REDIR_OUTPUT="> \"${TEST_OUTPUT}.out\""
|
||||||
|
if [ $VERBOSE -gt 1 ] ; then
|
||||||
|
REDIR_OUTPUT="| tee \"${TEST_OUTPUT}.out\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $use_valgrind -eq 1 ] ; then
|
||||||
|
eval valgrind --tool=memcheck \
|
||||||
|
--trace-children=yes \
|
||||||
|
--demangle=yes \
|
||||||
|
--log-file="${TEST_OUTPUT}.vg.out" \
|
||||||
|
--leak-check=full \
|
||||||
|
--show-reachable=yes \
|
||||||
|
--run-libc-freeres=yes \
|
||||||
|
"\"${top_builddir}/${TEST_COMMAND}\"" \"\$@\" ${REDIR_OUTPUT}
|
||||||
|
err=$?
|
||||||
|
|
||||||
|
else
|
||||||
|
eval "\"${top_builddir}/${TEST_COMMAND}"\" \"\$@\" ${REDIR_OUTPUT}
|
||||||
|
err=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $err -ne 0 ] ; then
|
||||||
|
echo "ERROR: \"${TEST_COMMAND} $@\" exited with non-zero exit status: $err" 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $use_valgrind -eq 1 ] ; then
|
||||||
|
if ! tail -1 "${TEST_OUTPUT}.vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then
|
||||||
|
echo "ERROR: valgrind found errors during execution:" 1>&2
|
||||||
|
cat "${TEST_OUTPUT}.vg.out"
|
||||||
|
err=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! "$CMP" -s "${top_builddir}/${TEST_OUTPUT}.expected" "${TEST_OUTPUT}.out" ; then
|
||||||
|
echo "ERROR: \"${TEST_COMMAND} $@\" (${TEST_OUTPUT}) failed (set VERBOSE=1 to see full output):" 1>&2
|
||||||
|
(cd "${CURDIR}" ; set -x ; diff "${top_builddir}/${TEST_OUTPUT}.expected" "$testsubdir/${TEST_OUTPUT}.out")
|
||||||
|
echo "cp \"$testsubdir/${TEST_OUTPUT}.out\" \"${top_builddir}/${TEST_OUTPUT}.expected\"" 1>&2
|
||||||
|
|
||||||
|
err=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
134
3P/json/tests/test1.c
Normal file
134
3P/json/tests/test1.c
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "parse_flags.h"
|
||||||
|
|
||||||
|
static int sort_fn (const void *j1, const void *j2)
|
||||||
|
{
|
||||||
|
json_object * const *jso1, * const *jso2;
|
||||||
|
int i1, i2;
|
||||||
|
|
||||||
|
jso1 = (json_object* const*)j1;
|
||||||
|
jso2 = (json_object* const*)j2;
|
||||||
|
if (!*jso1 && !*jso2)
|
||||||
|
return 0;
|
||||||
|
if (!*jso1)
|
||||||
|
return -1;
|
||||||
|
if (!*jso2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
i1 = json_object_get_int(*jso1);
|
||||||
|
i2 = json_object_get_int(*jso2);
|
||||||
|
|
||||||
|
return i1 - i2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
#define json_object_to_json_string(obj) json_object_to_json_string_ext(obj,sflags)
|
||||||
|
#else
|
||||||
|
/* no special define */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
json_object *my_string, *my_int, *my_object, *my_array;
|
||||||
|
int i;
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
int sflags = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
sflags = parse_flags(argc, argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
my_string = json_object_new_string("\t");
|
||||||
|
printf("my_string=%s\n", json_object_get_string(my_string));
|
||||||
|
printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string));
|
||||||
|
json_object_put(my_string);
|
||||||
|
|
||||||
|
my_string = json_object_new_string("\\");
|
||||||
|
printf("my_string=%s\n", json_object_get_string(my_string));
|
||||||
|
printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string));
|
||||||
|
json_object_put(my_string);
|
||||||
|
|
||||||
|
my_string = json_object_new_string("foo");
|
||||||
|
printf("my_string=%s\n", json_object_get_string(my_string));
|
||||||
|
printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string));
|
||||||
|
|
||||||
|
my_int = json_object_new_int(9);
|
||||||
|
printf("my_int=%d\n", json_object_get_int(my_int));
|
||||||
|
printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int));
|
||||||
|
|
||||||
|
my_array = json_object_new_array();
|
||||||
|
json_object_array_add(my_array, json_object_new_int(1));
|
||||||
|
json_object_array_add(my_array, json_object_new_int(2));
|
||||||
|
json_object_array_add(my_array, json_object_new_int(3));
|
||||||
|
json_object_array_put_idx(my_array, 4, json_object_new_int(5));
|
||||||
|
printf("my_array=\n");
|
||||||
|
for(i=0; i < json_object_array_length(my_array); i++)
|
||||||
|
{
|
||||||
|
json_object *obj = json_object_array_get_idx(my_array, i);
|
||||||
|
printf("\t[%d]=%s\n", i, json_object_to_json_string(obj));
|
||||||
|
}
|
||||||
|
printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array));
|
||||||
|
|
||||||
|
json_object_put(my_array);
|
||||||
|
|
||||||
|
my_array = json_object_new_array();
|
||||||
|
json_object_array_add(my_array, json_object_new_int(3));
|
||||||
|
json_object_array_add(my_array, json_object_new_int(1));
|
||||||
|
json_object_array_add(my_array, json_object_new_int(2));
|
||||||
|
json_object_array_put_idx(my_array, 4, json_object_new_int(0));
|
||||||
|
printf("my_array=\n");
|
||||||
|
for(i=0; i < json_object_array_length(my_array); i++)
|
||||||
|
{
|
||||||
|
json_object *obj = json_object_array_get_idx(my_array, i);
|
||||||
|
printf("\t[%d]=%s\n", i, json_object_to_json_string(obj));
|
||||||
|
}
|
||||||
|
printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array));
|
||||||
|
json_object_array_sort(my_array, sort_fn);
|
||||||
|
printf("my_array=\n");
|
||||||
|
for(i=0; i < json_object_array_length(my_array); i++)
|
||||||
|
{
|
||||||
|
json_object *obj = json_object_array_get_idx(my_array, i);
|
||||||
|
printf("\t[%d]=%s\n", i, json_object_to_json_string(obj));
|
||||||
|
}
|
||||||
|
printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array));
|
||||||
|
|
||||||
|
my_object = json_object_new_object();
|
||||||
|
json_object_object_add(my_object, "abc", json_object_new_int(12));
|
||||||
|
json_object_object_add(my_object, "foo", json_object_new_string("bar"));
|
||||||
|
json_object_object_add(my_object, "bool0", json_object_new_boolean(0));
|
||||||
|
json_object_object_add(my_object, "bool1", json_object_new_boolean(1));
|
||||||
|
json_object_object_add(my_object, "baz", json_object_new_string("bang"));
|
||||||
|
|
||||||
|
json_object *baz_obj = json_object_new_string("fark");
|
||||||
|
json_object_get(baz_obj);
|
||||||
|
json_object_object_add(my_object, "baz", baz_obj);
|
||||||
|
json_object_object_del(my_object, "baz");
|
||||||
|
|
||||||
|
/* baz_obj should still be valid */
|
||||||
|
printf("baz_obj.to_string()=%s\n", json_object_to_json_string(baz_obj));
|
||||||
|
json_object_put(baz_obj);
|
||||||
|
|
||||||
|
/*json_object_object_add(my_object, "arr", my_array);*/
|
||||||
|
printf("my_object=\n");
|
||||||
|
json_object_object_foreach(my_object, key, val)
|
||||||
|
{
|
||||||
|
printf("\t%s: %s\n", key, json_object_to_json_string(val));
|
||||||
|
}
|
||||||
|
printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object));
|
||||||
|
|
||||||
|
json_object_put(my_string);
|
||||||
|
json_object_put(my_int);
|
||||||
|
json_object_put(my_object);
|
||||||
|
json_object_put(my_array);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
36
3P/json/tests/test1.expected
Normal file
36
3P/json/tests/test1.expected
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
my_string=
|
||||||
|
my_string.to_string()="\t"
|
||||||
|
my_string=\
|
||||||
|
my_string.to_string()="\\"
|
||||||
|
my_string=foo
|
||||||
|
my_string.to_string()="foo"
|
||||||
|
my_int=9
|
||||||
|
my_int.to_string()=9
|
||||||
|
my_array=
|
||||||
|
[0]=1
|
||||||
|
[1]=2
|
||||||
|
[2]=3
|
||||||
|
[3]=null
|
||||||
|
[4]=5
|
||||||
|
my_array.to_string()=[ 1, 2, 3, null, 5 ]
|
||||||
|
my_array=
|
||||||
|
[0]=3
|
||||||
|
[1]=1
|
||||||
|
[2]=2
|
||||||
|
[3]=null
|
||||||
|
[4]=0
|
||||||
|
my_array.to_string()=[ 3, 1, 2, null, 0 ]
|
||||||
|
my_array=
|
||||||
|
[0]=null
|
||||||
|
[1]=0
|
||||||
|
[2]=1
|
||||||
|
[3]=2
|
||||||
|
[4]=3
|
||||||
|
my_array.to_string()=[ null, 0, 1, 2, 3 ]
|
||||||
|
baz_obj.to_string()="fark"
|
||||||
|
my_object=
|
||||||
|
abc: 12
|
||||||
|
foo: "bar"
|
||||||
|
bool0: false
|
||||||
|
bool1: true
|
||||||
|
my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
|
||||||
22
3P/json/tests/test1.test
Executable file
22
3P/json/tests/test1.test
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test1
|
||||||
|
_err=$?
|
||||||
|
|
||||||
|
for flag in plain spaced pretty ; do
|
||||||
|
run_output_test -o test1Formatted_${flag} test1Formatted ${flag}
|
||||||
|
_err2=$?
|
||||||
|
if [ $_err -eq 0 ] ; then
|
||||||
|
_err=$_err2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $_err
|
||||||
36
3P/json/tests/test1Formatted_plain.expected
Normal file
36
3P/json/tests/test1Formatted_plain.expected
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
my_string=
|
||||||
|
my_string.to_string()="\t"
|
||||||
|
my_string=\
|
||||||
|
my_string.to_string()="\\"
|
||||||
|
my_string=foo
|
||||||
|
my_string.to_string()="foo"
|
||||||
|
my_int=9
|
||||||
|
my_int.to_string()=9
|
||||||
|
my_array=
|
||||||
|
[0]=1
|
||||||
|
[1]=2
|
||||||
|
[2]=3
|
||||||
|
[3]=null
|
||||||
|
[4]=5
|
||||||
|
my_array.to_string()=[1,2,3,null,5]
|
||||||
|
my_array=
|
||||||
|
[0]=3
|
||||||
|
[1]=1
|
||||||
|
[2]=2
|
||||||
|
[3]=null
|
||||||
|
[4]=0
|
||||||
|
my_array.to_string()=[3,1,2,null,0]
|
||||||
|
my_array=
|
||||||
|
[0]=null
|
||||||
|
[1]=0
|
||||||
|
[2]=1
|
||||||
|
[3]=2
|
||||||
|
[4]=3
|
||||||
|
my_array.to_string()=[null,0,1,2,3]
|
||||||
|
baz_obj.to_string()="fark"
|
||||||
|
my_object=
|
||||||
|
abc: 12
|
||||||
|
foo: "bar"
|
||||||
|
bool0: false
|
||||||
|
bool1: true
|
||||||
|
my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true}
|
||||||
59
3P/json/tests/test1Formatted_pretty.expected
Normal file
59
3P/json/tests/test1Formatted_pretty.expected
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
my_string=
|
||||||
|
my_string.to_string()="\t"
|
||||||
|
my_string=\
|
||||||
|
my_string.to_string()="\\"
|
||||||
|
my_string=foo
|
||||||
|
my_string.to_string()="foo"
|
||||||
|
my_int=9
|
||||||
|
my_int.to_string()=9
|
||||||
|
my_array=
|
||||||
|
[0]=1
|
||||||
|
[1]=2
|
||||||
|
[2]=3
|
||||||
|
[3]=null
|
||||||
|
[4]=5
|
||||||
|
my_array.to_string()=[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
null,
|
||||||
|
5
|
||||||
|
]
|
||||||
|
my_array=
|
||||||
|
[0]=3
|
||||||
|
[1]=1
|
||||||
|
[2]=2
|
||||||
|
[3]=null
|
||||||
|
[4]=0
|
||||||
|
my_array.to_string()=[
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
null,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
my_array=
|
||||||
|
[0]=null
|
||||||
|
[1]=0
|
||||||
|
[2]=1
|
||||||
|
[3]=2
|
||||||
|
[4]=3
|
||||||
|
my_array.to_string()=[
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
]
|
||||||
|
baz_obj.to_string()="fark"
|
||||||
|
my_object=
|
||||||
|
abc: 12
|
||||||
|
foo: "bar"
|
||||||
|
bool0: false
|
||||||
|
bool1: true
|
||||||
|
my_object.to_string()={
|
||||||
|
"abc":12,
|
||||||
|
"foo":"bar",
|
||||||
|
"bool0":false,
|
||||||
|
"bool1":true
|
||||||
|
}
|
||||||
36
3P/json/tests/test1Formatted_spaced.expected
Normal file
36
3P/json/tests/test1Formatted_spaced.expected
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
my_string=
|
||||||
|
my_string.to_string()="\t"
|
||||||
|
my_string=\
|
||||||
|
my_string.to_string()="\\"
|
||||||
|
my_string=foo
|
||||||
|
my_string.to_string()="foo"
|
||||||
|
my_int=9
|
||||||
|
my_int.to_string()=9
|
||||||
|
my_array=
|
||||||
|
[0]=1
|
||||||
|
[1]=2
|
||||||
|
[2]=3
|
||||||
|
[3]=null
|
||||||
|
[4]=5
|
||||||
|
my_array.to_string()=[ 1, 2, 3, null, 5 ]
|
||||||
|
my_array=
|
||||||
|
[0]=3
|
||||||
|
[1]=1
|
||||||
|
[2]=2
|
||||||
|
[3]=null
|
||||||
|
[4]=0
|
||||||
|
my_array.to_string()=[ 3, 1, 2, null, 0 ]
|
||||||
|
my_array=
|
||||||
|
[0]=null
|
||||||
|
[1]=0
|
||||||
|
[2]=1
|
||||||
|
[3]=2
|
||||||
|
[4]=3
|
||||||
|
my_array.to_string()=[ null, 0, 1, 2, 3 ]
|
||||||
|
baz_obj.to_string()="fark"
|
||||||
|
my_object=
|
||||||
|
abc: 12
|
||||||
|
foo: "bar"
|
||||||
|
bool0: false
|
||||||
|
bool1: true
|
||||||
|
my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
|
||||||
34
3P/json/tests/test2.c
Normal file
34
3P/json/tests/test2.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "parse_flags.h"
|
||||||
|
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
#define json_object_to_json_string(obj) json_object_to_json_string_ext(obj,sflags)
|
||||||
|
#else
|
||||||
|
/* no special define */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
json_object *new_obj;
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
int sflags = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
#ifdef TEST_FORMATTED
|
||||||
|
sflags = parse_flags(argc, argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
3P/json/tests/test2.expected
Normal file
1
3P/json/tests/test2.expected
Normal file
@@ -0,0 +1 @@
|
|||||||
|
new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }
|
||||||
22
3P/json/tests/test2.test
Executable file
22
3P/json/tests/test2.test
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test2
|
||||||
|
_err=$?
|
||||||
|
|
||||||
|
for flag in plain spaced pretty ; do
|
||||||
|
run_output_test -o test2Formatted_${flag} test2Formatted ${flag}
|
||||||
|
_err2=$?
|
||||||
|
if [ $_err -eq 0 ] ; then
|
||||||
|
_err=$_err2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $_err
|
||||||
1
3P/json/tests/test2Formatted_plain.expected
Normal file
1
3P/json/tests/test2Formatted_plain.expected
Normal file
@@ -0,0 +1 @@
|
|||||||
|
new_obj.to_string()={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":[{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML","markup"]}]}}}
|
||||||
23
3P/json/tests/test2Formatted_pretty.expected
Normal file
23
3P/json/tests/test2Formatted_pretty.expected
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
new_obj.to_string()={
|
||||||
|
"glossary":{
|
||||||
|
"title":"example glossary",
|
||||||
|
"GlossDiv":{
|
||||||
|
"title":"S",
|
||||||
|
"GlossList":[
|
||||||
|
{
|
||||||
|
"ID":"SGML",
|
||||||
|
"SortAs":"SGML",
|
||||||
|
"GlossTerm":"Standard Generalized Markup Language",
|
||||||
|
"Acronym":"SGML",
|
||||||
|
"Abbrev":"ISO 8879:1986",
|
||||||
|
"GlossDef":"A meta-markup language, used to create markup languages such as DocBook.",
|
||||||
|
"GlossSeeAlso":[
|
||||||
|
"GML",
|
||||||
|
"XML",
|
||||||
|
"markup"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
3P/json/tests/test2Formatted_spaced.expected
Normal file
1
3P/json/tests/test2Formatted_spaced.expected
Normal file
@@ -0,0 +1 @@
|
|||||||
|
new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }
|
||||||
53
3P/json/tests/test4.c
Normal file
53
3P/json/tests/test4.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
|
||||||
|
void print_hex( const char* s)
|
||||||
|
{
|
||||||
|
const char *iter = s;
|
||||||
|
unsigned char ch;
|
||||||
|
while ((ch = *iter++) != 0)
|
||||||
|
{
|
||||||
|
if( ',' != ch)
|
||||||
|
printf("%x ", ch);
|
||||||
|
else
|
||||||
|
printf( ",");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\"";
|
||||||
|
const char *expected = "\xF0\xA0\x84\xA6,\xF0\xA0\x84\xA7,\xF0\x90\x84\xA6,\xF0\x90\x84\xA7";
|
||||||
|
struct json_object *parse_result = json_tokener_parse((char*)input);
|
||||||
|
const char *unjson = json_object_get_string(parse_result);
|
||||||
|
|
||||||
|
printf("input: %s\n", input);
|
||||||
|
|
||||||
|
int strings_match = !strcmp( expected, unjson);
|
||||||
|
int retval = 0;
|
||||||
|
if (strings_match)
|
||||||
|
{
|
||||||
|
printf("JSON parse result is correct: %s\n", unjson);
|
||||||
|
printf("PASS\n");
|
||||||
|
} else {
|
||||||
|
printf("JSON parse result doesn't match expected string\n");
|
||||||
|
printf("expected string bytes: ");
|
||||||
|
print_hex( expected);
|
||||||
|
printf("parsed string bytes: ");
|
||||||
|
print_hex( unjson);
|
||||||
|
printf("FAIL\n");
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
json_object_put(parse_result);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
3
3P/json/tests/test4.expected
Normal file
3
3P/json/tests/test4.expected
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27"
|
||||||
|
JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧
|
||||||
|
PASS
|
||||||
12
3P/json/tests/test4.test
Executable file
12
3P/json/tests/test4.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test4
|
||||||
|
exit $?
|
||||||
78
3P/json/tests/testReplaceExisting.c
Normal file
78
3P/json/tests/testReplaceExisting.c
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that replacing an existing object keeps the key valid,
|
||||||
|
* and that it keeps the order the same.
|
||||||
|
*/
|
||||||
|
json_object *my_object = json_object_new_object();
|
||||||
|
json_object_object_add(my_object, "foo1", json_object_new_string("bar1"));
|
||||||
|
json_object_object_add(my_object, "foo2", json_object_new_string("bar2"));
|
||||||
|
json_object_object_add(my_object, "deleteme", json_object_new_string("bar2"));
|
||||||
|
json_object_object_add(my_object, "foo3", json_object_new_string("bar3"));
|
||||||
|
|
||||||
|
printf("==== delete-in-loop test starting ====\n");
|
||||||
|
|
||||||
|
int orig_count = 0;
|
||||||
|
json_object_object_foreach(my_object, key0, val0)
|
||||||
|
{
|
||||||
|
printf("Key at index %d is [%s]", orig_count, key0);
|
||||||
|
if (strcmp(key0, "deleteme") == 0)
|
||||||
|
{
|
||||||
|
json_object_object_del(my_object, key0);
|
||||||
|
printf(" (deleted)\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf(" (kept)\n");
|
||||||
|
orig_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("==== replace-value first loop starting ====\n");
|
||||||
|
|
||||||
|
const char *original_key = NULL;
|
||||||
|
orig_count = 0;
|
||||||
|
json_object_object_foreach(my_object, key, val)
|
||||||
|
{
|
||||||
|
printf("Key at index %d is [%s]\n", orig_count, key);
|
||||||
|
orig_count++;
|
||||||
|
if (strcmp(key, "foo2") != 0)
|
||||||
|
continue;
|
||||||
|
printf("replacing value for key [%s]\n", key);
|
||||||
|
original_key = key;
|
||||||
|
json_object_object_add(my_object, key, json_object_new_string("zzz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("==== second loop starting ====\n");
|
||||||
|
|
||||||
|
int new_count = 0;
|
||||||
|
int retval = 0;
|
||||||
|
json_object_object_foreach(my_object, key2, val2)
|
||||||
|
{
|
||||||
|
printf("Key at index %d is [%s]\n", new_count, key2);
|
||||||
|
new_count++;
|
||||||
|
if (strcmp(key2, "foo2") != 0)
|
||||||
|
continue;
|
||||||
|
printf("pointer for key [%s] does %smatch\n", key2,
|
||||||
|
(key2 == original_key) ? "" : "NOT ");
|
||||||
|
if (key2 != original_key)
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
if (new_count != orig_count)
|
||||||
|
{
|
||||||
|
printf("mismatch between original count (%d) and new count (%d)\n",
|
||||||
|
orig_count, new_count);
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_put( my_object );
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
15
3P/json/tests/testReplaceExisting.expected
Normal file
15
3P/json/tests/testReplaceExisting.expected
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
==== delete-in-loop test starting ====
|
||||||
|
Key at index 0 is [foo1] (kept)
|
||||||
|
Key at index 1 is [foo2] (kept)
|
||||||
|
Key at index 2 is [deleteme] (deleted)
|
||||||
|
Key at index 3 is [foo3] (kept)
|
||||||
|
==== replace-value first loop starting ====
|
||||||
|
Key at index 0 is [foo1]
|
||||||
|
Key at index 1 is [foo2]
|
||||||
|
replacing value for key [foo2]
|
||||||
|
Key at index 2 is [foo3]
|
||||||
|
==== second loop starting ====
|
||||||
|
Key at index 0 is [foo1]
|
||||||
|
Key at index 1 is [foo2]
|
||||||
|
pointer for key [foo2] does match
|
||||||
|
Key at index 2 is [foo3]
|
||||||
12
3P/json/tests/testReplaceExisting.test
Executable file
12
3P/json/tests/testReplaceExisting.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test testReplaceExisting
|
||||||
|
exit $?
|
||||||
106
3P/json/tests/test_cast.c
Normal file
106
3P/json/tests/test_cast.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Tests if casting within the json_object_get_* functions work correctly.
|
||||||
|
* Also checks the json_object_get_type and json_object_is_type functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
static void getit(struct json_object *new_obj, const char *field);
|
||||||
|
static void checktype_header(void);
|
||||||
|
static void checktype(struct json_object *new_obj, const char *field);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *input = "{\n\
|
||||||
|
\"string_of_digits\": \"123\",\n\
|
||||||
|
\"regular_number\": 222,\n\
|
||||||
|
\"decimal_number\": 99.55,\n\
|
||||||
|
\"boolean_true\": true,\n\
|
||||||
|
\"boolean_false\": false,\n\
|
||||||
|
\"big_number\": 2147483649,\n\
|
||||||
|
\"a_null\": null,\n\
|
||||||
|
}";
|
||||||
|
/* Note: 2147483649 = INT_MAX + 2 */
|
||||||
|
|
||||||
|
struct json_object *new_obj;
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse(input);
|
||||||
|
printf("Parsed input: %s\n", input);
|
||||||
|
printf("Result is %s\n", (new_obj == NULL) ? "NULL (error!)" : "not NULL");
|
||||||
|
if (!new_obj)
|
||||||
|
return 1; // oops, we failed.
|
||||||
|
|
||||||
|
getit(new_obj, "string_of_digits");
|
||||||
|
getit(new_obj, "regular_number");
|
||||||
|
getit(new_obj, "decimal_number");
|
||||||
|
getit(new_obj, "boolean_true");
|
||||||
|
getit(new_obj, "boolean_false");
|
||||||
|
getit(new_obj, "big_number");
|
||||||
|
getit(new_obj, "a_null");
|
||||||
|
|
||||||
|
// Now check the behaviour of the json_object_is_type() function.
|
||||||
|
printf("\n================================\n");
|
||||||
|
checktype_header();
|
||||||
|
checktype(new_obj, NULL);
|
||||||
|
checktype(new_obj, "string_of_digits");
|
||||||
|
checktype(new_obj, "regular_number");
|
||||||
|
checktype(new_obj, "decimal_number");
|
||||||
|
checktype(new_obj, "boolean_true");
|
||||||
|
checktype(new_obj, "boolean_false");
|
||||||
|
checktype(new_obj, "big_number");
|
||||||
|
checktype(new_obj, "a_null");
|
||||||
|
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getit(struct json_object *new_obj, const char *field)
|
||||||
|
{
|
||||||
|
struct json_object *o = json_object_object_get(new_obj, field);
|
||||||
|
|
||||||
|
enum json_type o_type = json_object_get_type(o);
|
||||||
|
printf("new_obj.%s json_object_get_type()=%s\n", field,
|
||||||
|
json_type_to_name(o_type));
|
||||||
|
printf("new_obj.%s json_object_get_int()=%d\n", field,
|
||||||
|
json_object_get_int(o));
|
||||||
|
printf("new_obj.%s json_object_get_int64()=%" PRId64 "\n", field,
|
||||||
|
json_object_get_int64(o));
|
||||||
|
printf("new_obj.%s json_object_get_boolean()=%d\n", field,
|
||||||
|
json_object_get_boolean(o));
|
||||||
|
printf("new_obj.%s json_object_get_double()=%f\n", field,
|
||||||
|
json_object_get_double(o));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checktype_header()
|
||||||
|
{
|
||||||
|
printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n",
|
||||||
|
json_type_to_name(json_type_null),
|
||||||
|
json_type_to_name(json_type_boolean),
|
||||||
|
json_type_to_name(json_type_double),
|
||||||
|
json_type_to_name(json_type_int),
|
||||||
|
json_type_to_name(json_type_object),
|
||||||
|
json_type_to_name(json_type_array),
|
||||||
|
json_type_to_name(json_type_string));
|
||||||
|
}
|
||||||
|
static void checktype(struct json_object *new_obj, const char *field)
|
||||||
|
{
|
||||||
|
struct json_object *o = field ? json_object_object_get(new_obj, field) : new_obj;
|
||||||
|
printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n",
|
||||||
|
field ? "." : " ", field ? field : "",
|
||||||
|
json_object_is_type(o, json_type_null),
|
||||||
|
json_object_is_type(o, json_type_boolean),
|
||||||
|
json_object_is_type(o, json_type_double),
|
||||||
|
json_object_is_type(o, json_type_int),
|
||||||
|
json_object_is_type(o, json_type_object),
|
||||||
|
json_object_is_type(o, json_type_array),
|
||||||
|
json_object_is_type(o, json_type_string));
|
||||||
|
}
|
||||||
56
3P/json/tests/test_cast.expected
Normal file
56
3P/json/tests/test_cast.expected
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Parsed input: {
|
||||||
|
"string_of_digits": "123",
|
||||||
|
"regular_number": 222,
|
||||||
|
"decimal_number": 99.55,
|
||||||
|
"boolean_true": true,
|
||||||
|
"boolean_false": false,
|
||||||
|
"big_number": 2147483649,
|
||||||
|
"a_null": null,
|
||||||
|
}
|
||||||
|
Result is not NULL
|
||||||
|
new_obj.string_of_digits json_object_get_type()=string
|
||||||
|
new_obj.string_of_digits json_object_get_int()=123
|
||||||
|
new_obj.string_of_digits json_object_get_int64()=123
|
||||||
|
new_obj.string_of_digits json_object_get_boolean()=1
|
||||||
|
new_obj.string_of_digits json_object_get_double()=123.000000
|
||||||
|
new_obj.regular_number json_object_get_type()=int
|
||||||
|
new_obj.regular_number json_object_get_int()=222
|
||||||
|
new_obj.regular_number json_object_get_int64()=222
|
||||||
|
new_obj.regular_number json_object_get_boolean()=1
|
||||||
|
new_obj.regular_number json_object_get_double()=222.000000
|
||||||
|
new_obj.decimal_number json_object_get_type()=double
|
||||||
|
new_obj.decimal_number json_object_get_int()=99
|
||||||
|
new_obj.decimal_number json_object_get_int64()=99
|
||||||
|
new_obj.decimal_number json_object_get_boolean()=1
|
||||||
|
new_obj.decimal_number json_object_get_double()=99.550000
|
||||||
|
new_obj.boolean_true json_object_get_type()=boolean
|
||||||
|
new_obj.boolean_true json_object_get_int()=1
|
||||||
|
new_obj.boolean_true json_object_get_int64()=1
|
||||||
|
new_obj.boolean_true json_object_get_boolean()=1
|
||||||
|
new_obj.boolean_true json_object_get_double()=1.000000
|
||||||
|
new_obj.boolean_false json_object_get_type()=boolean
|
||||||
|
new_obj.boolean_false json_object_get_int()=0
|
||||||
|
new_obj.boolean_false json_object_get_int64()=0
|
||||||
|
new_obj.boolean_false json_object_get_boolean()=0
|
||||||
|
new_obj.boolean_false json_object_get_double()=0.000000
|
||||||
|
new_obj.big_number json_object_get_type()=int
|
||||||
|
new_obj.big_number json_object_get_int()=2147483647
|
||||||
|
new_obj.big_number json_object_get_int64()=2147483649
|
||||||
|
new_obj.big_number json_object_get_boolean()=1
|
||||||
|
new_obj.big_number json_object_get_double()=2147483649.000000
|
||||||
|
new_obj.a_null json_object_get_type()=null
|
||||||
|
new_obj.a_null json_object_get_int()=0
|
||||||
|
new_obj.a_null json_object_get_int64()=0
|
||||||
|
new_obj.a_null json_object_get_boolean()=0
|
||||||
|
new_obj.a_null json_object_get_double()=0.000000
|
||||||
|
|
||||||
|
================================
|
||||||
|
json_object_is_type: null,boolean,double,int,object,array,string
|
||||||
|
new_obj : 0,0,0,0,1,0,0
|
||||||
|
new_obj.string_of_digits : 0,0,0,0,0,0,1
|
||||||
|
new_obj.regular_number : 0,0,0,1,0,0,0
|
||||||
|
new_obj.decimal_number : 0,0,1,0,0,0,0
|
||||||
|
new_obj.boolean_true : 0,1,0,0,0,0,0
|
||||||
|
new_obj.boolean_false : 0,1,0,0,0,0,0
|
||||||
|
new_obj.big_number : 0,0,0,1,0,0,0
|
||||||
|
new_obj.a_null : 1,0,0,0,0,0,0
|
||||||
12
3P/json/tests/test_cast.test
Executable file
12
3P/json/tests/test_cast.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_cast
|
||||||
|
exit $?
|
||||||
31
3P/json/tests/test_locale.c
Normal file
31
3P/json/tests/test_locale.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LOCALE_H
|
||||||
|
#include <locale.h>
|
||||||
|
#endif /* HAVE_LOCALE_H */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
json_object *new_obj;
|
||||||
|
#ifdef HAVE_SETLOCALE
|
||||||
|
setlocale(LC_NUMERIC, "de_DE");
|
||||||
|
#else
|
||||||
|
printf("No locale\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[1.2,3.4,123456.78,5.0,2.3e10]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string_ext(new_obj,JSON_C_TO_STRING_NOZERO));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
}
|
||||||
|
|
||||||
2
3P/json/tests/test_locale.expected
Normal file
2
3P/json/tests/test_locale.expected
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
new_obj.to_string()=[ 1.200000, 3.400000, 123456.780000, 5.000000, 23000000000.000000 ]
|
||||||
|
new_obj.to_string()=[1.2,3.4,123456.78,5.0,23000000000.0]
|
||||||
12
3P/json/tests/test_locale.test
Executable file
12
3P/json/tests/test_locale.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_locale
|
||||||
|
exit $?
|
||||||
57
3P/json/tests/test_null.c
Normal file
57
3P/json/tests/test_null.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Tests if binary strings are supported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_object.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// this test has a space after the null character. check that it's still included
|
||||||
|
const char *input = " \0 ";
|
||||||
|
const char *expected = "\" \\u0000 \"";
|
||||||
|
struct json_object *string = json_object_new_string_len(input, 3);
|
||||||
|
const char *json = json_object_to_json_string(string);
|
||||||
|
|
||||||
|
int strings_match = !strcmp( expected, json);
|
||||||
|
int retval = 0;
|
||||||
|
if (strings_match)
|
||||||
|
{
|
||||||
|
printf("JSON write result is correct: %s\n", json);
|
||||||
|
printf("PASS\n");
|
||||||
|
} else {
|
||||||
|
printf("JSON write result doesn't match expected string\n");
|
||||||
|
printf("expected string: ");
|
||||||
|
printf("%s\n", expected);
|
||||||
|
printf("parsed string: ");
|
||||||
|
printf("%s\n", json);
|
||||||
|
printf("FAIL\n");
|
||||||
|
retval=1;
|
||||||
|
}
|
||||||
|
json_object_put(string);
|
||||||
|
|
||||||
|
struct json_object *parsed_str = json_tokener_parse(expected);
|
||||||
|
if (parsed_str)
|
||||||
|
{
|
||||||
|
int parsed_len = json_object_get_string_len(parsed_str);
|
||||||
|
const char *parsed_cstr = json_object_get_string(parsed_str);
|
||||||
|
int ii;
|
||||||
|
printf("Re-parsed object string len=%d, chars=[", parsed_len);
|
||||||
|
for (ii = 0; ii < parsed_len ; ii++)
|
||||||
|
{
|
||||||
|
printf("%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]);
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
|
json_object_put(parsed_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ERROR: failed to parse\n");
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
3
3P/json/tests/test_null.expected
Normal file
3
3P/json/tests/test_null.expected
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
JSON write result is correct: " \u0000 "
|
||||||
|
PASS
|
||||||
|
Re-parsed object string len=3, chars=[32, 0, 32]
|
||||||
12
3P/json/tests/test_null.test
Executable file
12
3P/json/tests/test_null.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_null
|
||||||
|
exit $?
|
||||||
290
3P/json/tests/test_parse.c
Normal file
290
3P/json/tests/test_parse.c
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "json_tokener.h"
|
||||||
|
|
||||||
|
static void test_basic_parse(void);
|
||||||
|
static void test_verbose_parse(void);
|
||||||
|
static void test_incremental_parse(void);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
test_basic_parse();
|
||||||
|
printf("==================================\n");
|
||||||
|
test_verbose_parse();
|
||||||
|
printf("==================================\n");
|
||||||
|
test_incremental_parse();
|
||||||
|
printf("==================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_basic_parse()
|
||||||
|
{
|
||||||
|
json_object *new_obj;
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("\"\003\"");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("/* hello */\"foo\"");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("// hello\n\"foo\"");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\"");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("null");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("True");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("12");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("12.3");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[\"\\n\"]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[\"\\nabc\\n\"]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[null]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[false]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{}");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{ \"foo\": \"bar\" }");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }");
|
||||||
|
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
|
||||||
|
json_object_put(new_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_verbose_parse()
|
||||||
|
{
|
||||||
|
json_object *new_obj;
|
||||||
|
enum json_tokener_error error = json_tokener_success;
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse_verbose("{ foo }", &error);
|
||||||
|
assert (error == json_tokener_error_parse_object_key_name);
|
||||||
|
assert (new_obj == NULL);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("{ foo }");
|
||||||
|
assert (new_obj == NULL);
|
||||||
|
|
||||||
|
new_obj = json_tokener_parse("foo");
|
||||||
|
assert (new_obj == NULL);
|
||||||
|
new_obj = json_tokener_parse_verbose("foo", &error);
|
||||||
|
assert (new_obj == NULL);
|
||||||
|
|
||||||
|
/* b/c the string starts with 'f' parsing return a boolean error */
|
||||||
|
assert (error == json_tokener_error_parse_boolean);
|
||||||
|
|
||||||
|
printf("json_tokener_parse_versbose() OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct incremental_step {
|
||||||
|
const char *string_to_parse;
|
||||||
|
int length;
|
||||||
|
int char_offset;
|
||||||
|
enum json_tokener_error expected_error;
|
||||||
|
int reset_tokener;
|
||||||
|
} incremental_steps[] = {
|
||||||
|
|
||||||
|
/* Check that full json messages can be parsed, both w/ and w/o a reset */
|
||||||
|
{ "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 },
|
||||||
|
{ "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 },
|
||||||
|
|
||||||
|
/* Check a basic incremental parse */
|
||||||
|
{ "{ \"foo", -1, -1, json_tokener_continue, 0 },
|
||||||
|
{ "\": {\"bar", -1, -1, json_tokener_continue, 0 },
|
||||||
|
{ "\":13}}", -1, -1, json_tokener_success, 1 },
|
||||||
|
|
||||||
|
/* Check that json_tokener_reset actually resets */
|
||||||
|
{ "{ \"foo", -1, -1, json_tokener_continue, 1 },
|
||||||
|
{ ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 },
|
||||||
|
|
||||||
|
/* Check incremental parsing with trailing characters */
|
||||||
|
{ "{ \"foo", -1, -1, json_tokener_continue, 0 },
|
||||||
|
{ "\": {\"bar", -1, -1, json_tokener_continue, 0 },
|
||||||
|
{ "\":13}}XXXX", 10, 6, json_tokener_success, 0 },
|
||||||
|
{ "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 },
|
||||||
|
|
||||||
|
/* Check that trailing characters can change w/o a reset */
|
||||||
|
{ "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 },
|
||||||
|
{ "\"Y\"", -1, -1, json_tokener_success, 1 },
|
||||||
|
|
||||||
|
/* To stop parsing a number we need to reach a non-digit, e.g. a \0 */
|
||||||
|
{ "1", 1, 1, json_tokener_continue, 0 },
|
||||||
|
{ "2", 2, 1, json_tokener_success, 0 },
|
||||||
|
|
||||||
|
/* Strings have a well defined end point, so we can stop at the quote */
|
||||||
|
{ "\"blue\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
|
||||||
|
/* Check each of the escape sequences defined by the spec */
|
||||||
|
{ "\"\\\"\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\\\\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\b\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\f\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\n\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\r\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "\"\\t\"", -1, -1, json_tokener_success, 0 },
|
||||||
|
|
||||||
|
{ "[1,2,3]", -1, -1, json_tokener_success, 0 },
|
||||||
|
|
||||||
|
/* This behaviour doesn't entirely follow the json spec, but until we have
|
||||||
|
a way to specify how strict to be we follow Postel's Law and be liberal
|
||||||
|
in what we accept (up to a point). */
|
||||||
|
{ "[1,2,3,]", -1, -1, json_tokener_success, 0 },
|
||||||
|
{ "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 },
|
||||||
|
|
||||||
|
{ "[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 3 },
|
||||||
|
{ "{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 3 },
|
||||||
|
|
||||||
|
{ NULL, -1, -1, json_tokener_success, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_incremental_parse()
|
||||||
|
{
|
||||||
|
json_object *new_obj;
|
||||||
|
enum json_tokener_error jerr;
|
||||||
|
json_tokener *tok;
|
||||||
|
const char *string_to_parse;
|
||||||
|
int ii;
|
||||||
|
int num_ok, num_error;
|
||||||
|
|
||||||
|
num_ok = 0;
|
||||||
|
num_error = 0;
|
||||||
|
|
||||||
|
printf("Starting incremental tests.\n");
|
||||||
|
printf("Note: quotes and backslashes seen in the output here are literal values passed\n");
|
||||||
|
printf(" to the parse functions. e.g. this is 4 characters: \"\\f\"\n");
|
||||||
|
|
||||||
|
string_to_parse = "{ \"foo"; /* } */
|
||||||
|
printf("json_tokener_parse(%s) ... ", string_to_parse);
|
||||||
|
new_obj = json_tokener_parse(string_to_parse);
|
||||||
|
if (new_obj == NULL) printf("got error as expected\n");
|
||||||
|
|
||||||
|
/* test incremental parsing in various forms */
|
||||||
|
tok = json_tokener_new();
|
||||||
|
for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++)
|
||||||
|
{
|
||||||
|
int this_step_ok = 0;
|
||||||
|
struct incremental_step *step = &incremental_steps[ii];
|
||||||
|
int length = step->length;
|
||||||
|
int expected_char_offset = step->char_offset;
|
||||||
|
|
||||||
|
if (step->reset_tokener & 2)
|
||||||
|
json_tokener_set_flags(tok, JSON_TOKENER_STRICT);
|
||||||
|
else
|
||||||
|
json_tokener_set_flags(tok, 0);
|
||||||
|
|
||||||
|
if (length == -1)
|
||||||
|
length = strlen(step->string_to_parse);
|
||||||
|
if (expected_char_offset == -1)
|
||||||
|
expected_char_offset = length;
|
||||||
|
|
||||||
|
printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ",
|
||||||
|
step->string_to_parse, length);
|
||||||
|
new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length);
|
||||||
|
|
||||||
|
jerr = json_tokener_get_error(tok);
|
||||||
|
if (step->expected_error != json_tokener_success)
|
||||||
|
{
|
||||||
|
if (new_obj != NULL)
|
||||||
|
printf("ERROR: invalid object returned: %s\n",
|
||||||
|
json_object_to_json_string(new_obj));
|
||||||
|
else if (jerr != step->expected_error)
|
||||||
|
printf("ERROR: got wrong error: %s\n",
|
||||||
|
json_tokener_error_desc(jerr));
|
||||||
|
else if (tok->char_offset != expected_char_offset)
|
||||||
|
printf("ERROR: wrong char_offset %d != expected %d\n",
|
||||||
|
tok->char_offset,
|
||||||
|
expected_char_offset);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr));
|
||||||
|
this_step_ok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new_obj == NULL)
|
||||||
|
printf("ERROR: expected valid object, instead: %s\n",
|
||||||
|
json_tokener_error_desc(jerr));
|
||||||
|
else if (tok->char_offset != expected_char_offset)
|
||||||
|
printf("ERROR: wrong char_offset %d != expected %d\n",
|
||||||
|
tok->char_offset,
|
||||||
|
expected_char_offset);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("OK: got object of type [%s]: %s\n",
|
||||||
|
json_type_to_name(json_object_get_type(new_obj)),
|
||||||
|
json_object_to_json_string(new_obj));
|
||||||
|
this_step_ok = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_obj)
|
||||||
|
json_object_put(new_obj);
|
||||||
|
|
||||||
|
if (step->reset_tokener & 1)
|
||||||
|
json_tokener_reset(tok);
|
||||||
|
|
||||||
|
if (this_step_ok)
|
||||||
|
num_ok++;
|
||||||
|
else
|
||||||
|
num_error++;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_tokener_free(tok);
|
||||||
|
|
||||||
|
printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
57
3P/json/tests/test_parse.expected
Normal file
57
3P/json/tests/test_parse.expected
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
new_obj.to_string()="\u0003"
|
||||||
|
new_obj.to_string()="foo"
|
||||||
|
new_obj.to_string()="foo"
|
||||||
|
new_obj.to_string()="ABC"
|
||||||
|
new_obj.to_string()=null
|
||||||
|
new_obj.to_string()=true
|
||||||
|
new_obj.to_string()=12
|
||||||
|
new_obj.to_string()=12.300000
|
||||||
|
new_obj.to_string()=[ "\n" ]
|
||||||
|
new_obj.to_string()=[ "\nabc\n" ]
|
||||||
|
new_obj.to_string()=[ null ]
|
||||||
|
new_obj.to_string()=[ ]
|
||||||
|
new_obj.to_string()=[ false ]
|
||||||
|
new_obj.to_string()=[ "abc", null, "def", 12 ]
|
||||||
|
new_obj.to_string()={ }
|
||||||
|
new_obj.to_string()={ "foo": "bar" }
|
||||||
|
new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true }
|
||||||
|
new_obj.to_string()={ "foo": [ null, "foo" ] }
|
||||||
|
new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] }
|
||||||
|
==================================
|
||||||
|
json_tokener_parse_versbose() OK
|
||||||
|
==================================
|
||||||
|
Starting incremental tests.
|
||||||
|
Note: quotes and backslashes seen in the output here are literal values passed
|
||||||
|
to the parse functions. e.g. this is 4 characters: "\f"
|
||||||
|
json_tokener_parse({ "foo) ... got error as expected
|
||||||
|
json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 }
|
||||||
|
json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 }
|
||||||
|
json_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 }
|
||||||
|
json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } }
|
||||||
|
json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character
|
||||||
|
json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } }
|
||||||
|
json_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character
|
||||||
|
json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 }
|
||||||
|
json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y"
|
||||||
|
json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue
|
||||||
|
json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12
|
||||||
|
json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue"
|
||||||
|
json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\""
|
||||||
|
json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\"
|
||||||
|
json_tokener_parse_ex(tok, "\b" , 4) ... OK: got object of type [string]: "\b"
|
||||||
|
json_tokener_parse_ex(tok, "\f" , 4) ... OK: got object of type [string]: "\f"
|
||||||
|
json_tokener_parse_ex(tok, "\n" , 4) ... OK: got object of type [string]: "\n"
|
||||||
|
json_tokener_parse_ex(tok, "\r" , 4) ... OK: got object of type [string]: "\r"
|
||||||
|
json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string]: "\t"
|
||||||
|
json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ]
|
||||||
|
json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ]
|
||||||
|
json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character
|
||||||
|
json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character
|
||||||
|
json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character
|
||||||
|
End Incremental Tests OK=29 ERROR=0
|
||||||
|
==================================
|
||||||
12
3P/json/tests/test_parse.test
Executable file
12
3P/json/tests/test_parse.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_parse
|
||||||
|
exit $?
|
||||||
115
3P/json/tests/test_parse_int64.c
Normal file
115
3P/json/tests/test_parse_int64.c
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "json_inttypes.h"
|
||||||
|
#include "json_util.h"
|
||||||
|
|
||||||
|
void checkit(const char *buf)
|
||||||
|
{
|
||||||
|
int64_t cint64 = -666;
|
||||||
|
|
||||||
|
int retval = json_parse_int64(buf, &cint64);
|
||||||
|
printf("buf=%s parseit=%d, value=%" PRId64 " \n", buf, retval, cint64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test calls json_parse_int64 with a variety of different strings.
|
||||||
|
* It's purpose is to ensure that the results are consistent across all
|
||||||
|
* different environments that it might be executed in.
|
||||||
|
*
|
||||||
|
* This always exits with a 0 exit value. The output should be compared
|
||||||
|
* against previously saved expected output.
|
||||||
|
*/
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char buf[100];
|
||||||
|
|
||||||
|
checkit("x");
|
||||||
|
|
||||||
|
checkit("0");
|
||||||
|
checkit("-0");
|
||||||
|
|
||||||
|
checkit("00000000");
|
||||||
|
checkit("-00000000");
|
||||||
|
|
||||||
|
checkit("1");
|
||||||
|
|
||||||
|
strcpy(buf, "2147483647"); // aka INT32_MAX
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-1");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, " -1");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "00001234");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "0001234x");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-00001234");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-00001234x");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "4294967295"); // aka UINT32_MAX
|
||||||
|
|
||||||
|
sprintf(buf, "4294967296"); // aka UINT32_MAX + 1
|
||||||
|
|
||||||
|
strcpy(buf, "21474836470"); // INT32_MAX * 10
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "31474836470"); // INT32_MAX * 10 + a bunch
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-2147483647"); // INT32_MIN + 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-2147483648"); // INT32_MIN
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-2147483649"); // INT32_MIN - 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-21474836480"); // INT32_MIN * 10
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "9223372036854775806"); // INT64_MAX - 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "9223372036854775807"); // INT64_MAX
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "9223372036854775808"); // INT64_MAX + 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-9223372036854775808"); // INT64_MIN
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "18446744073709551614"); // UINT64_MAX - 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "18446744073709551615"); // UINT64_MAX
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "18446744073709551616"); // UINT64_MAX + 1
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
strcpy(buf, "-18446744073709551616"); // -UINT64_MAX
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
// Ensure we can still parse valid numbers after parsing out of range ones.
|
||||||
|
strcpy(buf, "123");
|
||||||
|
checkit(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
29
3P/json/tests/test_parse_int64.expected
Normal file
29
3P/json/tests/test_parse_int64.expected
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
buf=x parseit=1, value=-666
|
||||||
|
buf=0 parseit=0, value=0
|
||||||
|
buf=-0 parseit=0, value=0
|
||||||
|
buf=00000000 parseit=0, value=0
|
||||||
|
buf=-00000000 parseit=0, value=0
|
||||||
|
buf=1 parseit=0, value=1
|
||||||
|
buf=2147483647 parseit=0, value=2147483647
|
||||||
|
buf=-1 parseit=0, value=-1
|
||||||
|
buf= -1 parseit=0, value=-1
|
||||||
|
buf=00001234 parseit=0, value=1234
|
||||||
|
buf=0001234x parseit=0, value=1234
|
||||||
|
buf=-00001234 parseit=0, value=-1234
|
||||||
|
buf=-00001234x parseit=0, value=-1234
|
||||||
|
buf=21474836470 parseit=0, value=21474836470
|
||||||
|
buf=31474836470 parseit=0, value=31474836470
|
||||||
|
buf=-2147483647 parseit=0, value=-2147483647
|
||||||
|
buf=-2147483648 parseit=0, value=-2147483648
|
||||||
|
buf=-2147483649 parseit=0, value=-2147483649
|
||||||
|
buf=-21474836480 parseit=0, value=-21474836480
|
||||||
|
buf=9223372036854775806 parseit=0, value=9223372036854775806
|
||||||
|
buf=9223372036854775807 parseit=0, value=9223372036854775807
|
||||||
|
buf=9223372036854775808 parseit=0, value=9223372036854775807
|
||||||
|
buf=-9223372036854775808 parseit=0, value=-9223372036854775808
|
||||||
|
buf=-9223372036854775809 parseit=0, value=-9223372036854775808
|
||||||
|
buf=18446744073709551614 parseit=0, value=9223372036854775807
|
||||||
|
buf=18446744073709551615 parseit=0, value=9223372036854775807
|
||||||
|
buf=18446744073709551616 parseit=0, value=9223372036854775807
|
||||||
|
buf=-18446744073709551616 parseit=0, value=-9223372036854775808
|
||||||
|
buf=123 parseit=0, value=123
|
||||||
166
3P/json/tests/test_printbuf.c
Normal file
166
3P/json/tests/test_printbuf.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
|
||||||
|
static void test_basic_printbuf_memset(void);
|
||||||
|
static void test_printbuf_memset_length(void);
|
||||||
|
|
||||||
|
static void test_basic_printbuf_memset()
|
||||||
|
{
|
||||||
|
struct printbuf *pb;
|
||||||
|
|
||||||
|
printf("%s: starting test\n", __func__);
|
||||||
|
pb = printbuf_new();
|
||||||
|
sprintbuf(pb, "blue:%d", 1);
|
||||||
|
printbuf_memset(pb, -1, 'x', 52);
|
||||||
|
printf("Buffer contents:%.*s\n", printbuf_length(pb), pb->buf);
|
||||||
|
printbuf_free(pb);
|
||||||
|
printf("%s: end test\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_printbuf_memset_length()
|
||||||
|
{
|
||||||
|
struct printbuf *pb;
|
||||||
|
|
||||||
|
printf("%s: starting test\n", __func__);
|
||||||
|
pb = printbuf_new();
|
||||||
|
printbuf_memset(pb, -1, ' ', 0);
|
||||||
|
printbuf_memset(pb, -1, ' ', 0);
|
||||||
|
printbuf_memset(pb, -1, ' ', 0);
|
||||||
|
printbuf_memset(pb, -1, ' ', 0);
|
||||||
|
printbuf_memset(pb, -1, ' ', 0);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
printbuf_memset(pb, -1, ' ', 2);
|
||||||
|
printbuf_memset(pb, -1, ' ', 4);
|
||||||
|
printbuf_memset(pb, -1, ' ', 6);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
printbuf_memset(pb, -1, ' ', 6);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
printbuf_memset(pb, -1, ' ', 8);
|
||||||
|
printbuf_memset(pb, -1, ' ', 10);
|
||||||
|
printbuf_memset(pb, -1, ' ', 10);
|
||||||
|
printbuf_memset(pb, -1, ' ', 10);
|
||||||
|
printbuf_memset(pb, -1, ' ', 20);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
|
||||||
|
// No length change should occur
|
||||||
|
printbuf_memset(pb, 0, 'x', 30);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
|
||||||
|
// This should extend it by one.
|
||||||
|
printbuf_memset(pb, 0, 'x', printbuf_length(pb) + 1);
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
|
||||||
|
printbuf_free(pb);
|
||||||
|
printf("%s: end test\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_printbuf_memappend(int *before_resize);
|
||||||
|
static void test_printbuf_memappend(int *before_resize)
|
||||||
|
{
|
||||||
|
struct printbuf *pb;
|
||||||
|
int initial_size;
|
||||||
|
|
||||||
|
printf("%s: starting test\n", __func__);
|
||||||
|
pb = printbuf_new();
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
|
||||||
|
initial_size = pb->size;
|
||||||
|
|
||||||
|
while(pb->size == initial_size)
|
||||||
|
{
|
||||||
|
printbuf_memappend_fast(pb, "x", 1);
|
||||||
|
}
|
||||||
|
*before_resize = printbuf_length(pb) - 1;
|
||||||
|
printf("Appended %d bytes for resize: [%s]\n", *before_resize + 1, pb->buf);
|
||||||
|
|
||||||
|
printbuf_reset(pb);
|
||||||
|
printbuf_memappend_fast(pb, "bluexyz123", 3);
|
||||||
|
printf("Partial append: %d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
char with_nulls[] = { 'a', 'b', '\0', 'c' };
|
||||||
|
printbuf_reset(pb);
|
||||||
|
printbuf_memappend_fast(pb, with_nulls, (int)sizeof(with_nulls));
|
||||||
|
printf("With embedded \\0 character: %d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
printbuf_free(pb);
|
||||||
|
pb = printbuf_new();
|
||||||
|
char *data = malloc(*before_resize);
|
||||||
|
memset(data, 'X', *before_resize);
|
||||||
|
printbuf_memappend_fast(pb, data, *before_resize);
|
||||||
|
printf("Append to just before resize: %d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
printbuf_free(pb);
|
||||||
|
|
||||||
|
pb = printbuf_new();
|
||||||
|
data = malloc(*before_resize + 1);
|
||||||
|
memset(data, 'X', *before_resize + 1);
|
||||||
|
printbuf_memappend_fast(pb, data, *before_resize + 1);
|
||||||
|
printf("Append to just after resize: %d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
printbuf_free(pb);
|
||||||
|
printf("%s: end test\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_sprintbuf(int before_resize);
|
||||||
|
static void test_sprintbuf(int before_resize)
|
||||||
|
{
|
||||||
|
struct printbuf *pb;
|
||||||
|
|
||||||
|
printf("%s: starting test\n", __func__);
|
||||||
|
pb = printbuf_new();
|
||||||
|
printf("Buffer length: %d\n", printbuf_length(pb));
|
||||||
|
|
||||||
|
char *data = malloc(before_resize + 1 + 1);
|
||||||
|
memset(data, 'X', before_resize + 1 + 1);
|
||||||
|
data[before_resize + 1] = '\0';
|
||||||
|
sprintbuf(pb, "%s", data);
|
||||||
|
free(data);
|
||||||
|
printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, (int)strlen(pb->buf));
|
||||||
|
|
||||||
|
printbuf_reset(pb);
|
||||||
|
sprintbuf(pb, "plain");
|
||||||
|
printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
sprintbuf(pb, "%d", 1);
|
||||||
|
printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
sprintbuf(pb, "%d", INT_MAX);
|
||||||
|
printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
sprintbuf(pb, "%d", INT_MIN);
|
||||||
|
printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
sprintbuf(pb, "%s", "%s");
|
||||||
|
printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
|
||||||
|
|
||||||
|
printbuf_free(pb);
|
||||||
|
printf("%s: end test\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int before_resize = 0;
|
||||||
|
|
||||||
|
mc_set_debug(1);
|
||||||
|
|
||||||
|
test_basic_printbuf_memset();
|
||||||
|
printf("========================================\n");
|
||||||
|
test_printbuf_memset_length();
|
||||||
|
printf("========================================\n");
|
||||||
|
test_printbuf_memappend(&before_resize);
|
||||||
|
printf("========================================\n");
|
||||||
|
test_sprintbuf(before_resize);
|
||||||
|
printf("========================================\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
3P/json/tests/test_printbuf.expected
Normal file
32
3P/json/tests/test_printbuf.expected
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
test_basic_printbuf_memset: starting test
|
||||||
|
Buffer contents:blue:1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
test_basic_printbuf_memset: end test
|
||||||
|
========================================
|
||||||
|
test_printbuf_memset_length: starting test
|
||||||
|
Buffer length: 0
|
||||||
|
Buffer length: 12
|
||||||
|
Buffer length: 18
|
||||||
|
Buffer length: 76
|
||||||
|
Buffer length: 76
|
||||||
|
Buffer length: 77
|
||||||
|
test_printbuf_memset_length: end test
|
||||||
|
========================================
|
||||||
|
test_printbuf_memappend: starting test
|
||||||
|
Buffer length: 0
|
||||||
|
Appended 32 bytes for resize: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
|
||||||
|
Partial append: 3, [blu]
|
||||||
|
With embedded \0 character: 4, [ab]
|
||||||
|
Append to just before resize: 31, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
|
||||||
|
Append to just after resize: 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
|
||||||
|
test_printbuf_memappend: end test
|
||||||
|
========================================
|
||||||
|
test_sprintbuf: starting test
|
||||||
|
Buffer length: 0
|
||||||
|
sprintbuf to just after resize(31+1): 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX], strlen(buf)=32
|
||||||
|
5, [plain]
|
||||||
|
6, [plain1]
|
||||||
|
16, [plain12147483647]
|
||||||
|
27, [plain12147483647-2147483648]
|
||||||
|
29, [plain12147483647-2147483648%s]
|
||||||
|
test_sprintbuf: end test
|
||||||
|
========================================
|
||||||
12
3P/json/tests/test_printbuf.test
Executable file
12
3P/json/tests/test_printbuf.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_printbuf
|
||||||
|
exit $?
|
||||||
71
3P/json/tests/test_set_serializer.c
Normal file
71
3P/json/tests/test_set_serializer.c
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "json.h"
|
||||||
|
#include "printbuf.h"
|
||||||
|
|
||||||
|
struct myinfo {
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int freeit_was_called = 0;
|
||||||
|
static void freeit(json_object *jso, void *userdata)
|
||||||
|
{
|
||||||
|
struct myinfo *info = userdata;
|
||||||
|
printf("freeit, value=%d\n", info->value);
|
||||||
|
// Don't actually free anything here, the userdata is stack allocated.
|
||||||
|
freeit_was_called = 1;
|
||||||
|
}
|
||||||
|
static int custom_serializer(struct json_object *o,
|
||||||
|
struct printbuf *pb,
|
||||||
|
int level,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
sprintbuf(pb, "Custom Output");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
json_object *my_object;
|
||||||
|
|
||||||
|
MC_SET_DEBUG(1);
|
||||||
|
|
||||||
|
printf("Test setting, then resetting a custom serializer:\n");
|
||||||
|
my_object = json_object_new_object();
|
||||||
|
json_object_object_add(my_object, "abc", json_object_new_int(12));
|
||||||
|
json_object_object_add(my_object, "foo", json_object_new_string("bar"));
|
||||||
|
|
||||||
|
printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
|
||||||
|
|
||||||
|
struct myinfo userdata = { .value = 123 };
|
||||||
|
json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
|
||||||
|
|
||||||
|
printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object));
|
||||||
|
|
||||||
|
printf("Next line of output should be from the custom freeit function:\n");
|
||||||
|
freeit_was_called = 0;
|
||||||
|
json_object_set_serializer(my_object, NULL, NULL, NULL);
|
||||||
|
assert(freeit_was_called);
|
||||||
|
|
||||||
|
printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object));
|
||||||
|
|
||||||
|
json_object_put(my_object);
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
my_object = json_object_new_object();
|
||||||
|
printf("Check that the custom serializer isn't free'd until the last json_object_put:\n");
|
||||||
|
json_object_set_serializer(my_object, custom_serializer, &userdata, freeit);
|
||||||
|
json_object_get(my_object);
|
||||||
|
json_object_put(my_object);
|
||||||
|
printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object));
|
||||||
|
printf("Next line of output should be from the custom freeit function:\n");
|
||||||
|
|
||||||
|
freeit_was_called = 0;
|
||||||
|
json_object_put(my_object);
|
||||||
|
assert(freeit_was_called);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
3P/json/tests/test_set_serializer.expected
Normal file
10
3P/json/tests/test_set_serializer.expected
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Test setting, then resetting a custom serializer:
|
||||||
|
my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
|
||||||
|
my_object.to_string(custom serializer)=Custom Output
|
||||||
|
Next line of output should be from the custom freeit function:
|
||||||
|
freeit, value=123
|
||||||
|
my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
|
||||||
|
Check that the custom serializer isn't free'd until the last json_object_put:
|
||||||
|
my_object.to_string(custom serializer)=Custom Output
|
||||||
|
Next line of output should be from the custom freeit function:
|
||||||
|
freeit, value=123
|
||||||
12
3P/json/tests/test_set_serializer.test
Executable file
12
3P/json/tests/test_set_serializer.test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Common definitions
|
||||||
|
if test -z "$srcdir"; then
|
||||||
|
srcdir="${0%/*}"
|
||||||
|
test "$srcdir" = "$0" && srcdir=.
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
fi
|
||||||
|
. "$srcdir/test-defs.sh"
|
||||||
|
|
||||||
|
run_output_test test_set_serializer
|
||||||
|
exit $?
|
||||||
10
3P/libubox/.gitignore
vendored
Normal file
10
3P/libubox/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Makefile
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
*.cmake
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
install_manifest.txt
|
||||||
|
jshn
|
||||||
|
*-example
|
||||||
24
3P/libubox/avl-cmp.c
Normal file
24
3P/libubox/avl-cmp.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "avl-cmp.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
avl_strcmp(const void *k1, const void *k2, void *ptr)
|
||||||
|
{
|
||||||
|
return strcmp(k1, k2);
|
||||||
|
}
|
||||||
|
|
||||||
21
3P/libubox/avl-cmp.h
Normal file
21
3P/libubox/avl-cmp.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef __AVL_CMP_H
|
||||||
|
#define __AVL_CMP_H
|
||||||
|
|
||||||
|
int avl_strcmp(const void *k1, const void *k2, void *ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
735
3P/libubox/avl.c
Normal file
735
3P/libubox/avl.c
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
/*
|
||||||
|
* PacketBB handler library (see RFC 5444)
|
||||||
|
* Copyright (c) 2010 Henning Rogge <hrogge@googlemail.com>
|
||||||
|
* Original OLSRd implementation by Hannes Gredler <hannes@gredler.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of olsr.org, olsrd nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Visit http://www.olsr.org/git for more information.
|
||||||
|
*
|
||||||
|
* If you find this software useful feel free to make a donation
|
||||||
|
* to the project. For more information see the website or contact
|
||||||
|
* the copyright holders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "avl.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* internal type save inline function to calculate the maximum of
|
||||||
|
* to integers without macro implementation.
|
||||||
|
*
|
||||||
|
* @param x first parameter of maximum function
|
||||||
|
* @param y second parameter of maximum function
|
||||||
|
* @return largest integer of both parameters
|
||||||
|
*/
|
||||||
|
static inline int avl_max(int x, int y) {
|
||||||
|
return x > y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* internal type save inline function to calculate the minimum of
|
||||||
|
* to integers without macro implementation.
|
||||||
|
*
|
||||||
|
* @param x first parameter of minimum function
|
||||||
|
* @param y second parameter of minimum function
|
||||||
|
* @return smallest integer of both parameters
|
||||||
|
*/
|
||||||
|
static inline int avl_min(int x, int y) {
|
||||||
|
return x < y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct avl_node *
|
||||||
|
avl_find_rec(struct avl_node *node, const void *key, avl_tree_comp comp, void *ptr, int *cmp_result);
|
||||||
|
static void avl_insert_before(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node);
|
||||||
|
static void avl_insert_after(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node);
|
||||||
|
static void post_insert(struct avl_tree *tree, struct avl_node *node);
|
||||||
|
static void avl_delete_worker(struct avl_tree *tree, struct avl_node *node);
|
||||||
|
static void avl_remove(struct avl_tree *tree, struct avl_node *node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new avl_tree struct
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param comp pointer to comparator for the tree
|
||||||
|
* @param allow_dups true if the tree allows multiple
|
||||||
|
* elements with the same
|
||||||
|
* @param ptr custom parameter for comparator
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
avl_init(struct avl_tree *tree, avl_tree_comp comp, bool allow_dups, void *ptr)
|
||||||
|
{
|
||||||
|
INIT_LIST_HEAD(&tree->list_head);
|
||||||
|
tree->root = NULL;
|
||||||
|
tree->count = 0;
|
||||||
|
tree->comp = comp;
|
||||||
|
tree->allow_dups = allow_dups;
|
||||||
|
tree->cmp_ptr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct avl_node *avl_next(struct avl_node *node)
|
||||||
|
{
|
||||||
|
return list_entry(node->list.next, struct avl_node, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a node in an avl-tree with a certain key
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to key
|
||||||
|
* @return pointer to avl-node with key, NULL if no node with
|
||||||
|
* this key exists.
|
||||||
|
*/
|
||||||
|
struct avl_node *
|
||||||
|
avl_find(const struct avl_tree *tree, const void *key)
|
||||||
|
{
|
||||||
|
struct avl_node *node;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
|
||||||
|
|
||||||
|
return diff == 0 ? node : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the last node in an avl-tree with a key less or equal
|
||||||
|
* than the specified key
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to specified key
|
||||||
|
* @return pointer to avl-node, NULL if no node with
|
||||||
|
* key less or equal specified key exists.
|
||||||
|
*/
|
||||||
|
struct avl_node *
|
||||||
|
avl_find_lessequal(const struct avl_tree *tree, const void *key) {
|
||||||
|
struct avl_node *node, *next;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
|
||||||
|
|
||||||
|
/* go left as long as key<node.key */
|
||||||
|
while (diff < 0) {
|
||||||
|
if (list_is_first(&node->list, &tree->list_head)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = (struct avl_node *)node->list.prev;
|
||||||
|
diff = (*tree->comp) (key, node->key, tree->cmp_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go right as long as key>=next_node.key */
|
||||||
|
next = node;
|
||||||
|
while (diff >= 0) {
|
||||||
|
node = next;
|
||||||
|
if (list_is_last(&node->list, &tree->list_head)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = (struct avl_node *)node->list.next;
|
||||||
|
diff = (*tree->comp) (key, next->key, tree->cmp_ptr);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the first node in an avl-tree with a key greater or equal
|
||||||
|
* than the specified key
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to specified key
|
||||||
|
* @return pointer to avl-node, NULL if no node with
|
||||||
|
* key greater or equal specified key exists.
|
||||||
|
*/
|
||||||
|
struct avl_node *
|
||||||
|
avl_find_greaterequal(const struct avl_tree *tree, const void *key) {
|
||||||
|
struct avl_node *node, *next;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = avl_find_rec(tree->root, key, tree->comp, tree->cmp_ptr, &diff);
|
||||||
|
|
||||||
|
/* go right as long as key>node.key */
|
||||||
|
while (diff > 0) {
|
||||||
|
if (list_is_last(&node->list, &tree->list_head)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = (struct avl_node *)node->list.next;
|
||||||
|
diff = (*tree->comp) (key, node->key, tree->cmp_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go left as long as key<=next_node.key */
|
||||||
|
next = node;
|
||||||
|
while (diff <= 0) {
|
||||||
|
node = next;
|
||||||
|
if (list_is_first(&node->list, &tree->list_head)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = (struct avl_node *)node->list.prev;
|
||||||
|
diff = (*tree->comp) (key, next->key, tree->cmp_ptr);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts an avl_node into a tree
|
||||||
|
* @param tree pointer to tree
|
||||||
|
* @param new pointer to node
|
||||||
|
* @return 0 if node was inserted successfully, -1 if it was not inserted
|
||||||
|
* because of a key collision
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
avl_insert(struct avl_tree *tree, struct avl_node *new)
|
||||||
|
{
|
||||||
|
struct avl_node *node, *next, *last;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
new->parent = NULL;
|
||||||
|
|
||||||
|
new->left = NULL;
|
||||||
|
new->right = NULL;
|
||||||
|
|
||||||
|
new->balance = 0;
|
||||||
|
new->leader = true;
|
||||||
|
|
||||||
|
if (tree->root == NULL) {
|
||||||
|
list_add(&new->list, &tree->list_head);
|
||||||
|
tree->root = new;
|
||||||
|
tree->count = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = avl_find_rec(tree->root, new->key, tree->comp, tree->cmp_ptr, &diff);
|
||||||
|
|
||||||
|
last = node;
|
||||||
|
|
||||||
|
while (!list_is_last(&last->list, &tree->list_head)) {
|
||||||
|
next = avl_next(last);
|
||||||
|
if (next->leader) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = (*tree->comp) (new->key, node->key, tree->cmp_ptr);
|
||||||
|
|
||||||
|
if (diff == 0) {
|
||||||
|
if (!tree->allow_dups)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
new->leader = 0;
|
||||||
|
|
||||||
|
avl_insert_after(tree, last, new);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->balance == 1) {
|
||||||
|
avl_insert_before(tree, node, new);
|
||||||
|
|
||||||
|
node->balance = 0;
|
||||||
|
new->parent = node;
|
||||||
|
node->left = new;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->balance == -1) {
|
||||||
|
avl_insert_after(tree, last, new);
|
||||||
|
|
||||||
|
node->balance = 0;
|
||||||
|
new->parent = node;
|
||||||
|
node->right = new;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff < 0) {
|
||||||
|
avl_insert_before(tree, node, new);
|
||||||
|
|
||||||
|
node->balance = -1;
|
||||||
|
new->parent = node;
|
||||||
|
node->left = new;
|
||||||
|
post_insert(tree, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_insert_after(tree, last, new);
|
||||||
|
|
||||||
|
node->balance = 1;
|
||||||
|
new->parent = node;
|
||||||
|
node->right = new;
|
||||||
|
post_insert(tree, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a node from an avl tree
|
||||||
|
* @param tree pointer to tree
|
||||||
|
* @param node pointer to node
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
avl_delete(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *next;
|
||||||
|
struct avl_node *parent;
|
||||||
|
struct avl_node *left;
|
||||||
|
struct avl_node *right;
|
||||||
|
if (node->leader) {
|
||||||
|
if (tree->allow_dups
|
||||||
|
&& !list_is_last(&node->list, &tree->list_head)
|
||||||
|
&& !(next = avl_next(node))->leader) {
|
||||||
|
next->leader = true;
|
||||||
|
next->balance = node->balance;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
left = node->left;
|
||||||
|
right = node->right;
|
||||||
|
|
||||||
|
next->parent = parent;
|
||||||
|
next->left = left;
|
||||||
|
next->right = right;
|
||||||
|
|
||||||
|
if (parent == NULL)
|
||||||
|
tree->root = next;
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (node == parent->left)
|
||||||
|
parent->left = next;
|
||||||
|
|
||||||
|
else
|
||||||
|
parent->right = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left != NULL)
|
||||||
|
left->parent = next;
|
||||||
|
|
||||||
|
if (right != NULL)
|
||||||
|
right->parent = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
avl_delete_worker(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_remove(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct avl_node *
|
||||||
|
avl_find_rec(struct avl_node *node, const void *key, avl_tree_comp comp, void *cmp_ptr, int *cmp_result)
|
||||||
|
{
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
diff = (*comp) (key, node->key, cmp_ptr);
|
||||||
|
*cmp_result = diff;
|
||||||
|
|
||||||
|
if (diff < 0) {
|
||||||
|
if (node->left != NULL)
|
||||||
|
return avl_find_rec(node->left, key, comp, cmp_ptr, cmp_result);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff > 0) {
|
||||||
|
if (node->right != NULL)
|
||||||
|
return avl_find_rec(node->right, key, comp, cmp_ptr, cmp_result);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_rotate_right(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *left, *parent;
|
||||||
|
|
||||||
|
left = node->left;
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
left->parent = parent;
|
||||||
|
node->parent = left;
|
||||||
|
|
||||||
|
if (parent == NULL)
|
||||||
|
tree->root = left;
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = left;
|
||||||
|
|
||||||
|
else
|
||||||
|
parent->right = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->left = left->right;
|
||||||
|
left->right = node;
|
||||||
|
|
||||||
|
if (node->left != NULL)
|
||||||
|
node->left->parent = node;
|
||||||
|
|
||||||
|
node->balance += 1 - avl_min(left->balance, 0);
|
||||||
|
left->balance += 1 + avl_max(node->balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_rotate_left(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *right, *parent;
|
||||||
|
|
||||||
|
right = node->right;
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
right->parent = parent;
|
||||||
|
node->parent = right;
|
||||||
|
|
||||||
|
if (parent == NULL)
|
||||||
|
tree->root = right;
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = right;
|
||||||
|
|
||||||
|
else
|
||||||
|
parent->right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->right = right->left;
|
||||||
|
right->left = node;
|
||||||
|
|
||||||
|
if (node->right != NULL)
|
||||||
|
node->right->parent = node;
|
||||||
|
|
||||||
|
node->balance -= 1 + avl_max(right->balance, 0);
|
||||||
|
right->balance -= 1 - avl_min(node->balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
post_insert(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *parent = node->parent;
|
||||||
|
|
||||||
|
if (parent == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node == parent->left) {
|
||||||
|
parent->balance--;
|
||||||
|
|
||||||
|
if (parent->balance == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->balance == -1) {
|
||||||
|
post_insert(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->balance == -1) {
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_left(tree, node);
|
||||||
|
avl_rotate_right(tree, node->parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->balance++;
|
||||||
|
|
||||||
|
if (parent->balance == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->balance == 1) {
|
||||||
|
post_insert(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->balance == 1) {
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_right(tree, node);
|
||||||
|
avl_rotate_left(tree, node->parent->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_insert_before(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node)
|
||||||
|
{
|
||||||
|
list_add_tail(&node->list, &pos_node->list);
|
||||||
|
tree->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_insert_after(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node)
|
||||||
|
{
|
||||||
|
list_add(&node->list, &pos_node->list);
|
||||||
|
tree->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_remove(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
list_del(&node->list);
|
||||||
|
tree->count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_post_delete(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *parent;
|
||||||
|
|
||||||
|
if ((parent = node->parent) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node == parent->left) {
|
||||||
|
parent->balance++;
|
||||||
|
|
||||||
|
if (parent->balance == 0) {
|
||||||
|
avl_post_delete(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->balance == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->right->balance == 0) {
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->right->balance == 1) {
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_right(tree, parent->right);
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->balance--;
|
||||||
|
|
||||||
|
if (parent->balance == 0) {
|
||||||
|
avl_post_delete(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->balance == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->left->balance == 0) {
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left->balance == -1) {
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_left(tree, parent->left);
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct avl_node *
|
||||||
|
avl_local_min(struct avl_node *node)
|
||||||
|
{
|
||||||
|
while (node->left != NULL)
|
||||||
|
node = node->left;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static struct avl_node *
|
||||||
|
avl_local_max(struct avl_node *node)
|
||||||
|
{
|
||||||
|
while (node->right != NULL)
|
||||||
|
node = node->right;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_delete_worker(struct avl_tree *tree, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *parent, *min;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
if (node->left == NULL && node->right == NULL) {
|
||||||
|
if (parent == NULL) {
|
||||||
|
tree->root = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left == node) {
|
||||||
|
parent->left = NULL;
|
||||||
|
parent->balance++;
|
||||||
|
|
||||||
|
if (parent->balance == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->balance == 0) {
|
||||||
|
avl_post_delete(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->right->balance == 0) {
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->right->balance == 1) {
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_right(tree, parent->right);
|
||||||
|
avl_rotate_left(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->right == node) {
|
||||||
|
parent->right = NULL;
|
||||||
|
parent->balance--;
|
||||||
|
|
||||||
|
if (parent->balance == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parent->balance == 0) {
|
||||||
|
avl_post_delete(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left->balance == 0) {
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left->balance == -1) {
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rotate_left(tree, parent->left);
|
||||||
|
avl_rotate_right(tree, parent);
|
||||||
|
avl_post_delete(tree, parent->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->left == NULL) {
|
||||||
|
if (parent == NULL) {
|
||||||
|
tree->root = node->right;
|
||||||
|
node->right->parent = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->right->parent = parent;
|
||||||
|
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = node->right;
|
||||||
|
|
||||||
|
else
|
||||||
|
parent->right = node->right;
|
||||||
|
|
||||||
|
avl_post_delete(tree, node->right);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->right == NULL) {
|
||||||
|
if (parent == NULL) {
|
||||||
|
tree->root = node->left;
|
||||||
|
node->left->parent = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->left->parent = parent;
|
||||||
|
|
||||||
|
if (parent->left == node)
|
||||||
|
parent->left = node->left;
|
||||||
|
|
||||||
|
else
|
||||||
|
parent->right = node->left;
|
||||||
|
|
||||||
|
avl_post_delete(tree, node->left);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
min = avl_local_min(node->right);
|
||||||
|
avl_delete_worker(tree, min);
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
min->balance = node->balance;
|
||||||
|
min->parent = parent;
|
||||||
|
min->left = node->left;
|
||||||
|
min->right = node->right;
|
||||||
|
|
||||||
|
if (min->left != NULL)
|
||||||
|
min->left->parent = min;
|
||||||
|
|
||||||
|
if (min->right != NULL)
|
||||||
|
min->right->parent = min;
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
tree->root = min;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->left == node) {
|
||||||
|
parent->left = min;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->right = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* c-basic-offset: 2
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
560
3P/libubox/avl.h
Normal file
560
3P/libubox/avl.h
Normal file
@@ -0,0 +1,560 @@
|
|||||||
|
/*
|
||||||
|
* PacketBB handler library (see RFC 5444)
|
||||||
|
* Copyright (c) 2010 Henning Rogge <hrogge@googlemail.com>
|
||||||
|
* Original OLSRd implementation by Hannes Gredler <hannes@gredler.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of olsr.org, olsrd nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Visit http://www.olsr.org/git for more information.
|
||||||
|
*
|
||||||
|
* If you find this software useful feel free to make a donation
|
||||||
|
* to the project. For more information see the website or contact
|
||||||
|
* the copyright holders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AVL_H
|
||||||
|
#define _AVL_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/* Support for OLSR.org linker symbol export */
|
||||||
|
#define EXPORT(sym) sym
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This element is a member of a avl-tree. It must be contained in all
|
||||||
|
* larger structs that should be put into a tree.
|
||||||
|
*/
|
||||||
|
struct avl_node {
|
||||||
|
/**
|
||||||
|
* Linked list node for supporting easy iteration and multiple
|
||||||
|
* elments with the same key.
|
||||||
|
*
|
||||||
|
* this must be the first element of an avl_node to
|
||||||
|
* make casting for lists easier
|
||||||
|
*/
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to parent node in tree, NULL if root node
|
||||||
|
*/
|
||||||
|
struct avl_node *parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to left child
|
||||||
|
*/
|
||||||
|
struct avl_node *left;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to right child
|
||||||
|
*/
|
||||||
|
struct avl_node *right;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pointer to key of node
|
||||||
|
*/
|
||||||
|
const void *key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* balance state of AVL tree (0,-1,+1)
|
||||||
|
*/
|
||||||
|
signed char balance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if first of a series of nodes with same key
|
||||||
|
*/
|
||||||
|
bool leader;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototype for avl comparators
|
||||||
|
* @param k1 first key
|
||||||
|
* @param k2 second key
|
||||||
|
* @param ptr custom data for tree comparator
|
||||||
|
* @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
|
||||||
|
*/
|
||||||
|
typedef int (*avl_tree_comp) (const void *k1, const void *k2, void *ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This struct is the central management part of an avl tree.
|
||||||
|
* One of them is necessary for each avl_tree.
|
||||||
|
*/
|
||||||
|
struct avl_tree {
|
||||||
|
/**
|
||||||
|
* Head of linked list node for supporting easy iteration
|
||||||
|
* and multiple elments with the same key.
|
||||||
|
*/
|
||||||
|
struct list_head list_head;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pointer to the root node of the avl tree, NULL if tree is empty
|
||||||
|
*/
|
||||||
|
struct avl_node *root;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of nodes in the avl tree
|
||||||
|
*/
|
||||||
|
unsigned int count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if multiple nodes with the same key are
|
||||||
|
* allowed in the tree, false otherwise
|
||||||
|
*/
|
||||||
|
bool allow_dups;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pointer to the tree comparator
|
||||||
|
*
|
||||||
|
* First two parameters are keys to compare,
|
||||||
|
* third parameter is a copy of cmp_ptr
|
||||||
|
*/
|
||||||
|
avl_tree_comp comp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* custom pointer delivered to the tree comparator
|
||||||
|
*/
|
||||||
|
void *cmp_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* internal enum for avl_find_... macros
|
||||||
|
*/
|
||||||
|
enum avl_find_mode {
|
||||||
|
AVL_FIND_EQUAL,
|
||||||
|
AVL_FIND_LESSEQUAL,
|
||||||
|
AVL_FIND_GREATEREQUAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AVL_TREE_INIT(_name, _comp, _allow_dups, _cmp_ptr) \
|
||||||
|
{ \
|
||||||
|
.list_head = LIST_HEAD_INIT(_name.list_head), \
|
||||||
|
.comp = _comp, \
|
||||||
|
.allow_dups = _allow_dups, \
|
||||||
|
.cmp_ptr = _cmp_ptr \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AVL_TREE(_name, _comp, _allow_dups, _cmp_ptr) \
|
||||||
|
struct avl_tree _name = \
|
||||||
|
AVL_TREE_INIT(_name, _comp, _allow_dups, _cmp_ptr)
|
||||||
|
|
||||||
|
void EXPORT(avl_init)(struct avl_tree *, avl_tree_comp, bool, void *);
|
||||||
|
struct avl_node *EXPORT(avl_find)(const struct avl_tree *, const void *);
|
||||||
|
struct avl_node *EXPORT(avl_find_greaterequal)(const struct avl_tree *tree, const void *key);
|
||||||
|
struct avl_node *EXPORT(avl_find_lessequal)(const struct avl_tree *tree, const void *key);
|
||||||
|
int EXPORT(avl_insert)(struct avl_tree *, struct avl_node *);
|
||||||
|
void EXPORT(avl_delete)(struct avl_tree *, struct avl_node *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param node pointer to node of the tree
|
||||||
|
* @return true if node is the first one of the tree, false otherwise
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
avl_is_first(struct avl_tree *tree, struct avl_node *node) {
|
||||||
|
return tree->list_head.next == &node->list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param node pointer to node of the tree
|
||||||
|
* @return true if node is the last one of the tree, false otherwise
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
avl_is_last(struct avl_tree *tree, struct avl_node *node) {
|
||||||
|
return tree->list_head.prev == &node->list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @return true if the tree is empty, false otherwise
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
avl_is_empty(struct avl_tree *tree) {
|
||||||
|
return tree->count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function to support returning the element from a avl tree query
|
||||||
|
* @param tree pointer to avl tree
|
||||||
|
* @param key pointer to key
|
||||||
|
* @param offset offset of node inside the embedded struct
|
||||||
|
* @param mode mode of lookup operation (less equal, equal or greater equal)
|
||||||
|
* @param pointer to elemen, NULL if no fitting one was found
|
||||||
|
*/
|
||||||
|
static inline void *
|
||||||
|
__avl_find_element(const struct avl_tree *tree, const void *key, size_t offset, enum avl_find_mode mode) {
|
||||||
|
void *node = NULL;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case AVL_FIND_EQUAL:
|
||||||
|
node = avl_find(tree, key);
|
||||||
|
break;
|
||||||
|
case AVL_FIND_LESSEQUAL:
|
||||||
|
node = avl_find_lessequal(tree, key);
|
||||||
|
break;
|
||||||
|
case AVL_FIND_GREATEREQUAL:
|
||||||
|
node = avl_find_greaterequal(tree, key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return node == NULL ? NULL : (((char *)node) - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to key
|
||||||
|
* @param element pointer to a node element
|
||||||
|
* (don't need to be initialized)
|
||||||
|
* @param node_element name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @return pointer to tree element with the specified key,
|
||||||
|
* NULL if no element was found
|
||||||
|
*/
|
||||||
|
#define avl_find_element(tree, key, element, node_element) \
|
||||||
|
((typeof(*(element)) *)__avl_find_element(tree, key, offsetof(typeof(*(element)), node_element), AVL_FIND_EQUAL))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to specified key
|
||||||
|
* @param element pointer to a node element
|
||||||
|
* (don't need to be initialized)
|
||||||
|
* @param node_element name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* return pointer to last tree element with less or equal key than specified key,
|
||||||
|
* NULL if no element was found
|
||||||
|
*/
|
||||||
|
#define avl_find_le_element(tree, key, element, node_element) \
|
||||||
|
((typeof(*(element)) *)__avl_find_element(tree, key, offsetof(typeof(*(element)), node_element), AVL_FIND_LESSEQUAL))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param key pointer to specified key
|
||||||
|
* @param element pointer to a node element
|
||||||
|
* (don't need to be initialized)
|
||||||
|
* @param node_element name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* return pointer to first tree element with greater or equal key than specified key,
|
||||||
|
* NULL if no element was found
|
||||||
|
*/
|
||||||
|
#define avl_find_ge_element(tree, key, element, node_element) \
|
||||||
|
((typeof(*(element)) *)__avl_find_element(tree, key, offsetof(typeof(*(element)), node_element), AVL_FIND_GREATEREQUAL))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function must not be called for an empty tree
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node element
|
||||||
|
* (don't need to be initialized)
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @return pointer to the first element of the avl_tree
|
||||||
|
* (automatically converted to type 'element')
|
||||||
|
*/
|
||||||
|
#define avl_first_element(tree, element, node_member) \
|
||||||
|
container_of((tree)->list_head.next, typeof(*(element)), node_member.list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tree pointer to tree
|
||||||
|
* @param element pointer to a node struct that contains the avl_node
|
||||||
|
* (don't need to be initialized)
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @return pointer to the last element of the avl_tree
|
||||||
|
* (automatically converted to type 'element')
|
||||||
|
*/
|
||||||
|
#define avl_last_element(tree, element, node_member) \
|
||||||
|
container_of((tree)->list_head.prev, typeof(*(element)), node_member.list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function must not be called for the last element of
|
||||||
|
* an avl tree
|
||||||
|
*
|
||||||
|
* @param element pointer to a node of the tree
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @return pointer to the node after 'element'
|
||||||
|
* (automatically converted to type 'element')
|
||||||
|
*/
|
||||||
|
#define avl_next_element(element, node_member) \
|
||||||
|
container_of((&(element)->node_member.list)->next, typeof(*(element)), node_member.list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function must not be called for the first element of
|
||||||
|
* an avl tree
|
||||||
|
*
|
||||||
|
* @param element pointer to a node of the tree
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @return pointer to the node before 'element'
|
||||||
|
* (automatically converted to type 'element')
|
||||||
|
*/
|
||||||
|
#define avl_prev_element(element, node_member) \
|
||||||
|
container_of((&(element)->node_member.list)->prev, typeof(*(element)), node_member.list)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param first pointer to first element of loop
|
||||||
|
* @param last pointer to last element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_element_range(first, last, element, node_member) \
|
||||||
|
for (element = (first); \
|
||||||
|
element->node_member.list.prev != &(last)->node_member.list; \
|
||||||
|
element = avl_next_element(element, node_member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree backwards, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param first pointer to first element of loop
|
||||||
|
* @param last pointer to last element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_element_range_reverse(first, last, element, node_member) \
|
||||||
|
for (element = (last); \
|
||||||
|
element->node_member.list.next != &(first)->node_member.list; \
|
||||||
|
element = avl_prev_element(element, node_member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over all elements of an avl_tree, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the tree during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_each_element(tree, element, node_member) \
|
||||||
|
avl_for_element_range(avl_first_element(tree, element, node_member), \
|
||||||
|
avl_last_element(tree, element, node_member), \
|
||||||
|
element, node_member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over all elements of an avl_tree backwards, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the tree during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_each_element_reverse(tree, element, node_member) \
|
||||||
|
avl_for_element_range_reverse(avl_first_element(tree, element, node_member), \
|
||||||
|
avl_last_element(tree, element, node_member), \
|
||||||
|
element, node_member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
* The loop runs from the element 'first' to the end of the tree.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param first pointer to first element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_element_to_last(tree, first, element, node_member) \
|
||||||
|
avl_for_element_range(first, avl_last_element(tree, element, node_member), element, node_member)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree backwards, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
* The loop runs from the element 'first' to the end of the tree.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param first pointer to first element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_element_to_last_reverse(tree, first, element, node_member) \
|
||||||
|
avl_for_element_range_reverse(first, avl_last_element(tree, element, node_member), element, node_member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
* The loop runs from the start of the tree to the element 'last'.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param last pointer to last element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_first_to_element(tree, last, element, node_member) \
|
||||||
|
avl_for_element_range(avl_first_element(tree, element, node_member), last, element, node_member)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree backwards, used similar to a for() command.
|
||||||
|
* This loop should not be used if elements are removed from the tree during
|
||||||
|
* the loop.
|
||||||
|
* The loop runs from the start of the tree to the element 'last'.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param last pointer to last element of loop
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the list during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
*/
|
||||||
|
#define avl_for_first_to_element_reverse(tree, last, element, node_member) \
|
||||||
|
avl_for_element_range_reverse(avl_first_element(tree, element, node_member), last, element, node_member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of nodes of a tree, used similar to a for() command.
|
||||||
|
* This loop can be used if the current element might be removed from
|
||||||
|
* the tree during the loop. Other elements should not be removed during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param first_element first element of loop
|
||||||
|
* @param last_element last element of loop
|
||||||
|
* @param element iterator pointer to tree element struct
|
||||||
|
* @param node_member name of avl_node within tree element struct
|
||||||
|
* @param ptr pointer to tree element struct which is used to store
|
||||||
|
* the next node during the loop
|
||||||
|
*/
|
||||||
|
#define avl_for_element_range_safe(first_element, last_element, element, node_member, ptr) \
|
||||||
|
for (element = (first_element), ptr = avl_next_element(first_element, node_member); \
|
||||||
|
element->node_member.list.prev != &(last_element)->node_member.list; \
|
||||||
|
element = ptr, ptr = avl_next_element(ptr, node_member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over a block of elements of a tree backwards, used similar to a for() command.
|
||||||
|
* This loop can be used if the current element might be removed from
|
||||||
|
* the tree during the loop. Other elements should not be removed during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param first_element first element of range (will be last returned by the loop)
|
||||||
|
* @param last_element last element of range (will be first returned by the loop)
|
||||||
|
* @param element iterator pointer to node element struct
|
||||||
|
* @param node_member name of avl_node within node element struct
|
||||||
|
* @param ptr pointer to node element struct which is used to store
|
||||||
|
* the previous node during the loop
|
||||||
|
*/
|
||||||
|
#define avl_for_element_range_reverse_safe(first_element, last_element, element, node_member, ptr) \
|
||||||
|
for (element = (last_element), ptr = avl_prev_element(last_element, node_member); \
|
||||||
|
element->node_member.list.next != &(first_element)->node_member.list; \
|
||||||
|
element = ptr, ptr = avl_prev_element(ptr, node_member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over all elements of an avl_tree, used similar to a for() command.
|
||||||
|
* This loop can be used if the current element might be removed from
|
||||||
|
* the tree during the loop. Other elements should not be removed during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the tree during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @param ptr pointer to a tree element which is used to store
|
||||||
|
* the next node during the loop
|
||||||
|
*/
|
||||||
|
#define avl_for_each_element_safe(tree, element, node_member, ptr) \
|
||||||
|
avl_for_element_range_safe(avl_first_element(tree, element, node_member), \
|
||||||
|
avl_last_element(tree, element, node_member), \
|
||||||
|
element, node_member, ptr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over all elements of an avl_tree backwards, used similar to a for() command.
|
||||||
|
* This loop can be used if the current element might be removed from
|
||||||
|
* the tree during the loop. Other elements should not be removed during
|
||||||
|
* the loop.
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the tree during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @param ptr pointer to a tree element which is used to store
|
||||||
|
* the next node during the loop
|
||||||
|
*/
|
||||||
|
#define avl_for_each_element_reverse_safe(tree, element, node_member, ptr) \
|
||||||
|
avl_for_element_range_reverse_safe(avl_first_element(tree, element, node_member), \
|
||||||
|
avl_last_element(tree, element, node_member), \
|
||||||
|
element, node_member, ptr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special loop that removes all elements of the tree and cleans up the tree
|
||||||
|
* root. The loop body is responsible to free the node elements of the tree.
|
||||||
|
*
|
||||||
|
* This loop is much faster than a normal one for clearing the tree because it
|
||||||
|
* does not rebalance the tree after each removal. Do NOT use a break command
|
||||||
|
* inside.
|
||||||
|
* You can free the memory of the elements within the loop.
|
||||||
|
* Do NOT call avl_delete() on the elements within the loop,
|
||||||
|
*
|
||||||
|
* @param tree pointer to avl-tree
|
||||||
|
* @param element pointer to a node of the tree, this element will
|
||||||
|
* contain the current node of the tree during the loop
|
||||||
|
* @param node_member name of the avl_node element inside the
|
||||||
|
* larger struct
|
||||||
|
* @param ptr pointer to a tree element which is used to store
|
||||||
|
* the next node during the loop
|
||||||
|
*/
|
||||||
|
#define avl_remove_all_elements(tree, element, node_member, ptr) \
|
||||||
|
for (element = avl_first_element(tree, element, node_member), \
|
||||||
|
ptr = avl_next_element(element, node_member), \
|
||||||
|
INIT_LIST_HEAD(&(tree)->list_head), \
|
||||||
|
(tree)->root = NULL; \
|
||||||
|
(tree)->count > 0; \
|
||||||
|
element = ptr, ptr = avl_next_element(ptr, node_member), (tree)->count--)
|
||||||
|
|
||||||
|
#endif /* _AVL_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* c-basic-offset: 2
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
287
3P/libubox/blob.c
Normal file
287
3P/libubox/blob.c
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* blob - library for generating/parsing tagged binary data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "blob.h"
|
||||||
|
|
||||||
|
static bool
|
||||||
|
blob_buffer_grow(struct blob_buf *buf, int minlen)
|
||||||
|
{
|
||||||
|
struct blob_buf *new;
|
||||||
|
int delta = ((minlen / 256) + 1) * 256;
|
||||||
|
new = realloc(buf->buf, buf->buflen + delta);
|
||||||
|
if (new) {
|
||||||
|
buf->buf = new;
|
||||||
|
memset(buf->buf + buf->buflen, 0, delta);
|
||||||
|
buf->buflen += delta;
|
||||||
|
}
|
||||||
|
return !!new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_init(struct blob_attr *attr, int id, unsigned int len)
|
||||||
|
{
|
||||||
|
len &= BLOB_ATTR_LEN_MASK;
|
||||||
|
len |= (id << BLOB_ATTR_ID_SHIFT) & BLOB_ATTR_ID_MASK;
|
||||||
|
attr->id_len = cpu_to_be32(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
offset_to_attr(struct blob_buf *buf, int offset)
|
||||||
|
{
|
||||||
|
void *ptr = (char *)buf->buf + offset - BLOB_COOKIE;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
blob_buf_grow(struct blob_buf *buf, int required)
|
||||||
|
{
|
||||||
|
int offset_head = attr_to_offset(buf, buf->head);
|
||||||
|
|
||||||
|
if (!buf->grow || !buf->grow(buf, required))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buf->head = offset_to_attr(buf, offset_head);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct blob_attr *
|
||||||
|
blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)
|
||||||
|
{
|
||||||
|
int offset = attr_to_offset(buf, pos);
|
||||||
|
int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen;
|
||||||
|
struct blob_attr *attr;
|
||||||
|
|
||||||
|
if (required > 0) {
|
||||||
|
if (!blob_buf_grow(buf, required))
|
||||||
|
return NULL;
|
||||||
|
attr = offset_to_attr(buf, offset);
|
||||||
|
} else {
|
||||||
|
attr = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
blob_init(attr, id, payload + sizeof(struct blob_attr));
|
||||||
|
blob_fill_pad(attr);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_buf_init(struct blob_buf *buf, int id)
|
||||||
|
{
|
||||||
|
if (!buf->grow)
|
||||||
|
buf->grow = blob_buffer_grow;
|
||||||
|
|
||||||
|
buf->head = buf->buf;
|
||||||
|
if (blob_add(buf, buf->buf, id, 0) == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blob_buf_free(struct blob_buf *buf)
|
||||||
|
{
|
||||||
|
free(buf->buf);
|
||||||
|
buf->buf = NULL;
|
||||||
|
buf->buflen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blob_fill_pad(struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
char *buf = (char *) attr;
|
||||||
|
int len = blob_pad_len(attr);
|
||||||
|
int delta = len - blob_raw_len(attr);
|
||||||
|
|
||||||
|
if (delta > 0)
|
||||||
|
memset(buf + len - delta, 0, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blob_set_raw_len(struct blob_attr *attr, unsigned int len)
|
||||||
|
{
|
||||||
|
len &= BLOB_ATTR_LEN_MASK;
|
||||||
|
attr->id_len &= ~cpu_to_be32(BLOB_ATTR_LEN_MASK);
|
||||||
|
attr->id_len |= cpu_to_be32(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct blob_attr *
|
||||||
|
blob_new(struct blob_buf *buf, int id, int payload)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
|
||||||
|
attr = blob_add(buf, blob_next(buf->head), id, payload);
|
||||||
|
if (!attr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr));
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct blob_attr *
|
||||||
|
blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
|
||||||
|
if (len < sizeof(struct blob_attr) || !ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
attr = blob_add(buf, blob_next(buf->head), 0, len - sizeof(struct blob_attr));
|
||||||
|
if (!attr)
|
||||||
|
return NULL;
|
||||||
|
blob_set_raw_len(buf->head, blob_pad_len(buf->head) + len);
|
||||||
|
memcpy(attr, ptr, len);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct blob_attr *
|
||||||
|
blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
|
||||||
|
attr = blob_new(buf, id, len);
|
||||||
|
if (!attr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
memcpy(blob_data(attr), ptr, len);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
blob_nest_start(struct blob_buf *buf, int id)
|
||||||
|
{
|
||||||
|
unsigned long offset = attr_to_offset(buf, buf->head);
|
||||||
|
buf->head = blob_new(buf, id, 0);
|
||||||
|
if (!buf->head)
|
||||||
|
return NULL;
|
||||||
|
return (void *) offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blob_nest_end(struct blob_buf *buf, void *cookie)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie);
|
||||||
|
blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head));
|
||||||
|
buf->head = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int blob_type_minlen[BLOB_ATTR_LAST] = {
|
||||||
|
[BLOB_ATTR_STRING] = 1,
|
||||||
|
[BLOB_ATTR_INT8] = sizeof(uint8_t),
|
||||||
|
[BLOB_ATTR_INT16] = sizeof(uint16_t),
|
||||||
|
[BLOB_ATTR_INT32] = sizeof(uint32_t),
|
||||||
|
[BLOB_ATTR_INT64] = sizeof(uint64_t),
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
blob_check_type(const void *ptr, unsigned int len, int type)
|
||||||
|
{
|
||||||
|
const char *data = ptr;
|
||||||
|
|
||||||
|
if (type >= BLOB_ATTR_LAST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (type >= BLOB_ATTR_INT8 && type <= BLOB_ATTR_INT64) {
|
||||||
|
if (len != blob_type_minlen[type])
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (len < blob_type_minlen[type])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == BLOB_ATTR_STRING && data[len - 1] != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||||
|
{
|
||||||
|
struct blob_attr *pos;
|
||||||
|
int found = 0;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
memset(data, 0, sizeof(struct blob_attr *) * max);
|
||||||
|
blob_for_each_attr(pos, attr, rem) {
|
||||||
|
int id = blob_id(pos);
|
||||||
|
int len = blob_len(pos);
|
||||||
|
|
||||||
|
if (id >= max)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
int type = info[id].type;
|
||||||
|
|
||||||
|
if (type < BLOB_ATTR_LAST) {
|
||||||
|
if (!blob_check_type(blob_data(pos), len, type))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info[id].minlen && len < info[id].minlen)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (info[id].maxlen && len > info[id].maxlen)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (info[id].validate && !info[id].validate(&info[id], pos))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data[id])
|
||||||
|
found++;
|
||||||
|
|
||||||
|
data[id] = pos;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2)
|
||||||
|
{
|
||||||
|
if (!a1 && !a2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!a1 || !a2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (blob_pad_len(a1) != blob_pad_len(a2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !memcmp(a1, a2, blob_pad_len(a1));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct blob_attr *
|
||||||
|
blob_memdup(struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
struct blob_attr *ret;
|
||||||
|
int size = blob_pad_len(attr);
|
||||||
|
|
||||||
|
ret = malloc(size);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(ret, attr, size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
257
3P/libubox/blob.h
Normal file
257
3P/libubox/blob.h
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* blob - library for generating/parsing tagged binary data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BLOB_H__
|
||||||
|
#define _BLOB_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define BLOB_COOKIE 0x01234567
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BLOB_ATTR_UNSPEC,
|
||||||
|
BLOB_ATTR_NESTED,
|
||||||
|
BLOB_ATTR_BINARY,
|
||||||
|
BLOB_ATTR_STRING,
|
||||||
|
BLOB_ATTR_INT8,
|
||||||
|
BLOB_ATTR_INT16,
|
||||||
|
BLOB_ATTR_INT32,
|
||||||
|
BLOB_ATTR_INT64,
|
||||||
|
BLOB_ATTR_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BLOB_ATTR_ID_MASK 0x7f000000
|
||||||
|
#define BLOB_ATTR_ID_SHIFT 24
|
||||||
|
#define BLOB_ATTR_LEN_MASK 0x00ffffff
|
||||||
|
#define BLOB_ATTR_ALIGN 4
|
||||||
|
#define BLOB_ATTR_EXTENDED 0x80000000
|
||||||
|
|
||||||
|
struct blob_attr {
|
||||||
|
uint32_t id_len;
|
||||||
|
char data[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct blob_attr_info {
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int minlen;
|
||||||
|
unsigned int maxlen;
|
||||||
|
bool (*validate)(const struct blob_attr_info *, struct blob_attr *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct blob_buf {
|
||||||
|
struct blob_attr *head;
|
||||||
|
bool (*grow)(struct blob_buf *buf, int minlen);
|
||||||
|
int buflen;
|
||||||
|
void *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blob_data: returns the data pointer for an attribute
|
||||||
|
*/
|
||||||
|
static inline void *
|
||||||
|
blob_data(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return (void *) attr->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blob_id: returns the id of an attribute
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
blob_id(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
int id = (be32_to_cpu(attr->id_len) & BLOB_ATTR_ID_MASK) >> BLOB_ATTR_ID_SHIFT;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
blob_is_extended(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return !!(attr->id_len & cpu_to_be32(BLOB_ATTR_EXTENDED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blob_len: returns the length of the attribute's payload
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
blob_len(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return (be32_to_cpu(attr->id_len) & BLOB_ATTR_LEN_MASK) - sizeof(struct blob_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blob_raw_len: returns the complete length of an attribute (including the header)
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
blob_raw_len(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return blob_len(attr) + sizeof(struct blob_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blob_pad_len: returns the padded length of an attribute (including the header)
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
blob_pad_len(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
unsigned int len = blob_raw_len(attr);
|
||||||
|
len = (len + BLOB_ATTR_ALIGN - 1) & ~(BLOB_ATTR_ALIGN - 1);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
blob_get_u8(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return *((uint8_t *) attr->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t
|
||||||
|
blob_get_u16(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
uint16_t *tmp = (uint16_t*)attr->data;
|
||||||
|
return be16_to_cpu(*tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
blob_get_u32(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
uint32_t *tmp = (uint32_t*)attr->data;
|
||||||
|
return be32_to_cpu(*tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
blob_get_u64(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = (uint32_t *) blob_data(attr);
|
||||||
|
uint64_t tmp = ((uint64_t) be32_to_cpu(ptr[0])) << 32;
|
||||||
|
tmp |= be32_to_cpu(ptr[1]);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int8_t
|
||||||
|
blob_get_int8(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return blob_get_u8(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int16_t
|
||||||
|
blob_get_int16(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return blob_get_u16(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t
|
||||||
|
blob_get_int32(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return blob_get_u32(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t
|
||||||
|
blob_get_int64(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return blob_get_u64(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *
|
||||||
|
blob_get_string(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return attr->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_next(const struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return (struct blob_attr *) ((char *) attr + blob_pad_len(attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void blob_fill_pad(struct blob_attr *attr);
|
||||||
|
extern void blob_set_raw_len(struct blob_attr *attr, unsigned int len);
|
||||||
|
extern bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2);
|
||||||
|
extern int blob_buf_init(struct blob_buf *buf, int id);
|
||||||
|
extern void blob_buf_free(struct blob_buf *buf);
|
||||||
|
extern bool blob_buf_grow(struct blob_buf *buf, int required);
|
||||||
|
extern struct blob_attr *blob_new(struct blob_buf *buf, int id, int payload);
|
||||||
|
extern void *blob_nest_start(struct blob_buf *buf, int id);
|
||||||
|
extern void blob_nest_end(struct blob_buf *buf, void *cookie);
|
||||||
|
extern struct blob_attr *blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len);
|
||||||
|
extern bool blob_check_type(const void *ptr, unsigned int len, int type);
|
||||||
|
extern int blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max);
|
||||||
|
extern struct blob_attr *blob_memdup(struct blob_attr *attr);
|
||||||
|
extern struct blob_attr *blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len);
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_put_string(struct blob_buf *buf, int id, const char *str)
|
||||||
|
{
|
||||||
|
return blob_put(buf, id, str, strlen(str) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_put_u8(struct blob_buf *buf, int id, uint8_t val)
|
||||||
|
{
|
||||||
|
return blob_put(buf, id, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_put_u16(struct blob_buf *buf, int id, uint16_t val)
|
||||||
|
{
|
||||||
|
val = cpu_to_be16(val);
|
||||||
|
return blob_put(buf, id, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_put_u32(struct blob_buf *buf, int id, uint32_t val)
|
||||||
|
{
|
||||||
|
val = cpu_to_be32(val);
|
||||||
|
return blob_put(buf, id, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct blob_attr *
|
||||||
|
blob_put_u64(struct blob_buf *buf, int id, uint64_t val)
|
||||||
|
{
|
||||||
|
val = cpu_to_be64(val);
|
||||||
|
return blob_put(buf, id, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define blob_put_int8 blob_put_u8
|
||||||
|
#define blob_put_int16 blob_put_u16
|
||||||
|
#define blob_put_int32 blob_put_u32
|
||||||
|
#define blob_put_int64 blob_put_u64
|
||||||
|
|
||||||
|
#define __blob_for_each_attr(pos, attr, rem) \
|
||||||
|
for (pos = (void *) attr; \
|
||||||
|
rem > 0 && (blob_pad_len(pos) <= rem) && \
|
||||||
|
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||||
|
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||||
|
|
||||||
|
|
||||||
|
#define blob_for_each_attr(pos, attr, rem) \
|
||||||
|
for (rem = attr ? blob_len(attr) : 0, \
|
||||||
|
pos = attr ? blob_data(attr) : 0; \
|
||||||
|
rem > 0 && (blob_pad_len(pos) <= rem) && \
|
||||||
|
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||||
|
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
320
3P/libubox/blobmsg.c
Normal file
320
3P/libubox/blobmsg.c
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010-2012 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "blobmsg.h"
|
||||||
|
|
||||||
|
static const int blob_type[__BLOBMSG_TYPE_LAST] = {
|
||||||
|
[BLOBMSG_TYPE_INT8] = BLOB_ATTR_INT8,
|
||||||
|
[BLOBMSG_TYPE_INT16] = BLOB_ATTR_INT16,
|
||||||
|
[BLOBMSG_TYPE_INT32] = BLOB_ATTR_INT32,
|
||||||
|
[BLOBMSG_TYPE_INT64] = BLOB_ATTR_INT64,
|
||||||
|
[BLOBMSG_TYPE_STRING] = BLOB_ATTR_STRING,
|
||||||
|
[BLOBMSG_TYPE_UNSPEC] = BLOB_ATTR_BINARY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t
|
||||||
|
blobmsg_namelen(const struct blobmsg_hdr *hdr)
|
||||||
|
{
|
||||||
|
return be16_to_cpu(hdr->namelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
|
||||||
|
{
|
||||||
|
const struct blobmsg_hdr *hdr;
|
||||||
|
const char *data;
|
||||||
|
int id, len;
|
||||||
|
|
||||||
|
if (blob_len(attr) < sizeof(struct blobmsg_hdr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
hdr = (void *) attr->data;
|
||||||
|
if (!hdr->namelen && name)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (blobmsg_namelen(hdr) > blob_len(attr) - sizeof(struct blobmsg_hdr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (hdr->name[blobmsg_namelen(hdr)] != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
id = blob_id(attr);
|
||||||
|
len = blobmsg_data_len(attr);
|
||||||
|
data = blobmsg_data(attr);
|
||||||
|
|
||||||
|
if (id > BLOBMSG_TYPE_LAST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!blob_type[id])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return blob_check_type(data, len, blob_type[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int blobmsg_check_array(const struct blob_attr *attr, int type)
|
||||||
|
{
|
||||||
|
struct blob_attr *cur;
|
||||||
|
bool name;
|
||||||
|
int rem;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
switch (blobmsg_type(attr)) {
|
||||||
|
case BLOBMSG_TYPE_TABLE:
|
||||||
|
name = true;
|
||||||
|
break;
|
||||||
|
case BLOBMSG_TYPE_ARRAY:
|
||||||
|
name = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_for_each_attr(cur, attr, rem) {
|
||||||
|
if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!blobmsg_check_attr(cur, name))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
|
||||||
|
{
|
||||||
|
return blobmsg_check_array(attr, type) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
|
||||||
|
struct blob_attr **tb, void *data, unsigned int len)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
memset(tb, 0, policy_len * sizeof(*tb));
|
||||||
|
__blob_for_each_attr(attr, data, len) {
|
||||||
|
if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
|
||||||
|
blob_id(attr) != policy[i].type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!blobmsg_check_attr(attr, false))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (tb[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tb[i++] = attr;
|
||||||
|
if (i == policy_len)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
|
||||||
|
struct blob_attr **tb, void *data, unsigned int len)
|
||||||
|
{
|
||||||
|
struct blobmsg_hdr *hdr;
|
||||||
|
struct blob_attr *attr;
|
||||||
|
uint8_t *pslen;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(tb, 0, policy_len * sizeof(*tb));
|
||||||
|
pslen = alloca(policy_len);
|
||||||
|
for (i = 0; i < policy_len; i++) {
|
||||||
|
if (!policy[i].name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pslen[i] = strlen(policy[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
__blob_for_each_attr(attr, data, len) {
|
||||||
|
hdr = blob_data(attr);
|
||||||
|
for (i = 0; i < policy_len; i++) {
|
||||||
|
if (!policy[i].name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
|
||||||
|
blob_id(attr) != policy[i].type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (blobmsg_namelen(hdr) != pslen[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!blobmsg_check_attr(attr, true))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (tb[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(policy[i].name, (char *) hdr->name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tb[i] = attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct blob_attr *
|
||||||
|
blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
struct blobmsg_hdr *hdr;
|
||||||
|
int attrlen, namelen;
|
||||||
|
char *pad_start, *pad_end;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = "";
|
||||||
|
|
||||||
|
namelen = strlen(name);
|
||||||
|
attrlen = blobmsg_hdrlen(namelen) + payload_len;
|
||||||
|
attr = blob_new(buf, type, attrlen);
|
||||||
|
if (!attr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
|
||||||
|
hdr = blob_data(attr);
|
||||||
|
hdr->namelen = cpu_to_be16(namelen);
|
||||||
|
strcpy((char *) hdr->name, (const char *)name);
|
||||||
|
pad_end = *data = blobmsg_data(attr);
|
||||||
|
pad_start = (char *) &hdr->name[namelen];
|
||||||
|
if (pad_start < pad_end)
|
||||||
|
memset(pad_start, 0, pad_end - pad_start);
|
||||||
|
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
|
||||||
|
{
|
||||||
|
return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)
|
||||||
|
{
|
||||||
|
struct blob_attr *head;
|
||||||
|
int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE;
|
||||||
|
unsigned long offset = attr_to_offset(buf, buf->head);
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = "";
|
||||||
|
|
||||||
|
head = blobmsg_new(buf, type, name, 0, &data);
|
||||||
|
if (!head)
|
||||||
|
return NULL;
|
||||||
|
blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name)));
|
||||||
|
buf->head = head;
|
||||||
|
return (void *)offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg)
|
||||||
|
{
|
||||||
|
va_list arg2;
|
||||||
|
char cbuf;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_copy(arg2, arg);
|
||||||
|
len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
|
||||||
|
va_end(arg2);
|
||||||
|
|
||||||
|
vsprintf(blobmsg_alloc_string_buffer(buf, name, len + 1), format, arg);
|
||||||
|
blobmsg_add_string_buffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
blobmsg_vprintf(buf, name, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
void *data_dest;
|
||||||
|
|
||||||
|
attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest);
|
||||||
|
if (!attr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data_dest = blobmsg_data(attr);
|
||||||
|
blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
|
||||||
|
blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
|
||||||
|
|
||||||
|
return data_dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr = blob_next(buf->head);
|
||||||
|
int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE;
|
||||||
|
int required = maxlen - (buf->buflen - offset);
|
||||||
|
|
||||||
|
if (required <= 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
blob_buf_grow(buf, required);
|
||||||
|
attr = blob_next(buf->head);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return blobmsg_data(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
blobmsg_add_string_buffer(struct blob_buf *buf)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
int len, attrlen;
|
||||||
|
|
||||||
|
attr = blob_next(buf->head);
|
||||||
|
len = strlen(blobmsg_data(attr)) + 1;
|
||||||
|
|
||||||
|
attrlen = blob_raw_len(attr) + len;
|
||||||
|
blob_set_raw_len(attr, attrlen);
|
||||||
|
blob_fill_pad(attr);
|
||||||
|
|
||||||
|
blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
|
||||||
|
const void *data, unsigned int len)
|
||||||
|
{
|
||||||
|
struct blob_attr *attr;
|
||||||
|
void *data_dest;
|
||||||
|
|
||||||
|
attr = blobmsg_new(buf, type, name, len, &data_dest);
|
||||||
|
if (!attr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
memcpy(data_dest, data, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user