diff options
Diffstat (limited to 'json-c/src')
40 files changed, 6120 insertions, 0 deletions
diff --git a/json-c/src/.gitignore b/json-c/src/.gitignore new file mode 100644 index 0000000..5534d69 --- /dev/null +++ b/json-c/src/.gitignore @@ -0,0 +1,37 @@ +.deps/ +.libs/ +/aclocal.m4 +/autom4te.cache +/config.guess +/json_config.h +/config.h +/config.log +/config.status +/config.sub +/configure +/depcomp +/install-sh +/json.pc +/libtool +/ltmain.sh +/Makefile +/Makefile.in +/missing +/stamp-h1 +/stamp-h2 +/tests/Makefile +/tests/Makefile.in +/tests/test1 +/tests/test2 +/tests/test4 +/tests/testSubDir +/tests/test_parse_int64 +/tests/test_parse +/tests/test_cast +/tests/test_null +/tests/test_printbuf +/Debug +/Release +*.lo +*.o +/libjson.la diff --git a/json-c/src/AUTHORS b/json-c/src/AUTHORS new file mode 100644 index 0000000..b389989 --- /dev/null +++ b/json-c/src/AUTHORS @@ -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) + diff --git a/json-c/src/COPYING b/json-c/src/COPYING new file mode 100644 index 0000000..f8ff2e1 --- /dev/null +++ b/json-c/src/COPYING @@ -0,0 +1,19 @@ +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. diff --git a/json-c/src/ChangeLog b/json-c/src/ChangeLog new file mode 100644 index 0000000..5d2c9af --- /dev/null +++ b/json-c/src/ChangeLog @@ -0,0 +1,129 @@ +0.10 +  * 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 diff --git a/json-c/src/Doxyfile b/json-c/src/Doxyfile new file mode 100644 index 0000000..3ff27eb --- /dev/null +++ b/json-c/src/Doxyfile @@ -0,0 +1,1153 @@ +# Doxyfile 1.3.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +#       TAG = value [value, ...] +# For lists items can also be appended using: +#       TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded  +# by quotes) that should identify the project. + +PROJECT_NAME           = json-c + +# The PROJECT_NUMBER tag can be used to enter a project or revision number.  +# This could be handy for archiving the generated documentation or  +# if some version control system is used. + +PROJECT_NUMBER         = 0.10 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)  +# base path where the generated documentation will be put.  +# If a relative path is entered, it will be relative to the location  +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY       = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create  +# 4096 sub-directories (in 2 levels) under the output directory of each output  +# format and will distribute the generated files over these directories.  +# Enabling this option can be useful when feeding doxygen a huge amount of source  +# files, where putting all generated files in the same directory would otherwise  +# cause performance problems for the file system. + +CREATE_SUBDIRS         = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all  +# documentation generated by doxygen is written. Doxygen will use this  +# information to generate all constant output in the proper language.  +# The default language is English, other supported languages are:  +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,  +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,  +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,  +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,  +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE        = English + +# This tag can be used to specify the encoding used in the generated output.  +# The encoding is not always determined by the language that is chosen,  +# but also whether or not the output is meant for Windows or non-Windows users.  +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES  +# forces the Windows encoding (this is the default for the Windows binary),  +# whereas setting the tag to NO uses a Unix-style encoding (the default for  +# all platforms other than Windows). + +USE_WINDOWS_ENCODING   = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will  +# include brief member descriptions after the members that are listed in  +# the file and class documentation (similar to JavaDoc).  +# Set to NO to disable this. + +BRIEF_MEMBER_DESC      = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend  +# the brief description of a member or function before the detailed description.  +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the  +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF           = YES + +# This tag implements a quasi-intelligent brief description abbreviator  +# that is used to form the text in various listings. Each string  +# in this list, if found as the leading text of the brief description, will be  +# stripped from the text and the result after processing the whole list, is used  +# as the annotated text. Otherwise, the brief description is used as-is. If left  +# blank, the following values are used ("$name" is automatically replaced with the  +# name of the entity): "The $name class" "The $name widget" "The $name file"  +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF       =  + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then  +# Doxygen will generate a detailed section even if there is only a brief  +# description. + +ALWAYS_DETAILED_SEC    = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited  +# members of a class in the documentation of that class as if those members were  +# ordinary class members. Constructors, destructors and assignment operators of  +# the base classes will not be shown. + +INLINE_INHERITED_MEMB  = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full  +# path before files name in the file list and in the header files. If set  +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES        = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag  +# can be used to strip a user-defined part of the path. Stripping is  +# only done if one of the specified strings matches the left-hand part of  +# the path. The tag can be used to show relative paths in the file list.  +# If left blank the directory from which doxygen is run is used as the  +# path to strip. + +STRIP_FROM_PATH        =  + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of  +# the path mentioned in the documentation of a class, which tells  +# the reader which header file to include in order to use a class.  +# If left blank only the name of the header file containing the class  +# definition is used. Otherwise one should specify the include paths that  +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH    =  + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter  +# (but less readable) file names. This can be useful is your file systems  +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES            = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen  +# will interpret the first line (until the first dot) of a JavaDoc-style  +# comment as the brief description. If set to NO, the JavaDoc  +# comments will behave just like the Qt-style comments (thus requiring an  +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF      = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen  +# treat a multi-line C++ special comment block (i.e. a block of //! or ///  +# comments) as a brief description. This used to be the default behaviour.  +# The new default is to treat a multi-line C++ comment block as a detailed  +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen  +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member  +# documentation. + +DETAILS_AT_TOP         = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented  +# member inherits the documentation from any documented member that it  +# re-implements. + +INHERIT_DOCS           = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC  +# tag is set to YES, then doxygen will reuse the documentation of the first  +# member in the group (if any) for the other members of the group. By default  +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC   = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab.  +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE               = 8 + +# This tag can be used to specify a number of aliases that acts  +# as commands in the documentation. An alias has the form "name=value".  +# For example adding "sideeffect=\par Side Effects:\n" will allow you to  +# put the command \sideeffect (or @sideeffect) in the documentation, which  +# will result in a user-defined paragraph with heading "Side Effects:".  +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES                =  + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources  +# only. Doxygen will then generate output that is more tailored for C.  +# For instance, some of the names that are used will be different. The list  +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C  = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources  +# only. Doxygen will then generate output that is more tailored for Java.  +# For instance, namespaces will be presented as packages, qualified scopes  +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA   = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of  +# the same type (for instance a group of public functions) to be put as a  +# subgroup of that type (e.g. under the Public Functions section). Set it to  +# NO to prevent subgrouping. Alternatively, this can be done per class using  +# the \nosubgrouping command. + +SUBGROUPING            = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in  +# documentation are documented, even if no documentation was available.  +# Private class members and static file members will be hidden unless  +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL            = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class  +# will be included in the documentation. + +EXTRACT_PRIVATE        = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file  +# will be included in the documentation. + +EXTRACT_STATIC         = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)  +# defined locally in source files will be included in the documentation.  +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES  = NO + +# This flag is only useful for Objective-C code. When set to YES local  +# methods, which are defined in the implementation section but not in  +# the interface are included in the documentation.  +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS  = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all  +# undocumented members of documented classes, files or namespaces.  +# If set to NO (the default) these members will be included in the  +# various overviews, but no documentation section is generated.  +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS     = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all  +# undocumented classes that are normally visible in the class hierarchy.  +# If set to NO (the default) these classes will be included in the various  +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES     = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all  +# friend (class|struct|union) declarations.  +# If set to NO (the default) these declarations will be included in the  +# documentation. + +HIDE_FRIEND_COMPOUNDS  = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any  +# documentation blocks found inside the body of a function.  +# If set to NO (the default) these blocks will be appended to the  +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS      = NO + +# The INTERNAL_DOCS tag determines if documentation  +# that is typed after a \internal command is included. If the tag is set  +# to NO (the default) then the documentation will be excluded.  +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS          = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate  +# file names in lower-case letters. If set to YES upper-case letters are also  +# allowed. This is useful if you have classes or files whose names only differ  +# in case and if your file system supports case sensitive file names. Windows  +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES       = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen  +# will show members with their full class and namespace scopes in the  +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES       = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen  +# will put a list of the files that are included by a file in the documentation  +# of that file. + +SHOW_INCLUDE_FILES     = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]  +# is inserted in the documentation for inline members. + +INLINE_INFO            = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen  +# will sort the (detailed) documentation of file and class members  +# alphabetically by member name. If set to NO the members will appear in  +# declaration order. + +SORT_MEMBER_DOCS       = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the  +# brief documentation of file, namespace and class members alphabetically  +# by member name. If set to NO (the default) the members will appear in  +# declaration order. + +SORT_BRIEF_DOCS        = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be  +# sorted by fully-qualified names, including namespaces. If set to  +# NO (the default), the class list will be sorted only by class name,  +# not including the namespace part.  +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the  +# alphabetical list. + +SORT_BY_SCOPE_NAME     = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or  +# disable (NO) the todo list. This list is created by putting \todo  +# commands in the documentation. + +GENERATE_TODOLIST      = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or  +# disable (NO) the test list. This list is created by putting \test  +# commands in the documentation. + +GENERATE_TESTLIST      = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or  +# disable (NO) the bug list. This list is created by putting \bug  +# commands in the documentation. + +GENERATE_BUGLIST       = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or  +# disable (NO) the deprecated list. This list is created by putting  +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional  +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS       =  + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines  +# the initial value of a variable or define consists of for it to appear in  +# the documentation. If the initializer consists of more lines than specified  +# here it will be hidden. Use a value of 0 to hide initializers completely.  +# The appearance of the initializer of individual variables and defines in the  +# documentation can be controlled using \showinitializer or \hideinitializer  +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES  = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated  +# at the bottom of the documentation of classes and structs. If set to YES the  +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES        = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated  +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET                  = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are  +# generated by doxygen. Possible values are YES and NO. If left blank  +# NO is used. + +WARNINGS               = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings  +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will  +# automatically be disabled. + +WARN_IF_UNDOCUMENTED   = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for  +# potential errors in the documentation, such as not documenting some  +# parameters in a documented function, or documenting parameters that  +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR      = YES + +# The WARN_FORMAT tag determines the format of the warning messages that  +# doxygen can produce. The string should contain the $file, $line, and $text  +# tags, which will be replaced by the file and line number from which the  +# warning originated and the warning text. + +WARN_FORMAT            = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning  +# and error messages should be written. If left blank the output is written  +# to stderr. + +WARN_LOGFILE           =  + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain  +# documented source files. You may enter file names like "myfile.cpp" or  +# directories like "/usr/src/myproject". Separate the files or directories  +# with spaces. + +INPUT                  =  + +# If the value of the INPUT tag contains directories, you can use the  +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp  +# and *.h) to filter out the source-files in the directories. If left  +# blank the following patterns are tested:  +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp  +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS          = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories  +# should be searched for input files as well. Possible values are YES and NO.  +# If left blank NO is used. + +RECURSIVE              = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should  +# excluded from the INPUT source files. This way you can easily exclude a  +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE                =  + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories  +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS       = NO + +# If the value of the INPUT tag contains directories, you can use the  +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude  +# certain files from those directories. + +EXCLUDE_PATTERNS       =  + +# The EXAMPLE_PATH tag can be used to specify one or more files or  +# directories that contain example code fragments that are included (see  +# the \include command). + +EXAMPLE_PATH           =  + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the  +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp  +# and *.h) to filter out the source-files in the directories. If left  +# blank all files are included. + +EXAMPLE_PATTERNS       =  + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be  +# searched for input files to be used with the \include or \dontinclude  +# commands irrespective of the value of the RECURSIVE tag.  +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE      = NO + +# The IMAGE_PATH tag can be used to specify one or more files or  +# directories that contain image that are included in the documentation (see  +# the \image command). + +IMAGE_PATH             =  + +# The INPUT_FILTER tag can be used to specify a program that doxygen should  +# invoke to filter for each input file. Doxygen will invoke the filter program  +# by executing (via popen()) the command <filter> <input-file>, where <filter>  +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an  +# input file. Doxygen will then use the output that the filter program writes  +# to standard output.  If FILTER_PATTERNS is specified, this tag will be  +# ignored. + +INPUT_FILTER           =  + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern  +# basis.  Doxygen will compare the file name with each pattern and apply the  +# filter if there is a match.  The filters are a list of the form:  +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further  +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER  +# is applied to all files. + +FILTER_PATTERNS        =  + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using  +# INPUT_FILTER) will be used to filter the input files when producing source  +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES    = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will  +# be generated. Documented entities will be cross-referenced with these sources.  +# Note: To get rid of all source code in the generated output, make sure also  +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER         = NO + +# Setting the INLINE_SOURCES tag to YES will include the body  +# of functions and classes directly in the documentation. + +INLINE_SOURCES         = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct  +# doxygen to hide any special comment blocks from generated source code  +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS    = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default)  +# then for each documented function all documented  +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default)  +# then for each documented function all documented entities  +# called/used by that function will be listed. + +REFERENCES_RELATION    = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen  +# will generate a verbatim copy of the header file for each class for  +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS       = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index  +# of all compounds will be generated. Enable this if the project  +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX     = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then  +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns  +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX    = 5 + +# In case all classes in a project start with a common prefix, all  +# classes will be put under the same header in the alphabetical index.  +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that  +# should be ignored while generating the index headers. + +IGNORE_PREFIX          =  + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will  +# generate HTML output. + +GENERATE_HTML          = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.  +# If a relative path is entered the value of OUTPUT_DIRECTORY will be  +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT            = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for  +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank  +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION    = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for  +# each generated HTML page. If it is left blank doxygen will generate a  +# standard header. + +HTML_HEADER            =  + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for  +# each generated HTML page. If it is left blank doxygen will generate a  +# standard footer. + +HTML_FOOTER            =  + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading  +# style sheet that is used by each HTML page. It can be used to  +# fine-tune the look of the HTML output. If the tag is left blank doxygen  +# will generate a default style sheet. Note that doxygen will try to copy  +# the style sheet file to the HTML output directory, so don't put your own  +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET        =  + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,  +# files or namespaces will be aligned in HTML using tables. If set to  +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS     = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files  +# will be generated that can be used as input for tools like the  +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)  +# of the generated HTML documentation. + +GENERATE_HTMLHELP      = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can  +# be used to specify the file name of the resulting .chm file. You  +# can add a path in front of the file if the result should not be  +# written to the html output directory. + +CHM_FILE               =  + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can  +# be used to specify the location (absolute path including file name) of  +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run  +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION           =  + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag  +# controls if a separate .chi index file is generated (YES) or that  +# it should be included in the master .chm file (NO). + +GENERATE_CHI           = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag  +# controls whether a binary table of contents is generated (YES) or a  +# normal table of contents (NO) in the .chm file. + +BINARY_TOC             = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members  +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND             = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at  +# top of each HTML page. The value NO (the default) enables the index and  +# the value YES disables it. + +DISABLE_INDEX          = NO + +# This tag can be used to set the number of enum values (range [1..20])  +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE   = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that  +# is generated for HTML Help). For this to work a browser that supports  +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,  +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are  +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW      = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be  +# used to set the initial width (in pixels) of the frame in which the tree  +# is shown. + +TREEVIEW_WIDTH         = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will  +# generate Latex output. + +GENERATE_LATEX         = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.  +# If a relative path is entered the value of OUTPUT_DIRECTORY will be  +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT           = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be  +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME         = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to  +# generate index for LaTeX. If left blank `makeindex' will be used as the  +# default command name. + +MAKEINDEX_CMD_NAME     = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact  +# LaTeX documents. This may be useful for small projects and may help to  +# save some trees in general. + +COMPACT_LATEX          = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used  +# by the printer. Possible values are: a4, a4wide, letter, legal and  +# executive. If left blank a4wide will be used. + +PAPER_TYPE             = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX  +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES         =  + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for  +# the generated latex document. The header should contain everything until  +# the first chapter. If it is left blank doxygen will generate a  +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER           =  + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated  +# is prepared for conversion to pdf (using ps2pdf). The pdf file will  +# contain links (just like the HTML output) instead of page references  +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS         = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of  +# plain latex in the generated Makefile. Set this option to YES to get a  +# higher quality PDF documentation. + +USE_PDFLATEX           = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.  +# command to the generated LaTeX files. This will instruct LaTeX to keep  +# running if errors occur, instead of asking the user for help.  +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE        = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not  +# include the index chapters (such as File Index, Compound Index, etc.)  +# in the output. + +LATEX_HIDE_INDICES     = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output  +# The RTF output is optimized for Word 97 and may not look very pretty with  +# other RTF readers or editors. + +GENERATE_RTF           = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.  +# If a relative path is entered the value of OUTPUT_DIRECTORY will be  +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT             = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact  +# RTF documents. This may be useful for small projects and may help to  +# save some trees in general. + +COMPACT_RTF            = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated  +# will contain hyperlink fields. The RTF file will  +# contain links (just like the HTML output) instead of page references.  +# This makes the output suitable for online browsing using WORD or other  +# programs which support those fields.  +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS         = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's  +# config file, i.e. a series of assignments. You only have to provide  +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE    =  + +# Set optional variables used in the generation of an rtf document.  +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE    =  + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will  +# generate man pages + +GENERATE_MAN           = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put.  +# If a relative path is entered the value of OUTPUT_DIRECTORY will be  +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT             = man + +# The MAN_EXTENSION tag determines the extension that is added to  +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION          = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output,  +# then it will generate one additional man file for each entity  +# documented in the real man page(s). These additional files  +# only source the real man page, but without them the man command  +# would be unable to find the correct page. The default is NO. + +MAN_LINKS              = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will  +# generate an XML file that captures the structure of  +# the code including all documentation. + +GENERATE_XML           = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put.  +# If a relative path is entered the value of OUTPUT_DIRECTORY will be  +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT             = xml + +# The XML_SCHEMA tag can be used to specify an XML schema,  +# which can be used by a validating XML parser to check the  +# syntax of the XML files. + +XML_SCHEMA             =  + +# The XML_DTD tag can be used to specify an XML DTD,  +# which can be used by a validating XML parser to check the  +# syntax of the XML files. + +XML_DTD                =  + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will  +# dump the program listings (including syntax highlighting  +# and cross-referencing information) to the XML output. Note that  +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING     = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will  +# generate an AutoGen Definitions (see autogen.sf.net) file  +# that captures the structure of the code including all  +# documentation. Note that this feature is still experimental  +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF   = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will  +# generate a Perl module file that captures the structure of  +# the code including all documentation. Note that this  +# feature is still experimental and incomplete at the  +# moment. + +GENERATE_PERLMOD       = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate  +# the necessary Makefile rules, Perl scripts and LaTeX code to be able  +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX          = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be  +# nicely formatted so it can be parsed by a human reader.  This is useful  +# if you want to understand what is going on.  On the other hand, if this  +# tag is set to NO the size of the Perl module output will be much smaller  +# and Perl will parse it just the same. + +PERLMOD_PRETTY         = YES + +# The names of the make variables in the generated doxyrules.make file  +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.  +# This is useful so different doxyrules.make files included by the same  +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX =  + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor    +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will  +# evaluate all C-preprocessor directives found in the sources and include  +# files. + +ENABLE_PREPROCESSING   = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro  +# names in the source code. If set to NO (the default) only conditional  +# compilation will be performed. Macro expansion can be done in a controlled  +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION        = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES  +# then the macro expansion is limited to the macros specified with the  +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF     = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files  +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES        = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that  +# contain include files that are not input files but should be processed by  +# the preprocessor. + +INCLUDE_PATH           =  + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard  +# patterns (like *.h and *.hpp) to filter out the header-files in the  +# directories. If left blank, the patterns specified with FILE_PATTERNS will  +# be used. + +INCLUDE_FILE_PATTERNS  =  + +# The PREDEFINED tag can be used to specify one or more macro names that  +# are defined before the preprocessor is started (similar to the -D option of  +# gcc). The argument of the tag is a list of macros of the form: name  +# or name=definition (no spaces). If the definition and the = are  +# omitted =1 is assumed. + +PREDEFINED             =  + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then  +# this tag can be used to specify a list of macro names that should be expanded.  +# The macro definition that is found in the sources will be used.  +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED      =  + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then  +# doxygen's preprocessor will remove all function-like macros that are alone  +# on a line, have an all uppercase name, and do not end with a semicolon. Such  +# function macros are typically used for boiler-plate code, and will confuse the  +# parser if not removed. + +SKIP_FUNCTION_MACROS   = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references    +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles.  +# Optionally an initial location of the external documentation  +# can be added for each tagfile. The format of a tag file without  +# this location is as follows:  +#   TAGFILES = file1 file2 ...  +# Adding location for the tag files is done as follows:  +#   TAGFILES = file1=loc1 "file2 = loc2" ...  +# where "loc1" and "loc2" can be relative or absolute paths or  +# URLs. If a location is present for each tag, the installdox tool  +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen  +# is run, you must also specify the path to the tagfile here. + +TAGFILES               =  + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create  +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE       =  + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed  +# in the class index. If set to NO only the inherited external classes  +# will be listed. + +ALLEXTERNALS           = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed  +# in the modules index. If set to NO, only the current project's groups will  +# be listed. + +EXTERNAL_GROUPS        = YES + +# The PERL_PATH should be the absolute path and name of the perl script  +# interpreter (i.e. the result of `which perl'). + +PERL_PATH              = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool    +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will  +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or  +# super classes. Setting the tag to NO turns the diagrams off. Note that this  +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is  +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS         = YES + +# If set to YES, the inheritance and collaboration graphs will hide  +# inheritance and usage relations if the target is undocumented  +# or is not a class. + +HIDE_UNDOC_RELATIONS   = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is  +# available from the path. This tool is part of Graphviz, a graph visualization  +# toolkit from AT&T and Lucent Bell Labs. The other options in this section  +# have no effect if this option is set to NO (the default) + +HAVE_DOT               = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen  +# will generate a graph for each documented class showing the direct and  +# indirect inheritance relations. Setting this tag to YES will force the  +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH            = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen  +# will generate a graph for each documented class showing the direct and  +# indirect implementation dependencies (inheritance, containment, and  +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH    = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and  +# collaboration diagrams in a style similar to the OMG's Unified Modeling  +# Language. + +UML_LOOK               = NO + +# If set to YES, the inheritance and collaboration graphs will show the  +# relations between templates and their instances. + +TEMPLATE_RELATIONS     = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT  +# tags are set to YES then doxygen will generate a graph for each documented  +# file showing the direct and indirect include dependencies of the file with  +# other documented files. + +INCLUDE_GRAPH          = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and  +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each  +# documented header file showing the documented files that directly or  +# indirectly include this file. + +INCLUDED_BY_GRAPH      = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will  +# generate a call dependency graph for every global function or class method.  +# Note that enabling this option will significantly increase the time of a run.  +# So in most cases it will be better to enable call graphs for selected  +# functions only using the \callgraph command. + +CALL_GRAPH             = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen  +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY    = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images  +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT       = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be  +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH               =  + +# The DOTFILE_DIRS tag can be used to specify one or more directories that  +# contain dot files that are included in the documentation (see the  +# \dotfile command). + +DOTFILE_DIRS           =  + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width  +# (in pixels) of the graphs generated by dot. If a graph becomes larger than  +# this value, doxygen will try to truncate the graph, so that it fits within  +# the specified constraint. Beware that most browsers cannot cope with very  +# large images. + +MAX_DOT_GRAPH_WIDTH    = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height  +# (in pixels) of the graphs generated by dot. If a graph becomes larger than  +# this value, doxygen will try to truncate the graph, so that it fits within  +# the specified constraint. Beware that most browsers cannot cope with very  +# large images. + +MAX_DOT_GRAPH_HEIGHT   = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the  +# graphs generated by dot. A depth value of 3 means that only nodes reachable  +# from the root by following a path via at most 3 edges will be shown. Nodes that  +# lay further from the root node will be omitted. Note that setting this option to  +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also  +# note that a graph may be further truncated if the graph's image dimensions are  +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).  +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH    = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will  +# generate a legend page explaining the meaning of the various boxes and  +# arrows in the dot generated graphs. + +GENERATE_LEGEND        = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will  +# remove the intermediate dot files that are used to generate  +# the various graphs. + +DOT_CLEANUP            = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine    +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be  +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE           = NO diff --git a/json-c/src/INSTALL b/json-c/src/INSTALL new file mode 100644 index 0000000..a4b3414 --- /dev/null +++ b/json-c/src/INSTALL @@ -0,0 +1,229 @@ +Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + +   This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +   These are generic installation instructions. + +   The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation.  It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions.  Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + +   It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring.  (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + +   If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release.  If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + +   The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'.  You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + +  1. `cd' to the directory containing the package's source code and type +     `./configure' to configure the package for your system.  If you're +     using `csh' on an old version of System V, you might need to type +     `sh ./configure' instead to prevent `csh' from trying to execute +     `configure' itself. + +     Running `configure' takes awhile.  While running, it prints some +     messages telling which features it is checking for. + +  2. Type `make' to compile the package. + +  3. Optionally, type `make check' to run any self-tests that come with +     the package. + +  4. Type `make install' to install the programs and any data files and +     documentation. + +  5. You can remove the program binaries and object files from the +     source code directory by typing `make clean'.  To also remove the +     files that `configure' created (so you can compile the package for +     a different kind of computer), type `make distclean'.  There is +     also a `make maintainer-clean' target, but that is intended mainly +     for the package's developers.  If you use it, you may have to get +     all sorts of other programs in order to regenerate files that came +     with the distribution. + +Compilers and Options +===================== + +   Some systems require unusual options for compilation or linking that +the `configure' script does not know about.  Run `./configure --help' +for details on some of the pertinent environment variables. + +   You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment.  Here +is an example: + +     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + +   *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +   You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory.  To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'.  `cd' to the +directory where you want the object files and executables to go and run +the `configure' script.  `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + +   If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory.  After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +   By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc.  You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + +   You can specify separate installation prefixes for +architecture-specific files and architecture-independent files.  If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + +   In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files.  Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + +   If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +   Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System).  The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + +   For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +   There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on.  Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option.  TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + +     CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + +     OS KERNEL-OS + +   See the file `config.sub' for the possible values of each field.  If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + +   If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + +   If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +   If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists.  Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +   Variables not defined in a site shell script can be set in the +environment passed to `configure'.  However, some packages may run +configure again during the build, and the customized values of these +variables may be lost.  In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'.  For example: + +     ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + +   `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' +     Print a summary of the options to `configure', and exit. + +`--version' +`-V' +     Print the version of Autoconf used to generate the `configure' +     script, and exit. + +`--cache-file=FILE' +     Enable the cache: use and save the results of the tests in FILE, +     traditionally `config.cache'.  FILE defaults to `/dev/null' to +     disable caching. + +`--config-cache' +`-C' +     Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' +     Do not print messages saying which checks are being made.  To +     suppress all normal output, redirect it to `/dev/null' (any error +     messages will still be shown). + +`--srcdir=DIR' +     Look for the package's source code in directory DIR.  Usually +     `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options.  Run +`configure --help' for more details. + diff --git a/json-c/src/Makefile.am b/json-c/src/Makefile.am new file mode 100644 index 0000000..d4a7bbb --- /dev/null +++ b/json-c/src/Makefile.am @@ -0,0 +1,46 @@ +include Makefile.am.inc + +EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj +SUBDIRS = . tests + +lib_LTLIBRARIES = libjson.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = json.pc + +libjsonincludedir = $(includedir)/json +libjsoninclude_HEADERS = \ +	arraylist.h \ +	bits.h \ +	debug.h \ +	json.h \ +	json_config.h \ +	json_inttypes.h \ +	json_object.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_la_LDFLAGS = -version-info 1:0:1 -no-undefined + +libjson_la_SOURCES = \ +	arraylist.c \ +	debug.c \ +	json_object.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 configure depcomp install-sh ltmain.sh missing + diff --git a/json-c/src/Makefile.am.inc b/json-c/src/Makefile.am.inc new file mode 100644 index 0000000..b1ebce8 --- /dev/null +++ b/json-c/src/Makefile.am.inc @@ -0,0 +1,2 @@ +AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT + diff --git a/json-c/src/NEWS b/json-c/src/NEWS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/json-c/src/NEWS diff --git a/json-c/src/README b/json-c/src/README new file mode 100644 index 0000000..05ec274 --- /dev/null +++ b/json-c/src/README @@ -0,0 +1,28 @@ +Building on Unix with git, gcc and autotools + +Home page for json-c: +  http://oss.metaparadigm.com/json-c/ + +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 + +If your system has pkgconfig then you can just add this to your makefile + +CFLAGS += $(shell pkg-config --cflags json) +LDFLAGS += $(shell pkg-config --libs json) diff --git a/json-c/src/README-WIN32.html b/json-c/src/README-WIN32.html new file mode 100644 index 0000000..28fc7d8 --- /dev/null +++ b/json-c/src/README-WIN32.html @@ -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>
 diff --git a/json-c/src/README.html b/json-c/src/README.html new file mode 100644 index 0000000..dc696af --- /dev/null +++ b/json-c/src/README.html @@ -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> diff --git a/json-c/src/RELEASE_CHECKLIST.txt b/json-c/src/RELEASE_CHECKLIST.txt new file mode 100644 index 0000000..1a8d555 --- /dev/null +++ b/json-c/src/RELEASE_CHECKLIST.txt @@ -0,0 +1,34 @@ + +Release checklist: + +release=0.10 +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 Windows +Check ChangeLog to see if anything should be added. + +git branch json-c-${release} +git checkout json-c-${release} +sh autogen.sh +XXX doxygen + +XXX Add generated files to git? + +cd .. +tar czf json-c-${release}.tar.gz json-c-${release} + +XXX upload tarball to ??? + +=================================== + +Post-release checklist: + +git branch master +Add new section to CHANGES +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 + diff --git a/json-c/src/arraylist.c b/json-c/src/arraylist.c new file mode 100644 index 0000000..9a673d6 --- /dev/null +++ b/json-c/src/arraylist.c @@ -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" + +#if 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)) 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; +} diff --git a/json-c/src/arraylist.h b/json-c/src/arraylist.h new file mode 100644 index 0000000..4f3113c --- /dev/null +++ b/json-c/src/arraylist.h @@ -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 diff --git a/json-c/src/autogen.sh b/json-c/src/autogen.sh new file mode 100644 index 0000000..c67b903 --- /dev/null +++ b/json-c/src/autogen.sh @@ -0,0 +1 @@ +autoreconf -v --install || exit 1 diff --git a/json-c/src/bits.h b/json-c/src/bits.h new file mode 100644 index 0000000..c8cbbc8 --- /dev/null +++ b/json-c/src/bits.h @@ -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 diff --git a/json-c/src/config.h.in b/json-c/src/config.h.in new file mode 100644 index 0000000..04f5dc5 --- /dev/null +++ b/json-c/src/config.h.in @@ -0,0 +1,127 @@ +/* config.h.in.  Generated from configure.in by autoheader.  */ + +/* 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 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 <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 `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/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 diff --git a/json-c/src/config.h.win32 b/json-c/src/config.h.win32 new file mode 100644 index 0000000..ec3a84a --- /dev/null +++ b/json-c/src/config.h.win32 @@ -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 diff --git a/json-c/src/configure.in b/json-c/src/configure.in new file mode 100644 index 0000000..b2c3cbe --- /dev/null +++ b/json-c/src/configure.in @@ -0,0 +1,41 @@ +AC_PREREQ(2.52) + +# Process this file with autoconf to produce a configure script. +AC_INIT([json-c], 0.10, [json-c@googlegroups.com]) + +AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) + +AC_PROG_MAKE_SET + +# Checks for programs. + +# Checks for libraries. + +# Checks for header files. +AM_CONFIG_HEADER(config.h) +AM_CONFIG_HEADER(json_config.h) +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/param.h] stdarg.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(strndup strerror vsnprintf vasprintf open vsyslog strncasecmp) + +AM_PROG_LIBTOOL + +AC_CONFIG_FILES([ +Makefile +json.pc +tests/Makefile +]) + +AC_OUTPUT + diff --git a/json-c/src/debug.c b/json-c/src/debug.c new file mode 100644 index 0000000..e0294ca --- /dev/null +++ b/json-c/src/debug.c @@ -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); +} diff --git a/json-c/src/debug.h b/json-c/src/debug.h new file mode 100644 index 0000000..1e09701 --- /dev/null +++ b/json-c/src/debug.h @@ -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 diff --git a/json-c/src/json-c.vcproj b/json-c/src/json-c.vcproj new file mode 100644 index 0000000..0b88754 --- /dev/null +++ b/json-c/src/json-c.vcproj @@ -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> diff --git a/json-c/src/json.h b/json-c/src/json.h new file mode 100644 index 0000000..d49715b --- /dev/null +++ b/json-c/src/json.h @@ -0,0 +1,33 @@ +/* + * $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" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/json-c/src/json.pc.in b/json-c/src/json.pc.in new file mode 100644 index 0000000..b3d140b --- /dev/null +++ b/json-c/src/json.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: json +Description: JSON implementation in C +Version: @VERSION@ +Requires:  +Libs:  -L${libdir} -ljson +Cflags: -I${includedir}/json diff --git a/json-c/src/json_config.h.in b/json-c/src/json_config.h.in new file mode 100644 index 0000000..7888e02 --- /dev/null +++ b/json-c/src/json_config.h.in @@ -0,0 +1,3 @@ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef JSON_C_HAVE_INTTYPES_H diff --git a/json-c/src/json_inttypes.h b/json-c/src/json_inttypes.h new file mode 100644 index 0000000..55e5279 --- /dev/null +++ b/json-c/src/json_inttypes.h @@ -0,0 +1,32 @@ + +#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" + +#include <stdint.h> + +#else + +#ifdef JSON_C_HAVE_INTTYPES_H +#include <inttypes.h> +#endif +/* inttypes.h includes stdint.h */ + +#endif + +#endif diff --git a/json-c/src/json_object.c b/json-c/src/json_object.c new file mode 100644 index 0000000..84af414 --- /dev/null +++ b/json-c/src/json_object.c @@ -0,0 +1,588 @@ +/* + * $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 !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); + + +/* 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 '"': +    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 == '"') 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; +} + +extern void json_object_put(struct json_object *jso) +{ +  if(jso) { +    jso->_ref_count--; +    if(!jso->_ref_count) jso->_delete(jso); +  } +} + + +/* 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; +} + +/* json_object_to_json_string */ + +const char* json_object_to_json_string(struct json_object *jso) +{ +  if(!jso) return "null"; +  if(!jso->_pb) { +    if(!(jso->_pb = printbuf_new())) return NULL; +  } else { +    printbuf_reset(jso->_pb); +  } +  if(jso->_to_json_string(jso, jso->_pb) < 0) return NULL; +  return jso->_pb->buf; +} + + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object* jso, +					     struct printbuf *pb) +{ +  int i=0; +  struct json_object_iter iter; +  sprintbuf(pb, "{"); + +  /* CAW: scope operator to make ANSI correctness */ +  /* CAW: switched to json_object_object_foreachC which uses an iterator struct */ +	json_object_object_foreachC(jso, iter) { +			if(i) sprintbuf(pb, ","); +			sprintbuf(pb, " \""); +			json_escape_str(pb, iter.key, strlen(iter.key)); +			sprintbuf(pb, "\": "); +			if(iter.val == NULL) sprintbuf(pb, "null"); +			else iter.val->_to_json_string(iter.val, pb); +			i++; +	} + +  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) +{ +  lh_table_delete(jso->o.c_object, key); +  lh_table_insert(jso->o.c_object, strdup(key), val); +} + +struct json_object* json_object_object_get(struct json_object* jso, const char *key) +{ +  struct json_object *result; +  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 (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) +{ +  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) +{ +  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) +{ +  return sprintbuf(pb, "%lf", jso->o.c_double); +} + +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) +{ +  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 = malloc(len); +  memcpy(jso->o.c_string.str, (void *)s, len); +  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 i; +  sprintbuf(pb, "["); +  for(i=0; i < json_object_array_length(jso); i++) { +	  struct json_object *val; +	  if(i) { sprintbuf(pb, ", "); } +	  else { sprintbuf(pb, " "); } + +      val = json_object_array_get_idx(jso, i); +	  if(val == NULL) { sprintbuf(pb, "null"); } +	  else { val->_to_json_string(val, pb); } +  } +  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); +} + diff --git a/json-c/src/json_object.h b/json-c/src/json_object.h new file mode 100644 index 0000000..f7ec9ea --- /dev/null +++ b/json-c/src/json_object.h @@ -0,0 +1,454 @@ +/* + * $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 + +#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; + +/* 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 + */ +extern void 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 + * @param obj the json_object instance + * @returns a string in JSON format + */ +extern const char* json_object_to_json_string(struct json_object *obj); + + +/* 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); + +/** 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 + * @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__) + +# define json_object_object_foreach(obj,key,val) \ + char *key; struct json_object *val; \ + for(struct lh_entry *entry = json_object_get_object(obj)->head; ({ if(entry) { key = (char*)entry->k; val = (struct json_object*)entry->v; } ; entry; }); entry = entry->next ) + +#else /* ANSI C or MSC */ + +# define json_object_object_foreach(obj,key,val) \ + char *key; struct json_object *val; struct lh_entry *entry; \ + for(entry = json_object_get_object(obj)->head; (entry ? (key = (char*)entry->k, val = (struct json_object*)entry->v, entry) : 0); entry = entry->next) + +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ + +/** 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 diff --git a/json-c/src/json_object_iterator.c b/json-c/src/json_object_iterator.c new file mode 100644 index 0000000..7066649 --- /dev/null +++ b/json-c/src/json_object_iterator.c @@ -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; +} diff --git a/json-c/src/json_object_iterator.h b/json-c/src/json_object_iterator.h new file mode 100644 index 0000000..f6e7ca6 --- /dev/null +++ b/json-c/src/json_object_iterator.h @@ -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 diff --git a/json-c/src/json_object_private.h b/json-c/src/json_object_private.h new file mode 100644 index 0000000..112ce76 --- /dev/null +++ b/json-c/src/json_object_private.h @@ -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_delete_fn)(struct json_object *o); +typedef int (json_object_to_json_string_fn)(struct json_object *o, +					    struct printbuf *pb); + +struct json_object +{ +  enum json_type o_type; +  json_object_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; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/json-c/src/json_tokener.c b/json-c/src/json_tokener.c new file mode 100644 index 0000000..1c82484 --- /dev/null +++ b/json-c/src/json_tokener.c @@ -0,0 +1,733 @@ +/* + * $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" + +#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) +{ +	if (jerr < 0 || jerr > 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(void) +{ +  struct json_tokener *tok; + +  tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); +  if (!tok) return NULL; +  tok->pb = printbuf_new(); +  json_tokener_reset(tok); +  return tok; +} + +void json_tokener_free(struct json_tokener *tok) +{ +  json_tokener_reset(tok); +  if(tok) printbuf_free(tok->pb); +  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. + * + * POP_CHAR() and ADVANCE_CHAR() macros are used for code that is + * common to both the main loop and the tighter loops. + */ + +/* POP_CHAR(dest, tok) macro: + *   Not really a pop()...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 POP_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'; + +  tok->char_offset = 0; +  tok->err = json_tokener_success; + +  while (POP_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)) || (!POP_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, strlen(json_null_str))) == 0) { +	if(tok->st_pos == 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) || !POP_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) || !POP_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(tok->pb->buf); +	    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) || !POP_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': +	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); +	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_CHAR(str, tok); +	            ADVANCE_CHAR(str, tok); + +                    /* Advance to the first char of the next sequence and +                     * continue processing with the next sequence. +                     */ +	            if (!ADVANCE_CHAR(str, tok) || !POP_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) || !POP_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, strlen(json_true_str))) == 0) { +	if(tok->st_pos == 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, strlen(json_false_str))) == 0) { +	if(tok->st_pos == 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) || !POP_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 && sscanf(tok->pb->buf, "%lf", &numd) == 1) { +          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: +      if(c == ']') { +	saved_state = json_tokener_state_finish; +	state = json_tokener_state_eatws; +      } else { +	if(tok->depth >= JSON_TOKENER_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; +	state = json_tokener_state_eatws; +      } else { +	tok->err = json_tokener_error_parse_array; +	goto out; +      } +      break; + +    case json_tokener_state_object_field_start: +      if(c == '}') { +	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) || !POP_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 >= JSON_TOKENER_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; +	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; +  } + +  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; +} diff --git a/json-c/src/json_tokener.h b/json-c/src/json_tokener.h new file mode 100644 index 0000000..d104c75 --- /dev/null +++ b/json-c/src/json_tokener.h @@ -0,0 +1,188 @@ +/* + * $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 +}; + +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_MAX_DEPTH 32 + +struct json_tokener +{ +  char *str; +  struct printbuf *pb; +  int depth, is_double, st_pos, char_offset; +  enum json_tokener_error err; +  unsigned int ucs_char; +  char quote_char; +  struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; +}; + +/** + * 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 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); + +/**  + * 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 diff --git a/json-c/src/json_util.c b/json-c/src/json_util.c new file mode 100644 index 0000000..faf9abd --- /dev/null +++ b/json-c/src/json_util.c @@ -0,0 +1,234 @@ +/* + * $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> + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* HAVE_SYS_STAT_H */ + +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H */ + +#if 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 !HAVE_OPEN && defined(WIN32) +# define open _open +#endif + + +#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" + +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 (struct json_object*)error_ptr(-1); +  } +  if(!(pb = printbuf_new())) { +    close(fd); +    MC_ERROR("json_object_from_file: printbuf_new failed\n"); +    return (struct json_object*)error_ptr(-1); +  } +  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 (struct json_object*)error_ptr(-1); +  } +  obj = json_tokener_parse(pb->buf); +  printbuf_free(pb); +  return obj; +} + +int json_object_to_file(char *filename, struct json_object *obj) +{ +  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(obj))) { +    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; +} + +int json_parse_int64(const char *buf, int64_t *retval) +{ +	int64_t num64; +	const char *buf_skip_space; +	int orig_has_neg; +	if (sscanf(buf, "%" SCNd64, &num64) != 1) +	{ +		MC_DEBUG("Failed to parse, sscanf != 1\n"); +		return 1; +	} +	buf_skip_space = buf; +	orig_has_neg = 0; +	// Skip leading spaces +	while (isspace((int)*buf_skip_space) && *buf_skip_space) +		buf_skip_space++; +	if (*buf_skip_space == '-') +	{ +		buf_skip_space++; +		orig_has_neg = 1; +	} +	// Skip leading zeros, but keep at least one digit +	while (buf_skip_space[0] == '0' && buf_skip_space[1] != '\0') +		buf_skip_space++; +	if (buf_skip_space[0] == '0' && buf_skip_space[1] == '\0') +		orig_has_neg = 0; // "-0" is the same as just plain "0" +	 +	if (errno != ERANGE) +	{ +		char buf_cmp[100]; +		char *buf_cmp_start = buf_cmp; +		int recheck_has_neg = 0; +		int buf_cmp_len; +#ifdef _MSC_VER +		_snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); +#else +		snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); +#endif +		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 NOT successfully parsed the value. +		 */ +		if (orig_has_neg != recheck_has_neg || +		    strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 || +			(strlen(buf_skip_space) != buf_cmp_len && +			 isdigit((int)buf_skip_space[buf_cmp_len]) +		    ) +		   ) +		{ +			errno = ERANGE; +		} +	} +	if (errno == ERANGE) +	{ +		if (orig_has_neg) +			num64 = INT64_MIN; +		else +			num64 = INT64_MAX; +	} +	*retval = num64; +	return 0; +} + +#if HAVE_REALLOC == 0 +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) +{ +	if (o_type < 0 || o_type >= 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]; +} + diff --git a/json-c/src/json_util.h b/json-c/src/json_util.h new file mode 100644 index 0000000..a77305e --- /dev/null +++ b/json-c/src/json_util.h @@ -0,0 +1,38 @@ +/* + * $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_parse_int64(const char *buf, int64_t *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 diff --git a/json-c/src/linkhash.c b/json-c/src/linkhash.c new file mode 100644 index 0000000..ddedc12 --- /dev/null +++ b/json-c/src/linkhash.c @@ -0,0 +1,229 @@ +/* + * $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(++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(++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); +} + diff --git a/json-c/src/linkhash.h b/json-c/src/linkhash.h new file mode 100644 index 0000000..bbb5488 --- /dev/null +++ b/json-c/src/linkhash.h @@ -0,0 +1,291 @@ +/* + * $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); + + +void lh_abort(const char *msg, ...); +void lh_table_resize(struct lh_table *t, int new_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/json-c/src/printbuf.c b/json-c/src/printbuf.c new file mode 100644 index 0000000..b951c7b --- /dev/null +++ b/json-c/src/printbuf.c @@ -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> + +#if 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 !HAVE_VSNPRINTF && defined(_MSC_VER) +# define vsnprintf _vsnprintf +#elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_VSNPRINTF && defined(WIN32) */ + +#if !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); +  } +} diff --git a/json-c/src/printbuf.h b/json-c/src/printbuf.h new file mode 100644 index 0000000..b1bde7f --- /dev/null +++ b/json-c/src/printbuf.h @@ -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  | 
