From 6d59966c4ef28fb4462f735c11f43ca93a62049f Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:17 +0000 Subject: [PATCH 001/276] create new svn project git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@1 327403b1-1117-474d-bef2-5cb71233fd97 From f0d08887b857fce1fe95a68d29eb7a07cd527d7c Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:18 +0000 Subject: [PATCH 002/276] import of version 0.1 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@2 327403b1-1117-474d-bef2-5cb71233fd97 --- Doxyfile | 1153 +++++++++++++++++++++++++++++++++++++++++ Makefile | 40 ++ README.html | 32 ++ arraylist.c | 94 ++++ arraylist.h | 52 ++ bits.h | 38 ++ debug.c | 75 +++ debug.h | 33 ++ json.h | 30 ++ json_object.c | 493 ++++++++++++++++++ json_object.h | 300 +++++++++++ json_object_private.h | 25 + json_tokener.c | 426 +++++++++++++++ json_tokener.h | 70 +++ json_util.c | 79 +++ json_util.h | 13 + linkhash.c | 225 ++++++++ linkhash.h | 270 ++++++++++ printbuf.c | 106 ++++ printbuf.h | 43 ++ test1.c | 134 +++++ test2.c | 19 + 22 files changed, 3750 insertions(+) create mode 100644 Doxyfile create mode 100644 Makefile create mode 100644 README.html create mode 100644 arraylist.c create mode 100644 arraylist.h create mode 100644 bits.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 json.h create mode 100644 json_object.c create mode 100644 json_object.h create mode 100644 json_object_private.h create mode 100644 json_tokener.c create mode 100644 json_tokener.h create mode 100644 json_util.c create mode 100644 json_util.h create mode 100644 linkhash.c create mode 100644 linkhash.h create mode 100644 printbuf.c create mode 100644 printbuf.h create mode 100644 test1.c create mode 100644 test2.c diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..a964501 --- /dev/null +++ b/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.1 + +# 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 , where +# is the value of the INPUT_FILTER tag, and 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/Makefile b/Makefile new file mode 100644 index 0000000..f32694b --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +# $Id: Makefile,v 1.4 2004/07/22 01:37:44 mclark Exp $ + +CFLAGS += -g -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +LDFLAGS += +LDLIBS += + +LIB_OBJS = debug.o \ + linkhash.o \ + printbuf.o \ + arraylist.o \ + json_object.o \ + json_tokener.o + +LIB_HDRS = debug.h \ + linkhash.h \ + printbuf.h \ + arraylist.h \ + json_object.h \ + json_tokener.h + +TESTS = test1 test2 + +all: tests + +tests: $(TESTS) +test1: test1.o $(LIB_OBJS) +test2: test2.o $(LIB_OBJS) + +clean: + rm -f *.o *~ $(TESTS) + +cex.o: cex.c cex.h +debug.o: debug.c debug.h +linkhash.o: linkhash.c linkhash.h +arraylist.o: arraylist.c arraylist.h +json_object.o: json_object.c $(LIB_HDRS) +json_tokener.o: json_tokener.c $(LIB_HDRS) +test1.o: test1.c $(LIB_HDRS) +test2.o: test2.c $(LIB_HDRS) + diff --git a/README.html b/README.html new file mode 100644 index 0000000..5b9a8dc --- /dev/null +++ b/README.html @@ -0,0 +1,32 @@ +

JSON-C - A JSON implementation in C

+

Latest release: json-c-0.1.tar.gz

+ +

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.

+ +

Minimal documentation exists here, +Although you are probably better reading the example code in test1.c.

+ +

JSON-C currently depends on some gcc 3.0+ features so can probably only be + compiled with gcc 3.0+. It also uses some specifc glibc functions such as + vasprintf. Patches welcome to port to other compilers / platforms.

+ +

Please send bug reports to michael@metaparadigm.com

+ +

Anonymous CVS

+

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
+# cvs login
+Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
+CVS password: <enter 'anoncvs'>
+# cvs co json-c

+ +

Copyright Metaparadigm Pte. Ltd. 2004. Michael Clark

+ +

This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public (LGPL) +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version.

+ +
diff --git a/arraylist.c b/arraylist.c new file mode 100644 index 0000000..854d130 --- /dev/null +++ b/arraylist.c @@ -0,0 +1,94 @@ +/* + * $Id: arraylist.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include + +#include "bits.h" +#include "arraylist.h" + + +struct array_list* +array_list_new(array_list_free_fn *free_fn) +{ + struct array_list *this; + + if(!(this = calloc(1, sizeof(struct array_list)))) return NULL; + this->size = ARRAY_LIST_DEFAULT_SIZE; + this->length = 0; + this->free_fn = free_fn; + if(!(this->array = calloc(sizeof(void*), this->size))) { + free(this); + return NULL; + } + return this; +} + +extern void +array_list_free(struct array_list *this) +{ + int i; + for(i = 0; i < this->length; i++) + if(this->array[i]) this->free_fn(this->array[i]); + free(this->array); + free(this); +} + +void* +array_list_get_idx(struct array_list *this, int i) +{ + if(i >= this->length) return NULL; + return this->array[i]; +} + +static int array_list_expand_internal(struct array_list *this, int max) +{ + void *t; + int new_size; + + if(max < this->size) return 0; + new_size = max(this->size << 1, max); + if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1; + this->array = t; + bzero(this->array + this->size, (new_size-this->size)*sizeof(void*)); + this->size = new_size; + return 0; +} + +int +array_list_put_idx(struct array_list *this, int idx, void *data) +{ + if(array_list_expand_internal(this, idx)) return -1; + if(this->array[idx]) this->free_fn(this->array[idx]); + this->array[idx] = data; + if(this->length <= idx) this->length = idx + 1; + return 0; +} + +int +array_list_add(struct array_list *this, void *data) +{ + return array_list_put_idx(this, this->length, data); +} + +int +array_list_length(struct array_list *this) +{ + return this->length; +} diff --git a/arraylist.h b/arraylist.h new file mode 100644 index 0000000..d82f14a --- /dev/null +++ b/arraylist.h @@ -0,0 +1,52 @@ +/* + * $Id: arraylist.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _arraylist_h_ +#define _arraylist_h_ + +#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 *this); + +extern void* +array_list_get_idx(struct array_list *this, int i); + +extern int +array_list_put_idx(struct array_list *this, int i, void *data); + +extern int +array_list_add(struct array_list *this, void *data); + +extern int +array_list_length(struct array_list *this); + +#endif diff --git a/bits.h b/bits.h new file mode 100644 index 0000000..39b25d7 --- /dev/null +++ b/bits.h @@ -0,0 +1,38 @@ +/* + * $Id: bits.h,v 1.3 2004/07/21 10:10:22 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _bits_h_ +#define _bits_h_ + +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +#define error_ptr(error) ((void*)error) +#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) + +#endif diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..6ae1ca3 --- /dev/null +++ b/debug.c @@ -0,0 +1,75 @@ +/* + * $Id: debug.c,v 1.3 2004/08/07 03:11:38 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" + + +static int _syslog = 0; +static int _debug = 0; + +void mc_set_debug(int debug) { _debug = debug; } +int mc_get_debug() { 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(_syslog) vsyslog(LOG_ERR, msg, ap); + else vprintf(msg, ap); + exit(1); +} + + +void mc_debug(const char *msg, ...) +{ + va_list ap; + if(_debug) { + va_start(ap, msg); + if(_syslog) vsyslog(LOG_DEBUG, msg, ap); + else vprintf(msg, ap); + } +} + +void mc_error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + if(_syslog) vsyslog(LOG_ERR, msg, ap); + else vfprintf(stderr, msg, ap); +} + +void mc_info(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + if(_syslog) vsyslog(LOG_INFO, msg, ap); + else vfprintf(stderr, msg, ap); +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..a52e62a --- /dev/null +++ b/debug.h @@ -0,0 +1,33 @@ +/* + * $Id: debug.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#define errstr strerror(errno) + +extern void mc_set_debug(int debug); +extern int mc_get_debug(); + +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, ...); + +#endif diff --git a/json.h b/json.h new file mode 100644 index 0000000..14bff2b --- /dev/null +++ b/json.h @@ -0,0 +1,30 @@ +/* + * $Id: json.h,v 1.4 2004/08/07 03:13:52 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_h_ +#define _json_h_ + +#include "bits.h" +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_tokener.h" + +#endif diff --git a/json_object.c b/json_object.c new file mode 100644 index 0000000..a7b0c1d --- /dev/null +++ b/json_object.c @@ -0,0 +1,493 @@ +/* + * $Id: json_object.c,v 1.10 2004/08/07 03:12:43 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include + +#include "debug.h" +#include "printbuf.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_object.h" +#include "json_object_private.h" + + +/* #define REFCOUNT_DEBUG */ + +char *json_number_chars = "0123456789.+-e"; +char *json_hex_chars = "0123456789abcdef"; + +#ifdef REFCOUNT_DEBUG +static char* json_type_name[] = { + "null", + "boolean", + "double", + "int", + "object", + "array", + "string", +}; +#endif + +static void json_object_generic_delete(struct json_object* this); +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() __attribute__ ((constructor)); +static void json_object_init() { + 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() __attribute__ ((destructor)); +static void json_object_fini() { + struct lh_entry *ent; + if(mc_get_debug() && 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_name[obj->o_type], obj); + } + } + mc_debug("json_object_fini: freeing object table\n"); + lh_table_free(json_object_table); +} +#endif + + +/* string escaping */ + +static int json_escape_str(struct printbuf *pb, char *str) +{ + int pos = 0, start_offset = 0; + char c; + do { + c = str[pos]; + switch(c) { + case '\b': + case '\n': + case '\r': + case '\t': + 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); + start_offset = ++pos; + break; + default: + if(c && 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 if(c) pos++; + } + } while(c); + 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 *this) +{ + if(this) { + this->_ref_count++; + } + return this; +} + +extern void json_object_put(struct json_object *this) +{ + if(this) { + this->_ref_count--; + if(!this->_ref_count) this->_delete(this); + } +} + + +/* generic object construction and destruction parts */ + +static void json_object_generic_delete(struct json_object* this) +{ +#ifdef REFCOUNT_DEBUG + mc_debug("json_object_delete_%s: %p\n", + json_type_name[this->o_type], this); + lh_table_delete(json_object_table, this); +#endif + printbuf_free(this->_pb); + free(this); +} + +static struct json_object* json_object_new(enum json_type o_type) +{ + struct json_object *this = calloc(sizeof(struct json_object), 1); + if(!this) return NULL; + this->o_type = o_type; + this->_ref_count = 1; + this->_delete = &json_object_generic_delete; +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, this, this); + mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this); +#endif + return this; +} + + +/* type checking functions */ + +int json_object_is_type(struct json_object *this, enum json_type type) +{ + return (this->o_type == type); +} + +enum json_type json_object_get_type(struct json_object *this) +{ + return this->o_type; +} + + +/* json_object_to_json_string */ + +char* json_object_to_json_string(struct json_object *this) +{ + if(!this) return "null"; + if(!this->_pb) { + if(!(this->_pb = printbuf_new())) return NULL; + } else { + printbuf_reset(this->_pb); + } + if(this->_to_json_string(this, this->_pb) < 0) return NULL; + return this->_pb->buf; +} + + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + int i=0; + sprintbuf(pb, "{"); + json_object_object_foreach(this, key, val) { + if(i) sprintbuf(pb, ","); + sprintbuf(pb, " \""); + json_escape_str(pb, key); + sprintbuf(pb, "\": "); + if(val == NULL) sprintbuf(pb, "null"); + else val->_to_json_string(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* this) +{ + lh_table_free(this->o.c_object); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_object() +{ + struct json_object *this = json_object_new(json_type_object); + if(!this) return NULL; + this->_delete = &json_object_object_delete; + this->_to_json_string = &json_object_object_to_json_string; + this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES, + NULL, &json_object_lh_entry_free); + return this; +} + +struct lh_table* json_object_get_object(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_object: + return this->o.c_object; + default: + return NULL; + } +} + +void json_object_object_add(struct json_object* this, char *key, + struct json_object *val) +{ + lh_table_delete(this->o.c_object, key); + lh_table_insert(this->o.c_object, strdup(key), val); +} + +struct json_object* json_object_object_get(struct json_object* this, char *key) +{ + return (struct json_object*) lh_table_lookup(this->o.c_object, key); +} + +void json_object_object_del(struct json_object* this, char *key) +{ + lh_table_delete(this->o.c_object, key); +} + + +/* json_object_boolean */ + +static int json_object_boolean_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + if(this->o.c_boolean) return sprintbuf(pb, "true"); + else return sprintbuf(pb, "false"); +} + +struct json_object* json_object_new_boolean(boolean b) +{ + struct json_object *this = json_object_new(json_type_boolean); + if(!this) return NULL; + this->_to_json_string = &json_object_boolean_to_json_string; + this->o.c_boolean = b; + return this; +} + +boolean json_object_get_boolean(struct json_object *this) +{ + if(!this) return FALSE; + switch(this->o_type) { + case json_type_boolean: + return this->o.c_boolean; + case json_type_int: + return (this->o.c_int != 0); + case json_type_double: + return (this->o.c_double != 0); + case json_type_string: + if(strlen(this->o.c_string)) return TRUE; + default: + return TRUE; + } +} + + +/* json_object_int */ + +static int json_object_int_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + return sprintbuf(pb, "%d", this->o.c_int); +} + +struct json_object* json_object_new_int(int i) +{ + struct json_object *this = json_object_new(json_type_int); + if(!this) return NULL; + this->_to_json_string = &json_object_int_to_json_string; + this->o.c_int = i; + return this; +} + +int json_object_get_int(struct json_object *this) +{ + int cint; + + if(!this) return 0; + switch(this->o_type) { + case json_type_int: + return this->o.c_int; + case json_type_double: + return this->o.c_double; + case json_type_boolean: + return this->o.c_boolean; + case json_type_string: + if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint; + default: + return 0; + } +} + + +/* json_object_double */ + +static int json_object_double_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + return sprintbuf(pb, "%lf", this->o.c_double); +} + +struct json_object* json_object_new_double(double d) +{ + struct json_object *this = json_object_new(json_type_double); + if(!this) return NULL; + this->_to_json_string = &json_object_double_to_json_string; + this->o.c_double = d; + return this; +} + +double json_object_get_double(struct json_object *this) +{ + double cdouble; + + if(!this) return 0.0; + switch(this->o_type) { + case json_type_double: + return this->o.c_double; + case json_type_int: + return this->o.c_int; + case json_type_boolean: + return this->o.c_boolean; + case json_type_string: + if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble; + default: + return 0.0; + } +} + + +/* json_object_string */ + +static int json_object_string_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + sprintbuf(pb, "\""); + json_escape_str(pb, this->o.c_string); + sprintbuf(pb, "\""); + return 0; +} + +static void json_object_string_delete(struct json_object* this) +{ + free(this->o.c_string); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_string(char *s) +{ + struct json_object *this = json_object_new(json_type_string); + if(!this) return NULL; + this->_delete = &json_object_string_delete; + this->_to_json_string = &json_object_string_to_json_string; + this->o.c_string = strdup(s); + return this; +} + +struct json_object* json_object_new_string_len(char *s, int len) +{ + struct json_object *this = json_object_new(json_type_string); + if(!this) return NULL; + this->_delete = &json_object_string_delete; + this->_to_json_string = &json_object_string_to_json_string; + this->o.c_string = strndup(s, len); + return this; +} + +char* json_object_get_string(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_string: + return this->o.c_string; + default: + return json_object_to_json_string(this); + } +} + + +/* json_object_array */ + +static int json_object_array_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + sprintbuf(pb, "["); + for(int i=0; i < json_object_array_length(this); i++) { + if(i) sprintbuf(pb, ", "); + else sprintbuf(pb, " "); + struct json_object *val = json_object_array_get_idx(this, 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* this) +{ + array_list_free(this->o.c_array); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_array() +{ + struct json_object *this = json_object_new(json_type_array); + if(!this) return NULL; + this->_delete = &json_object_array_delete; + this->_to_json_string = &json_object_array_to_json_string; + this->o.c_array = array_list_new(&json_object_array_entry_free); + return this; +} + +struct array_list* json_object_get_array(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_array: + return this->o.c_array; + default: + return NULL; + } +} + +int json_object_array_length(struct json_object *this) +{ + return array_list_length(this->o.c_array); +} + +int json_object_array_add(struct json_object *this,struct json_object *val) +{ + return array_list_add(this->o.c_array, val); +} + +int json_object_array_put_idx(struct json_object *this, int idx, + struct json_object *val) +{ + return array_list_put_idx(this->o.c_array, idx, val); +} + +struct json_object* json_object_array_get_idx(struct json_object *this, + int idx) +{ + return (struct json_object*)array_list_get_idx(this->o.c_array, idx); +} + diff --git a/json_object.h b/json_object.h new file mode 100644 index 0000000..9fc9bd0 --- /dev/null +++ b/json_object.h @@ -0,0 +1,300 @@ +/* + * $Id: json_object.h,v 1.8 2004/08/07 04:21:27 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_object_h_ +#define _json_object_h_ + +#define JSON_OBJECT_DEF_HASH_ENTIRES 16 + +#undef FALSE +#define FALSE ((boolean)0) + +#undef TRUE +#define TRUE ((boolean)1) + +extern char *json_number_chars; +extern char *json_hex_chars; + +/* forward structure definitions */ + +typedef int boolean; +struct printbuf; +struct lh_table; +struct array_list; +struct json_object; + +/* supported object types */ + +enum json_type { + json_type_null, + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, +}; + +/* reference counting functions */ + +/** + * Increment the reference count of json_object + * @param this the json_object instance + */ +extern struct json_object* json_object_get(struct json_object *this); + +/** + * Decrement the reference count of json_object and free if it reaches zero + * @param this the json_object instance + */ +extern void json_object_put(struct json_object *this); + + +/** + * Check if the json_object is of a given type + * @param this the json_object instance + * @param type one of: + 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 *this, enum json_type type); + +/** + * Get the type of the json_object + * @param this the json_object instance + * @returns type being one of: + 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 *this); + + +/** Stringify object to json format + * @param this the json_object instance + * @returns a string in JSON format + */ +extern char* json_object_to_json_string(struct json_object *this); + + +/* object type methods */ + +/** Create a new empty object + * @returns a json_object of type json_type_object + */ +extern struct json_object* json_object_new_object(); + +/** Get the hashtable of a json_object of type json_type_object + * @param this the json_object instance + * @returns a linkhash + */ +extern struct lh_table* json_object_get_object(struct json_object *this); + +/** 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 you must wrap the passed object with json_object_get + * + * @param this 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* this, char *key, + struct json_object *val); + +/** Get the json_object associate with a given object field + * @param this the json_object instance + * @param key the object field name + * @returns the json_object associated with the given field name + */ +extern struct json_object* json_object_object_get(struct json_object* this, + char *key); + +/** Delete the given json_object field + * + * The reference count will be decremented for the deleted object + * + * @param this the json_object instance + * @param key the object field name + */ +extern void json_object_object_del(struct json_object* this, char *key); + +/** Iterate through all keys and values of an object + * @param this 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 + */ +#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 ) + + +/* 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(); + +/** Get the arraylist of a json_object of type json_type_array + * @param this the json_object instance + * @returns an arraylist + */ +extern struct array_list* json_object_get_array(struct json_object *this); + +/** Get the length of a json_object of type json_type_array + * @param this the json_object instance + * @returns an int + */ +extern int json_object_array_length(struct json_object *this); + +/** 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 this the json_object instance + * @param val the json_object to be added + */ +extern int json_object_array_add(struct json_object *this, + 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 this 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 *this, int idx, + struct json_object *val); + +/** Get the element at specificed index of the array (a json_object of type json_type_array) + * @param this 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 *this, + int idx); + +/* boolean type methods */ + +/** Create a new empty json_object of type json_type_boolean + * @param b a boolean TRUE or FALSE (0 or 1) + * @returns a json_object of type json_type_boolean + */ +extern struct json_object* json_object_new_boolean(boolean b); + +/** Get the boolean value of a json_object + * + * The type is coerced to a boolean if the passed object is not a boolean. + * 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 this the json_object instance + * @returns a boolean + */ +extern boolean json_object_get_boolean(struct json_object *this); + + +/* int type methods */ + +/** 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_int(int 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. + * + * @param this the json_object instance + * @returns an int + */ +extern int json_object_get_int(struct json_object *this); + + +/* 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 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 dboule conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned. + * + * @param this the json_object instance + * @returns an double + */ +extern double json_object_get_double(struct json_object *this); + + +/* 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(char *s); + +extern struct json_object* json_object_new_string_len(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 this the json_object instance + * @returns a string + */ +extern char* json_object_get_string(struct json_object *this); + +#endif diff --git a/json_object_private.h b/json_object_private.h new file mode 100644 index 0000000..91ce99c --- /dev/null +++ b/json_object_private.h @@ -0,0 +1,25 @@ +#ifndef _json_object_private_h_ +#define _json_object_private_h_ + +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 { + boolean c_boolean; + double c_double; + int c_int; + struct lh_table *c_object; + struct array_list *c_array; + char *c_string; + } o; +}; + +#endif diff --git a/json_tokener.c b/json_tokener.c new file mode 100644 index 0000000..bb65381 --- /dev/null +++ b/json_tokener.c @@ -0,0 +1,426 @@ +/* + * $Id: json_tokener.c,v 1.10 2004/07/27 00:42:31 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include +#include + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "arraylist.h" +#include "json_object.h" +#include "json_tokener.h" + + +static struct json_object* json_tokener_do_parse(struct json_tokener *this); + +struct json_object* json_tokener_parse(char * s) +{ + struct json_tokener tok; + struct json_object* obj; + + tok.source = s; + tok.pos = 0; + tok.pb = printbuf_new(); + obj = json_tokener_do_parse(&tok); + printbuf_free(tok.pb); + return obj; +} + +static struct json_object* json_tokener_do_parse(struct json_tokener *this) +{ + enum json_tokener_state state, saved_state; + enum json_tokener_error err = json_tokener_success; + struct json_object *current = NULL, *obj; + char *obj_field_name = NULL; + char quote_char; + int deemed_double, start_offset; + + state = json_tokener_state_eatws; + saved_state = json_tokener_state_start; + + char c; + do { + c = this->source[this->pos]; + switch(state) { + + case json_tokener_state_eatws: + if(isspace(c)) { + this->pos++; + } else if(c == '/') { + state = json_tokener_state_comment_start; + start_offset = this->pos++; + } else { + state = saved_state; + } + break; + + case json_tokener_state_start: + switch(c) { + case '{': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_object; + current = json_object_new_object(); + this->pos++; + break; + case '[': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_array; + current = json_object_new_array(); + this->pos++; + break; + case 'N': + case 'n': + state = json_tokener_state_null; + start_offset = this->pos++; + break; + case '"': + case '\'': + quote_char = c; + printbuf_reset(this->pb); + state = json_tokener_state_string; + start_offset = ++this->pos; + break; + case 'T': + case 't': + case 'F': + case 'f': + state = json_tokener_state_boolean; + start_offset = this->pos++; + break; + case '0' ... '9': + case '-': + deemed_double = 0; + state = json_tokener_state_number; + start_offset = this->pos++; + break; + default: + err = json_tokener_error_parse_unexpected; + goto out; + } + break; + + case json_tokener_state_finish: + goto out; + + case json_tokener_state_null: + if(strncasecmp("null", this->source + start_offset, + this->pos - start_offset)) + return error_ptr(-json_tokener_error_parse_null); + if(this->pos - start_offset == 4) { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->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 { + err = json_tokener_error_parse_comment; + goto out; + } + this->pos++; + break; + + case json_tokener_state_comment: + if(c == '*') state = json_tokener_state_comment_end; + this->pos++; + break; + + case json_tokener_state_comment_eol: + if(c == '\n') { + if(mc_get_debug()) { + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset); + mc_debug("json_tokener_comment: %s\n", tmp); + free(tmp); + } + state = json_tokener_state_eatws; + } + this->pos++; + break; + + case json_tokener_state_comment_end: + if(c == '/') { + if(mc_get_debug()) { + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset + 1); + mc_debug("json_tokener_comment: %s\n", tmp); + free(tmp); + } + state = json_tokener_state_eatws; + } else { + state = json_tokener_state_comment; + } + this->pos++; + break; + + case json_tokener_state_string: + if(c == quote_char) { + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset); + current = json_object_new_string(this->pb->buf); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == '\\') { + saved_state = json_tokener_state_string; + state = json_tokener_state_string_escape; + } + this->pos++; + break; + + case json_tokener_state_string_escape: + switch(c) { + case '"': + case '\\': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + start_offset = this->pos++; + state = saved_state; + break; + case 'b': + case 'n': + case 'r': + case 't': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + if(c == 'b') printbuf_memappend(this->pb, "\b", 1); + else if(c == 'n') printbuf_memappend(this->pb, "\n", 1); + else if(c == 'r') printbuf_memappend(this->pb, "\r", 1); + else if(c == 't') printbuf_memappend(this->pb, "\t", 1); + start_offset = ++this->pos; + state = saved_state; + break; + case 'u': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + start_offset = ++this->pos; + state = json_tokener_state_escape_unicode; + break; + default: + err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_escape_unicode: + if(strchr(json_hex_chars, c)) { + this->pos++; + if(this->pos - start_offset == 4) { + unsigned char utf_out[3]; + unsigned int ucs_char = + (hexdigit(*(this->source + start_offset)) << 12) + + (hexdigit(*(this->source + start_offset + 1)) << 8) + + (hexdigit(*(this->source + start_offset + 2)) << 4) + + hexdigit(*(this->source + start_offset + 3)); + if (ucs_char < 0x80) { + utf_out[0] = ucs_char; + printbuf_memappend(this->pb, utf_out, 1); + } else if (ucs_char < 0x800) { + utf_out[0] = 0xc0 | (ucs_char >> 6); + utf_out[1] = 0x80 | (ucs_char & 0x3f); + printbuf_memappend(this->pb, utf_out, 2); + } else { + utf_out[0] = 0xe0 | (ucs_char >> 12); + utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); + utf_out[2] = 0x80 | (ucs_char & 0x3f); + printbuf_memappend(this->pb, utf_out, 3); + } + start_offset = this->pos; + state = saved_state; + } + } else { + err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_boolean: + if(strncasecmp("true", this->source + start_offset, + this->pos - start_offset) == 0) { + if(this->pos - start_offset == 4) { + current = json_object_new_boolean(1); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->pos++; + } + } else if(strncasecmp("false", this->source + start_offset, + this->pos - start_offset) == 0) { + if(this->pos - start_offset == 5) { + current = json_object_new_boolean(0); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->pos++; + } + } else { + err = json_tokener_error_parse_boolean; + goto out; + } + break; + + case json_tokener_state_number: + if(!c || !strchr(json_number_chars, c)) { + int numi; + double numd; + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset); + if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) { + current = json_object_new_int(numi); + } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) { + current = json_object_new_double(numd); + } else { + free(tmp); + err = json_tokener_error_parse_number; + goto out; + } + free(tmp); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + if(c == '.' || c == 'e') deemed_double = 1; + this->pos++; + } + break; + + case json_tokener_state_array: + if(c == ']') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + obj = json_tokener_do_parse(this); + if(is_error(obj)) { + err = (enum json_tokener_error)obj; + goto out; + } + json_object_array_add(current, obj); + saved_state = json_tokener_state_array_sep; + state = json_tokener_state_eatws; + } + break; + + case json_tokener_state_array_sep: + if(c == ']') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + this->pos++; + saved_state = json_tokener_state_array; + state = json_tokener_state_eatws; + } else { + json_object_put(current); + return error_ptr(-json_tokener_error_parse_array); + } + break; + + case json_tokener_state_object: + state = json_tokener_state_object_field_start; + start_offset = this->pos; + break; + + case json_tokener_state_object_field_start: + if(c == '}') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if (c == '"' || c == '\'') { + quote_char = c; + printbuf_reset(this->pb); + state = json_tokener_state_object_field; + start_offset = ++this->pos; + } + break; + + case json_tokener_state_object_field: + if(c == quote_char) { + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset); + obj_field_name = strdup(this->pb->buf); + saved_state = json_tokener_state_object_field_end; + state = json_tokener_state_eatws; + } else if(c == '\\') { + saved_state = json_tokener_state_object_field; + state = json_tokener_state_string_escape; + } + this->pos++; + break; + + case json_tokener_state_object_field_end: + if(c == ':') { + this->pos++; + saved_state = json_tokener_state_object_value; + state = json_tokener_state_eatws; + } else { + return error_ptr(-json_tokener_error_parse_object); + } + break; + + case json_tokener_state_object_value: + obj = json_tokener_do_parse(this); + if(is_error(obj)) { + err = (enum json_tokener_error)obj; + goto out; + } + 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; + break; + + case json_tokener_state_object_sep: + if(c == '}') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + this->pos++; + saved_state = json_tokener_state_object; + state = json_tokener_state_eatws; + } else { + err = json_tokener_error_parse_object; + goto out; + } + break; + + } + } while(c); + + if(state != json_tokener_state_finish && + saved_state != json_tokener_state_finish) + err = json_tokener_error_parse_eof; + + out: + free(obj_field_name); + if(err == json_tokener_success) return current; + mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", + err, state, c); + json_object_put(current); + return error_ptr(-err); +} diff --git a/json_tokener.h b/json_tokener.h new file mode 100644 index 0000000..c39577d --- /dev/null +++ b/json_tokener.h @@ -0,0 +1,70 @@ +/* + * $Id: json_tokener.h,v 1.5 2004/07/22 01:20:05 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_tokener_h_ +#define _json_tokener_h_ + +#include "json_object.h" + +enum json_tokener_error { + json_tokener_success, + 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, + json_tokener_error_parse_string, + json_tokener_error_parse_comment, + json_tokener_error_parse_eof, +}; + +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_sep, + json_tokener_state_object, + 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_sep, +}; + +struct json_tokener +{ + char *source; + int pos; + struct printbuf *pb; +}; + +extern struct json_object* json_tokener_parse(char *s); + +#endif diff --git a/json_util.c b/json_util.c new file mode 100644 index 0000000..483644e --- /dev/null +++ b/json_util.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + + +struct json_object* json_object_from_file(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 error_ptr(-1); + } + if(!(pb = printbuf_new())) { + mc_error("json_object_from_file: printbuf_new failed\n"); + return 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 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) +{ + char *json_str; + int fd, ret, 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))) return -1; + wsize = strlen(json_str); + 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; + } + wpos += ret; + } + + close(fd); + return 0; +} diff --git a/json_util.h b/json_util.h new file mode 100644 index 0000000..32a0428 --- /dev/null +++ b/json_util.h @@ -0,0 +1,13 @@ +#ifndef _json_util_h_ +#define _json_util_h_ + +#include "json_object.h" + + +#define JSON_FILE_BUF_SIZE 4096 + +/* utlitiy functions */ +extern struct json_object* json_object_from_file(char *filename); +extern int json_object_to_file(char *filename, struct json_object *obj); + +#endif diff --git a/linkhash.c b/linkhash.c new file mode 100644 index 0000000..b67eee7 --- /dev/null +++ b/linkhash.c @@ -0,0 +1,225 @@ +/* + * $Id: linkhash.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include +#include + +#include "linkhash.h" + + +void lh_abort(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + exit(1); +} + + +unsigned long lh_ptr_hash(void *k) +{ + return ((long)k * LH_PRIME) >> 4; +} + + +int lh_ptr_equal(void *k1, void *k2) +{ + return (k1 == k2); +} + + +unsigned long lh_char_hash(void *k) +{ + unsigned int h = 0; + const char* data = k; + + while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME; + + return h; +} + + +int lh_char_equal(void *k1, void *k2) +{ + return (strcmp((char*)k1, (char*)k2) == 0); +} + + +struct lh_table* lh_table_new(int size, 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 = 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 = 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, 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, 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, void *v) +{ + unsigned long h, n; + + t->inserts++; + if(t->count > t->size * 0.66) 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, void *k) +{ + unsigned long h = t->hash_fn(k); + unsigned long n = h % t->size; + + t->lookups++; + while( 1 ) { + 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; + } + return NULL; +} + + +void* lh_table_lookup(struct lh_table *t, void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(e) return e->v; + return NULL; +} + + +int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) +{ + int n = e - t->table; + 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, 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/linkhash.h b/linkhash.h new file mode 100644 index 0000000..c61e419 --- /dev/null +++ b/linkhash.h @@ -0,0 +1,270 @@ +/* + * $Id: linkhash.h,v 1.3 2004/08/07 03:29:47 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _linkhash_h_ +#define _linkhash_h_ + +/** + * golden prime used in hash functions + */ +#define LH_PRIME 0x9e370001UL + +/** + * 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) (void *k); +/** + * callback function prototypes + */ +typedef int (lh_equal_fn) (void *k1, void *k2); + +/** + * An entry in the hash table + */ +struct lh_entry { + /** + * The key. + */ + void *k; + /** + * The value. + */ + 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. + */ + 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(void *k); +extern int lh_ptr_equal(void *k1, void *k2); + +extern unsigned long lh_char_hash(void *k); +extern int lh_char_equal(void *k1, 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, 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, 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, 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, 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, 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. + */ +extern void* lh_table_lookup(struct lh_table *t, void *k); + + +/** + * 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, void *k); + + +#endif diff --git a/printbuf.c b/printbuf.c new file mode 100644 index 0000000..76c04e4 --- /dev/null +++ b/printbuf.c @@ -0,0 +1,106 @@ +/* + * $Id: printbuf.c,v 1.3 2004/08/07 03:12:21 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include +#include +#include +#include + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" + + +struct printbuf* printbuf_new() +{ + struct printbuf *p; + + if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL; + p->size = 32; + p->bpos = 0; + if(!(p->buf = malloc(p->size))) { + free(p); + return NULL; + } + return p; +} + + +int printbuf_memappend(struct printbuf *p, char *buf, int size) +{ + char *t; + if(p->size - p->bpos <= size) { + int new_size = max(p->size * 2, p->bpos + size + 8); +#if 0 + mc_debug("printbuf_memappend: realloc " + "bpos=%d wrsize=%d old_size=%d new_size=%d\n", + p->bpos, size, p->size, new_size); +#endif + if(!(t = realloc(p->buf, new_size))) return -1; + p->size = new_size; + p->buf = t; + } + memcpy(p->buf + p->bpos, buf, size); + p->bpos += size; + p->buf[p->bpos]= '\0'; + return size; +} + + +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 writeen - this code handles both cases. */ + if(size == -1 || size > 127) { + int ret; + va_start(ap, msg); + if((size = vasprintf(&t, msg, ap)) == -1) return -1; + va_end(ap); + ret = printbuf_memappend(p, t, size); + free(t); + return ret; + } else { + return printbuf_memappend(p, buf, 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/printbuf.h b/printbuf.h new file mode 100644 index 0000000..6a9568f --- /dev/null +++ b/printbuf.h @@ -0,0 +1,43 @@ +/* + * $Id: printbuf.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _printbuf_h_ +#define _printbuf_h_ + +struct printbuf { + char *buf; + int bpos; + int size; +}; + +extern struct printbuf* +printbuf_new(); + +extern int +printbuf_memappend(struct printbuf *p, char *buf, int size); + +extern int +sprintbuf(struct printbuf *p, const char *msg, ...); + +extern void +printbuf_reset(struct printbuf *p); + +extern void +printbuf_free(struct printbuf *p); + +#endif diff --git a/test1.c b/test1.c new file mode 100644 index 0000000..b65a7cd --- /dev/null +++ b/test1.c @@ -0,0 +1,134 @@ +#include +#include +#include + +#include "json.h" + + +int main(int argc, char **argv) +{ + struct json_object *my_string, *my_int, *my_object, *my_array; + struct json_object *new_obj; + + my_string = json_object_new_string("\t"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + json_object_put(my_string); + + my_string = json_object_new_string("foo"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + + my_int = json_object_new_int(9); + printf("my_int=%d\n", json_object_get_int(my_int)); + printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int)); + + my_array = json_object_new_array(); + json_object_array_add(my_array, json_object_new_int(1)); + json_object_array_add(my_array, json_object_new_int(2)); + json_object_array_add(my_array, json_object_new_int(3)); + json_object_array_put_idx(my_array, 4, json_object_new_int(5)); + printf("my_array=\n"); + for(int i=0; i < json_object_array_length(my_array); i++) { + struct json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + + my_object = json_object_new_object(); + json_object_object_add(my_object, "abc", json_object_new_int(12)); + json_object_object_add(my_object, "foo", json_object_new_string("bar")); + json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); + json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); + json_object_object_add(my_object, "baz", json_object_new_string("bang")); + json_object_object_add(my_object, "baz", json_object_new_string("fark")); + json_object_object_del(my_object, "baz"); + json_object_object_add(my_object, "arr", my_array); + printf("my_object=\n"); + json_object_object_foreach(my_object, key, val) { + printf("\t%s: %s\n", key, json_object_to_json_string(val)); + } + printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); + + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("foo"); + if(is_error(new_obj)) printf("got error as expected\n"); + + json_object_put(my_string); + json_object_put(my_int); + json_object_put(my_object); + //json_object_put(my_array); + + return 0; +} diff --git a/test2.c b/test2.c new file mode 100644 index 0000000..b7bdf62 --- /dev/null +++ b/test2.c @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "json.h" + + +int main(int argc, char **argv) +{ + struct json_object *new_obj; + + mc_set_debug(1); + + new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + return 0; +} From 4504df71178fe7a0eb8e7c37fa548b7c853a800f Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:20 +0000 Subject: [PATCH 003/276] =?UTF-8?q?=20=20*=20printbuf.c=20-=20C.=20Watford?= =?UTF-8?q?=20(christopher=20dot=20watford=20at=20gmail=20dot=20com)=20=20?= =?UTF-8?q?=20=20=20Added=20a=20Win32/Win64=20compliant=20implementation?= =?UTF-8?q?=20of=20vasprintf=20=20=20*=20debug.c=20-=20C.=20Watford=20(chr?= =?UTF-8?q?istopher=20dot=20watford=20at=20gmail=20dot=20com)=20=20=20=20?= =?UTF-8?q?=20Removed=20usage=20of=20vsyslog=20on=20Win32/Win64=20systems,?= =?UTF-8?q?=20needs=20to=20be=20handled=20=20=20=20=20by=20a=20configure?= =?UTF-8?q?=20script=20=20=20*=20json=5Fobject.c=20-=20C.=20Watford=20(chr?= =?UTF-8?q?istopher=20dot=20watford=20at=20gmail=20dot=20com)=20=20=20=20?= =?UTF-8?q?=20Added=20scope=20operator=20to=20wrap=20usage=20of=20json=5Fo?= =?UTF-8?q?bject=5Fobject=5Fforeach,=20this=20=20=20=20=20needs=20to=20be?= =?UTF-8?q?=20rethought=20to=20be=20more=20ANSI=20C=20friendly=20=20=20*?= =?UTF-8?q?=20json=5Fobject.h=20-=20C.=20Watford=20(christopher=20dot=20wa?= =?UTF-8?q?tford=20at=20gmail=20dot=20com)=20=20=20=20=20Added=20Microsoft?= =?UTF-8?q?=20C=20friendly=20version=20of=20json=5Fobject=5Fobject=5Fforea?= =?UTF-8?q?ch=20=20=20*=20json=5Ftokener.c=20-=20C.=20Watford=20(christoph?= =?UTF-8?q?er=20dot=20watford=20at=20gmail=20dot=20com)=20=20=20=20=20Adde?= =?UTF-8?q?d=20a=20Win32/Win64=20compliant=20implementation=20of=20strndup?= =?UTF-8?q?=20=20=20*=20json=5Futil.c=20-=20C.=20Watford=20(christopher=20?= =?UTF-8?q?dot=20watford=20at=20gmail=20dot=20com)=20=20=20=20=20Added=20c?= =?UTF-8?q?ast=20and=20mask=20to=20suffice=20size=5Ft=20v.=20unsigned=20in?= =?UTF-8?q?t=20conversion=20=20=20=20=20correctness=20=20=20*=20json=5Ftok?= =?UTF-8?q?ener.c=20-=20sign=20reversal=20issue=20on=20error=20info=20for?= =?UTF-8?q?=20nested=20object=20parse=20=20=20=20=20spotted=20by=20Johan?= =?UTF-8?q?=20Bj=EF=BF=BDrklund=20(johbjo09=20at=20kth.se)=20=20=20*=20jso?= =?UTF-8?q?n=5Fobject.c=20-=20escape=20"=20in=20json=5Fescape=5Fstr=20=20?= =?UTF-8?q?=20*=20Change=20to=20automake=20and=20libtool=20to=20build=20sh?= =?UTF-8?q?ared=20and=20static=20library=20=20=20=20=20Michael=20Clark=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@4 327403b1-1117-474d-bef2-5cb71233fd97 --- AUTHORS | 2 + COPYING | 481 ++++++++++++++++++++++++++++++++++++++++++ ChangeLog | 24 +++ Doxyfile | 2 +- INSTALL | 229 ++++++++++++++++++++ Makefile | 40 ---- Makefile.am | 40 ++++ NEWS | 1 + README | 23 ++ README-WIN32.html | 63 ++++++ README.html | 70 +++--- arraylist.c | 18 +- bits.h | 19 +- config.h.in | 117 ++++++++++ config.h.win32 | 101 +++++++++ configure.in | 33 +++ debug.c | 50 +++-- debug.h | 8 +- json-c.vcproj | 179 ++++++++++++++++ json.pc.in | 11 + json_object.c | 58 +++-- json_object.h | 29 ++- json_object_private.h | 26 +++ json_tokener.c | 45 +++- json_tokener.h | 14 +- json_util.c | 56 ++++- json_util.h | 29 +++ linkhash.c | 25 ++- linkhash.h | 6 +- printbuf.c | 59 +++++- printbuf.h | 4 +- test1.c | 1 - 32 files changed, 1704 insertions(+), 159 deletions(-) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 README-WIN32.html create mode 100644 config.h.in create mode 100644 config.h.win32 create mode 100644 configure.in create mode 100644 json-c.vcproj create mode 100644 json.pc.in diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..38f2ce0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Michael Clark +C. Watford (christopher.watford@gmail.com) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..8f652d6 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,24 @@ +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 + +0.1 + * initial release diff --git a/Doxyfile b/Doxyfile index a964501..7e5f306 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.1 +PROJECT_NUMBER = 0.2 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..a4b3414 --- /dev/null +++ b/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/Makefile b/Makefile deleted file mode 100644 index f32694b..0000000 --- a/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# $Id: Makefile,v 1.4 2004/07/22 01:37:44 mclark Exp $ - -CFLAGS += -g -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT -LDFLAGS += -LDLIBS += - -LIB_OBJS = debug.o \ - linkhash.o \ - printbuf.o \ - arraylist.o \ - json_object.o \ - json_tokener.o - -LIB_HDRS = debug.h \ - linkhash.h \ - printbuf.h \ - arraylist.h \ - json_object.h \ - json_tokener.h - -TESTS = test1 test2 - -all: tests - -tests: $(TESTS) -test1: test1.o $(LIB_OBJS) -test2: test2.o $(LIB_OBJS) - -clean: - rm -f *.o *~ $(TESTS) - -cex.o: cex.c cex.h -debug.o: debug.c debug.h -linkhash.o: linkhash.c linkhash.h -arraylist.o: arraylist.c arraylist.h -json_object.o: json_object.c $(LIB_HDRS) -json_tokener.o: json_tokener.c $(LIB_HDRS) -test1.o: test1.c $(LIB_HDRS) -test2.o: test2.c $(LIB_HDRS) - diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..9e86ccd --- /dev/null +++ b/Makefile.am @@ -0,0 +1,40 @@ +AUTOMAKE_OPTIONS = 1.6 + +CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT + +libjson_la_LIBADD = $(JSON_LIBS) + +lib_LTLIBRARIES = libjson.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = json.pc + +libjsonincludedir = $(includedir)/json +libjsoninclude_HEADERS = \ + json.h \ + bits.h \ + debug.h \ + linkhash.h \ + arraylist.h \ + json_util.h \ + json_object.h \ + json_tokener.h + +libjson_la_LDFLAGS = -version-info 0:1:0 + +libjson_la_SOURCES = \ + arraylist.c \ + debug.c \ + json_object.c \ + json_tokener.c \ + json_util.c \ + linkhash.c \ + printbuf.c + +check_PROGRAMS = test1 test2 + +test1_SOURCES = test1.c +test1_LDADD = $(lib_LTLIBRARIES) + +test2_SOURCES = test2.c +test2_LDADD = $(lib_LTLIBRARIES) diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..41e843b --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +News diff --git a/README b/README new file mode 100644 index 0000000..93c0226 --- /dev/null +++ b/README @@ -0,0 +1,23 @@ +Building on Unix with gcc and autotools + +If checking out from CVS: + + cp /usr/share/libtool/ltmain.sh . + aclocal-1.6 + automake-1.6 --add-missing + autoconf + +Then configure, make, make install + + +Test programs + +To build 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/README-WIN32.html b/README-WIN32.html new file mode 100644 index 0000000..c20fc83 --- /dev/null +++ b/README-WIN32.html @@ -0,0 +1,63 @@ + + + + JSON-C - A JSON implementation in C - Win32 specific notes + + + +

Windows specific notes for JSON-C

+

Please send Win32 bug reports to christopher.watford@gmail.com

+

Win32 Specific Changes:

+
    +
  • + Various functions have been redefined to their Win32 version (i.e. open + on win32 is _open)
  • +
  • + Implemented missing functions from MS's libc (i.e. vasprintf and strndup)
  • +
  • + Added code to allow Win64 support without integer resizing issues, this + probably makes it much nicer on 64bit machines everywhere (i.e. using ptrdiff_t + for pointer math)
  • +
+

Porting Changelog:

+
+
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
+
+

Anonymous CVS

+

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
+ # cvs login
+ Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
+ CVS password: <enter 'anoncvs'>
+ # cvs co json-c

+

Copyright Metaparadigm Pte. Ltd. 2004. Michael + Clark +

+

This program is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public (LGPL) License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version.

+
+ + diff --git a/README.html b/README.html index 5b9a8dc..840132b 100644 --- a/README.html +++ b/README.html @@ -1,32 +1,38 @@ -

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.1.tar.gz

- -

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.

- -

Minimal documentation exists here, -Although you are probably better reading the example code in test1.c.

- -

JSON-C currently depends on some gcc 3.0+ features so can probably only be - compiled with gcc 3.0+. It also uses some specifc glibc functions such as - vasprintf. Patches welcome to port to other compilers / platforms.

- -

Please send bug reports to michael@metaparadigm.com

- -

Anonymous CVS

-

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
-# cvs login
-Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
-CVS password: <enter 'anoncvs'>
-# cvs co json-c

- -

Copyright Metaparadigm Pte. Ltd. 2004. Michael Clark

- -

This program is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public (LGPL) -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version.

- -
+ + + + JSON-C - A JSON implementation in C + + + +

JSON-C - A JSON implementation in C

+

Latest release: json-c-0.2.tar.gz

+

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.

+

Minimal documentation exists here, + Although you are probably better reading the example code in test1.c.

+

To setup JSON-C to build on your system please run configure before + compiling. If you are on Win32 and are not using the VS project file, be sure + to rename config.h.win32 to config.h before building.

+

Win32 specific notes can be found here.

+

Please send bug reports to michael@metaparadigm.com

+

Please send Win32 bug reports to christopher.watford@gmail.com

+

Anonymous CVS

+

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
+ # cvs login
+ Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
+ CVS password: <enter 'anoncvs'>
+ # cvs co json-c

+

Copyright Metaparadigm Pte. Ltd. 2004. Michael + Clark +

+

This program is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public (LGPL) License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version.

+
+ + diff --git a/arraylist.c b/arraylist.c index 854d130..be93e26 100644 --- a/arraylist.c +++ b/arraylist.c @@ -1,5 +1,5 @@ /* - * $Id: arraylist.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * $Id: arraylist.c,v 1.3 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,14 +16,20 @@ * */ -#include -#include -#include +#include "config.h" + +#if STDC_HEADERS +# include +# include +#endif /* STDC_HEADERS */ + +#if HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ #include "bits.h" #include "arraylist.h" - struct array_list* array_list_new(array_list_free_fn *free_fn) { @@ -66,7 +72,7 @@ static int array_list_expand_internal(struct array_list *this, int max) new_size = max(this->size << 1, max); if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1; this->array = t; - bzero(this->array + this->size, (new_size-this->size)*sizeof(void*)); + (void)memset(this->array + this->size, 0, (new_size-this->size)*sizeof(void*)); this->size = new_size; return 0; } diff --git a/bits.h b/bits.h index 39b25d7..41e6592 100644 --- a/bits.h +++ b/bits.h @@ -1,5 +1,5 @@ /* - * $Id: bits.h,v 1.3 2004/07/21 10:10:22 mclark Exp $ + * $Id: bits.h,v 1.4 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,20 +19,35 @@ #ifndef _bits_h_ #define _bits_h_ +#include "config.h" + +#if STDC_HEADERS +# include +#endif /* STDC_HEADERS */ + +/* CAW: wrapped in ifndef's to make win32 compliant +** this fails to take over GCC specifics, but this +** seems to be unimportant. + */ + +#ifndef min #define min(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) +#endif +#ifndef max #define max(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) +#endif #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) #define error_ptr(error) ((void*)error) -#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) +#define is_error(ptr) ((ptrdiff_t)ptr < (ptrdiff_t)-4000L) #endif diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..83ab797 --- /dev/null +++ b/config.h.in @@ -0,0 +1,117 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the 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 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 header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the 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 + +/* 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 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' if does not define. */ +#undef size_t diff --git a/config.h.win32 b/config.h.win32 new file mode 100644 index 0000000..878d6c3 --- /dev/null +++ b/config.h.win32 @@ -0,0 +1,101 @@ +/* + * $Id: config.h.win32,v 1.1 2005/06/14 22:41:51 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +/* config.h.win32 Generated by configure. */ + +#define PACKAGE_STRING "JSON C Library 0.2" +#define PACKAGE_BUGREPORT "michael@metaparadigm.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 header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the 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 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 header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the 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 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 header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the 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/configure.in b/configure.in new file mode 100644 index 0000000..4f7ec9d --- /dev/null +++ b/configure.in @@ -0,0 +1,33 @@ +AC_PREREQ(2.52) + +# Process this file with autoconf to produce a configure script. +AC_INIT([JSON C Library], 0.2, [michael@metaparadigm.com], [json-c]) + +AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) + +# Checks for programs. + +# Checks for libraries. + +# Checks for header files. +AM_CONFIG_HEADER(config.h) +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/param.h] stdarg.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_OUTPUT([ +Makefile +json.pc +]) diff --git a/debug.c b/debug.c index 6ae1ca3..a4d12f1 100644 --- a/debug.c +++ b/debug.c @@ -1,5 +1,5 @@ /* - * $Id: debug.c,v 1.3 2004/08/07 03:11:38 mclark Exp $ + * $Id: debug.c,v 1.4 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,17 +16,27 @@ * */ +#include "config.h" + #include #include #include #include -#include -#include + +#if HAVE_SYSLOG_H +# include +#endif /* HAVE_SYSLOG_H */ + +#if HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#if HAVE_SYS_PARAM_H #include +#endif /* HAVE_SYS_PARAM_H */ #include "debug.h" - static int _syslog = 0; static int _debug = 0; @@ -42,8 +52,12 @@ void mc_abort(const char *msg, ...) { va_list ap; va_start(ap, msg); - if(_syslog) vsyslog(LOG_ERR, msg, ap); - else vprintf(msg, ap); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_ERR, msg, ap); + } else +#endif + vprintf(msg, ap); exit(1); } @@ -53,8 +67,12 @@ void mc_debug(const char *msg, ...) va_list ap; if(_debug) { va_start(ap, msg); - if(_syslog) vsyslog(LOG_DEBUG, msg, ap); - else vprintf(msg, ap); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_DEBUG, msg, ap); + } else +#endif + vprintf(msg, ap); } } @@ -62,14 +80,22 @@ void mc_error(const char *msg, ...) { va_list ap; va_start(ap, msg); - if(_syslog) vsyslog(LOG_ERR, msg, ap); - else vfprintf(stderr, msg, ap); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_ERR, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); } void mc_info(const char *msg, ...) { va_list ap; va_start(ap, msg); - if(_syslog) vsyslog(LOG_INFO, msg, ap); - else vfprintf(stderr, msg, ap); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_INFO, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); } diff --git a/debug.h b/debug.h index a52e62a..581b76d 100644 --- a/debug.h +++ b/debug.h @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * $Id: debug.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,7 +19,13 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ +#include "config.h" + +#if HAVE_STRERROR #define errstr strerror(errno) +#else /* !HAVE_STRERROR */ +#define errstr +#endif /* HAVE_STRERROR */ extern void mc_set_debug(int debug); extern int mc_get_debug(); diff --git a/json-c.vcproj b/json-c.vcproj new file mode 100644 index 0000000..0b88754 --- /dev/null +++ b/json-c.vcproj @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/json.pc.in b/json.pc.in new file mode 100644 index 0000000..b3d140b --- /dev/null +++ b/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_object.c b/json_object.c index a7b0c1d..b88aa4d 100644 --- a/json_object.c +++ b/json_object.c @@ -1,5 +1,5 @@ /* - * $Id: json_object.c,v 1.10 2004/08/07 03:12:43 mclark Exp $ + * $Id: json_object.c,v 1.13 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,6 +16,8 @@ * */ +#include "config.h" + #include #include #include @@ -26,9 +28,9 @@ #include "arraylist.h" #include "json_object.h" #include "json_object_private.h" +#include "json_tokener.h" - -/* #define REFCOUNT_DEBUG */ +/* #define REFCOUNT_DEBUG 1 */ char *json_number_chars = "0123456789.+-e"; char *json_hex_chars = "0123456789abcdef"; @@ -43,7 +45,7 @@ static char* json_type_name[] = { "array", "string", }; -#endif +#endif /* REFCOUNT_DEBUG */ static void json_object_generic_delete(struct json_object* this); static struct json_object* json_object_new(enum json_type o_type); @@ -75,7 +77,7 @@ static void json_object_fini() { mc_debug("json_object_fini: freeing object table\n"); lh_table_free(json_object_table); } -#endif +#endif /* REFCOUNT_DEBUG */ /* string escaping */ @@ -91,12 +93,14 @@ static int json_escape_str(struct printbuf *pb, char *str) case '\n': case '\r': case '\t': + 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); start_offset = ++pos; break; default: @@ -143,7 +147,7 @@ static void json_object_generic_delete(struct json_object* this) mc_debug("json_object_delete_%s: %p\n", json_type_name[this->o_type], this); lh_table_delete(json_object_table, this); -#endif +#endif /* REFCOUNT_DEBUG */ printbuf_free(this->_pb); free(this); } @@ -158,7 +162,7 @@ static struct json_object* json_object_new(enum json_type o_type) #ifdef REFCOUNT_DEBUG lh_table_insert(json_object_table, this, this); mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this); -#endif +#endif /* REFCOUNT_DEBUG */ return this; } @@ -197,16 +201,21 @@ static int json_object_object_to_json_string(struct json_object* this, struct printbuf *pb) { int i=0; + struct json_object_iter iter; sprintbuf(pb, "{"); - json_object_object_foreach(this, key, val) { - if(i) sprintbuf(pb, ","); - sprintbuf(pb, " \""); - json_escape_str(pb, key); - sprintbuf(pb, "\": "); - if(val == NULL) sprintbuf(pb, "null"); - else val->_to_json_string(val, pb); - i++; - } + + /* CAW: scope operator to make ANSI correctness */ + /* CAW: switched to json_object_object_foreachC which uses an iterator struct */ + json_object_object_foreachC(this, iter) { + if(i) sprintbuf(pb, ","); + sprintbuf(pb, " \""); + json_escape_str(pb, iter.key); + sprintbuf(pb, "\": "); + if(iter.val == NULL) sprintbuf(pb, "null"); + else iter.val->_to_json_string(iter.val, pb); + i++; + } + return sprintbuf(pb, " }"); } @@ -324,7 +333,7 @@ int json_object_get_int(struct json_object *this) case json_type_int: return this->o.c_int; case json_type_double: - return this->o.c_double; + return (int)this->o.c_double; case json_type_boolean: return this->o.c_boolean; case json_type_string: @@ -426,13 +435,16 @@ char* json_object_get_string(struct json_object *this) static int json_object_array_to_json_string(struct json_object* this, struct printbuf *pb) { + int i; sprintbuf(pb, "["); - for(int i=0; i < json_object_array_length(this); i++) { - if(i) sprintbuf(pb, ", "); - else sprintbuf(pb, " "); - struct json_object *val = json_object_array_get_idx(this, i); - if(val == NULL) sprintbuf(pb, "null"); - else val->_to_json_string(val, pb); + for(i=0; i < json_object_array_length(this); i++) { + struct json_object *val; + if(i) { sprintbuf(pb, ", "); } + else { sprintbuf(pb, " "); } + + val = json_object_array_get_idx(this, i); + if(val == NULL) { sprintbuf(pb, "null"); } + else { val->_to_json_string(val, pb); } } return sprintbuf(pb, " ]"); } diff --git a/json_object.h b/json_object.h index 9fc9bd0..0f32ead 100644 --- a/json_object.h +++ b/json_object.h @@ -1,5 +1,5 @@ /* - * $Id: json_object.h,v 1.8 2004/08/07 04:21:27 mclark Exp $ + * $Id: json_object.h,v 1.9 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,6 +19,8 @@ #ifndef _json_object_h_ #define _json_object_h_ +#include "config.h" + #define JSON_OBJECT_DEF_HASH_ENTIRES 16 #undef FALSE @@ -37,6 +39,7 @@ struct printbuf; struct lh_table; struct array_list; struct json_object; +struct json_object_iter; /* supported object types */ @@ -143,14 +146,30 @@ extern struct json_object* json_object_object_get(struct json_object* this, extern void json_object_object_del(struct json_object* this, char *key); /** Iterate through all keys and values of an object - * @param this the json_object instance + * @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 */ -#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 ) +#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 */ diff --git a/json_object_private.h b/json_object_private.h index 91ce99c..4548144 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -1,3 +1,21 @@ +/* + * $Id: json_object_private.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + #ifndef _json_object_private_h_ #define _json_object_private_h_ @@ -22,4 +40,12 @@ struct json_object } o; }; +/* CAW: added for ANSI C iteration correctness */ +struct json_object_iter +{ + char *key; + struct json_object *val; + struct lh_entry *entry; +}; + #endif diff --git a/json_tokener.c b/json_tokener.c index bb65381..668d749 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.c,v 1.10 2004/07/27 00:42:31 mclark Exp $ + * $Id: json_tokener.c,v 1.14 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,6 +16,8 @@ * */ +#include "config.h" + #include #include #include @@ -28,7 +30,6 @@ #include "json_object.h" #include "json_tokener.h" - static struct json_object* json_tokener_do_parse(struct json_tokener *this); struct json_object* json_tokener_parse(char * s) @@ -44,6 +45,27 @@ struct json_object* json_tokener_parse(char * s) 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 = 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 + static struct json_object* json_tokener_do_parse(struct json_tokener *this) { enum json_tokener_state state, saved_state; @@ -52,11 +74,11 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) char *obj_field_name = NULL; char quote_char; int deemed_double, start_offset; + char c; state = json_tokener_state_eatws; saved_state = json_tokener_state_start; - char c; do { c = this->source[this->pos]; switch(state) { @@ -105,7 +127,20 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) state = json_tokener_state_boolean; start_offset = this->pos++; break; - case '0' ... '9': +#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 '-': deemed_double = 0; state = json_tokener_state_number; @@ -422,5 +457,5 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", err, state, c); json_object_put(current); - return error_ptr(-err); + return error_ptr((ptrdiff_t)-err); } diff --git a/json_tokener.h b/json_tokener.h index c39577d..9bdf238 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.h,v 1.5 2004/07/22 01:20:05 mclark Exp $ + * $Id: json_tokener.h,v 1.6 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,6 +19,7 @@ #ifndef _json_tokener_h_ #define _json_tokener_h_ +#include "config.h" #include "json_object.h" enum json_tokener_error { @@ -65,6 +66,17 @@ struct json_tokener struct printbuf *pb; }; +#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 */ + +#if !HAVE_STRNDUP + char* strndup(const char* str, size_t n); +#endif /* !HAVE_STRNDUP */ + extern struct json_object* json_tokener_parse(char *s); #endif diff --git a/json_util.c b/json_util.c index 483644e..07abd89 100644 --- a/json_util.c +++ b/json_util.c @@ -1,11 +1,50 @@ +/* + * $Id: json_util.c,v 1.2 2005/06/14 22:41:51 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include "config.h" + #include #include +#include #include #include -#include + +#if HAVE_SYS_TYPES_H #include +#endif /* HAVE_SYS_TYPES_H */ + +#if HAVE_SYS_STAT_H #include +#endif /* HAVE_SYS_STAT_H */ + +#if HAVE_FCNTL_H #include +#endif /* HAVE_FCNTL_H */ + +#if HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif /* defined(WIN32) */ #include "bits.h" #include "debug.h" @@ -14,7 +53,6 @@ #include "json_tokener.h" #include "json_util.h" - struct json_object* json_object_from_file(char *filename) { struct printbuf *pb; @@ -49,7 +87,8 @@ struct json_object* json_object_from_file(char *filename) int json_object_to_file(char *filename, struct json_object *obj) { char *json_str; - int fd, ret, wpos, wsize; + int fd, ret; + unsigned int wpos, wsize; if(!obj) { mc_error("json_object_to_file: object is null\n"); @@ -61,8 +100,11 @@ int json_object_to_file(char *filename, struct json_object *obj) filename, strerror(errno)); return -1; } - if(!(json_str = json_object_to_json_string(obj))) return -1; - wsize = strlen(json_str); + + if(!(json_str = json_object_to_json_string(obj))) { 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) { @@ -71,7 +113,9 @@ int json_object_to_file(char *filename, struct json_object *obj) filename, strerror(errno)); return -1; } - wpos += ret; + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; } close(fd); diff --git a/json_util.h b/json_util.h index 32a0428..3915419 100644 --- a/json_util.h +++ b/json_util.h @@ -1,8 +1,37 @@ +/* + * $Id: json_util.h,v 1.2 2005/06/14 22:41:51 mclark Exp $ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + #ifndef _json_util_h_ #define _json_util_h_ +#include "config.h" + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif + #include "json_object.h" +#if !HAVE_OPEN && defined(WIN32) +# define open _open +#endif #define JSON_FILE_BUF_SIZE 4096 diff --git a/linkhash.c b/linkhash.c index b67eee7..81abc48 100644 --- a/linkhash.c +++ b/linkhash.c @@ -1,5 +1,5 @@ /* - * $Id: linkhash.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * $Id: linkhash.c,v 1.3 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,14 +16,17 @@ * */ +#include "config.h" + #include #include #include #include +#include +#include #include "linkhash.h" - void lh_abort(const char *msg, ...) { va_list ap; @@ -32,19 +35,17 @@ void lh_abort(const char *msg, ...) exit(1); } - unsigned long lh_ptr_hash(void *k) { - return ((long)k * LH_PRIME) >> 4; + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); } - int lh_ptr_equal(void *k1, void *k2) { return (k1 == k2); } - unsigned long lh_char_hash(void *k) { unsigned int h = 0; @@ -55,13 +56,11 @@ unsigned long lh_char_hash(void *k) return h; } - int lh_char_equal(void *k1, void *k2) { return (strcmp((char*)k1, (char*)k2) == 0); } - struct lh_table* lh_table_new(int size, char *name, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn, @@ -84,21 +83,18 @@ struct lh_table* lh_table_new(int size, char *name, return t; } - struct lh_table* lh_kchar_table_new(int size, 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, 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; @@ -119,7 +115,6 @@ void lh_table_resize(struct lh_table *t, int new_size) free(new_t); } - void lh_table_free(struct lh_table *t) { struct lh_entry *c; @@ -193,7 +188,11 @@ void* lh_table_lookup(struct lh_table *t, void *k) int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) { - int n = e - t->table; + 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); diff --git a/linkhash.h b/linkhash.h index c61e419..d6be31d 100644 --- a/linkhash.h +++ b/linkhash.h @@ -1,5 +1,5 @@ /* - * $Id: linkhash.h,v 1.3 2004/08/07 03:29:47 mclark Exp $ + * $Id: linkhash.h,v 1.4 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,6 +19,8 @@ #ifndef _linkhash_h_ #define _linkhash_h_ +#include "config.h" + /** * golden prime used in hash functions */ @@ -34,10 +36,8 @@ */ #define LH_FREED (void*)-2 - struct lh_entry; - /** * callback function prototypes */ diff --git a/printbuf.c b/printbuf.c index 76c04e4..7e70fb0 100644 --- a/printbuf.c +++ b/printbuf.c @@ -1,5 +1,5 @@ /* - * $Id: printbuf.c,v 1.3 2004/08/07 03:12:21 mclark Exp $ + * $Id: printbuf.c,v 1.4 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -16,16 +16,22 @@ * */ +#include "config.h" + #include #include -#include #include +#if HAVE_STDARG_H +# include +#else /* !HAVE_STDARG_H */ +# error Not enough var arg support! +#endif /* HAVE_STDARG_H */ + #include "bits.h" #include "debug.h" #include "printbuf.h" - struct printbuf* printbuf_new() { struct printbuf *p; @@ -46,11 +52,11 @@ int printbuf_memappend(struct printbuf *p, char *buf, int size) char *t; if(p->size - p->bpos <= size) { int new_size = max(p->size * 2, p->bpos + size + 8); -#if 0 +#ifdef PRINTBUF_DEBUG mc_debug("printbuf_memappend: realloc " "bpos=%d wrsize=%d old_size=%d new_size=%d\n", p->bpos, size, p->size, new_size); -#endif +#endif /* PRINTBUF_DEBUG */ if(!(t = realloc(p->buf, new_size))) return -1; p->size = new_size; p->buf = t; @@ -61,6 +67,46 @@ int printbuf_memappend(struct printbuf *p, char *buf, int size) return size; } +#if !HAVE_VSNPRINTF && defined(WIN32) +# 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, ...) { @@ -76,7 +122,7 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) /* 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 writeen - this code handles both cases. */ + would have been writen - this code handles both cases. */ if(size == -1 || size > 127) { int ret; va_start(ap, msg); @@ -90,7 +136,6 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) } } - void printbuf_reset(struct printbuf *p) { p->buf[0] = '\0'; diff --git a/printbuf.h b/printbuf.h index 6a9568f..6f43a0e 100644 --- a/printbuf.h +++ b/printbuf.h @@ -1,5 +1,5 @@ /* - * $Id: printbuf.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * $Id: printbuf.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -19,6 +19,8 @@ #ifndef _printbuf_h_ #define _printbuf_h_ +#undef PRINTBUF_DEBUG + struct printbuf { char *buf; int bpos; diff --git a/test1.c b/test1.c index b65a7cd..2376d4a 100644 --- a/test1.c +++ b/test1.c @@ -4,7 +4,6 @@ #include "json.h" - int main(int argc, char **argv) { struct json_object *my_string, *my_int, *my_object, *my_array; From 7b899b6dc540aecfc6622337bcceeabf701e79b9 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:21 +0000 Subject: [PATCH 004/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@6 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 6 ++++++ README | 5 +++-- README.html | 2 +- bits.h | 8 ++++++-- configure.in | 2 +- json_tokener.c | 8 ++++---- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f652d6..5b69097 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +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 + 0.2 * printbuf.c - C. Watford (christopher.watford@gmail.com) Added a Win32/Win64 compliant implementation of vasprintf diff --git a/README b/README index 93c0226..9f9fe0b 100644 --- a/README +++ b/README @@ -2,9 +2,10 @@ Building on Unix with gcc and autotools If checking out from CVS: - cp /usr/share/libtool/ltmain.sh . aclocal-1.6 - automake-1.6 --add-missing + libtoolize --copy + autoheader + automake-1.6 --add-missing --copy autoconf Then configure, make, make install diff --git a/README.html b/README.html index 840132b..52b4495 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.2.tar.gz

+

Latest release: json-c-0.3.tar.gz

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.

diff --git a/bits.h b/bits.h index 41e6592..49e5967 100644 --- a/bits.h +++ b/bits.h @@ -1,5 +1,5 @@ /* - * $Id: bits.h,v 1.4 2005/06/14 22:41:51 mclark Exp $ + * $Id: bits.h,v 1.7 2005/07/15 02:40:44 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -48,6 +48,10 @@ #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) #define error_ptr(error) ((void*)error) -#define is_error(ptr) ((ptrdiff_t)ptr < (ptrdiff_t)-4000L) +#ifdef _MSC_VER +#define is_error(ptr) ((UINT_PTR)ptr > (UINT_PTR)-4000L) +#else +#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) +#endif #endif diff --git a/configure.in b/configure.in index 4f7ec9d..f0a7d3a 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([JSON C Library], 0.2, [michael@metaparadigm.com], [json-c]) +AC_INIT([JSON C Library], 0.3, [michael@metaparadigm.com], [json-c]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) diff --git a/json_tokener.c b/json_tokener.c index 668d749..a224c7d 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.c,v 1.14 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_tokener.c,v 1.15 2005/07/15 03:19:43 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -273,16 +273,16 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) hexdigit(*(this->source + start_offset + 3)); if (ucs_char < 0x80) { utf_out[0] = ucs_char; - printbuf_memappend(this->pb, utf_out, 1); + printbuf_memappend(this->pb, (char*)utf_out, 1); } else if (ucs_char < 0x800) { utf_out[0] = 0xc0 | (ucs_char >> 6); utf_out[1] = 0x80 | (ucs_char & 0x3f); - printbuf_memappend(this->pb, utf_out, 2); + printbuf_memappend(this->pb, (char*)utf_out, 2); } else { utf_out[0] = 0xe0 | (ucs_char >> 12); utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); utf_out[2] = 0x80 | (ucs_char & 0x3f); - printbuf_memappend(this->pb, utf_out, 3); + printbuf_memappend(this->pb, (char*)utf_out, 3); } start_offset = this->pos; state = saved_state; From 0370baa74c76e49abffdcd90f70494b2d5298f1a Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:22 +0000 Subject: [PATCH 005/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@8 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 6 ++++++ README.html | 2 +- json_tokener.c | 11 +++++++---- test1.c | 3 +++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b69097..5dea73e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +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 + 0.3 * fix pointer arithmetic bug for error pointer check in is_error() macro * fix type passed to printbuf_memappend in json_tokener diff --git a/README.html b/README.html index 52b4495..65d9917 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.3.tar.gz

+

Latest release: json-c-0.4.tar.gz

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.

diff --git a/json_tokener.c b/json_tokener.c index a224c7d..fdb5113 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.c,v 1.15 2005/07/15 03:19:43 mclark Exp $ + * $Id: json_tokener.c,v 1.17 2005/07/26 07:49:11 mclark Exp $ * * Copyright Metaparadigm Pte. Ltd. 2004. * Michael Clark @@ -350,7 +350,7 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) } else { obj = json_tokener_do_parse(this); if(is_error(obj)) { - err = (enum json_tokener_error)obj; + err = -(enum json_tokener_error)obj; goto out; } json_object_array_add(current, obj); @@ -389,6 +389,9 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) printbuf_reset(this->pb); state = json_tokener_state_object_field; start_offset = ++this->pos; + } else { + err = json_tokener_error_parse_object; + goto out; } break; @@ -419,7 +422,7 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) case json_tokener_state_object_value: obj = json_tokener_do_parse(this); if(is_error(obj)) { - err = (enum json_tokener_error)obj; + err = -(enum json_tokener_error)obj; goto out; } json_object_object_add(current, obj_field_name, obj); @@ -457,5 +460,5 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", err, state, c); json_object_put(current); - return error_ptr((ptrdiff_t)-err); + return error_ptr(-err); } diff --git a/test1.c b/test1.c index 2376d4a..7f34cdc 100644 --- a/test1.c +++ b/test1.c @@ -121,6 +121,9 @@ int main(int argc, char **argv) printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + new_obj = json_tokener_parse("{ foo }"); + if(is_error(new_obj)) printf("got error as expected\n"); + new_obj = json_tokener_parse("foo"); if(is_error(new_obj)) printf("got error as expected\n"); From f6a6e486ffc38235edc3c1197278c8a505c523eb Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:23 +0000 Subject: [PATCH 006/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@10 327403b1-1117-474d-bef2-5cb71233fd97 --- COPYING | 499 ++---------------------------------------- ChangeLog | 12 + Makefile.am | 4 - README | 6 +- README-WIN32.html | 6 +- README.html | 8 +- arraylist.c | 15 +- arraylist.h | 25 +-- autogen.sh | 1 + bits.h | 31 +-- config.h.win32 | 15 +- debug.c | 15 +- debug.h | 15 +- json.h | 23 +- json_object.c | 15 +- json_object.h | 89 ++++---- json_object_private.h | 15 +- json_tokener.c | 15 +- json_tokener.h | 19 +- json_util.c | 15 +- json_util.h | 15 +- linkhash.c | 15 +- linkhash.h | 15 +- printbuf.c | 15 +- printbuf.h | 15 +- test1.c | 3 +- 26 files changed, 165 insertions(+), 756 deletions(-) create mode 100644 autogen.sh diff --git a/COPYING b/COPYING index eb685a5..b07ea94 100644 --- a/COPYING +++ b/COPYING @@ -1,481 +1,18 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! +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 +BRIAN PAUL 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/ChangeLog b/ChangeLog index 5dea73e..3b0d1bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +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 + 0.4 * Fix additional error case in object parsing * Add back sign reversal in nested object parse as error pointer diff --git a/Makefile.am b/Makefile.am index 9e86ccd..4b01dc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,5 @@ -AUTOMAKE_OPTIONS = 1.6 - CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT -libjson_la_LIBADD = $(JSON_LIBS) - lib_LTLIBRARIES = libjson.la pkgconfigdir = $(libdir)/pkgconfig diff --git a/README b/README index 9f9fe0b..beeba53 100644 --- a/README +++ b/README @@ -2,11 +2,7 @@ Building on Unix with gcc and autotools If checking out from CVS: - aclocal-1.6 - libtoolize --copy - autoheader - automake-1.6 --add-missing --copy - autoconf + sh autogen.sh Then configure, make, make install diff --git a/README-WIN32.html b/README-WIN32.html index c20fc83..fb50159 100644 --- a/README-WIN32.html +++ b/README-WIN32.html @@ -51,13 +51,11 @@ Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
CVS password: <enter 'anoncvs'>
# cvs co json-c

-

Copyright Metaparadigm Pte. Ltd. 2004. Michael +

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael Clark

This program is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public (LGPL) License as published by the - Free Software Foundation; either version 2.1 of the License, or (at your - option) any later version.

+ the terms of the MIT License. See COPYING for details.


diff --git a/README.html b/README.html index 65d9917..c55600a 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.4.tar.gz

+

Latest release: json-c-0.5.tar.gz

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.

@@ -26,13 +26,11 @@ Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
CVS password: <enter 'anoncvs'>
# cvs co json-c

-

Copyright Metaparadigm Pte. Ltd. 2004. Michael +

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael Clark

This program is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public (LGPL) License as published by the - Free Software Foundation; either version 2.1 of the License, or (at your - option) any later version.

+ the terms of the MIT License. See COPYING for details.


diff --git a/arraylist.c b/arraylist.c index be93e26..dbd075d 100644 --- a/arraylist.c +++ b/arraylist.c @@ -1,18 +1,11 @@ /* - * $Id: arraylist.c,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/arraylist.h b/arraylist.h index d82f14a..2948e04 100644 --- a/arraylist.h +++ b/arraylist.h @@ -1,18 +1,11 @@ /* - * $Id: arraylist.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ + * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ @@ -35,18 +28,18 @@ extern struct array_list* array_list_new(array_list_free_fn *free_fn); extern void -array_list_free(struct array_list *this); +array_list_free(struct array_list *al); extern void* -array_list_get_idx(struct array_list *this, int i); +array_list_get_idx(struct array_list *al, int i); extern int -array_list_put_idx(struct array_list *this, int i, void *data); +array_list_put_idx(struct array_list *al, int i, void *data); extern int -array_list_add(struct array_list *this, void *data); +array_list_add(struct array_list *al, void *data); extern int -array_list_length(struct array_list *this); +array_list_length(struct array_list *al); #endif diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 0000000..c67b903 --- /dev/null +++ b/autogen.sh @@ -0,0 +1 @@ +autoreconf -v --install || exit 1 diff --git a/bits.h b/bits.h index 49e5967..379793a 100644 --- a/bits.h +++ b/bits.h @@ -1,18 +1,11 @@ /* - * $Id: bits.h,v 1.7 2005/07/15 02:40:44 mclark Exp $ + * $Id: bits.h,v 1.9 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ @@ -31,27 +24,15 @@ */ #ifndef min -#define min(x,y) ({ \ - typeof(x) _x = (x); \ - typeof(y) _y = (y); \ - (void) (&_x == &_y); \ - _x < _y ? _x : _y; }) +#define min(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef max -#define max(x,y) ({ \ - typeof(x) _x = (x); \ - typeof(y) _y = (y); \ - (void) (&_x == &_y); \ - _x > _y ? _x : _y; }) +#define max(a,b) ((a) > (b) ? (a) : (b)) #endif #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) #define error_ptr(error) ((void*)error) -#ifdef _MSC_VER -#define is_error(ptr) ((UINT_PTR)ptr > (UINT_PTR)-4000L) -#else #define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) -#endif #endif diff --git a/config.h.win32 b/config.h.win32 index 878d6c3..7f7e6ae 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -1,18 +1,11 @@ /* - * $Id: config.h.win32,v 1.1 2005/06/14 22:41:51 mclark Exp $ + * $Id: config.h.win32,v 1.2 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/debug.c b/debug.c index a4d12f1..eaa6fca 100644 --- a/debug.c +++ b/debug.c @@ -1,18 +1,11 @@ /* - * $Id: debug.c,v 1.4 2005/06/14 22:41:51 mclark Exp $ + * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/debug.h b/debug.h index 581b76d..f825a44 100644 --- a/debug.h +++ b/debug.h @@ -1,18 +1,11 @@ /* - * $Id: debug.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * $Id: debug.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/json.h b/json.h index 14bff2b..a5a3432 100644 --- a/json.h +++ b/json.h @@ -1,24 +1,21 @@ /* - * $Id: json.h,v 1.4 2004/08/07 03:13:52 mclark Exp $ + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * 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" @@ -27,4 +24,8 @@ #include "json_object.h" #include "json_tokener.h" +#ifdef __cplusplus +} +#endif + #endif diff --git a/json_object.c b/json_object.c index b88aa4d..fecd72b 100644 --- a/json_object.c +++ b/json_object.c @@ -1,18 +1,11 @@ /* - * $Id: json_object.c,v 1.13 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_object.c,v 1.14 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/json_object.h b/json_object.h index 0f32ead..4232447 100644 --- a/json_object.h +++ b/json_object.h @@ -1,18 +1,11 @@ /* - * $Id: json_object.h,v 1.9 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_object.h,v 1.11 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ @@ -50,27 +43,27 @@ enum json_type { json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string }; /* reference counting functions */ /** * Increment the reference count of json_object - * @param this the json_object instance + * @param obj the json_object instance */ -extern struct json_object* json_object_get(struct json_object *this); +extern struct json_object* json_object_get(struct json_object *obj); /** * Decrement the reference count of json_object and free if it reaches zero - * @param this the json_object instance + * @param obj the json_object instance */ -extern void json_object_put(struct json_object *this); +extern void json_object_put(struct json_object *obj); /** * Check if the json_object is of a given type - * @param this the json_object instance + * @param obj the json_object instance * @param type one of: json_type_boolean, json_type_double, @@ -79,11 +72,11 @@ extern void json_object_put(struct json_object *this); json_type_array, json_type_string, */ -extern int json_object_is_type(struct json_object *this, enum json_type type); +extern int json_object_is_type(struct json_object *obj, enum json_type type); /** * Get the type of the json_object - * @param this the json_object instance + * @param obj the json_object instance * @returns type being one of: json_type_boolean, json_type_double, @@ -92,14 +85,14 @@ extern int json_object_is_type(struct json_object *this, enum json_type type); json_type_array, json_type_string, */ -extern enum json_type json_object_get_type(struct json_object *this); +extern enum json_type json_object_get_type(struct json_object *obj); /** Stringify object to json format - * @param this the json_object instance + * @param obj the json_object instance * @returns a string in JSON format */ -extern char* json_object_to_json_string(struct json_object *this); +extern char* json_object_to_json_string(struct json_object *obj); /* object type methods */ @@ -110,10 +103,10 @@ extern char* json_object_to_json_string(struct json_object *this); extern struct json_object* json_object_new_object(); /** Get the hashtable of a json_object of type json_type_object - * @param this the json_object instance + * @param obj the json_object instance * @returns a linkhash */ -extern struct lh_table* json_object_get_object(struct json_object *this); +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 * @@ -121,29 +114,29 @@ extern struct lh_table* json_object_get_object(struct json_object *this); * 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 this the json_object instance + * @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* this, char *key, +extern void json_object_object_add(struct json_object* obj, char *key, struct json_object *val); /** Get the json_object associate with a given object field - * @param this the json_object instance + * @param obj the json_object instance * @param key the object field name * @returns the json_object associated with the given field name */ -extern struct json_object* json_object_object_get(struct json_object* this, +extern struct json_object* json_object_object_get(struct json_object* obj, char *key); /** Delete the given json_object field * * The reference count will be decremented for the deleted object * - * @param this the json_object instance + * @param obj the json_object instance * @param key the object field name */ -extern void json_object_object_del(struct json_object* this, char *key); +extern void json_object_object_del(struct json_object* obj, char *key); /** Iterate through all keys and values of an object * @param obj the json_object instance @@ -179,16 +172,16 @@ extern void json_object_object_del(struct json_object* this, char *key); extern struct json_object* json_object_new_array(); /** Get the arraylist of a json_object of type json_type_array - * @param this the json_object instance + * @param obj the json_object instance * @returns an arraylist */ -extern struct array_list* json_object_get_array(struct json_object *this); +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 this the json_object instance + * @param obj the json_object instance * @returns an int */ -extern int json_object_array_length(struct json_object *this); +extern int json_object_array_length(struct json_object *obj); /** Add an element to the end of a json_object of type json_type_array * @@ -196,10 +189,10 @@ extern int json_object_array_length(struct json_object *this); * 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 this the json_object instance + * @param obj the json_object instance * @param val the json_object to be added */ -extern int json_object_array_add(struct json_object *this, +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) @@ -213,19 +206,19 @@ extern int json_object_array_add(struct json_object *this, * The array size will be automatically be expanded to the size of the * index if the index is larger than the current size. * - * @param this the json_object instance + * @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 *this, int idx, +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 this the json_object instance + * @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 *this, +extern struct json_object* json_object_array_get_idx(struct json_object *obj, int idx); /* boolean type methods */ @@ -244,10 +237,10 @@ extern struct json_object* json_object_new_boolean(boolean b); * 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 this the json_object instance + * @param obj the json_object instance * @returns a boolean */ -extern boolean json_object_get_boolean(struct json_object *this); +extern boolean json_object_get_boolean(struct json_object *obj); /* int type methods */ @@ -264,10 +257,10 @@ extern struct json_object* json_object_new_int(int i); * double objects will return their integer conversion. Strings will be * parsed as an integer. If no conversion exists then 0 is returned. * - * @param this the json_object instance + * @param obj the json_object instance * @returns an int */ -extern int json_object_get_int(struct json_object *this); +extern int json_object_get_int(struct json_object *obj); /* double type methods */ @@ -284,10 +277,10 @@ extern struct json_object* json_object_new_double(double d); * integer objects will return their dboule conversion. Strings will be * parsed as a double. If no conversion exists then 0.0 is returned. * - * @param this the json_object instance + * @param obj the json_object instance * @returns an double */ -extern double json_object_get_double(struct json_object *this); +extern double json_object_get_double(struct json_object *obj); /* string type methods */ @@ -311,9 +304,9 @@ extern struct json_object* json_object_new_string_len(char *s, int len); * 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 this the json_object instance + * @param obj the json_object instance * @returns a string */ -extern char* json_object_get_string(struct json_object *this); +extern char* json_object_get_string(struct json_object *obj); #endif diff --git a/json_object_private.h b/json_object_private.h index 4548144..35a44f3 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -1,18 +1,11 @@ /* - * $Id: json_object_private.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/json_tokener.c b/json_tokener.c index fdb5113..6a1ea89 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,18 +1,11 @@ /* - * $Id: json_tokener.c,v 1.17 2005/07/26 07:49:11 mclark Exp $ + * $Id: json_tokener.c,v 1.18 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/json_tokener.h b/json_tokener.h index 9bdf238..f36c058 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -1,18 +1,11 @@ /* - * $Id: json_tokener.h,v 1.6 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_tokener.h,v 1.8 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ @@ -32,7 +25,7 @@ enum json_tokener_error { json_tokener_error_parse_object, json_tokener_error_parse_string, json_tokener_error_parse_comment, - json_tokener_error_parse_eof, + json_tokener_error_parse_eof }; enum json_tokener_state { @@ -56,7 +49,7 @@ enum json_tokener_state { json_tokener_state_object_field, json_tokener_state_object_field_end, json_tokener_state_object_value, - json_tokener_state_object_sep, + json_tokener_state_object_sep }; struct json_tokener diff --git a/json_util.c b/json_util.c index 07abd89..0aaf0f7 100644 --- a/json_util.c +++ b/json_util.c @@ -1,18 +1,11 @@ /* - * $Id: json_util.c,v 1.2 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_util.c,v 1.3 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/json_util.h b/json_util.h index 3915419..cbaab5d 100644 --- a/json_util.h +++ b/json_util.h @@ -1,18 +1,11 @@ /* - * $Id: json_util.h,v 1.2 2005/06/14 22:41:51 mclark Exp $ + * $Id: json_util.h,v 1.3 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/linkhash.c b/linkhash.c index 81abc48..6cfc9a0 100644 --- a/linkhash.c +++ b/linkhash.c @@ -1,18 +1,11 @@ /* - * $Id: linkhash.c,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/linkhash.h b/linkhash.h index d6be31d..86110b8 100644 --- a/linkhash.h +++ b/linkhash.h @@ -1,18 +1,11 @@ /* - * $Id: linkhash.h,v 1.4 2005/06/14 22:41:51 mclark Exp $ + * $Id: linkhash.h,v 1.5 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/printbuf.c b/printbuf.c index 7e70fb0..79bdaf5 100644 --- a/printbuf.c +++ b/printbuf.c @@ -1,18 +1,11 @@ /* - * $Id: printbuf.c,v 1.4 2005/06/14 22:41:51 mclark Exp $ + * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/printbuf.h b/printbuf.h index 6f43a0e..bc1669b 100644 --- a/printbuf.h +++ b/printbuf.h @@ -1,18 +1,11 @@ /* - * $Id: printbuf.h,v 1.3 2005/06/14 22:41:51 mclark Exp $ + * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ * - * Copyright Metaparadigm Pte. Ltd. 2004. + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public (LGPL) - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details: http://www.gnu.org/ + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. * */ diff --git a/test1.c b/test1.c index 7f34cdc..8e49d10 100644 --- a/test1.c +++ b/test1.c @@ -8,6 +8,7 @@ int main(int argc, char **argv) { struct json_object *my_string, *my_int, *my_object, *my_array; struct json_object *new_obj; + int i; my_string = json_object_new_string("\t"); printf("my_string=%s\n", json_object_get_string(my_string)); @@ -28,7 +29,7 @@ int main(int argc, char **argv) json_object_array_add(my_array, json_object_new_int(3)); json_object_array_put_idx(my_array, 4, json_object_new_int(5)); printf("my_array=\n"); - for(int i=0; i < json_object_array_length(my_array); i++) { + for(i=0; i < json_object_array_length(my_array); i++) { struct json_object *obj = json_object_array_get_idx(my_array, i); printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); } From 837240f75f359934054ccc065c7426aeb002d472 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:25 +0000 Subject: [PATCH 007/276] =?UTF-8?q?=20=20*=20Fix=20bug=20in=20escaping=20o?= =?UTF-8?q?f=20control=20characters=20=20=20=20=20Johan=20Bj=EF=BF=BDrklun?= =?UTF-8?q?d,=20johbjo09=20at=20kth=20dot=20se=20=20=20*=20Remove=20includ?= =?UTF-8?q?e=20"config.h"=20from=20headers=20(should=20only=20=20=20=20=20?= =?UTF-8?q?be=20included=20from=20.c=20files)=20=20=20=20=20Michael=20Clar?= =?UTF-8?q?k=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@12 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 7 +++++++ README.html | 2 +- bits.h | 13 +------------ debug.h | 10 +--------- json_object.c | 14 ++++++++++---- json_object.h | 4 +--- json_tokener.c | 10 +++++++++- json_tokener.h | 14 +------------- json_util.c | 7 ++++++- json_util.h | 14 +------------- linkhash.h | 4 +--- 11 files changed, 39 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b0d1bb..a0f848e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +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 + 0.5 * Make headers C++ compatible by change *this to *obj * Add ifdef C++ extern "C" to headers diff --git a/README.html b/README.html index c55600a..7b3a65e 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.5.tar.gz

+

Latest release: json-c-0.6.tar.gz

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.

diff --git a/bits.h b/bits.h index 379793a..2c107cc 100644 --- a/bits.h +++ b/bits.h @@ -1,5 +1,5 @@ /* - * $Id: bits.h,v 1.9 2006/01/26 02:16:28 mclark Exp $ + * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,17 +12,6 @@ #ifndef _bits_h_ #define _bits_h_ -#include "config.h" - -#if STDC_HEADERS -# include -#endif /* STDC_HEADERS */ - -/* CAW: wrapped in ifndef's to make win32 compliant -** this fails to take over GCC specifics, but this -** seems to be unimportant. - */ - #ifndef min #define min(a,b) ((a) < (b) ? (a) : (b)) #endif diff --git a/debug.h b/debug.h index f825a44..1db69ef 100644 --- a/debug.h +++ b/debug.h @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,14 +12,6 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ -#include "config.h" - -#if HAVE_STRERROR -#define errstr strerror(errno) -#else /* !HAVE_STRERROR */ -#define errstr -#endif /* HAVE_STRERROR */ - extern void mc_set_debug(int debug); extern int mc_get_debug(); diff --git a/json_object.c b/json_object.c index fecd72b..525e217 100644 --- a/json_object.c +++ b/json_object.c @@ -1,5 +1,5 @@ /* - * $Id: json_object.c,v 1.14 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_object.c,v 1.15 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -23,6 +23,10 @@ #include "json_object_private.h" #include "json_tokener.h" +#if !HAVE_STRNDUP + char* strndup(const char* str, size_t n); +#endif /* !HAVE_STRNDUP */ + /* #define REFCOUNT_DEBUG 1 */ char *json_number_chars = "0123456789.+-e"; @@ -78,10 +82,12 @@ static void json_object_fini() { static int json_escape_str(struct printbuf *pb, char *str) { int pos = 0, start_offset = 0; - char c; + unsigned char c; do { c = str[pos]; switch(c) { + case '\0': + break; case '\b': case '\n': case '\r': @@ -97,14 +103,14 @@ static int json_escape_str(struct printbuf *pb, char *str) start_offset = ++pos; break; default: - if(c && c < ' ') { + 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 if(c) pos++; + } else pos++; } } while(c); if(pos - start_offset > 0) diff --git a/json_object.h b/json_object.h index 4232447..5c25968 100644 --- a/json_object.h +++ b/json_object.h @@ -1,5 +1,5 @@ /* - * $Id: json_object.h,v 1.11 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,8 +12,6 @@ #ifndef _json_object_h_ #define _json_object_h_ -#include "config.h" - #define JSON_OBJECT_DEF_HASH_ENTIRES 16 #undef FALSE diff --git a/json_tokener.c b/json_tokener.c index 6a1ea89..a3ebf10 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.c,v 1.18 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_tokener.c,v 1.19 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -23,6 +23,14 @@ #include "json_object.h" #include "json_tokener.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 struct json_object* json_tokener_do_parse(struct json_tokener *this); struct json_object* json_tokener_parse(char * s) diff --git a/json_tokener.h b/json_tokener.h index f36c058..12227a9 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.h,v 1.8 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_tokener.h,v 1.9 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,7 +12,6 @@ #ifndef _json_tokener_h_ #define _json_tokener_h_ -#include "config.h" #include "json_object.h" enum json_tokener_error { @@ -59,17 +58,6 @@ struct json_tokener struct printbuf *pb; }; -#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 */ - -#if !HAVE_STRNDUP - char* strndup(const char* str, size_t n); -#endif /* !HAVE_STRNDUP */ - extern struct json_object* json_tokener_parse(char *s); #endif diff --git a/json_util.c b/json_util.c index 0aaf0f7..e20be24 100644 --- a/json_util.c +++ b/json_util.c @@ -1,5 +1,5 @@ /* - * $Id: json_util.c,v 1.3 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -39,6 +39,11 @@ # include #endif /* defined(WIN32) */ +#if !HAVE_OPEN && defined(WIN32) +# define open _open +#endif + + #include "bits.h" #include "debug.h" #include "printbuf.h" diff --git a/json_util.h b/json_util.h index cbaab5d..30fe2ab 100644 --- a/json_util.h +++ b/json_util.h @@ -1,5 +1,5 @@ /* - * $Id: json_util.h,v 1.3 2006/01/26 02:16:28 mclark Exp $ + * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,20 +12,8 @@ #ifndef _json_util_h_ #define _json_util_h_ -#include "config.h" - -#ifdef WIN32 -# define WIN32_LEAN_AND_MEAN -# include -# include -#endif - #include "json_object.h" -#if !HAVE_OPEN && defined(WIN32) -# define open _open -#endif - #define JSON_FILE_BUF_SIZE 4096 /* utlitiy functions */ diff --git a/linkhash.h b/linkhash.h index 86110b8..5c9fa85 100644 --- a/linkhash.h +++ b/linkhash.h @@ -1,5 +1,5 @@ /* - * $Id: linkhash.h,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -12,8 +12,6 @@ #ifndef _linkhash_h_ #define _linkhash_h_ -#include "config.h" - /** * golden prime used in hash functions */ From a850f8e29e8aeb3f7c94210376012c50251912d0 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 13 Mar 2007 08:26:26 +0000 Subject: [PATCH 008/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@14 327403b1-1117-474d-bef2-5cb71233fd97 --- COPYING | 13 +- ChangeLog | 6 + Makefile.am | 2 +- json_object.c | 6 +- json_tokener.c | 403 ++++++++++++++++++++++++++++--------------------- json_tokener.h | 46 ++++-- test1.c | 26 ++++ 7 files changed, 308 insertions(+), 194 deletions(-) diff --git a/COPYING b/COPYING index b07ea94..f8ff2e1 100644 --- a/COPYING +++ b/COPYING @@ -10,9 +10,10 @@ 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 -BRIAN PAUL 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. +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/ChangeLog b/ChangeLog index a0f848e..1523c6c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +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 diff --git a/Makefile.am b/Makefile.am index 4b01dc1..98f1553 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT lib_LTLIBRARIES = libjson.la diff --git a/json_object.c b/json_object.c index 525e217..d6c56dc 100644 --- a/json_object.c +++ b/json_object.c @@ -1,5 +1,5 @@ /* - * $Id: json_object.c,v 1.15 2006/01/30 23:07:57 mclark Exp $ + * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -93,6 +93,8 @@ static int json_escape_str(struct printbuf *pb, char *str) 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); @@ -100,6 +102,8 @@ static int json_escape_str(struct printbuf *pb, char *str) 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: diff --git a/json_tokener.c b/json_tokener.c index a3ebf10..ada0f9b 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.c,v 1.19 2006/01/30 23:07:57 mclark Exp $ + * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -23,6 +23,7 @@ #include "json_object.h" #include "json_tokener.h" + #if !HAVE_STRNCASECMP && defined(_MSC_VER) /* MSC has the version as _strnicmp */ # define strncasecmp _strnicmp @@ -31,67 +32,136 @@ #endif /* HAVE_STRNCASECMP */ -static struct json_object* json_tokener_do_parse(struct json_tokener *this); +static const char* json_null_str = "null"; +static const char* json_true_str = "true"; +static const char* json_false_str = "false"; -struct json_object* json_tokener_parse(char * s) +const char* json_tokener_errors[] = { + "success", + "continue", + "nesting to 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", +}; + + +struct json_tokener* json_tokener_new() { - struct json_tokener tok; + struct json_tokener *tok = calloc(1, sizeof(struct json_tokener)); + 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; + 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(char *str) +{ + struct json_tokener* tok; struct json_object* obj; - tok.source = s; - tok.pos = 0; - tok.pb = printbuf_new(); - obj = json_tokener_do_parse(&tok); - printbuf_free(tok.pb); + tok = json_tokener_new(); + obj = json_tokener_parse_ex(tok, str, -1); + if(tok->err != json_tokener_success) + obj = error_ptr(-tok->err); + 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 = min(len,n); - char* s = (char*)malloc(sizeof(char) * (nn + 1)); + if(str) { + size_t len = strlen(str); + size_t nn = min(len,n); + char* s = (char*)malloc(sizeof(char) * (nn + 1)); - if(s) { - memcpy(s, str, nn); - s[nn] = '\0'; - } + if(s) { + memcpy(s, str, nn); + s[nn] = '\0'; + } - return s; - } + return s; + } - return NULL; + return NULL; } #endif -static struct json_object* json_tokener_do_parse(struct json_tokener *this) + +#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 + +struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + char *str, int len) { - enum json_tokener_state state, saved_state; - enum json_tokener_error err = json_tokener_success; - struct json_object *current = NULL, *obj; - char *obj_field_name = NULL; - char quote_char; - int deemed_double, start_offset; + struct json_object *obj = NULL; char c; - state = json_tokener_state_eatws; - saved_state = json_tokener_state_start; + tok->char_offset = 0; + tok->err = json_tokener_success; do { - c = this->source[this->pos]; + if(tok->char_offset == len) { + if(tok->depth == 0 && state == json_tokener_state_eatws && + saved_state == json_tokener_state_finish) + tok->err = json_tokener_success; + else + tok->err = json_tokener_continue; + goto out; + } + + c = *str; + redo_char: switch(state) { case json_tokener_state_eatws: if(isspace(c)) { - this->pos++; + /* okay */ } else if(c == '/') { + printbuf_reset(tok->pb); + printbuf_memappend(tok->pb, &c, 1); state = json_tokener_state_comment_start; - start_offset = this->pos++; } else { state = saved_state; + goto redo_char; } break; @@ -99,35 +169,34 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) switch(c) { case '{': state = json_tokener_state_eatws; - saved_state = json_tokener_state_object; + saved_state = json_tokener_state_object_field_start; current = json_object_new_object(); - this->pos++; break; case '[': state = json_tokener_state_eatws; saved_state = json_tokener_state_array; current = json_object_new_array(); - this->pos++; break; case 'N': case 'n': state = json_tokener_state_null; - start_offset = this->pos++; - break; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; case '"': case '\'': - quote_char = c; - printbuf_reset(this->pb); state = json_tokener_state_string; - start_offset = ++this->pos; + printbuf_reset(tok->pb); + tok->quote_char = c; break; case 'T': case 't': case 'F': case 'f': state = json_tokener_state_boolean; - start_offset = this->pos++; - break; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; #if defined(__GNUC__) case '0' ... '9': #else @@ -143,30 +212,38 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) case '9': #endif case '-': - deemed_double = 0; state = json_tokener_state_number; - start_offset = this->pos++; - break; + printbuf_reset(tok->pb); + tok->is_double = 0; + goto redo_char; default: - err = json_tokener_error_parse_unexpected; + tok->err = json_tokener_error_parse_unexpected; goto out; } break; case json_tokener_state_finish: - goto out; + 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: - if(strncasecmp("null", this->source + start_offset, - this->pos - start_offset)) - return error_ptr(-json_tokener_error_parse_null); - if(this->pos - start_offset == 4) { - current = NULL; - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; + printbuf_memappend(tok->pb, &c, 1); + if(strncasecmp(json_null_str, tok->pb->buf, + 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 { - this->pos++; + tok->err = json_tokener_error_parse_null; + goto out; } + tok->st_pos++; break; case json_tokener_state_comment_start: @@ -175,291 +252,265 @@ static struct json_object* json_tokener_do_parse(struct json_tokener *this) } else if(c == '/') { state = json_tokener_state_comment_eol; } else { - err = json_tokener_error_parse_comment; + tok->err = json_tokener_error_parse_comment; goto out; } - this->pos++; + printbuf_memappend(tok->pb, &c, 1); break; case json_tokener_state_comment: if(c == '*') state = json_tokener_state_comment_end; - this->pos++; + printbuf_memappend(tok->pb, &c, 1); break; case json_tokener_state_comment_eol: if(c == '\n') { - if(mc_get_debug()) { - char *tmp = strndup(this->source + start_offset, - this->pos - start_offset); - mc_debug("json_tokener_comment: %s\n", tmp); - free(tmp); - } + mc_debug("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; + } else { + printbuf_memappend(tok->pb, &c, 1); } - this->pos++; break; case json_tokener_state_comment_end: + printbuf_memappend(tok->pb, &c, 1); if(c == '/') { - if(mc_get_debug()) { - char *tmp = strndup(this->source + start_offset, - this->pos - start_offset + 1); - mc_debug("json_tokener_comment: %s\n", tmp); - free(tmp); - } + mc_debug("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; } else { state = json_tokener_state_comment; } - this->pos++; break; case json_tokener_state_string: - if(c == quote_char) { - printbuf_memappend(this->pb, this->source + start_offset, - this->pos - start_offset); - current = json_object_new_string(this->pb->buf); + if(c == tok->quote_char) { + current = json_object_new_string(tok->pb->buf); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if(c == '\\') { saved_state = json_tokener_state_string; state = json_tokener_state_string_escape; + } else { + printbuf_memappend(tok->pb, &c, 1); } - this->pos++; break; case json_tokener_state_string_escape: switch(c) { case '"': case '\\': - printbuf_memappend(this->pb, this->source + start_offset, - this->pos - start_offset - 1); - start_offset = this->pos++; + case '/': + printbuf_memappend(tok->pb, &c, 1); state = saved_state; break; case 'b': case 'n': case 'r': case 't': - printbuf_memappend(this->pb, this->source + start_offset, - this->pos - start_offset - 1); - if(c == 'b') printbuf_memappend(this->pb, "\b", 1); - else if(c == 'n') printbuf_memappend(this->pb, "\n", 1); - else if(c == 'r') printbuf_memappend(this->pb, "\r", 1); - else if(c == 't') printbuf_memappend(this->pb, "\t", 1); - start_offset = ++this->pos; + if(c == 'b') printbuf_memappend(tok->pb, "\b", 1); + else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1); + else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1); + else if(c == 't') printbuf_memappend(tok->pb, "\t", 1); state = saved_state; break; case 'u': - printbuf_memappend(this->pb, this->source + start_offset, - this->pos - start_offset - 1); - start_offset = ++this->pos; + tok->ucs_char = 0; + tok->st_pos = 0; state = json_tokener_state_escape_unicode; break; default: - err = json_tokener_error_parse_string; + tok->err = json_tokener_error_parse_string; goto out; } break; case json_tokener_state_escape_unicode: if(strchr(json_hex_chars, c)) { - this->pos++; - if(this->pos - start_offset == 4) { + tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4)); + if(tok->st_pos == 4) { unsigned char utf_out[3]; - unsigned int ucs_char = - (hexdigit(*(this->source + start_offset)) << 12) + - (hexdigit(*(this->source + start_offset + 1)) << 8) + - (hexdigit(*(this->source + start_offset + 2)) << 4) + - hexdigit(*(this->source + start_offset + 3)); - if (ucs_char < 0x80) { - utf_out[0] = ucs_char; - printbuf_memappend(this->pb, (char*)utf_out, 1); - } else if (ucs_char < 0x800) { - utf_out[0] = 0xc0 | (ucs_char >> 6); - utf_out[1] = 0x80 | (ucs_char & 0x3f); - printbuf_memappend(this->pb, (char*)utf_out, 2); + if (tok->ucs_char < 0x80) { + utf_out[0] = tok->ucs_char; + printbuf_memappend(tok->pb, (char*)utf_out, 1); + } else if (tok->ucs_char < 0x800) { + utf_out[0] = 0xc0 | (tok->ucs_char >> 6); + utf_out[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend(tok->pb, (char*)utf_out, 2); } else { - utf_out[0] = 0xe0 | (ucs_char >> 12); - utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); - utf_out[2] = 0x80 | (ucs_char & 0x3f); - printbuf_memappend(this->pb, (char*)utf_out, 3); + utf_out[0] = 0xe0 | (tok->ucs_char >> 12); + utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + utf_out[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend(tok->pb, (char*)utf_out, 3); } - start_offset = this->pos; state = saved_state; } } else { - err = json_tokener_error_parse_string; + tok->err = json_tokener_error_parse_string; goto out; } break; case json_tokener_state_boolean: - if(strncasecmp("true", this->source + start_offset, - this->pos - start_offset) == 0) { - if(this->pos - start_offset == 4) { + printbuf_memappend(tok->pb, &c, 1); + if(strncasecmp(json_true_str, tok->pb->buf, + 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; - } else { - this->pos++; + goto redo_char; } - } else if(strncasecmp("false", this->source + start_offset, - this->pos - start_offset) == 0) { - if(this->pos - start_offset == 5) { + } else if(strncasecmp(json_false_str, tok->pb->buf, + 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; - } else { - this->pos++; + goto redo_char; } } else { - err = json_tokener_error_parse_boolean; + tok->err = json_tokener_error_parse_boolean; goto out; } + tok->st_pos++; break; case json_tokener_state_number: - if(!c || !strchr(json_number_chars, c)) { + if(c && strchr(json_number_chars, c)) { + printbuf_memappend(tok->pb, &c, 1); + if(c == '.' || c == 'e') tok->is_double = 1; + } else { int numi; double numd; - char *tmp = strndup(this->source + start_offset, - this->pos - start_offset); - if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) { + if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { current = json_object_new_int(numi); - } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) { + } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { current = json_object_new_double(numd); } else { - free(tmp); - err = json_tokener_error_parse_number; + tok->err = json_tokener_error_parse_number; goto out; } - free(tmp); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; - } else { - if(c == '.' || c == 'e') deemed_double = 1; - this->pos++; + goto redo_char; } break; case json_tokener_state_array: if(c == ']') { - this->pos++; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else { - obj = json_tokener_do_parse(this); - if(is_error(obj)) { - err = -(enum json_tokener_error)obj; + if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) { + tok->err = json_tokener_error_depth; goto out; } - json_object_array_add(current, obj); - saved_state = json_tokener_state_array_sep; - state = json_tokener_state_eatws; + 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 == ']') { - this->pos++; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if(c == ',') { - this->pos++; saved_state = json_tokener_state_array; state = json_tokener_state_eatws; } else { - json_object_put(current); - return error_ptr(-json_tokener_error_parse_array); + tok->err = json_tokener_error_parse_array; + goto out; } break; - case json_tokener_state_object: - state = json_tokener_state_object_field_start; - start_offset = this->pos; - break; - case json_tokener_state_object_field_start: if(c == '}') { - this->pos++; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if (c == '"' || c == '\'') { - quote_char = c; - printbuf_reset(this->pb); + tok->quote_char = c; + printbuf_reset(tok->pb); state = json_tokener_state_object_field; - start_offset = ++this->pos; } else { - err = json_tokener_error_parse_object; + tok->err = json_tokener_error_parse_object_key_name; goto out; } break; case json_tokener_state_object_field: - if(c == quote_char) { - printbuf_memappend(this->pb, this->source + start_offset, - this->pos - start_offset); - obj_field_name = strdup(this->pb->buf); + if(c == tok->quote_char) { + obj_field_name = strdup(tok->pb->buf); saved_state = json_tokener_state_object_field_end; state = json_tokener_state_eatws; } else if(c == '\\') { saved_state = json_tokener_state_object_field; state = json_tokener_state_string_escape; + } else { + printbuf_memappend(tok->pb, &c, 1); } - this->pos++; break; case json_tokener_state_object_field_end: if(c == ':') { - this->pos++; saved_state = json_tokener_state_object_value; state = json_tokener_state_eatws; } else { - return error_ptr(-json_tokener_error_parse_object); + tok->err = json_tokener_error_parse_object_key_sep; + goto out; } break; case json_tokener_state_object_value: - obj = json_tokener_do_parse(this); - if(is_error(obj)) { - err = -(enum json_tokener_error)obj; + 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; - break; + goto redo_char; case json_tokener_state_object_sep: if(c == '}') { - this->pos++; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if(c == ',') { - this->pos++; - saved_state = json_tokener_state_object; + saved_state = json_tokener_state_object_field_start; state = json_tokener_state_eatws; } else { - err = json_tokener_error_parse_object; + tok->err = json_tokener_error_parse_object_value_sep; goto out; } break; } + str++; + tok->char_offset++; } while(c); if(state != json_tokener_state_finish && saved_state != json_tokener_state_finish) - err = json_tokener_error_parse_eof; + tok->err = json_tokener_error_parse_eof; out: - free(obj_field_name); - if(err == json_tokener_success) return current; - mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", - err, state, c); - json_object_put(current); - return error_ptr(-err); + if(tok->err == json_tokener_success) return json_object_get(current); + 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_tokener.h b/json_tokener.h index 12227a9..d2c2127 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -1,5 +1,5 @@ /* - * $Id: json_tokener.h,v 1.9 2006/01/30 23:07:57 mclark Exp $ + * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark @@ -16,15 +16,19 @@ 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, + 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, - json_tokener_error_parse_eof + json_tokener_error_parse_comment }; enum json_tokener_state { @@ -42,22 +46,44 @@ enum json_tokener_state { 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, 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 +struct json_tokener_srec { - char *source; - int pos; - struct printbuf *pb; + enum json_tokener_state state, saved_state; + struct json_object *obj; + struct json_object *current; + char *obj_field_name; }; -extern struct json_object* json_tokener_parse(char *s); +#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]; +}; + +extern const char* json_tokener_errors[]; + +extern struct json_tokener* json_tokener_new(); +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(char *str); +extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + char *str, int len); #endif diff --git a/test1.c b/test1.c index 8e49d10..a1c1c35 100644 --- a/test1.c +++ b/test1.c @@ -6,15 +6,23 @@ int main(int argc, char **argv) { + struct json_tokener *tok; struct json_object *my_string, *my_int, *my_object, *my_array; struct json_object *new_obj; int i; + mc_set_debug(1); + my_string = json_object_new_string("\t"); printf("my_string=%s\n", json_object_get_string(my_string)); printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); json_object_put(my_string); + my_string = json_object_new_string("\\"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + json_object_put(my_string); + my_string = json_object_new_string("foo"); printf("my_string=%s\n", json_object_get_string(my_string)); printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); @@ -98,6 +106,10 @@ int main(int argc, char **argv) printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + new_obj = json_tokener_parse("[false]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); @@ -128,6 +140,20 @@ int main(int argc, char **argv) new_obj = json_tokener_parse("foo"); if(is_error(new_obj)) printf("got error as expected\n"); + new_obj = json_tokener_parse("{ \"foo"); + if(is_error(new_obj)) printf("got error as expected\n"); + + /* test incremental parsing */ + tok = json_tokener_new(); + new_obj = json_tokener_parse_ex(tok, "{ \"foo", 6); + if(is_error(new_obj)) printf("got error as expected\n"); + new_obj = json_tokener_parse_ex(tok, "\": {\"bar", 8); + if(is_error(new_obj)) printf("got error as expected\n"); + new_obj = json_tokener_parse_ex(tok, "\":13}}", 6); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + json_tokener_free(tok); + json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); From ecf2c9b74b0b6801e988629715cdcf113d389fad Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Thu, 17 May 2007 13:30:29 +0000 Subject: [PATCH 009/276] Update version number to 0.7 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@17 327403b1-1117-474d-bef2-5cb71233fd97 --- README.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.html b/README.html index 7b3a65e..518a3c4 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.6.tar.gz

+

Latest release: json-c-0.7.tar.gz

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.

@@ -20,12 +20,8 @@

Win32 specific notes can be found here.

Please send bug reports to michael@metaparadigm.com

Please send Win32 bug reports to christopher.watford@gmail.com

-

Anonymous CVS

-

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
- # cvs login
- Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
- CVS password: <enter 'anoncvs'>
- # cvs co json-c

+

Anonymous Subversion

+

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael Clark

From dfaf67043658eef1d76df9d3f71b4952302ee936 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Thu, 25 Oct 2007 02:26:00 +0000 Subject: [PATCH 010/276] * Add macros to enable compiling out debug code Geoffrey Young, geoff at modperlcookbook dot org git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@18 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 4 ++++ config.h.in | 2 +- debug.h | 18 ++++++++++++++++++ json_object.c | 24 +++++++++++++----------- json_tokener.c | 6 +++--- json_util.c | 12 ++++++------ printbuf.c | 2 +- test1.c | 4 ++-- test2.c | 2 +- 9 files changed, 49 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1523c6c..7121199 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +0.8 + * Add macros to enable compiling out debug code + 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 diff --git a/config.h.in b/config.h.in index 83ab797..44e10aa 100644 --- a/config.h.in +++ b/config.h.in @@ -113,5 +113,5 @@ /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc -/* Define to `unsigned' if does not define. */ +/* Define to `unsigned int' if does not define. */ #undef size_t diff --git a/debug.h b/debug.h index 1db69ef..8c183e1 100644 --- a/debug.h +++ b/debug.h @@ -21,4 +21,22 @@ extern void mc_debug(const char *msg, ...); extern void mc_error(const char *msg, ...); extern void mc_info(const char *msg, ...); +#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_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) +#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) +#define MC_ERROR(x, ...) mc_error(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_ABORT(x, ...) if (0) mc_abort(x, ##__VA_ARGS__) +#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) +#define MC_ERROR(x, ...) if (0) mc_error(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) +#endif + #endif diff --git a/json_object.c b/json_object.c index d6c56dc..a629f61 100644 --- a/json_object.c +++ b/json_object.c @@ -27,7 +27,7 @@ char* strndup(const char* str, size_t n); #endif /* !HAVE_STRNDUP */ -/* #define REFCOUNT_DEBUG 1 */ +#define REFCOUNT_DEBUG 1 char *json_number_chars = "0123456789.+-e"; char *json_hex_chars = "0123456789abcdef"; @@ -56,22 +56,24 @@ static struct lh_table *json_object_table; static void json_object_init() __attribute__ ((constructor)); static void json_object_init() { - mc_debug("json_object_init: creating object table\n"); + 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() __attribute__ ((destructor)); static void json_object_fini() { struct lh_entry *ent; - if(mc_get_debug() && 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_name[obj->o_type], obj); + 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_name[obj->o_type], obj); + } } } - mc_debug("json_object_fini: freeing object table\n"); + MC_DEBUG("json_object_fini: freeing object table\n"); lh_table_free(json_object_table); } #endif /* REFCOUNT_DEBUG */ @@ -147,7 +149,7 @@ extern void json_object_put(struct json_object *this) static void json_object_generic_delete(struct json_object* this) { #ifdef REFCOUNT_DEBUG - mc_debug("json_object_delete_%s: %p\n", + MC_DEBUG("json_object_delete_%s: %p\n", json_type_name[this->o_type], this); lh_table_delete(json_object_table, this); #endif /* REFCOUNT_DEBUG */ @@ -164,7 +166,7 @@ static struct json_object* json_object_new(enum json_type o_type) this->_delete = &json_object_generic_delete; #ifdef REFCOUNT_DEBUG lh_table_insert(json_object_table, this, this); - mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this); + MC_DEBUG("json_object_new_%s: %p\n", json_type_name[this->o_type], this); #endif /* REFCOUNT_DEBUG */ return this; } diff --git a/json_tokener.c b/json_tokener.c index ada0f9b..ba329fe 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -265,7 +265,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_comment_eol: if(c == '\n') { - mc_debug("json_tokener_comment: %s\n", tok->pb->buf); + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; } else { printbuf_memappend(tok->pb, &c, 1); @@ -275,7 +275,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_comment_end: printbuf_memappend(tok->pb, &c, 1); if(c == '/') { - mc_debug("json_tokener_comment: %s\n", tok->pb->buf); + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; } else { state = json_tokener_state_comment; @@ -510,7 +510,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, out: if(tok->err == json_tokener_success) return json_object_get(current); - mc_debug("json_tokener_parse_ex: error %s at offset %d\n", + 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_util.c b/json_util.c index e20be24..903a694 100644 --- a/json_util.c +++ b/json_util.c @@ -59,12 +59,12 @@ struct json_object* json_object_from_file(char *filename) int fd, ret; if((fd = open(filename, O_RDONLY)) < 0) { - mc_error("json_object_from_file: error reading file %s: %s\n", + MC_ERROR("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); return error_ptr(-1); } if(!(pb = printbuf_new())) { - mc_error("json_object_from_file: printbuf_new failed\n"); + MC_ERROR("json_object_from_file: printbuf_new failed\n"); return error_ptr(-1); } while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { @@ -72,7 +72,7 @@ struct json_object* json_object_from_file(char *filename) } close(fd); if(ret < 0) { - mc_abort("json_object_from_file: error reading file %s: %s\n", + MC_ABORT("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); printbuf_free(pb); return error_ptr(-1); @@ -89,12 +89,12 @@ int json_object_to_file(char *filename, struct json_object *obj) unsigned int wpos, wsize; if(!obj) { - mc_error("json_object_to_file: object is null\n"); + 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", + MC_ERROR("json_object_to_file: error opening file %s: %s\n", filename, strerror(errno)); return -1; } @@ -107,7 +107,7 @@ int json_object_to_file(char *filename, struct json_object *obj) 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", + MC_ERROR("json_object_to_file: error writing file %s: %s\n", filename, strerror(errno)); return -1; } diff --git a/printbuf.c b/printbuf.c index 79bdaf5..0ee45e0 100644 --- a/printbuf.c +++ b/printbuf.c @@ -46,7 +46,7 @@ int printbuf_memappend(struct printbuf *p, char *buf, int size) if(p->size - p->bpos <= size) { int new_size = max(p->size * 2, p->bpos + size + 8); #ifdef PRINTBUF_DEBUG - mc_debug("printbuf_memappend: realloc " + MC_DEBUG("printbuf_memappend: realloc " "bpos=%d wrsize=%d old_size=%d new_size=%d\n", p->bpos, size, p->size, new_size); #endif /* PRINTBUF_DEBUG */ diff --git a/test1.c b/test1.c index a1c1c35..f894fac 100644 --- a/test1.c +++ b/test1.c @@ -11,7 +11,7 @@ int main(int argc, char **argv) struct json_object *new_obj; int i; - mc_set_debug(1); + MC_SET_DEBUG(1); my_string = json_object_new_string("\t"); printf("my_string=%s\n", json_object_get_string(my_string)); @@ -51,7 +51,7 @@ int main(int argc, char **argv) json_object_object_add(my_object, "baz", json_object_new_string("bang")); json_object_object_add(my_object, "baz", json_object_new_string("fark")); json_object_object_del(my_object, "baz"); - json_object_object_add(my_object, "arr", my_array); + /*json_object_object_add(my_object, "arr", my_array);*/ printf("my_object=\n"); json_object_object_foreach(my_object, key, val) { printf("\t%s: %s\n", key, json_object_to_json_string(val)); diff --git a/test2.c b/test2.c index b7bdf62..afbd386 100644 --- a/test2.c +++ b/test2.c @@ -9,7 +9,7 @@ int main(int argc, char **argv) { struct json_object *new_obj; - mc_set_debug(1); + MC_SET_DEBUG(1); new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); From c8f4a6e7de8a4307ca795f307774ef66e1248c11 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 7 Dec 2007 02:44:24 +0000 Subject: [PATCH 011/276] * Fix bug with use of capital E in numbers with exponents Mateusz Loskot, mateusz at loskot dot net * Add stddef.h include git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@19 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ json_object.c | 3 ++- json_tokener.c | 3 ++- json_tokener.h | 2 +- json_util.c | 1 + test1.c | 1 + test2.c | 1 + 7 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7121199..002c995 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,9 @@ 0.8 * 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 0.7 * Add escaping of backslash to json output diff --git a/json_object.c b/json_object.c index a629f61..c1ffb0a 100644 --- a/json_object.c +++ b/json_object.c @@ -13,6 +13,7 @@ #include #include +#include #include #include "debug.h" @@ -29,7 +30,7 @@ #define REFCOUNT_DEBUG 1 -char *json_number_chars = "0123456789.+-e"; +char *json_number_chars = "0123456789.+-eE"; char *json_hex_chars = "0123456789abcdef"; #ifdef REFCOUNT_DEBUG diff --git a/json_tokener.c b/json_tokener.c index ba329fe..c904f48 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -378,7 +379,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_number: if(c && strchr(json_number_chars, c)) { printbuf_memappend(tok->pb, &c, 1); - if(c == '.' || c == 'e') tok->is_double = 1; + if(c == '.' || c == 'e' || c == 'E') tok->is_double = 1; } else { int numi; double numd; diff --git a/json_tokener.h b/json_tokener.h index d2c2127..2c7ea69 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -71,7 +71,7 @@ struct json_tokener char *str; struct printbuf *pb; int depth, is_double, st_pos, char_offset; - enum json_tokener_error err; + ptrdiff_t err; unsigned int ucs_char; char quote_char; struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; diff --git a/json_util.c b/json_util.c index 903a694..1a65596 100644 --- a/json_util.c +++ b/json_util.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/test1.c b/test1.c index f894fac..a64a255 100644 --- a/test1.c +++ b/test1.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "json.h" diff --git a/test2.c b/test2.c index afbd386..39c4884 100644 --- a/test2.c +++ b/test2.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "json.h" From 14862b1ef32f285ef040f10c9319973b0285e8f7 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 7 Dec 2007 02:50:42 +0000 Subject: [PATCH 012/276] 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@20 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ debug.h | 2 +- json_object.c | 8 ++++---- json_object.h | 4 ++-- json_tokener.h | 2 +- linkhash.h | 3 +++ printbuf.h | 2 +- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 002c995..0c964d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ * 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 diff --git a/debug.h b/debug.h index 8c183e1..951e994 100644 --- a/debug.h +++ b/debug.h @@ -13,7 +13,7 @@ #define _DEBUG_H_ extern void mc_set_debug(int debug); -extern int mc_get_debug(); +extern int mc_get_debug(void); extern void mc_set_syslog(int syslog); extern void mc_abort(const char *msg, ...); diff --git a/json_object.c b/json_object.c index c1ffb0a..c702c26 100644 --- a/json_object.c +++ b/json_object.c @@ -55,14 +55,14 @@ static struct json_object* json_object_new(enum json_type o_type); static struct lh_table *json_object_table; -static void json_object_init() __attribute__ ((constructor)); -static void json_object_init() { +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() __attribute__ ((destructor)); -static void json_object_fini() { +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) { diff --git a/json_object.h b/json_object.h index 5c25968..d4fc887 100644 --- a/json_object.h +++ b/json_object.h @@ -98,7 +98,7 @@ extern char* json_object_to_json_string(struct json_object *obj); /** Create a new empty object * @returns a json_object of type json_type_object */ -extern struct json_object* json_object_new_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 @@ -167,7 +167,7 @@ extern void json_object_object_del(struct json_object* obj, char *key); /** 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(); +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 diff --git a/json_tokener.h b/json_tokener.h index 2c7ea69..350b1c1 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -79,7 +79,7 @@ struct json_tokener extern const char* json_tokener_errors[]; -extern struct json_tokener* json_tokener_new(); +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(char *str); diff --git a/linkhash.h b/linkhash.h index 5c9fa85..785ddf4 100644 --- a/linkhash.h +++ b/linkhash.h @@ -258,4 +258,7 @@ extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); extern int lh_table_delete(struct lh_table *t, void *k); +void lh_abort(const char *msg, ...); +void lh_table_resize(struct lh_table *t, int new_size); + #endif diff --git a/printbuf.h b/printbuf.h index bc1669b..4591a58 100644 --- a/printbuf.h +++ b/printbuf.h @@ -21,7 +21,7 @@ struct printbuf { }; extern struct printbuf* -printbuf_new(); +printbuf_new(void); extern int printbuf_memappend(struct printbuf *p, char *buf, int size); From a3272546b13225d4102130dc70799cfb40eee076 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 26 Jan 2008 01:10:47 +0000 Subject: [PATCH 013/276] fix to allow compile with -Werror -- Geoffrey Young, geoff at modperlcookbook dot org git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@21 327403b1-1117-474d-bef2-5cb71233fd97 --- json_tokener.h | 1 + 1 file changed, 1 insertion(+) diff --git a/json_tokener.h b/json_tokener.h index 350b1c1..117d6ef 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -12,6 +12,7 @@ #ifndef _json_tokener_h_ #define _json_tokener_h_ +#include #include "json_object.h" enum json_tokener_error { From a0d35c7ebff00e97038db537349d83e30a11df82 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 8 Aug 2008 06:54:28 +0000 Subject: [PATCH 014/276] change version to 0.8 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@22 327403b1-1117-474d-bef2-5cb71233fd97 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index f0a7d3a..cc25b59 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([JSON C Library], 0.3, [michael@metaparadigm.com], [json-c]) +AC_INIT([JSON C Library], 0.8, [michael@metaparadigm.com], [json-c]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 8cdac64ccd52a0c4f0dbd2775bad951463577daf Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 5 Jan 2009 03:57:59 +0000 Subject: [PATCH 015/276] Add va_end for every va_start. Dotan Barak, dotanba at gmail dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@23 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ debug.c | 4 ++++ linkhash.c | 1 + printbuf.c | 3 ++- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0c964d6..784663a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 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 diff --git a/debug.c b/debug.c index eaa6fca..f699976 100644 --- a/debug.c +++ b/debug.c @@ -51,6 +51,7 @@ void mc_abort(const char *msg, ...) } else #endif vprintf(msg, ap); + va_end(ap); exit(1); } @@ -66,6 +67,7 @@ void mc_debug(const char *msg, ...) } else #endif vprintf(msg, ap); + va_end(ap); } } @@ -79,6 +81,7 @@ void mc_error(const char *msg, ...) } else #endif vfprintf(stderr, msg, ap); + va_end(ap); } void mc_info(const char *msg, ...) @@ -91,4 +94,5 @@ void mc_info(const char *msg, ...) } else #endif vfprintf(stderr, msg, ap); + va_end(ap); } diff --git a/linkhash.c b/linkhash.c index 6cfc9a0..fc72bf6 100644 --- a/linkhash.c +++ b/linkhash.c @@ -25,6 +25,7 @@ void lh_abort(const char *msg, ...) va_list ap; va_start(ap, msg); vprintf(msg, ap); + va_end(ap); exit(1); } diff --git a/printbuf.c b/printbuf.c index 0ee45e0..cdda47e 100644 --- a/printbuf.c +++ b/printbuf.c @@ -119,8 +119,9 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) if(size == -1 || size > 127) { int ret; va_start(ap, msg); - if((size = vasprintf(&t, msg, ap)) == -1) return -1; + size = vasprintf(&t, msg, ap); va_end(ap); + if(size == -1) return -1; ret = printbuf_memappend(p, t, size); free(t); return ret; From 80a6007009e5d73aab66cdd3b50a13dc3db97559 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 5 Jan 2009 06:55:02 +0000 Subject: [PATCH 016/276] changes to make 'make dist' work properly git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@24 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 7 ++++++- configure.in | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 98f1553..0961218 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,8 +12,10 @@ libjsoninclude_HEADERS = \ debug.h \ linkhash.h \ arraylist.h \ + printbuf.h \ json_util.h \ json_object.h \ + json_object_private.h \ json_tokener.h libjson_la_LDFLAGS = -version-info 0:1:0 @@ -27,10 +29,13 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 +check_PROGRAMS = test1 test2 test3 test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) test2_SOURCES = test2.c test2_LDADD = $(lib_LTLIBRARIES) + +test3_SOURCES = test3.c +test3_LDADD = $(lib_LTLIBRARIES) diff --git a/configure.in b/configure.in index cc25b59..7bcf3dc 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([JSON C Library], 0.8, [michael@metaparadigm.com], [json-c]) +AC_INIT([json-c], 0.8, [michael@metaparadigm.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 4b831c3b2f2784ef151e166a1ed0153d15af5429 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 5 Jan 2009 07:01:14 +0000 Subject: [PATCH 017/276] Update version to 0.8 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@25 327403b1-1117-474d-bef2-5cb71233fd97 --- README.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.html b/README.html index 518a3c4..e69beb9 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.7.tar.gz

+

Latest release: json-c-0.8.tar.gz

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.

From 436aa98d67e7ee2c018e9b9c6f55c2d00a94eaea Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 6 Jan 2009 22:53:25 +0000 Subject: [PATCH 018/276] update auto generated files git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@26 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 2 ++ config.h.in | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am index 0961218..43120b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,7 @@ AM_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +EXTRA_DIST = doc + lib_LTLIBRARIES = libjson.la pkgconfigdir = $(libdir)/pkgconfig diff --git a/config.h.in b/config.h.in index 44e10aa..5139ae8 100644 --- a/config.h.in +++ b/config.h.in @@ -80,6 +80,10 @@ /* Define to 1 if you have the `vsyslog' function. */ #undef HAVE_VSYSLOG +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + /* Name of package */ #undef PACKAGE From 68cafad0786f9a17d1f026f65d6707e0f0df6816 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 6 Jan 2009 22:56:57 +0000 Subject: [PATCH 019/276] Add const correctness to public interfaces Gerard Krol, g dot c dot krol at student dot tudelft dot nl Update version number to 0.9 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@27 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 4 ++++ configure.in | 2 +- json_object.c | 20 ++++++++++---------- json_object.h | 18 +++++++++--------- json_util.c | 2 +- linkhash.c | 24 ++++++++++++------------ linkhash.h | 30 +++++++++++++++--------------- printbuf.c | 2 +- printbuf.h | 2 +- 9 files changed, 54 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index 784663a..c91e2c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +0.9 + * 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 diff --git a/configure.in b/configure.in index 7bcf3dc..8f0fff3 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.8, [michael@metaparadigm.com]) +AC_INIT([json-c], 0.9, [michael@metaparadigm.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) diff --git a/json_object.c b/json_object.c index c702c26..f0ce5f7 100644 --- a/json_object.c +++ b/json_object.c @@ -30,11 +30,11 @@ #define REFCOUNT_DEBUG 1 -char *json_number_chars = "0123456789.+-eE"; -char *json_hex_chars = "0123456789abcdef"; +const char *json_number_chars = "0123456789.+-eE"; +const char *json_hex_chars = "0123456789abcdef"; #ifdef REFCOUNT_DEBUG -static char* json_type_name[] = { +static const char* json_type_name[] = { "null", "boolean", "double", @@ -188,7 +188,7 @@ enum json_type json_object_get_type(struct json_object *this) /* json_object_to_json_string */ -char* json_object_to_json_string(struct json_object *this) +const char* json_object_to_json_string(struct json_object *this) { if(!this) return "null"; if(!this->_pb) { @@ -259,19 +259,19 @@ struct lh_table* json_object_get_object(struct json_object *this) } } -void json_object_object_add(struct json_object* this, char *key, +void json_object_object_add(struct json_object* this, const char *key, struct json_object *val) { lh_table_delete(this->o.c_object, key); lh_table_insert(this->o.c_object, strdup(key), val); } -struct json_object* json_object_object_get(struct json_object* this, char *key) +struct json_object* json_object_object_get(struct json_object* this, const char *key) { return (struct json_object*) lh_table_lookup(this->o.c_object, key); } -void json_object_object_del(struct json_object* this, char *key) +void json_object_object_del(struct json_object* this, const char *key) { lh_table_delete(this->o.c_object, key); } @@ -404,7 +404,7 @@ static void json_object_string_delete(struct json_object* this) json_object_generic_delete(this); } -struct json_object* json_object_new_string(char *s) +struct json_object* json_object_new_string(const char *s) { struct json_object *this = json_object_new(json_type_string); if(!this) return NULL; @@ -414,7 +414,7 @@ struct json_object* json_object_new_string(char *s) return this; } -struct json_object* json_object_new_string_len(char *s, int len) +struct json_object* json_object_new_string_len(const char *s, int len) { struct json_object *this = json_object_new(json_type_string); if(!this) return NULL; @@ -424,7 +424,7 @@ struct json_object* json_object_new_string_len(char *s, int len) return this; } -char* json_object_get_string(struct json_object *this) +const char* json_object_get_string(struct json_object *this) { if(!this) return NULL; switch(this->o_type) { diff --git a/json_object.h b/json_object.h index d4fc887..bbfea85 100644 --- a/json_object.h +++ b/json_object.h @@ -20,8 +20,8 @@ #undef TRUE #define TRUE ((boolean)1) -extern char *json_number_chars; -extern char *json_hex_chars; +extern const char *json_number_chars; +extern const char *json_hex_chars; /* forward structure definitions */ @@ -90,7 +90,7 @@ extern enum json_type json_object_get_type(struct json_object *obj); * @param obj the json_object instance * @returns a string in JSON format */ -extern char* json_object_to_json_string(struct json_object *obj); +extern const char* json_object_to_json_string(struct json_object *obj); /* object type methods */ @@ -116,7 +116,7 @@ extern struct lh_table* json_object_get_object(struct json_object *obj); * @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, char *key, +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 @@ -125,7 +125,7 @@ extern void json_object_object_add(struct json_object* obj, char *key, * @returns the json_object associated with the given field name */ extern struct json_object* json_object_object_get(struct json_object* obj, - char *key); + const char *key); /** Delete the given json_object field * @@ -134,7 +134,7 @@ extern struct json_object* json_object_object_get(struct json_object* obj, * @param obj the json_object instance * @param key the object field name */ -extern void json_object_object_del(struct json_object* obj, char *key); +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 @@ -290,9 +290,9 @@ extern double json_object_get_double(struct json_object *obj); * @param s the string * @returns a json_object of type json_type_string */ -extern struct json_object* json_object_new_string(char *s); +extern struct json_object* json_object_new_string(const char *s); -extern struct json_object* json_object_new_string_len(char *s, int len); +extern struct json_object* json_object_new_string_len(const char *s, int len); /** Get the string value of a json_object * @@ -305,6 +305,6 @@ extern struct json_object* json_object_new_string_len(char *s, int len); * @param obj the json_object instance * @returns a string */ -extern char* json_object_get_string(struct json_object *obj); +extern const char* json_object_get_string(struct json_object *obj); #endif diff --git a/json_util.c b/json_util.c index 1a65596..0262ca2 100644 --- a/json_util.c +++ b/json_util.c @@ -85,7 +85,7 @@ struct json_object* json_object_from_file(char *filename) int json_object_to_file(char *filename, struct json_object *obj) { - char *json_str; + const char *json_str; int fd, ret; unsigned int wpos, wsize; diff --git a/linkhash.c b/linkhash.c index fc72bf6..5d4e46f 100644 --- a/linkhash.c +++ b/linkhash.c @@ -29,18 +29,18 @@ void lh_abort(const char *msg, ...) exit(1); } -unsigned long lh_ptr_hash(void *k) +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(void *k1, void *k2) +int lh_ptr_equal(const void *k1, const void *k2) { return (k1 == k2); } -unsigned long lh_char_hash(void *k) +unsigned long lh_char_hash(const void *k) { unsigned int h = 0; const char* data = k; @@ -50,12 +50,12 @@ unsigned long lh_char_hash(void *k) return h; } -int lh_char_equal(void *k1, void *k2) +int lh_char_equal(const void *k1, const void *k2) { - return (strcmp((char*)k1, (char*)k2) == 0); + return (strcmp((const char*)k1, (const char*)k2) == 0); } -struct lh_table* lh_table_new(int size, char *name, +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) @@ -77,13 +77,13 @@ struct lh_table* lh_table_new(int size, char *name, return t; } -struct lh_table* lh_kchar_table_new(int size, char *name, +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, char *name, +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); @@ -122,7 +122,7 @@ void lh_table_free(struct lh_table *t) } -int lh_table_insert(struct lh_table *t, void *k, void *v) +int lh_table_insert(struct lh_table *t, void *k, const void *v) { unsigned long h, n; @@ -156,7 +156,7 @@ int lh_table_insert(struct lh_table *t, void *k, void *v) } -struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k) +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; @@ -172,7 +172,7 @@ struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k) } -void* lh_table_lookup(struct lh_table *t, void *k) +const void* lh_table_lookup(struct lh_table *t, const void *k) { struct lh_entry *e = lh_table_lookup_entry(t, k); if(e) return e->v; @@ -209,7 +209,7 @@ int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) } -int lh_table_delete(struct lh_table *t, void *k) +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; diff --git a/linkhash.h b/linkhash.h index 785ddf4..9b5ef9d 100644 --- a/linkhash.h +++ b/linkhash.h @@ -36,11 +36,11 @@ typedef void (lh_entry_free_fn) (struct lh_entry *e); /** * callback function prototypes */ -typedef unsigned long (lh_hash_fn) (void *k); +typedef unsigned long (lh_hash_fn) (const void *k); /** * callback function prototypes */ -typedef int (lh_equal_fn) (void *k1, void *k2); +typedef int (lh_equal_fn) (const void *k1, const void *k2); /** * An entry in the hash table @@ -53,7 +53,7 @@ struct lh_entry { /** * The value. */ - void *v; + const void *v; /** * The next entry */ @@ -106,7 +106,7 @@ struct lh_table { /** * Name of the hash table. */ - char *name; + const char *name; /** * The first entry. @@ -132,11 +132,11 @@ struct lh_table { /** * Pre-defined hash and equality functions */ -extern unsigned long lh_ptr_hash(void *k); -extern int lh_ptr_equal(void *k1, void *k2); +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(void *k); -extern int lh_char_equal(void *k1, void *k2); +extern unsigned long lh_char_hash(const void *k); +extern int lh_char_equal(const void *k1, const void *k2); /** @@ -170,7 +170,7 @@ for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) * and C strings respectively. * @return a pointer onto the linkhash table. */ -extern struct lh_table* lh_table_new(int size, char *name, +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); @@ -183,7 +183,7 @@ extern struct lh_table* lh_table_new(int size, char *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, char *name, +extern struct lh_table* lh_kchar_table_new(int size, const char *name, lh_entry_free_fn *free_fn); @@ -195,7 +195,7 @@ extern struct lh_table* lh_kchar_table_new(int size, char *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, char *name, +extern struct lh_table* lh_kptr_table_new(int size, const char *name, lh_entry_free_fn *free_fn); @@ -214,7 +214,7 @@ extern void lh_table_free(struct lh_table *t); * @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, void *v); +extern int lh_table_insert(struct lh_table *t, void *k, const void *v); /** @@ -223,7 +223,7 @@ extern int lh_table_insert(struct lh_table *t, void *k, void *v); * @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, void *k); +extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); /** * Lookup a record into the table @@ -231,7 +231,7 @@ extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k); * @param k a pointer to the key to lookup * @return a pointer to the found value or NULL if it does not exist. */ -extern void* lh_table_lookup(struct lh_table *t, void *k); +extern const void* lh_table_lookup(struct lh_table *t, const void *k); /** @@ -255,7 +255,7 @@ extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); * @return 0 if the item was deleted. * @return -1 if it was not found. */ -extern int lh_table_delete(struct lh_table *t, void *k); +extern int lh_table_delete(struct lh_table *t, const void *k); void lh_abort(const char *msg, ...); diff --git a/printbuf.c b/printbuf.c index cdda47e..6522a69 100644 --- a/printbuf.c +++ b/printbuf.c @@ -40,7 +40,7 @@ struct printbuf* printbuf_new() } -int printbuf_memappend(struct printbuf *p, char *buf, int size) +int printbuf_memappend(struct printbuf *p, const char *buf, int size) { char *t; if(p->size - p->bpos <= size) { diff --git a/printbuf.h b/printbuf.h index 4591a58..95f7a24 100644 --- a/printbuf.h +++ b/printbuf.h @@ -24,7 +24,7 @@ extern struct printbuf* printbuf_new(void); extern int -printbuf_memappend(struct printbuf *p, char *buf, int size); +printbuf_memappend(struct printbuf *p, const char *buf, int size); extern int sprintbuf(struct printbuf *p, const char *msg, ...); From e6548a3dc2097b6d3affa07a3a57f80e2a4a99f7 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 10 Jan 2009 13:58:06 +0000 Subject: [PATCH 020/276] fix typo in json_object.h git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@28 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 2 +- json_object.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index f0ce5f7..3ff4d64 100644 --- a/json_object.c +++ b/json_object.c @@ -243,7 +243,7 @@ struct json_object* json_object_new_object() if(!this) return NULL; this->_delete = &json_object_object_delete; this->_to_json_string = &json_object_object_to_json_string; - this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES, + this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, NULL, &json_object_lh_entry_free); return this; } diff --git a/json_object.h b/json_object.h index bbfea85..4c8f6db 100644 --- a/json_object.h +++ b/json_object.h @@ -12,7 +12,7 @@ #ifndef _json_object_h_ #define _json_object_h_ -#define JSON_OBJECT_DEF_HASH_ENTIRES 16 +#define JSON_OBJECT_DEF_HASH_ENTRIES 16 #undef FALSE #define FALSE ((boolean)0) From 75d0f12135e93af51253c248ca17da9c8f6bcda5 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 10 Jan 2009 14:14:12 +0000 Subject: [PATCH 021/276] fix typo git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@29 327403b1-1117-474d-bef2-5cb71233fd97 --- json_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_util.h b/json_util.h index 30fe2ab..b3f53b6 100644 --- a/json_util.h +++ b/json_util.h @@ -16,7 +16,7 @@ #define JSON_FILE_BUF_SIZE 4096 -/* utlitiy functions */ +/* utility functions */ extern struct json_object* json_object_from_file(char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); From e8de07880652465a3894124258796846832f0fff Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 25 Feb 2009 01:45:00 +0000 Subject: [PATCH 022/276] * Fixed warning reported by adding -Wstrict-prototypes -Wold-style-definition to the compilatin flags. Dotan Barak, dotanba at gmail dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@30 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ debug.c | 2 +- json_object.c | 4 ++-- json_tokener.c | 2 +- printbuf.c | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index c91e2c7..e8f0d35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ 0.9 + * 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 diff --git a/debug.c b/debug.c index f699976..e0294ca 100644 --- a/debug.c +++ b/debug.c @@ -34,7 +34,7 @@ static int _syslog = 0; static int _debug = 0; void mc_set_debug(int debug) { _debug = debug; } -int mc_get_debug() { return _debug; } +int mc_get_debug(void) { return _debug; } extern void mc_set_syslog(int syslog) { diff --git a/json_object.c b/json_object.c index 3ff4d64..a746859 100644 --- a/json_object.c +++ b/json_object.c @@ -237,7 +237,7 @@ static void json_object_object_delete(struct json_object* this) json_object_generic_delete(this); } -struct json_object* json_object_new_object() +struct json_object* json_object_new_object(void) { struct json_object *this = json_object_new(json_type_object); if(!this) return NULL; @@ -466,7 +466,7 @@ static void json_object_array_delete(struct json_object* this) json_object_generic_delete(this); } -struct json_object* json_object_new_array() +struct json_object* json_object_new_array(void) { struct json_object *this = json_object_new(json_type_array); if(!this) return NULL; diff --git a/json_tokener.c b/json_tokener.c index c904f48..3f196db 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -55,7 +55,7 @@ const char* json_tokener_errors[] = { }; -struct json_tokener* json_tokener_new() +struct json_tokener* json_tokener_new(void) { struct json_tokener *tok = calloc(1, sizeof(struct json_tokener)); tok->pb = printbuf_new(); diff --git a/printbuf.c b/printbuf.c index 6522a69..bbb8657 100644 --- a/printbuf.c +++ b/printbuf.c @@ -25,7 +25,7 @@ #include "debug.h" #include "printbuf.h" -struct printbuf* printbuf_new() +struct printbuf* printbuf_new(void) { struct printbuf *p; From 22dee7cb59da4a96fe2ee0e33b4f394645698359 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 25 Feb 2009 01:51:40 +0000 Subject: [PATCH 023/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@31 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ arraylist.c | 2 +- json_object.c | 3 +-- json_tokener.c | 3 +++ linkhash.c | 2 -- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index e8f0d35..2009a1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ 0.9 + * 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 diff --git a/arraylist.c b/arraylist.c index dbd075d..bc167a8 100644 --- a/arraylist.c +++ b/arraylist.c @@ -16,7 +16,7 @@ # include #endif /* STDC_HEADERS */ -#if HAVE_STRINGS_H +#if defined HAVE_STRINGS_H && !defined _STRING_H && !defined __USE_BSD # include #endif /* HAVE_STRINGS_H */ diff --git a/json_object.c b/json_object.c index a746859..44b6cd6 100644 --- a/json_object.c +++ b/json_object.c @@ -22,7 +22,6 @@ #include "arraylist.h" #include "json_object.h" #include "json_object_private.h" -#include "json_tokener.h" #if !HAVE_STRNDUP char* strndup(const char* str, size_t n); @@ -306,7 +305,7 @@ boolean json_object_get_boolean(struct json_object *this) case json_type_double: return (this->o.c_double != 0); case json_type_string: - if(strlen(this->o.c_string)) return TRUE; + return (strlen(this->o.c_string) != 0); default: return TRUE; } diff --git a/json_tokener.c b/json_tokener.c index 3f196db..9c05728 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -83,6 +83,9 @@ static void json_tokener_reset_level(struct json_tokener *tok, int depth) 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; diff --git a/linkhash.c b/linkhash.c index 5d4e46f..7385401 100644 --- a/linkhash.c +++ b/linkhash.c @@ -9,8 +9,6 @@ * */ -#include "config.h" - #include #include #include From 266a3fd30141b31632eead6739ace524bc172de5 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 25 Feb 2009 01:55:31 +0000 Subject: [PATCH 024/276] * Don't use this as a variable, so we can compile with a C++ compiler Michael Clark, git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@32 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 + arraylist.c | 64 +++++------ json_object.c | 286 +++++++++++++++++++++++++------------------------- 3 files changed, 177 insertions(+), 175 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2009a1e..d0018ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * Don't use this as a variable, so we can compile with a C++ compiler + Michael Clark, * 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 diff --git a/arraylist.c b/arraylist.c index bc167a8..7726de6 100644 --- a/arraylist.c +++ b/arraylist.c @@ -26,68 +26,68 @@ struct array_list* array_list_new(array_list_free_fn *free_fn) { - struct array_list *this; + struct array_list *arr; - if(!(this = calloc(1, sizeof(struct array_list)))) return NULL; - this->size = ARRAY_LIST_DEFAULT_SIZE; - this->length = 0; - this->free_fn = free_fn; - if(!(this->array = calloc(sizeof(void*), this->size))) { - free(this); + if(!(arr = calloc(1, sizeof(struct array_list)))) return NULL; + arr->size = ARRAY_LIST_DEFAULT_SIZE; + arr->length = 0; + arr->free_fn = free_fn; + if(!(arr->array = calloc(sizeof(void*), arr->size))) { + free(arr); return NULL; } - return this; + return arr; } extern void -array_list_free(struct array_list *this) +array_list_free(struct array_list *arr) { int i; - for(i = 0; i < this->length; i++) - if(this->array[i]) this->free_fn(this->array[i]); - free(this->array); - free(this); + 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 *this, int i) +array_list_get_idx(struct array_list *arr, int i) { - if(i >= this->length) return NULL; - return this->array[i]; + if(i >= arr->length) return NULL; + return arr->array[i]; } -static int array_list_expand_internal(struct array_list *this, int max) +static int array_list_expand_internal(struct array_list *arr, int max) { void *t; int new_size; - if(max < this->size) return 0; - new_size = max(this->size << 1, max); - if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1; - this->array = t; - (void)memset(this->array + this->size, 0, (new_size-this->size)*sizeof(void*)); - this->size = new_size; + if(max < arr->size) return 0; + new_size = max(arr->size << 1, max); + if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; + arr->array = 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 *this, int idx, void *data) +array_list_put_idx(struct array_list *arr, int idx, void *data) { - if(array_list_expand_internal(this, idx)) return -1; - if(this->array[idx]) this->free_fn(this->array[idx]); - this->array[idx] = data; - if(this->length <= idx) this->length = idx + 1; + 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 *this, void *data) +array_list_add(struct array_list *arr, void *data) { - return array_list_put_idx(this, this->length, data); + return array_list_put_idx(arr, arr->length, data); } int -array_list_length(struct array_list *this) +array_list_length(struct array_list *arr) { - return this->length; + return arr->length; } diff --git a/json_object.c b/json_object.c index 44b6cd6..28ca102 100644 --- a/json_object.c +++ b/json_object.c @@ -44,7 +44,7 @@ static const char* json_type_name[] = { }; #endif /* REFCOUNT_DEBUG */ -static void json_object_generic_delete(struct json_object* this); +static void json_object_generic_delete(struct json_object* jso); static struct json_object* json_object_new(enum json_type o_type); @@ -127,82 +127,82 @@ static int json_escape_str(struct printbuf *pb, char *str) /* reference counting */ -extern struct json_object* json_object_get(struct json_object *this) +extern struct json_object* json_object_get(struct json_object *jso) { - if(this) { - this->_ref_count++; + if(jso) { + jso->_ref_count++; } - return this; + return jso; } -extern void json_object_put(struct json_object *this) +extern void json_object_put(struct json_object *jso) { - if(this) { - this->_ref_count--; - if(!this->_ref_count) this->_delete(this); + 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* this) +static void json_object_generic_delete(struct json_object* jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", - json_type_name[this->o_type], this); - lh_table_delete(json_object_table, this); + json_type_name[jso->o_type], jso); + lh_table_delete(json_object_table, jso); #endif /* REFCOUNT_DEBUG */ - printbuf_free(this->_pb); - free(this); + printbuf_free(jso->_pb); + free(jso); } static struct json_object* json_object_new(enum json_type o_type) { - struct json_object *this = calloc(sizeof(struct json_object), 1); - if(!this) return NULL; - this->o_type = o_type; - this->_ref_count = 1; - this->_delete = &json_object_generic_delete; + struct json_object *jso = 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, this, this); - MC_DEBUG("json_object_new_%s: %p\n", json_type_name[this->o_type], this); + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_name[jso->o_type], jso); #endif /* REFCOUNT_DEBUG */ - return this; + return jso; } /* type checking functions */ -int json_object_is_type(struct json_object *this, enum json_type type) +int json_object_is_type(struct json_object *jso, enum json_type type) { - return (this->o_type == type); + return (jso->o_type == type); } -enum json_type json_object_get_type(struct json_object *this) +enum json_type json_object_get_type(struct json_object *jso) { - return this->o_type; + return jso->o_type; } /* json_object_to_json_string */ -const char* json_object_to_json_string(struct json_object *this) +const char* json_object_to_json_string(struct json_object *jso) { - if(!this) return "null"; - if(!this->_pb) { - if(!(this->_pb = printbuf_new())) return NULL; + if(!jso) return "null"; + if(!jso->_pb) { + if(!(jso->_pb = printbuf_new())) return NULL; } else { - printbuf_reset(this->_pb); + printbuf_reset(jso->_pb); } - if(this->_to_json_string(this, this->_pb) < 0) return NULL; - return this->_pb->buf; + 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* this, +static int json_object_object_to_json_string(struct json_object* jso, struct printbuf *pb) { int i=0; @@ -211,7 +211,7 @@ static int json_object_object_to_json_string(struct json_object* this, /* CAW: scope operator to make ANSI correctness */ /* CAW: switched to json_object_object_foreachC which uses an iterator struct */ - json_object_object_foreachC(this, iter) { + json_object_object_foreachC(jso, iter) { if(i) sprintbuf(pb, ","); sprintbuf(pb, " \""); json_escape_str(pb, iter.key); @@ -230,82 +230,82 @@ static void json_object_lh_entry_free(struct lh_entry *ent) json_object_put((struct json_object*)ent->v); } -static void json_object_object_delete(struct json_object* this) +static void json_object_object_delete(struct json_object* jso) { - lh_table_free(this->o.c_object); - json_object_generic_delete(this); + lh_table_free(jso->o.c_object); + json_object_generic_delete(jso); } struct json_object* json_object_new_object(void) { - struct json_object *this = json_object_new(json_type_object); - if(!this) return NULL; - this->_delete = &json_object_object_delete; - this->_to_json_string = &json_object_object_to_json_string; - this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, + 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 this; + return jso; } -struct lh_table* json_object_get_object(struct json_object *this) +struct lh_table* json_object_get_object(struct json_object *jso) { - if(!this) return NULL; - switch(this->o_type) { + if(!jso) return NULL; + switch(jso->o_type) { case json_type_object: - return this->o.c_object; + return jso->o.c_object; default: return NULL; } } -void json_object_object_add(struct json_object* this, const char *key, +void json_object_object_add(struct json_object* jso, const char *key, struct json_object *val) { - lh_table_delete(this->o.c_object, key); - lh_table_insert(this->o.c_object, strdup(key), 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* this, const char *key) +struct json_object* json_object_object_get(struct json_object* jso, const char *key) { - return (struct json_object*) lh_table_lookup(this->o.c_object, key); + return (struct json_object*) lh_table_lookup(jso->o.c_object, key); } -void json_object_object_del(struct json_object* this, const char *key) +void json_object_object_del(struct json_object* jso, const char *key) { - lh_table_delete(this->o.c_object, key); + lh_table_delete(jso->o.c_object, key); } /* json_object_boolean */ -static int json_object_boolean_to_json_string(struct json_object* this, +static int json_object_boolean_to_json_string(struct json_object* jso, struct printbuf *pb) { - if(this->o.c_boolean) return sprintbuf(pb, "true"); + if(jso->o.c_boolean) return sprintbuf(pb, "true"); else return sprintbuf(pb, "false"); } struct json_object* json_object_new_boolean(boolean b) { - struct json_object *this = json_object_new(json_type_boolean); - if(!this) return NULL; - this->_to_json_string = &json_object_boolean_to_json_string; - this->o.c_boolean = b; - return this; + 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; } -boolean json_object_get_boolean(struct json_object *this) +boolean json_object_get_boolean(struct json_object *jso) { - if(!this) return FALSE; - switch(this->o_type) { + if(!jso) return FALSE; + switch(jso->o_type) { case json_type_boolean: - return this->o.c_boolean; + return jso->o.c_boolean; case json_type_int: - return (this->o.c_int != 0); + return (jso->o.c_int != 0); case json_type_double: - return (this->o.c_double != 0); + return (jso->o.c_double != 0); case json_type_string: - return (strlen(this->o.c_string) != 0); + return (strlen(jso->o.c_string) != 0); default: return TRUE; } @@ -314,35 +314,35 @@ boolean json_object_get_boolean(struct json_object *this) /* json_object_int */ -static int json_object_int_to_json_string(struct json_object* this, +static int json_object_int_to_json_string(struct json_object* jso, struct printbuf *pb) { - return sprintbuf(pb, "%d", this->o.c_int); + return sprintbuf(pb, "%d", jso->o.c_int); } struct json_object* json_object_new_int(int i) { - struct json_object *this = json_object_new(json_type_int); - if(!this) return NULL; - this->_to_json_string = &json_object_int_to_json_string; - this->o.c_int = i; - return this; + 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_int = i; + return jso; } -int json_object_get_int(struct json_object *this) +int json_object_get_int(struct json_object *jso) { int cint; - if(!this) return 0; - switch(this->o_type) { + if(!jso) return 0; + switch(jso->o_type) { case json_type_int: - return this->o.c_int; + return jso->o.c_int; case json_type_double: - return (int)this->o.c_double; + return (int)jso->o.c_double; case json_type_boolean: - return this->o.c_boolean; + return jso->o.c_boolean; case json_type_string: - if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint; + if(sscanf(jso->o.c_string, "%d", &cint) == 1) return cint; default: return 0; } @@ -351,35 +351,35 @@ int json_object_get_int(struct json_object *this) /* json_object_double */ -static int json_object_double_to_json_string(struct json_object* this, +static int json_object_double_to_json_string(struct json_object* jso, struct printbuf *pb) { - return sprintbuf(pb, "%lf", this->o.c_double); + return sprintbuf(pb, "%lf", jso->o.c_double); } struct json_object* json_object_new_double(double d) { - struct json_object *this = json_object_new(json_type_double); - if(!this) return NULL; - this->_to_json_string = &json_object_double_to_json_string; - this->o.c_double = d; - return this; + 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 *this) +double json_object_get_double(struct json_object *jso) { double cdouble; - if(!this) return 0.0; - switch(this->o_type) { + if(!jso) return 0.0; + switch(jso->o_type) { case json_type_double: - return this->o.c_double; + return jso->o.c_double; case json_type_int: - return this->o.c_int; + return jso->o.c_int; case json_type_boolean: - return this->o.c_boolean; + return jso->o.c_boolean; case json_type_string: - if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble; + if(sscanf(jso->o.c_string, "%lf", &cdouble) == 1) return cdouble; default: return 0.0; } @@ -388,66 +388,66 @@ double json_object_get_double(struct json_object *this) /* json_object_string */ -static int json_object_string_to_json_string(struct json_object* this, +static int json_object_string_to_json_string(struct json_object* jso, struct printbuf *pb) { sprintbuf(pb, "\""); - json_escape_str(pb, this->o.c_string); + json_escape_str(pb, jso->o.c_string); sprintbuf(pb, "\""); return 0; } -static void json_object_string_delete(struct json_object* this) +static void json_object_string_delete(struct json_object* jso) { - free(this->o.c_string); - json_object_generic_delete(this); + free(jso->o.c_string); + json_object_generic_delete(jso); } struct json_object* json_object_new_string(const char *s) { - struct json_object *this = json_object_new(json_type_string); - if(!this) return NULL; - this->_delete = &json_object_string_delete; - this->_to_json_string = &json_object_string_to_json_string; - this->o.c_string = strdup(s); - return this; + 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 = strdup(s); + return jso; } struct json_object* json_object_new_string_len(const char *s, int len) { - struct json_object *this = json_object_new(json_type_string); - if(!this) return NULL; - this->_delete = &json_object_string_delete; - this->_to_json_string = &json_object_string_to_json_string; - this->o.c_string = strndup(s, len); - return this; + 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 = strndup(s, len); + return jso; } -const char* json_object_get_string(struct json_object *this) +const char* json_object_get_string(struct json_object *jso) { - if(!this) return NULL; - switch(this->o_type) { + if(!jso) return NULL; + switch(jso->o_type) { case json_type_string: - return this->o.c_string; + return jso->o.c_string; default: - return json_object_to_json_string(this); + return json_object_to_json_string(jso); } } /* json_object_array */ -static int json_object_array_to_json_string(struct json_object* this, +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(this); i++) { + 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(this, i); + val = json_object_array_get_idx(jso, i); if(val == NULL) { sprintbuf(pb, "null"); } else { val->_to_json_string(val, pb); } } @@ -459,52 +459,52 @@ 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* this) +static void json_object_array_delete(struct json_object* jso) { - array_list_free(this->o.c_array); - json_object_generic_delete(this); + array_list_free(jso->o.c_array); + json_object_generic_delete(jso); } struct json_object* json_object_new_array(void) { - struct json_object *this = json_object_new(json_type_array); - if(!this) return NULL; - this->_delete = &json_object_array_delete; - this->_to_json_string = &json_object_array_to_json_string; - this->o.c_array = array_list_new(&json_object_array_entry_free); - return this; + 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 *this) +struct array_list* json_object_get_array(struct json_object *jso) { - if(!this) return NULL; - switch(this->o_type) { + if(!jso) return NULL; + switch(jso->o_type) { case json_type_array: - return this->o.c_array; + return jso->o.c_array; default: return NULL; } } -int json_object_array_length(struct json_object *this) +int json_object_array_length(struct json_object *jso) { - return array_list_length(this->o.c_array); + return array_list_length(jso->o.c_array); } -int json_object_array_add(struct json_object *this,struct json_object *val) +int json_object_array_add(struct json_object *jso,struct json_object *val) { - return array_list_add(this->o.c_array, val); + return array_list_add(jso->o.c_array, val); } -int json_object_array_put_idx(struct json_object *this, int idx, +int json_object_array_put_idx(struct json_object *jso, int idx, struct json_object *val) { - return array_list_put_idx(this->o.c_array, idx, val); + return array_list_put_idx(jso->o.c_array, idx, val); } -struct json_object* json_object_array_get_idx(struct json_object *this, +struct json_object* json_object_array_get_idx(struct json_object *jso, int idx) { - return (struct json_object*)array_list_get_idx(this->o.c_array, idx); + return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); } From aaec1ef3c542accb118af48c09edc7e07675671a Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 25 Feb 2009 02:31:32 +0000 Subject: [PATCH 025/276] * 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, git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@33 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ arraylist.c | 7 ++++--- arraylist.h | 8 ++++++++ debug.h | 8 ++++++++ json_object.c | 4 +++- json_object.h | 23 ++++++++++++++++------- json_object_private.h | 8 ++++++++ json_tokener.c | 6 ++++-- json_tokener.h | 8 ++++++++ json_util.c | 6 +++--- json_util.h | 8 ++++++++ linkhash.c | 6 +++--- linkhash.h | 8 ++++++++ printbuf.c | 7 ++++--- printbuf.h | 8 ++++++++ test1.c | 8 ++++---- test2.c | 2 +- 17 files changed, 101 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index d0018ac..4cdd9a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 0.9 * 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, * Null pointer dereference fix. Fix json_object_get_boolean strlen test to not return TRUE for zero length string. Remove redundant includes. diff --git a/arraylist.c b/arraylist.c index 7726de6..1d93f44 100644 --- a/arraylist.c +++ b/arraylist.c @@ -28,11 +28,12 @@ array_list_new(array_list_free_fn *free_fn) { struct array_list *arr; - if(!(arr = calloc(1, sizeof(struct array_list)))) return NULL; + 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 = calloc(sizeof(void*), arr->size))) { + if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) { free(arr); return NULL; } @@ -64,7 +65,7 @@ static int array_list_expand_internal(struct array_list *arr, int max) if(max < arr->size) return 0; new_size = max(arr->size << 1, max); if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; - arr->array = t; + arr->array = (void**)t; (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); arr->size = new_size; return 0; diff --git a/arraylist.h b/arraylist.h index 2948e04..bc85c80 100644 --- a/arraylist.h +++ b/arraylist.h @@ -12,6 +12,10 @@ #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); @@ -42,4 +46,8 @@ array_list_add(struct array_list *al, void *data); extern int array_list_length(struct array_list *al); +#ifdef __cplusplus +} +#endif + #endif diff --git a/debug.h b/debug.h index 951e994..59a4dfc 100644 --- a/debug.h +++ b/debug.h @@ -12,6 +12,10 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ +#ifdef __cplusplus +extern "C" { +#endif + extern void mc_set_debug(int debug); extern int mc_get_debug(void); @@ -39,4 +43,8 @@ extern void mc_info(const char *msg, ...); #define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/json_object.c b/json_object.c index 28ca102..6c20579 100644 --- a/json_object.c +++ b/json_object.c @@ -159,7 +159,9 @@ static void json_object_generic_delete(struct json_object* jso) static struct json_object* json_object_new(enum json_type o_type) { - struct json_object *jso = calloc(sizeof(struct json_object), 1); + 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; diff --git a/json_object.h b/json_object.h index 4c8f6db..80d2313 100644 --- a/json_object.h +++ b/json_object.h @@ -12,6 +12,10 @@ #ifndef _json_object_h_ #define _json_object_h_ +#ifdef __cplusplus +extern "C" { +#endif + #define JSON_OBJECT_DEF_HASH_ENTRIES 16 #undef FALSE @@ -26,15 +30,16 @@ extern const char *json_hex_chars; /* forward structure definitions */ typedef int boolean; -struct printbuf; -struct lh_table; -struct array_list; -struct json_object; -struct json_object_iter; +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 */ -enum json_type { +typedef enum json_type { json_type_null, json_type_boolean, json_type_double, @@ -42,7 +47,7 @@ enum json_type { json_type_object, json_type_array, json_type_string -}; +} json_type; /* reference counting functions */ @@ -307,4 +312,8 @@ extern struct json_object* json_object_new_string_len(const char *s, int len); */ extern const char* json_object_get_string(struct json_object *obj); +#ifdef __cplusplus +} +#endif + #endif diff --git a/json_object_private.h b/json_object_private.h index 35a44f3..9fb4011 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -12,6 +12,10 @@ #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); @@ -41,4 +45,8 @@ struct json_object_iter struct lh_entry *entry; }; +#ifdef __cplusplus +} +#endif + #endif diff --git a/json_tokener.c b/json_tokener.c index 9c05728..beaa956 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -57,7 +57,9 @@ const char* json_tokener_errors[] = { struct json_tokener* json_tokener_new(void) { - struct json_tokener *tok = calloc(1, sizeof(struct json_tokener)); + struct json_tokener *tok; + + tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); tok->pb = printbuf_new(); json_tokener_reset(tok); return tok; @@ -100,7 +102,7 @@ struct json_object* json_tokener_parse(char *str) tok = json_tokener_new(); obj = json_tokener_parse_ex(tok, str, -1); if(tok->err != json_tokener_success) - obj = error_ptr(-tok->err); + obj = (struct json_object*)error_ptr(-tok->err); json_tokener_free(tok); return obj; } diff --git a/json_tokener.h b/json_tokener.h index 117d6ef..59035bb 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -15,6 +15,10 @@ #include #include "json_object.h" +#ifdef __cplusplus +extern "C" { +#endif + enum json_tokener_error { json_tokener_success, json_tokener_continue, @@ -87,4 +91,8 @@ extern struct json_object* json_tokener_parse(char *str); extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, char *str, int len); +#ifdef __cplusplus +} +#endif + #endif diff --git a/json_util.c b/json_util.c index 0262ca2..af6f3d6 100644 --- a/json_util.c +++ b/json_util.c @@ -62,11 +62,11 @@ struct json_object* json_object_from_file(char *filename) if((fd = open(filename, O_RDONLY)) < 0) { MC_ERROR("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); - return error_ptr(-1); + return (struct json_object*)error_ptr(-1); } if(!(pb = printbuf_new())) { MC_ERROR("json_object_from_file: printbuf_new failed\n"); - return error_ptr(-1); + return (struct json_object*)error_ptr(-1); } while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { printbuf_memappend(pb, buf, ret); @@ -76,7 +76,7 @@ struct json_object* json_object_from_file(char *filename) MC_ABORT("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); printbuf_free(pb); - return error_ptr(-1); + return (struct json_object*)error_ptr(-1); } obj = json_tokener_parse(pb->buf); printbuf_free(pb); diff --git a/json_util.h b/json_util.h index b3f53b6..6ab0287 100644 --- a/json_util.h +++ b/json_util.h @@ -14,10 +14,18 @@ #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(char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); +#ifdef __cplusplus +} +#endif + #endif diff --git a/linkhash.c b/linkhash.c index 7385401..998cf7d 100644 --- a/linkhash.c +++ b/linkhash.c @@ -41,7 +41,7 @@ int lh_ptr_equal(const void *k1, const void *k2) unsigned long lh_char_hash(const void *k) { unsigned int h = 0; - const char* data = k; + const char* data = (const char*)k; while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME; @@ -61,12 +61,12 @@ struct lh_table* lh_table_new(int size, const char *name, int i; struct lh_table *t; - t = calloc(1, sizeof(struct lh_table)); + 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 = calloc(size, sizeof(struct lh_entry)); + 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; diff --git a/linkhash.h b/linkhash.h index 9b5ef9d..90f219d 100644 --- a/linkhash.h +++ b/linkhash.h @@ -12,6 +12,10 @@ #ifndef _linkhash_h_ #define _linkhash_h_ +#ifdef __cplusplus +extern "C" { +#endif + /** * golden prime used in hash functions */ @@ -261,4 +265,8 @@ 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/printbuf.c b/printbuf.c index bbb8657..a2182f4 100644 --- a/printbuf.c +++ b/printbuf.c @@ -29,10 +29,11 @@ struct printbuf* printbuf_new(void) { struct printbuf *p; - if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL; + p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); + if(!p) return NULL; p->size = 32; p->bpos = 0; - if(!(p->buf = malloc(p->size))) { + if(!(p->buf = (char*)malloc(p->size))) { free(p); return NULL; } @@ -50,7 +51,7 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) "bpos=%d wrsize=%d old_size=%d new_size=%d\n", p->bpos, size, p->size, new_size); #endif /* PRINTBUF_DEBUG */ - if(!(t = realloc(p->buf, new_size))) return -1; + if(!(t = (char*)realloc(p->buf, new_size))) return -1; p->size = new_size; p->buf = t; } diff --git a/printbuf.h b/printbuf.h index 95f7a24..20c81cb 100644 --- a/printbuf.h +++ b/printbuf.h @@ -12,6 +12,10 @@ #ifndef _printbuf_h_ #define _printbuf_h_ +#ifdef __cplusplus +extern "C" { +#endif + #undef PRINTBUF_DEBUG struct printbuf { @@ -35,4 +39,8 @@ printbuf_reset(struct printbuf *p); extern void printbuf_free(struct printbuf *p); +#ifdef __cplusplus +} +#endif + #endif diff --git a/test1.c b/test1.c index a64a255..d2e6d0b 100644 --- a/test1.c +++ b/test1.c @@ -7,9 +7,9 @@ int main(int argc, char **argv) { - struct json_tokener *tok; - struct json_object *my_string, *my_int, *my_object, *my_array; - struct json_object *new_obj; + json_tokener *tok; + json_object *my_string, *my_int, *my_object, *my_array; + json_object *new_obj; int i; MC_SET_DEBUG(1); @@ -39,7 +39,7 @@ int main(int argc, char **argv) json_object_array_put_idx(my_array, 4, json_object_new_int(5)); printf("my_array=\n"); for(i=0; i < json_object_array_length(my_array); i++) { - struct json_object *obj = json_object_array_get_idx(my_array, i); + json_object *obj = json_object_array_get_idx(my_array, i); printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); } printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); diff --git a/test2.c b/test2.c index 39c4884..5f95565 100644 --- a/test2.c +++ b/test2.c @@ -8,7 +8,7 @@ int main(int argc, char **argv) { - struct json_object *new_obj; + json_object *new_obj; MC_SET_DEBUG(1); From 95f55a761c9ad640cbad9f84627575e7b5a76fe1 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 27 Apr 2009 08:16:58 +0000 Subject: [PATCH 026/276] optimizations to json_tokener_parse_ex(), printbuf_memappend() -- Brent Miller, bdmiller at yahoo dash inc dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@34 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 + json_tokener.c | 289 +++++++++++++++++++++++++++++++++---------------- printbuf.c | 15 ++- printbuf.h | 18 +++ 4 files changed, 226 insertions(+), 98 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4cdd9a0..b07ea57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * optimizations to json_tokener_parse_ex(), printbuf_memappend() + Brent Miller, bdmiller at yahoo dash inc dot com * 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 diff --git a/json_tokener.c b/json_tokener.c index beaa956..8e8c6d9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -7,6 +7,10 @@ * 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" @@ -135,35 +139,68 @@ char* strndup(const char* str, size_t n) #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, char *str, int len) { struct json_object *obj = NULL; - char c; + char c = '\1'; tok->char_offset = 0; tok->err = json_tokener_success; - do { - if(tok->char_offset == len) { - if(tok->depth == 0 && state == json_tokener_state_eatws && - saved_state == json_tokener_state_finish) - tok->err = json_tokener_success; - else - tok->err = json_tokener_continue; - goto out; - } + while (POP_CHAR(c, tok)) { - c = *str; redo_char: switch(state) { case json_tokener_state_eatws: - if(isspace(c)) { - /* okay */ - } else if(c == '/') { + /* Advance until we change state */ + while (isspace(c)) { + if ((!ADVANCE_CHAR(str, tok)) || (!POP_CHAR(c, tok))) + goto out; + } + if(c == '/') { printbuf_reset(tok->pb); - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); state = json_tokener_state_comment_start; } else { state = saved_state; @@ -236,7 +273,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto redo_char; case json_tokener_state_null: - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); if(strncasecmp(json_null_str, tok->pb->buf, min(tok->st_pos+1, strlen(json_null_str))) == 0) { if(tok->st_pos == strlen(json_null_str)) { @@ -261,25 +298,42 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_comment; goto out; } - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); break; case json_tokener_state_comment: - if(c == '*') state = json_tokener_state_comment_end; - printbuf_memappend(tok->pb, &c, 1); - break; + { + /* Advance until we change state */ + 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: - if(c == '\n') { + { + /* Advance until we change state */ + 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; - } else { - printbuf_memappend(tok->pb, &c, 1); } break; case json_tokener_state_comment_end: - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); if(c == '/') { MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; @@ -289,15 +343,27 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_string: - if(c == tok->quote_char) { - current = json_object_new_string(tok->pb->buf); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - } else if(c == '\\') { - saved_state = json_tokener_state_string; - state = json_tokener_state_string_escape; - } else { - printbuf_memappend(tok->pb, &c, 1); + { + /* Advance until we change state */ + 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; @@ -306,17 +372,17 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case '"': case '\\': case '/': - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); state = saved_state; break; case 'b': case 'n': case 'r': case 't': - if(c == 'b') printbuf_memappend(tok->pb, "\b", 1); - else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1); - else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1); - else if(c == 't') printbuf_memappend(tok->pb, "\t", 1); + 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': @@ -331,33 +397,46 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_escape_unicode: - 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 utf_out[3]; - if (tok->ucs_char < 0x80) { - utf_out[0] = tok->ucs_char; - printbuf_memappend(tok->pb, (char*)utf_out, 1); - } else if (tok->ucs_char < 0x800) { - utf_out[0] = 0xc0 | (tok->ucs_char >> 6); - utf_out[1] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend(tok->pb, (char*)utf_out, 2); - } else { - utf_out[0] = 0xe0 | (tok->ucs_char >> 12); - utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); - utf_out[2] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend(tok->pb, (char*)utf_out, 3); - } - state = saved_state; + /* Note that the following code is inefficient for handling large + * chunks of extended chars, calling printbuf_memappend() once + * for each multi-byte character of input. + * This is a good area for future optimization. + */ + { + /* Advance until we change state */ + 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 utf_out[3]; + if (tok->ucs_char < 0x80) { + utf_out[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char*)utf_out, 1); + } else if (tok->ucs_char < 0x800) { + utf_out[0] = 0xc0 | (tok->ucs_char >> 6); + utf_out[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)utf_out, 2); + } else { + utf_out[0] = 0xe0 | (tok->ucs_char >> 12); + utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + utf_out[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)utf_out, 3); + } + state = saved_state; + break; + } + } else { + tok->err = json_tokener_error_parse_string; + goto out; + } + if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) + goto out; } - } else { - tok->err = json_tokener_error_parse_string; - goto out; } break; case json_tokener_state_boolean: - printbuf_memappend(tok->pb, &c, 1); + printbuf_memappend_fast(tok->pb, &c, 1); if(strncasecmp(json_true_str, tok->pb->buf, min(tok->st_pos+1, strlen(json_true_str))) == 0) { if(tok->st_pos == strlen(json_true_str)) { @@ -382,23 +461,35 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_number: - if(c && strchr(json_number_chars, c)) { - printbuf_memappend(tok->pb, &c, 1); - if(c == '.' || c == 'e' || c == 'E') tok->is_double = 1; - } else { - int numi; - double numd; - if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { - current = json_object_new_int(numi); - } 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; + { + /* Advance until we change state */ + char *case_start = str; + int case_len=0; + while(c && strchr(json_number_chars, c)) { + ++case_len; + if(c == '.' || 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; + } } - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; + if (case_len>0) + printbuf_memappend_fast(tok->pb, case_start, case_len); + } + { + int numi; + double numd; + if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { + current = json_object_new_int(numi); + } 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; @@ -452,15 +543,27 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_object_field: - if(c == tok->quote_char) { - obj_field_name = strdup(tok->pb->buf); - saved_state = json_tokener_state_object_field_end; - state = json_tokener_state_eatws; - } else if(c == '\\') { - saved_state = json_tokener_state_object_field; - state = json_tokener_state_string_escape; - } else { - printbuf_memappend(tok->pb, &c, 1); + { + /* Advance until we change state */ + 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; @@ -506,15 +609,17 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; } - str++; - tok->char_offset++; - } while(c); - - if(state != json_tokener_state_finish && - saved_state != json_tokener_state_finish) - tok->err = json_tokener_error_parse_eof; + 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) return json_object_get(current); MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", json_tokener_errors[tok->err], tok->char_offset); diff --git a/printbuf.c b/printbuf.c index a2182f4..a9c711c 100644 --- a/printbuf.c +++ b/printbuf.c @@ -7,6 +7,10 @@ * 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" @@ -118,16 +122,15 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) if output is truncated whereas some return the number of bytes that would have been writen - this code handles both cases. */ if(size == -1 || size > 127) { - int ret; va_start(ap, msg); - size = vasprintf(&t, msg, ap); + if((size = vasprintf(&t, msg, ap)) == -1) return -1; va_end(ap); - if(size == -1) return -1; - ret = printbuf_memappend(p, t, size); + printbuf_memappend(p, t, size); free(t); - return ret; + return size; } else { - return printbuf_memappend(p, buf, size); + printbuf_memappend(p, buf, size); + return size; } } diff --git a/printbuf.h b/printbuf.h index 20c81cb..53fa921 100644 --- a/printbuf.h +++ b/printbuf.h @@ -7,6 +7,10 @@ * 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_ @@ -27,9 +31,23 @@ struct printbuf { extern struct printbuf* printbuf_new(void); +/* As an optimization, printbuf_memappend 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. + */ 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) + extern int sprintbuf(struct printbuf *p, const char *msg, ...); From 6f70e44b7d2d355d3a9c5c9e2d12133342d9b8ed Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 27 Apr 2009 08:19:27 +0000 Subject: [PATCH 027/276] Fix json_object_get_boolean to return false for empty string Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@35 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 6c20579..e412e4f 100644 --- a/json_object.c +++ b/json_object.c @@ -309,7 +309,7 @@ boolean json_object_get_boolean(struct json_object *jso) case json_type_string: return (strlen(jso->o.c_string) != 0); default: - return TRUE; + return FALSE; } } From 24ea8c041463aafa2dd60b0bc3ae527f292cb791 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Mon, 27 Apr 2009 08:22:22 +0000 Subject: [PATCH 028/276] update changelog for json_object_get_boolean fix git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@36 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index b07ea57..bcff91f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * 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 * Don't use this as a variable, so we can compile with a C++ compiler From 9bc863ed3f340ece01784d3519f08438a3e67c68 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Tue, 12 May 2009 02:36:04 +0000 Subject: [PATCH 029/276] Change note about CVS repository to point to subversion repos git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@38 327403b1-1117-474d-bef2-5cb71233fd97 --- README-WIN32.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README-WIN32.html b/README-WIN32.html index fb50159..261de39 100644 --- a/README-WIN32.html +++ b/README-WIN32.html @@ -45,12 +45,8 @@ Added cast and mask to suffice size_t v. unsigned int conversion correctness -

Anonymous CVS

-

# export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot
- # cvs login
- Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot
- CVS password: <enter 'anoncvs'>
- # cvs co json-c

+

Anonymous Subversion

^M +

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

^M

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael Clark

From ffa742a5527d9c3f252c83aa858361b2598fd259 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Tue, 12 May 2009 02:40:24 +0000 Subject: [PATCH 030/276] Ooops. remove literal ^M (copy and paste problem) git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@39 327403b1-1117-474d-bef2-5cb71233fd97 --- README-WIN32.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README-WIN32.html b/README-WIN32.html index 261de39..678fc9d 100644 --- a/README-WIN32.html +++ b/README-WIN32.html @@ -45,8 +45,8 @@ Added cast and mask to suffice size_t v. unsigned int conversion correctness -

Anonymous Subversion

^M -

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

^M +

Anonymous Subversion

+

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael Clark

From c5cbf8214ab628bead203d2ac3a1948bc3005801 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Tue, 30 Jun 2009 03:40:53 +0000 Subject: [PATCH 031/276] Disable REFCOUNT_DEBUG by default in json_object.c git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@40 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 1 + json_object.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index bcff91f..6065747 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ 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 diff --git a/json_object.c b/json_object.c index e412e4f..f52445c 100644 --- a/json_object.c +++ b/json_object.c @@ -27,7 +27,7 @@ char* strndup(const char* str, size_t n); #endif /* !HAVE_STRNDUP */ -#define REFCOUNT_DEBUG 1 +/* #define REFCOUNT_DEBUG 1 */ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdef"; From 543bb1431f12cd62e7d9d4b65989919409e239c9 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 8 Jul 2009 03:46:10 +0000 Subject: [PATCH 032/276] Erik Hovland (3): Fix any noticeable spelling or grammar errors. Make sure every va_start has a va_end. Check all pointers for validity. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@41 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 4 ++++ json_tokener.c | 1 + printbuf.c | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6065747..6f956f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ 0.9 + * 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() diff --git a/json_tokener.c b/json_tokener.c index 8e8c6d9..a1951b9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -64,6 +64,7 @@ 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; diff --git a/printbuf.c b/printbuf.c index a9c711c..a809aa9 100644 --- a/printbuf.c +++ b/printbuf.c @@ -120,10 +120,10 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) /* 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 writen - this code handles both cases. */ + would have been written - this code handles both cases. */ if(size == -1 || size > 127) { va_start(ap, msg); - if((size = vasprintf(&t, msg, ap)) == -1) return -1; + if((size = vasprintf(&t, msg, ap)) == -1) { va_end(ap); return -1; } va_end(ap); printbuf_memappend(p, t, size); free(t); From b1a22ac85f8251688f77da52d000958fab3a8d66 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Wed, 8 Jul 2009 04:02:05 +0000 Subject: [PATCH 033/276] Add const qualifier to the json_tokener_parse functions Eric Haszlakiewicz, EHASZLA at transunion dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@42 327403b1-1117-474d-bef2-5cb71233fd97 --- json_tokener.c | 14 +++++++------- json_tokener.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index a1951b9..02facda 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -99,7 +99,7 @@ void json_tokener_reset(struct json_tokener *tok) tok->err = json_tokener_success; } -struct json_object* json_tokener_parse(char *str) +struct json_object* json_tokener_parse(const char *str) { struct json_tokener* tok; struct json_object* obj; @@ -180,7 +180,7 @@ char* strndup(const char* str, size_t n) struct json_object* json_tokener_parse_ex(struct json_tokener *tok, - char *str, int len) + const char *str, int len) { struct json_object *obj = NULL; char c = '\1'; @@ -305,7 +305,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_comment: { /* Advance until we change state */ - char *case_start = str; + 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); @@ -320,7 +320,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_comment_eol: { /* Advance until we change state */ - char *case_start = str; + 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); @@ -346,7 +346,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_string: { /* Advance until we change state */ - char *case_start = str; + const char *case_start = str; while(1) { if(c == tok->quote_char) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); @@ -464,7 +464,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_number: { /* Advance until we change state */ - char *case_start = str; + const char *case_start = str; int case_len=0; while(c && strchr(json_number_chars, c)) { ++case_len; @@ -546,7 +546,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_object_field: { /* Advance until we change state */ - char *case_start = str; + const char *case_start = str; while(1) { if(c == tok->quote_char) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); diff --git a/json_tokener.h b/json_tokener.h index 59035bb..7d40b40 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -87,9 +87,9 @@ extern const char* json_tokener_errors[]; 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(char *str); +extern struct json_object* json_tokener_parse(const char *str); extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, - char *str, int len); + const char *str, int len); #ifdef __cplusplus } From 7fb9b03ffdc5942c4e542b53f2bf96f4d36d3059 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 25 Jul 2009 00:13:44 +0000 Subject: [PATCH 034/276] * Rename min and max so we can never clash with C or C++ std library Ian Atha, thatha at yahoo-inc dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@43 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ arraylist.c | 2 +- bits.h | 8 ++++---- json_tokener.c | 8 ++++---- printbuf.c | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f956f0..af71d9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * Rename min and max so we can never clash with C or C++ std library + Ian Atha, thatha at yahoo-inc dot com * Fix any noticeable spelling or grammar errors. * Make sure every va_start has a va_end. * Check all pointers for validity. diff --git a/arraylist.c b/arraylist.c index 1d93f44..cd04eea 100644 --- a/arraylist.c +++ b/arraylist.c @@ -63,7 +63,7 @@ static int array_list_expand_internal(struct array_list *arr, int max) int new_size; if(max < arr->size) return 0; - new_size = max(arr->size << 1, max); + 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*)); diff --git a/bits.h b/bits.h index 2c107cc..f308da3 100644 --- a/bits.h +++ b/bits.h @@ -12,12 +12,12 @@ #ifndef _bits_h_ #define _bits_h_ -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) +#ifndef json_min +#define json_min(a,b) ((a) < (b) ? (a) : (b)) #endif -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) +#ifndef json_max +#define json_max(a,b) ((a) > (b) ? (a) : (b)) #endif #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) diff --git a/json_tokener.c b/json_tokener.c index 02facda..04f11ba 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -119,7 +119,7 @@ char* strndup(const char* str, size_t n) { if(str) { size_t len = strlen(str); - size_t nn = min(len,n); + size_t nn = json_min(len,n); char* s = (char*)malloc(sizeof(char) * (nn + 1)); if(s) { @@ -276,7 +276,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_null: printbuf_memappend_fast(tok->pb, &c, 1); if(strncasecmp(json_null_str, tok->pb->buf, - min(tok->st_pos+1, strlen(json_null_str))) == 0) { + 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; @@ -439,7 +439,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_boolean: printbuf_memappend_fast(tok->pb, &c, 1); if(strncasecmp(json_true_str, tok->pb->buf, - min(tok->st_pos+1, strlen(json_true_str))) == 0) { + 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; @@ -447,7 +447,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto redo_char; } } else if(strncasecmp(json_false_str, tok->pb->buf, - min(tok->st_pos+1, strlen(json_false_str))) == 0) { + 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; diff --git a/printbuf.c b/printbuf.c index a809aa9..97366c3 100644 --- a/printbuf.c +++ b/printbuf.c @@ -49,7 +49,7 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) { char *t; if(p->size - p->bpos <= size) { - int new_size = max(p->size * 2, p->bpos + size + 8); + int new_size = json_max(p->size * 2, p->bpos + size + 8); #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " "bpos=%d wrsize=%d old_size=%d new_size=%d\n", From c80ba8dd42d6826d784725d67db3c20d3c71db49 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 25 Jul 2009 00:21:18 +0000 Subject: [PATCH 035/276] typo fix git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@44 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index af71d9a..4546ce5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ 0.9 * Rename min and max so we can never clash with C or C++ std library - Ian Atha, thatha at yahoo-inc dot com + 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. From b22565d1fd432e23ff1be9e1d76221409576e349 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 31 Jul 2009 02:12:46 +0000 Subject: [PATCH 036/276] Update changelog git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@45 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4546ce5..7d2c823 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * 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. From 1363df08d29486d31bfb8bf527ee990f430d8250 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 31 Jul 2009 02:50:48 +0000 Subject: [PATCH 037/276] Update version to 0.9 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@46 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 2 +- README.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 43120b2..bf5d7ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT EXTRA_DIST = doc diff --git a/README.html b/README.html index e69beb9..c5cba3a 100644 --- a/README.html +++ b/README.html @@ -8,7 +8,7 @@

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.8.tar.gz

+

Latest release: json-c-0.9.tar.gz

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.

From db92cc02b9ffe8d82200e7e8c96e28aae5b01271 Mon Sep 17 00:00:00 2001 From: Christopher Watford Date: Fri, 31 Jul 2009 02:59:02 +0000 Subject: [PATCH 038/276] Add README.html, README-WIN32.html and config.h.win32 to EXTRA_DIST in Makefile.am git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@47 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index bf5d7ce..ba897d9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT -EXTRA_DIST = doc +EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc lib_LTLIBRARIES = libjson.la From 09abeffda32472b951e8c6a1eb9bd6f0a58fd0b1 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 19 Aug 2009 07:23:23 +0000 Subject: [PATCH 039/276] Add note about autoconf README changes to ChangeLog git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@49 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7d2c823..dddd995 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.9 + * Add README.html README-WIN32.html config.h.win32 to Makefile.am + Michael Clark, * 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 From 50626cd81f633ebb7165205754ca7ecf6f1a03c3 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 19 Aug 2009 08:18:25 +0000 Subject: [PATCH 040/276] Add mailing lists to README.html git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@50 327403b1-1117-474d-bef2-5cb71233fd97 --- README.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.html b/README.html index c5cba3a..743a4b3 100644 --- a/README.html +++ b/README.html @@ -22,11 +22,15 @@

Please send Win32 bug reports to christopher.watford@gmail.com

Anonymous Subversion

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

-

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael - Clark -

This program is free software; you can redistribute it and/or modify it under the terms of the MIT License. See COPYING for details.

+

Mailing Lists

+
+

Copyright Metaparadigm Pte. Ltd. 2009. Michael Clark +

From 51658855fb211e97efc883c7c89ef1cc9bf9c1f0 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 19 Aug 2009 08:31:29 +0000 Subject: [PATCH 041/276] Add json-c.vcproj to EXTRA_DIST git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@51 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index ba897d9..fbedab8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT -EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc +EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj lib_LTLIBRARIES = libjson.la From f8663fc16fc1082b72ab721f5a6b3781543293a8 Mon Sep 17 00:00:00 2001 From: Brent Miller Date: Thu, 20 Aug 2009 06:41:32 +0000 Subject: [PATCH 042/276] * Correct comment describing printbuf_memappend in printbuf.h git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@52 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 3 +++ printbuf.h | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index dddd995..1a90e10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ + * 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, diff --git a/printbuf.h b/printbuf.h index 53fa921..5d4963f 100644 --- a/printbuf.h +++ b/printbuf.h @@ -31,10 +31,12 @@ struct printbuf { extern struct printbuf* printbuf_new(void); -/* As an optimization, printbuf_memappend 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. +/* 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); From 126ad95fc4895412b631f90657e72e8c75780667 Mon Sep 17 00:00:00 2001 From: Brent Miller Date: Thu, 20 Aug 2009 06:50:22 +0000 Subject: [PATCH 043/276] * Add handling of surrogate pairs git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@53 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 + Makefile.am | 5 ++- json_tokener.c | 102 ++++++++++++++++++++++++++++++++++++++++--------- test4.c | 44 +++++++++++++++++++++ 4 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 test4.c diff --git a/ChangeLog b/ChangeLog index 1a90e10..a99c7ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ + * 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 diff --git a/Makefile.am b/Makefile.am index fbedab8..1c1a9ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test3 +check_PROGRAMS = test1 test2 test3 test4 test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -41,3 +41,6 @@ test2_LDADD = $(lib_LTLIBRARIES) test3_SOURCES = test3.c test3_LDADD = $(lib_LTLIBRARIES) + +test4_SOURCES = test4.c +test4_LDADD = $(lib_LTLIBRARIES) diff --git a/json_tokener.c b/json_tokener.c index 04f11ba..8d0b5dc 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -58,6 +58,12 @@ const char* json_tokener_errors[] = { "expected comment", }; +/* 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) { @@ -176,6 +182,7 @@ char* strndup(const char* str, size_t n) #define ADVANCE_CHAR(str, tok) \ ( ++(str), ((tok)->char_offset)++, c) + /* End optimization macro defs */ @@ -398,40 +405,97 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_escape_unicode: - /* Note that the following code is inefficient for handling large - * chunks of extended chars, calling printbuf_memappend() once - * for each multi-byte character of input. - * This is a good area for future optimization. - */ { - /* Advance until we change state */ + 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 utf_out[3]; + 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) { - utf_out[0] = tok->ucs_char; - printbuf_memappend_fast(tok->pb, (char*)utf_out, 1); + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1); } else if (tok->ucs_char < 0x800) { - utf_out[0] = 0xc0 | (tok->ucs_char >> 6); - utf_out[1] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char*)utf_out, 2); + 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 { - utf_out[0] = 0xe0 | (tok->ucs_char >> 12); - utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); - utf_out[2] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char*)utf_out, 3); - } + /* 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 (!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; diff --git a/test4.c b/test4.c new file mode 100644 index 0000000..921383d --- /dev/null +++ b/test4.c @@ -0,0 +1,44 @@ +/* + * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson +*/ + +#include +#include +#include +#include + +void print_hex( const unsigned char* s) { + const unsigned char *iter = s; + unsigned char ch; + while ((ch = *iter++) != 0) { + if( ',' != ch) + printf("%x ", ch); + else + printf( ","); + } + printf("\n"); +} + +int main() { + const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; + const char *expected = "\xF0\xA0\x84\xA6,\xF0\xA0\x84\xA7,\xF0\x90\x84\xA6,\xF0\x90\x84\xA7"; + struct json_object *parse_result = json_tokener_parse((char*)input); + const char *unjson = json_object_get_string(parse_result); + + printf("input: %s\n", input); + + int strings_match = !strcmp( expected, unjson); + if (strings_match) { + printf("JSON parse result is correct: %s\n", unjson); + printf("PASS\n"); + return(0); + } else { + printf("JSON parse result doesn't match expected string\n"); + printf("expected string bytes: "); + print_hex( expected); + printf("parsed string bytes: "); + print_hex( unjson); + printf("FAIL\n"); + return(1); + } +} From f5dd43a9d10abb2de50956d23505da08896f0c64 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Thu, 27 Aug 2009 06:40:00 +0000 Subject: [PATCH 044/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@54 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 6 ++++++ linkhash.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a99c7ed..2011cc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +0.10 + * 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 diff --git a/linkhash.c b/linkhash.c index 998cf7d..3a9ba0e 100644 --- a/linkhash.c +++ b/linkhash.c @@ -158,13 +158,15 @@ 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( 1 ) { + 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; } From 88ded9ceb8296eb6661c4d6f8f266ac74d81b9c4 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Thu, 27 Aug 2009 06:40:59 +0000 Subject: [PATCH 045/276] * Make json_object_from_file take const char *filename Spotted by Vikram Raj V, vsagar at attinteractive dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@55 327403b1-1117-474d-bef2-5cb71233fd97 --- json_util.c | 2 +- json_util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/json_util.c b/json_util.c index af6f3d6..06e4a71 100644 --- a/json_util.c +++ b/json_util.c @@ -52,7 +52,7 @@ #include "json_tokener.h" #include "json_util.h" -struct json_object* json_object_from_file(char *filename) +struct json_object* json_object_from_file(const char *filename) { struct printbuf *pb; struct json_object *obj; diff --git a/json_util.h b/json_util.h index 6ab0287..134390f 100644 --- a/json_util.h +++ b/json_util.h @@ -21,7 +21,7 @@ extern "C" { #define JSON_FILE_BUF_SIZE 4096 /* utility functions */ -extern struct json_object* json_object_from_file(char *filename); +extern struct json_object* json_object_from_file(const char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); #ifdef __cplusplus From c4dceae1c53bc37cacc46a806f8a02524d12a382 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 6 Oct 2010 16:39:20 +0000 Subject: [PATCH 046/276] * 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 git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@56 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 4 ++ Doxyfile | 2 +- Makefile.am | 32 +++++++---- config.h.in | 6 +- json_inttypes.h | 21 +++++++ json_object.c | 72 ++++++++++++++++++++++-- json_object.h | 28 +++++++++- json_object_private.h | 3 +- json_tokener.c | 24 ++++++-- json_util.c | 65 ++++++++++++++++++++++ json_util.h | 1 + parse_int64.test | 12 ++++ test-defs.sh | 114 ++++++++++++++++++++++++++++++++++++++ test1.c | 2 +- test1.expected | 44 +++++++++++++++ test1.test | 12 ++++ test2.expected | 1 + test2.test | 12 ++++ test4.c | 17 ++++-- test4.expected | 3 + test4.test | 12 ++++ test_parse_int64.c | 99 +++++++++++++++++++++++++++++++++ test_parse_int64.expected | 23 ++++++++ 23 files changed, 569 insertions(+), 40 deletions(-) create mode 100644 json_inttypes.h create mode 100644 parse_int64.test create mode 100644 test-defs.sh create mode 100644 test1.expected create mode 100644 test1.test create mode 100644 test2.expected create mode 100644 test2.test create mode 100644 test4.expected create mode 100644 test4.test create mode 100644 test_parse_int64.c create mode 100644 test_parse_int64.expected diff --git a/ChangeLog b/ChangeLog index 2011cc2..6105c8e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ 0.10 + * 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 diff --git a/Doxyfile b/Doxyfile index 7e5f306..3ff27eb 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.2 +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. diff --git a/Makefile.am b/Makefile.am index 1c1a9ba..dc920f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,16 +9,17 @@ pkgconfig_DATA = json.pc libjsonincludedir = $(includedir)/json libjsoninclude_HEADERS = \ - json.h \ + arraylist.h \ bits.h \ debug.h \ - linkhash.h \ - arraylist.h \ - printbuf.h \ - json_util.h \ + json.h \ + json_inttypes.h \ json_object.h \ - json_object_private.h \ - json_tokener.h + json_object_private.h \ + json_tokener.h \ + json_util.h \ + linkhash.h \ + printbuf.h libjson_la_LDFLAGS = -version-info 0:1:0 @@ -31,7 +32,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test3 test4 +check_PROGRAMS = test1 test2 test4 test_parse_int64 test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -39,8 +40,17 @@ test1_LDADD = $(lib_LTLIBRARIES) test2_SOURCES = test2.c test2_LDADD = $(lib_LTLIBRARIES) -test3_SOURCES = test3.c -test3_LDADD = $(lib_LTLIBRARIES) - test4_SOURCES = test4.c test4_LDADD = $(lib_LTLIBRARIES) + +test_parse_int64_SOURCES = test_parse_int64.c +test_parse_int64_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test +EXTRA_DIST += $(TESTS) +testsubdir=testSubDir +TESTS_ENVIRONMENT = top_builddir=$(top_builddir) + +distclean-local: + -rm -rf $(testsubdir) + diff --git a/config.h.in b/config.h.in index 5139ae8..83ab797 100644 --- a/config.h.in +++ b/config.h.in @@ -80,10 +80,6 @@ /* Define to 1 if you have the `vsyslog' function. */ #undef HAVE_VSYSLOG -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - /* Name of package */ #undef PACKAGE @@ -117,5 +113,5 @@ /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc -/* Define to `unsigned int' if does not define. */ +/* Define to `unsigned' if does not define. */ #undef size_t diff --git a/json_inttypes.h b/json_inttypes.h new file mode 100644 index 0000000..1cbafc2 --- /dev/null +++ b/json_inttypes.h @@ -0,0 +1,21 @@ + +#ifndef _json_inttypes_h_ +#define _json_inttypes_h_ + +#if defined(_MSC_VER) && _MSC_VER < 1600 + +/* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ +typedef __int64 int64_t; +#define PRId64 "I64d" +#define SCNd64 "I64d" + +#else + +#ifdef HAVE_INTTYPES_H +#include +#endif +/* inttypes.h includes stdint.h */ + +#endif + +#endif diff --git a/json_object.c b/json_object.c index f52445c..c2b6fe2 100644 --- a/json_object.c +++ b/json_object.c @@ -20,8 +20,10 @@ #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); @@ -41,6 +43,7 @@ static const char* json_type_name[] = { "object", "array", "string", + "int64", }; #endif /* REFCOUNT_DEBUG */ @@ -304,6 +307,8 @@ boolean json_object_get_boolean(struct json_object *jso) return jso->o.c_boolean; case json_type_int: return (jso->o.c_int != 0); + case json_type_int64: + return (jso->o.c_int64 != 0); case json_type_double: return (jso->o.c_double != 0); case json_type_string: @@ -322,7 +327,11 @@ static int json_object_int_to_json_string(struct json_object* jso, return sprintbuf(pb, "%d", jso->o.c_int); } -struct json_object* json_object_new_int(int i) +static int json_object_int64_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; @@ -331,20 +340,69 @@ struct json_object* json_object_new_int(int i) return jso; } -int json_object_get_int(struct json_object *jso) +int32_t json_object_get_int(struct json_object *jso) { - int cint; + if(!jso) return 0; + + enum json_type o_type = jso->o_type; + int64_t 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, &cint64) != 0) + return 0; /* whoops, it didn't work. */ + o_type = json_type_int64; + } + + switch(jso->o_type) { + case json_type_int: + return jso->o.c_int; + case json_type_int64: + /* 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_int64); + if(!jso) return NULL; + jso->_to_json_string = &json_object_int64_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_int; + return (int64_t)jso->o.c_int; + case json_type_int64: + return jso->o.c_int64; case json_type_double: - return (int)jso->o.c_double; + return (int64_t)jso->o.c_double; case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if(sscanf(jso->o.c_string, "%d", &cint) == 1) return cint; + if (json_parse_int64(jso->o.c_string, &cint) == 0) return cint; default: return 0; } @@ -378,6 +436,8 @@ double json_object_get_double(struct json_object *jso) return jso->o.c_double; case json_type_int: return jso->o.c_int; + case json_type_int64: + return jso->o.c_int64; case json_type_boolean: return jso->o.c_boolean; case json_type_string: diff --git a/json_object.h b/json_object.h index 80d2313..cea4c81 100644 --- a/json_object.h +++ b/json_object.h @@ -46,7 +46,8 @@ typedef enum json_type { json_type_int, json_type_object, json_type_array, - json_type_string + json_type_string, + json_type_int64 } json_type; /* reference counting functions */ @@ -74,6 +75,7 @@ extern void json_object_put(struct json_object *obj); json_type_object, json_type_array, json_type_string, + json_type_int64, */ extern int json_object_is_type(struct json_object *obj, enum json_type type); @@ -87,6 +89,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); json_type_object, json_type_array, json_type_string, + json_type_int64, */ extern enum json_type json_object_get_type(struct json_object *obj); @@ -252,7 +255,15 @@ extern boolean json_object_get_boolean(struct json_object *obj); * @param i the integer * @returns a json_object of type json_type_int */ -extern struct json_object* json_object_new_int(int i); +extern struct json_object* json_object_new_int(int32_t i); + + +/** Create a new empty json_object of type json_type_int64 + * @param i the integer + * @returns a json_object of type json_type_int64 + */ +extern struct json_object* json_object_new_int64(int64_t i); + /** Get the int value of a json_object * @@ -263,7 +274,18 @@ extern struct json_object* json_object_new_int(int i); * @param obj the json_object instance * @returns an int */ -extern int json_object_get_int(struct json_object *obj); +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. + * + * @param obj the json_object instance + * @returns an int64 + */ +extern int64_t json_object_get_int64(struct json_object *obj); /* double type methods */ diff --git a/json_object_private.h b/json_object_private.h index 9fb4011..a0f9845 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -30,7 +30,8 @@ struct json_object union data { boolean c_boolean; double c_double; - int c_int; + int32_t c_int; + int64_t c_int64; struct lh_table *c_object; struct array_list *c_array; char *c_string; diff --git a/json_tokener.c b/json_tokener.c index 8d0b5dc..dbaacaa 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -20,14 +20,16 @@ #include #include #include +#include #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 */ @@ -542,11 +544,21 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, printbuf_memappend_fast(tok->pb, case_start, case_len); } { - int numi; - double numd; - if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) { - current = json_object_new_int(numi); - } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) { + int64_t num64; + double numd; + if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { + // Decode the type based on the value range to keep compatibilty + // with code that checks the type of objects. i.e. this: + // json_object_get_type(o) == json_type_int + // will continue to work. + // The other option would be to eliminate any distinction between + // int and int64 types, but that would change the ABI of + // json_object_get_int(). + if (num64 < INT32_MAX && num64 > INT32_MIN) + current = json_object_new_int(num64); + else + 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; diff --git a/json_util.c b/json_util.c index 06e4a71..e5a9dc6 100644 --- a/json_util.c +++ b/json_util.c @@ -17,6 +17,7 @@ #include #include #include +#include #if HAVE_SYS_TYPES_H #include @@ -48,6 +49,7 @@ #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" @@ -120,3 +122,66 @@ int json_object_to_file(char *filename, struct json_object *obj) close(fd); return 0; } + +int json_parse_int64(const char *buf, int64_t *retval) +{ + int64_t num64; + if (sscanf(buf, "%" SCNd64, &num64) != 1) + { + printf("Failed to parse, sscanf != 1\n"); + return 1; + } + const char *buf_skip_space = buf; + int 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 + while (*buf_skip_space == '0' && *buf_skip_space) + buf_skip_space++; + + if (errno != ERANGE) + { + char buf_cmp[100]; + char *buf_cmp_start = buf_cmp; + int recheck_has_neg = 0; + snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); + if (*buf_cmp_start == '-') + { + recheck_has_neg = 1; + buf_cmp_start++; + } + // No need to skip leading spaces or zeros here. + + int 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(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; +} diff --git a/json_util.h b/json_util.h index 134390f..fbfcb14 100644 --- a/json_util.h +++ b/json_util.h @@ -23,6 +23,7 @@ extern "C" { /* 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); #ifdef __cplusplus } diff --git a/parse_int64.test b/parse_int64.test new file mode 100644 index 0000000..2b7fbfb --- /dev/null +++ b/parse_int64.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_parse_int64 +exit $? diff --git a/test-defs.sh b/test-defs.sh new file mode 100644 index 0000000..2014b37 --- /dev/null +++ b/test-defs.sh @@ -0,0 +1,114 @@ + +#! /bin/sh + +# Make sure srcdir is an absolute path. Supply the variable +# if it does not exist. We want to be able to run the tests +# stand-alone!! +# +srcdir=${srcdir-.} +if test ! -d $srcdir ; then + echo "test-defs.sh: installation error" 1>&2 + exit 1 +fi + +# Use absolute paths +case "$srcdir" in + /* | [A-Za-z]:\\*) ;; + *) srcdir=`\cd $srcdir && pwd` ;; +esac + +case "$top_builddir" in + /* | [A-Za-z]:\\*) ;; + *) top_builddir=`\cd ${top_builddir-..} && pwd` ;; +esac + +progname=`echo "$0" | sed 's,^.*/,,'` +testname=`echo "$progname" | sed 's,-.*$,,'` +testsubdir=${testsubdir-testSubDir} + +# User can set VERBOSE to cause output redirection +case "$VERBOSE" in +[Nn]|[Nn][Oo]|0|"") + VERBOSE=0 + exec > /dev/null 2>&1 + ;; +[Yy]|[Yy][Ee][Ss]) + VERBOSE=1 + ;; +esac + +rm -rf "$testsubdir/$progname" > /dev/null 2>&1 +mkdir -p "$testsubdir/$progname" +cd "$testsubdir/$progname" \ + || { echo "Cannot make or change into $testsubdir/$progname"; exit 1; } + +echo "=== Running test $progname" + +CMP="${CMP-cmp}" + +use_valgrind=${USE_VALGRIND-1} +valgrind_path=$(which valgrind 2> /dev/null) +if [ -z "${valgrind_path}" -o ! -x "${valgrind_path}" ] ; then + use_valgrind=0 +fi + +# +# This is a common function to check the results of a test program +# that is intended to generate consistent output across runs. +# +# ${top_builddir} must be set to the top level build directory. +# +# Output will be written to the current directory. +# +# It must be passed the name of the test command to run, which must be present +# in the ${top_builddir} directory. +# +# It will compare the output of running that against .expected +# +run_output_test() +{ + TEST_COMMAND="$1" + + REDIR_OUTPUT="> \"${TEST_COMMAND}.out\"" + if [ $VERBOSE -gt 1 ] ; then + REDIR_OUTPUT="| tee \"${TEST_COMMAND}.out\"" + fi + + if [ $use_valgrind -eq 1 ] ; then + eval valgrind --tool=memcheck \ + --trace-children=yes \ + --demangle=yes \ + --log-file=vg.out \ + --leak-check=full \ + --show-reachable=yes \ + --run-libc-freeres=yes \ + "\"${top_builddir}/${TEST_COMMAND}\"" ${REDIR_OUTPUT} + err=$? + + else + eval "\"${top_builddir}/${TEST_COMMAND}"\" ${REDIR_OUTPUT} + err=$? + fi + + if [ $err -ne 0 ] ; then + echo "ERROR: ${TEST_COMMAND} exited with non-zero exit status: $err" 1>&2 + fi + + if [ $use_valgrind -eq 1 ] ; then + if ! tail -1 "vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then + echo "ERROR: valgrind found errors during execution:" 1>&2 + cat vg.out + err=1 + fi + fi + + if ! "$CMP" -s "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" ; then + echo "ERROR: ${TEST_COMMAND} failed:" 1>&2 + diff "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" 1>&2 + err=1 + fi + + return $err +} + + diff --git a/test1.c b/test1.c index d2e6d0b..a3cc6d9 100644 --- a/test1.c +++ b/test1.c @@ -158,7 +158,7 @@ int main(int argc, char **argv) json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); - //json_object_put(my_array); + json_object_put(my_array); return 0; } diff --git a/test1.expected b/test1.expected new file mode 100644 index 0000000..e38ef50 --- /dev/null +++ b/test1.expected @@ -0,0 +1,44 @@ +my_string= +my_string.to_string()="\t" +my_string=\ +my_string.to_string()="\\" +my_string=foo +my_string.to_string()="foo" +my_int=9 +my_int.to_string()=9 +my_array= + [0]=1 + [1]=2 + [2]=3 + [3]=null + [4]=5 +my_array.to_string()=[ 1, 2, 3, null, 5 ] +my_object= + abc: 12 + foo: "bar" + bool0: false + bool1: true +my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } +new_obj.to_string()="\u0003" +new_obj.to_string()="foo" +new_obj.to_string()="foo" +new_obj.to_string()="ABC" +new_obj.to_string()=null +new_obj.to_string()=true +new_obj.to_string()=12 +new_obj.to_string()=12.300000 +new_obj.to_string()=[ "\n" ] +new_obj.to_string()=[ "\nabc\n" ] +new_obj.to_string()=[ null ] +new_obj.to_string()=[ ] +new_obj.to_string()=[ false ] +new_obj.to_string()=[ "abc", null, "def", 12 ] +new_obj.to_string()={ } +new_obj.to_string()={ "foo": "bar" } +new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } +new_obj.to_string()={ "foo": [ null, "foo" ] } +new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } +got error as expected +got error as expected +got error as expected +new_obj.to_string()={ "foo": { "bar": 13 } } diff --git a/test1.test b/test1.test new file mode 100644 index 0000000..6074fac --- /dev/null +++ b/test1.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test1 +exit $? diff --git a/test2.expected b/test2.expected new file mode 100644 index 0000000..0b740a9 --- /dev/null +++ b/test2.expected @@ -0,0 +1 @@ +new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } } diff --git a/test2.test b/test2.test new file mode 100644 index 0000000..cbb3830 --- /dev/null +++ b/test2.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test2 +exit $? diff --git a/test4.c b/test4.c index 921383d..555afd1 100644 --- a/test4.c +++ b/test4.c @@ -4,11 +4,14 @@ #include #include -#include -#include +#include "config.h" -void print_hex( const unsigned char* s) { - const unsigned char *iter = s; +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" + +void print_hex( const char* s) { + const char *iter = s; unsigned char ch; while ((ch = *iter++) != 0) { if( ',' != ch) @@ -28,10 +31,10 @@ int main() { printf("input: %s\n", input); int strings_match = !strcmp( expected, unjson); + int retval = 0; if (strings_match) { printf("JSON parse result is correct: %s\n", unjson); printf("PASS\n"); - return(0); } else { printf("JSON parse result doesn't match expected string\n"); printf("expected string bytes: "); @@ -39,6 +42,8 @@ int main() { printf("parsed string bytes: "); print_hex( unjson); printf("FAIL\n"); - return(1); + retval = 1; } + json_object_put(parse_result); + return retval; } diff --git a/test4.expected b/test4.expected new file mode 100644 index 0000000..68d4336 --- /dev/null +++ b/test4.expected @@ -0,0 +1,3 @@ +input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27" +JSON parse result is correct: 𠄦,ð „§,ð„¦,ð„§ +PASS diff --git a/test4.test b/test4.test new file mode 100644 index 0000000..8bcc460 --- /dev/null +++ b/test4.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test4 +exit $? diff --git a/test_parse_int64.c b/test_parse_int64.c new file mode 100644 index 0000000..42d4575 --- /dev/null +++ b/test_parse_int64.c @@ -0,0 +1,99 @@ + +#include +#include + +#include "config.h" + +#include "json_inttypes.h" +#include "json_util.h" + +void checkit(const char *buf) +{ + int64_t cint64 = -666; + + int retval = json_parse_int64(buf, &cint64); + printf("buf=%s parseit=%d, value=%" PRId64 " \n", buf, retval, cint64); +} + +/** + * This test calls json_parse_int64 with a variety of different strings. + * It's purpose is to ensure that the results are consistent across all + * different environments that it might be executed in. + * + * This always exits with a 0 exit value. The output should be compared + * against previously saved expected output. + */ +int main() +{ + char buf[100]; + + checkit("x"); + + checkit("1"); + + strcpy(buf, "2147483647"); // aka INT32_MAX + checkit(buf); + + strcpy(buf, "-1"); + checkit(buf); + + strcpy(buf, " -1"); + checkit(buf); + + strcpy(buf, "00001234"); + checkit(buf); + + strcpy(buf, "0001234x"); + checkit(buf); + + strcpy(buf, "-00001234"); + checkit(buf); + + strcpy(buf, "-00001234x"); + checkit(buf); + + strcpy(buf, "4294967295"); // aka UINT32_MAX + + sprintf(buf, "4294967296"); // aka UINT32_MAX + 1 + + strcpy(buf, "21474836470"); // INT32_MAX * 10 + checkit(buf); + + strcpy(buf, "31474836470"); // INT32_MAX * 10 + a bunch + checkit(buf); + + strcpy(buf, "-2147483647"); // INT32_MIN + 1 + checkit(buf); + + strcpy(buf, "-2147483648"); // INT32_MIN + checkit(buf); + + strcpy(buf, "-2147483649"); // INT32_MIN - 1 + checkit(buf); + + strcpy(buf, "-21474836480"); // INT32_MIN * 10 + checkit(buf); + + strcpy(buf, "9223372036854775807"); // INT64_MAX + checkit(buf); + + strcpy(buf, "9223372036854775808"); // INT64_MAX + 1 + checkit(buf); + + strcpy(buf, "-9223372036854775808"); // INT64_MIN + checkit(buf); + + strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1 + checkit(buf); + + strcpy(buf, "18446744073709551615"); // UINT64_MAX + checkit(buf); + + strcpy(buf, "18446744073709551616"); // UINT64_MAX + 1 + checkit(buf); + + strcpy(buf, "-18446744073709551616"); // -UINT64_MAX + checkit(buf); + + return 0; +} diff --git a/test_parse_int64.expected b/test_parse_int64.expected new file mode 100644 index 0000000..2d01ca7 --- /dev/null +++ b/test_parse_int64.expected @@ -0,0 +1,23 @@ +Failed to parse, sscanf != 1 +buf=x parseit=1, value=-666 +buf=1 parseit=0, value=1 +buf=2147483647 parseit=0, value=2147483647 +buf=-1 parseit=0, value=-1 +buf= -1 parseit=0, value=-1 +buf=00001234 parseit=0, value=1234 +buf=0001234x parseit=0, value=1234 +buf=-00001234 parseit=0, value=-1234 +buf=-00001234x parseit=0, value=-1234 +buf=21474836470 parseit=0, value=21474836470 +buf=31474836470 parseit=0, value=31474836470 +buf=-2147483647 parseit=0, value=-2147483647 +buf=-2147483648 parseit=0, value=-2147483648 +buf=-2147483649 parseit=0, value=-2147483649 +buf=-21474836480 parseit=0, value=-21474836480 +buf=9223372036854775807 parseit=0, value=9223372036854775807 +buf=9223372036854775808 parseit=0, value=9223372036854775807 +buf=-9223372036854775808 parseit=0, value=-9223372036854775808 +buf=-9223372036854775809 parseit=0, value=-9223372036854775808 +buf=18446744073709551615 parseit=0, value=9223372036854775807 +buf=18446744073709551616 parseit=0, value=9223372036854775807 +buf=-18446744073709551616 parseit=0, value=-9223372036854775808 From d34701ed386a2e018ff62b225060b281a4eb808d Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Thu, 7 Oct 2010 01:05:14 +0000 Subject: [PATCH 047/276] Update executable properties git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@57 327403b1-1117-474d-bef2-5cb71233fd97 --- autogen.sh | 0 parse_int64.test | 0 test-defs.sh | 0 test1.test | 0 test2.test | 0 test4.test | 0 6 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 autogen.sh mode change 100644 => 100755 parse_int64.test mode change 100644 => 100755 test-defs.sh mode change 100644 => 100755 test1.test mode change 100644 => 100755 test2.test mode change 100644 => 100755 test4.test diff --git a/autogen.sh b/autogen.sh old mode 100644 new mode 100755 diff --git a/parse_int64.test b/parse_int64.test old mode 100644 new mode 100755 diff --git a/test-defs.sh b/test-defs.sh old mode 100644 new mode 100755 diff --git a/test1.test b/test1.test old mode 100644 new mode 100755 diff --git a/test2.test b/test2.test old mode 100644 new mode 100755 diff --git a/test4.test b/test4.test old mode 100644 new mode 100755 From bd0a567673b12dd0c6c2afbb75e85c86dad07dc9 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 13 Oct 2010 14:09:41 +0000 Subject: [PATCH 048/276] * Fix file descriptor leak if memory allocation fails in json_util Zachary Blair, zack_blair at hotmail dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@58 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 2 ++ json_util.c | 1 + 2 files changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6105c8e..6f54e13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ 0.10 + * 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 diff --git a/json_util.c b/json_util.c index e5a9dc6..203a70f 100644 --- a/json_util.c +++ b/json_util.c @@ -67,6 +67,7 @@ struct json_object* json_object_from_file(const char *filename) 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); } From f1ae67dbf0d5d921d2786cc63878dcc21e2a32ea Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 13 Oct 2010 14:10:51 +0000 Subject: [PATCH 049/276] * Fix file descriptor leak if memory allocation fails in json_util Zachary Blair, zack_blair at hotmail dot com git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@59 327403b1-1117-474d-bef2-5cb71233fd97 --- json_util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/json_util.c b/json_util.c index 203a70f..0dcd6d5 100644 --- a/json_util.c +++ b/json_util.c @@ -103,8 +103,10 @@ int json_object_to_file(char *filename, struct json_object *obj) return -1; } - if(!(json_str = json_object_to_json_string(obj))) { 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; From 252669cee672b101cc43b2baae86db4a8bcb80eb Mon Sep 17 00:00:00 2001 From: ehaszla Date: Tue, 7 Dec 2010 18:15:35 +0000 Subject: [PATCH 050/276] Simplify things by storing integer values only as int64_t's internally, and omit the range check during parsing since we already have the checks when accessing the value. There is no longer a json_type_int64, only json_type_int. Fix some problems with parsing 0 and -0 values, and add a couple of tests. Fix some minor compile issues on HPUX environments. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@60 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 21 ++++----------------- json_object.h | 13 ++++++++----- json_object_private.h | 1 - json_tokener.c | 14 ++------------ json_util.c | 22 ++++++++++++++++++---- printbuf.c | 2 +- test_parse_int64.c | 6 ++++++ test_parse_int64.expected | 5 ++++- 8 files changed, 43 insertions(+), 41 deletions(-) diff --git a/json_object.c b/json_object.c index c2b6fe2..2b6dad4 100644 --- a/json_object.c +++ b/json_object.c @@ -43,7 +43,6 @@ static const char* json_type_name[] = { "object", "array", "string", - "int64", }; #endif /* REFCOUNT_DEBUG */ @@ -306,8 +305,6 @@ boolean json_object_get_boolean(struct json_object *jso) case json_type_boolean: return jso->o.c_boolean; case json_type_int: - return (jso->o.c_int != 0); - case json_type_int64: return (jso->o.c_int64 != 0); case json_type_double: return (jso->o.c_double != 0); @@ -324,10 +321,6 @@ boolean json_object_get_boolean(struct json_object *jso) static int json_object_int_to_json_string(struct json_object* jso, struct printbuf *pb) { - return sprintbuf(pb, "%d", jso->o.c_int); -} - -static int json_object_int64_to_json_string(struct json_object* jso, struct printbuf *pb) { return sprintbuf(pb, "%"PRId64, jso->o.c_int64); } @@ -336,7 +329,7 @@ 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_int = i; + jso->o.c_int64 = i; return jso; } @@ -355,13 +348,11 @@ int32_t json_object_get_int(struct json_object *jso) */ if (json_parse_int64(jso->o.c_string, &cint64) != 0) return 0; /* whoops, it didn't work. */ - o_type = json_type_int64; + o_type = json_type_int; } switch(jso->o_type) { case json_type_int: - return jso->o.c_int; - case json_type_int64: /* Make sure we return the correct values for out of range numbers. */ if (cint64 <= INT32_MIN) return INT32_MIN; @@ -380,9 +371,9 @@ int32_t json_object_get_int(struct json_object *jso) struct json_object* json_object_new_int64(int64_t i) { - struct json_object *jso = json_object_new(json_type_int64); + struct json_object *jso = json_object_new(json_type_int); if(!jso) return NULL; - jso->_to_json_string = &json_object_int64_to_json_string; + jso->_to_json_string = &json_object_int_to_json_string; jso->o.c_int64 = i; return jso; } @@ -394,8 +385,6 @@ int64_t json_object_get_int64(struct json_object *jso) if(!jso) return 0; switch(jso->o_type) { case json_type_int: - return (int64_t)jso->o.c_int; - case json_type_int64: return jso->o.c_int64; case json_type_double: return (int64_t)jso->o.c_double; @@ -435,8 +424,6 @@ double json_object_get_double(struct json_object *jso) case json_type_double: return jso->o.c_double; case json_type_int: - return jso->o.c_int; - case json_type_int64: return jso->o.c_int64; case json_type_boolean: return jso->o.c_boolean; diff --git a/json_object.h b/json_object.h index cea4c81..9a44c6e 100644 --- a/json_object.h +++ b/json_object.h @@ -47,7 +47,6 @@ typedef enum json_type { json_type_object, json_type_array, json_type_string, - json_type_int64 } json_type; /* reference counting functions */ @@ -75,7 +74,6 @@ extern void json_object_put(struct json_object *obj); json_type_object, json_type_array, json_type_string, - json_type_int64, */ extern int json_object_is_type(struct json_object *obj, enum json_type type); @@ -89,7 +87,6 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); json_type_object, json_type_array, json_type_string, - json_type_int64, */ extern enum json_type json_object_get_type(struct json_object *obj); @@ -252,15 +249,17 @@ extern boolean 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_int64 +/** Create a new empty json_object of type json_type_int * @param i the integer - * @returns a json_object of type json_type_int64 + * @returns a json_object of type json_type_int */ extern struct json_object* json_object_new_int64(int64_t i); @@ -271,6 +270,10 @@ extern struct json_object* json_object_new_int64(int64_t i); * double objects will return their integer conversion. Strings will be * parsed as an integer. If no conversion exists then 0 is returned. * + * 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 */ diff --git a/json_object_private.h b/json_object_private.h index a0f9845..04f510a 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -30,7 +30,6 @@ struct json_object union data { boolean c_boolean; double c_double; - int32_t c_int; int64_t c_int64; struct lh_table *c_object; struct array_list *c_array; diff --git a/json_tokener.c b/json_tokener.c index dbaacaa..da414e7 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -204,7 +204,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_eatws: /* Advance until we change state */ - while (isspace(c)) { + while (isspace((int)c)) { if ((!ADVANCE_CHAR(str, tok)) || (!POP_CHAR(c, tok))) goto out; } @@ -547,17 +547,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, int64_t num64; double numd; if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { - // Decode the type based on the value range to keep compatibilty - // with code that checks the type of objects. i.e. this: - // json_object_get_type(o) == json_type_int - // will continue to work. - // The other option would be to eliminate any distinction between - // int and int64 types, but that would change the ABI of - // json_object_get_int(). - if (num64 < INT32_MAX && num64 > INT32_MIN) - current = json_object_new_int(num64); - else - current = json_object_new_int64(num64); + 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 { diff --git a/json_util.c b/json_util.c index 0dcd6d5..9eca953 100644 --- a/json_util.c +++ b/json_util.c @@ -10,6 +10,7 @@ */ #include "config.h" +#undef realloc #include #include @@ -131,7 +132,7 @@ int json_parse_int64(const char *buf, int64_t *retval) int64_t num64; if (sscanf(buf, "%" SCNd64, &num64) != 1) { - printf("Failed to parse, sscanf != 1\n"); + MC_DEBUG("Failed to parse, sscanf != 1\n"); return 1; } const char *buf_skip_space = buf; @@ -144,9 +145,11 @@ int json_parse_int64(const char *buf, int64_t *retval) buf_skip_space++; orig_has_neg = 1; } - // Skip leading zeros - while (*buf_skip_space == '0' && *buf_skip_space) + // 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) { @@ -171,7 +174,7 @@ int json_parse_int64(const char *buf, int64_t *retval) 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(buf_skip_space[buf_cmp_len]) + isdigit((int)buf_skip_space[buf_cmp_len]) ) ) { @@ -188,3 +191,14 @@ int json_parse_int64(const char *buf, int64_t *retval) *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 diff --git a/printbuf.c b/printbuf.c index 97366c3..6ed1e94 100644 --- a/printbuf.c +++ b/printbuf.c @@ -123,7 +123,7 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) would have been written - this code handles both cases. */ if(size == -1 || size > 127) { va_start(ap, msg); - if((size = vasprintf(&t, msg, ap)) == -1) { va_end(ap); return -1; } + if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } va_end(ap); printbuf_memappend(p, t, size); free(t); diff --git a/test_parse_int64.c b/test_parse_int64.c index 42d4575..0893356 100644 --- a/test_parse_int64.c +++ b/test_parse_int64.c @@ -29,6 +29,12 @@ int main() checkit("x"); + checkit("0"); + checkit("-0"); + + checkit("00000000"); + checkit("-00000000"); + checkit("1"); strcpy(buf, "2147483647"); // aka INT32_MAX diff --git a/test_parse_int64.expected b/test_parse_int64.expected index 2d01ca7..23a9803 100644 --- a/test_parse_int64.expected +++ b/test_parse_int64.expected @@ -1,5 +1,8 @@ -Failed to parse, sscanf != 1 buf=x parseit=1, value=-666 +buf=0 parseit=0, value=0 +buf=-0 parseit=0, value=0 +buf=00000000 parseit=0, value=0 +buf=-00000000 parseit=0, value=0 buf=1 parseit=0, value=1 buf=2147483647 parseit=0, value=2147483647 buf=-1 parseit=0, value=-1 From 5644272f038417ad6bf4851a05e0273b9c630275 Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Tue, 7 Dec 2010 23:22:33 +0000 Subject: [PATCH 051/276] set svn:ignore and .gitignore to skip intermediate build files git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@61 327403b1-1117-474d-bef2-5cb71233fd97 --- .gitignore | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a4cab25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.deps +.libs +aclocal.m4 +autom4te.cache +config.guess +config.h +config.log +config.status +config.sub +configure +depcomp +install-sh +json.pc +libtool +ltmain.sh +Makefile +Makefile.in +missing +stamp-h1 +test1 +test2 +test4 +testSubDir +test_parse_int64 \ No newline at end of file From a503ee8217a9912f3c58acae33cf3d1d840dab6c Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Wed, 8 Dec 2010 03:52:07 +0000 Subject: [PATCH 052/276] add json_tokener_parse_verbose, and return NULL on parser errors git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@62 327403b1-1117-474d-bef2-5cb71233fd97 --- bits.h | 3 ++- json_tokener.c | 18 +++++++++++++++++- json_tokener.h | 3 ++- test1.c | 15 +++++++++++++-- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/bits.h b/bits.h index f308da3..c8cbbc8 100644 --- a/bits.h +++ b/bits.h @@ -22,6 +22,7 @@ #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) #define error_ptr(error) ((void*)error) -#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) +#define error_description(error) (json_tokener_errors[error]) +#define is_error(ptr) (ptr == NULL) #endif diff --git a/json_tokener.c b/json_tokener.c index da414e7..df106b1 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -115,11 +115,27 @@ struct json_object* json_tokener_parse(const char *str) tok = json_tokener_new(); obj = json_tokener_parse_ex(tok, str, -1); if(tok->err != json_tokener_success) - obj = (struct json_object*)error_ptr(-tok->err); + obj = NULL; json_tokener_free(tok); 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(); + obj = json_tokener_parse_ex(tok, str, -1); + *error = tok->err; + if(tok->err != json_tokener_success) { + obj = NULL; + } + + json_tokener_free(tok); + return obj; +} + #if !HAVE_STRNDUP /* CAW: compliant version of strndup() */ diff --git a/json_tokener.h b/json_tokener.h index 7d40b40..162a152 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -76,7 +76,7 @@ struct json_tokener char *str; struct printbuf *pb; int depth, is_double, st_pos, char_offset; - ptrdiff_t err; + enum json_tokener_error err; unsigned int ucs_char; char quote_char; struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; @@ -88,6 +88,7 @@ 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); extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len); diff --git a/test1.c b/test1.c index a3cc6d9..ac1b882 100644 --- a/test1.c +++ b/test1.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "json.h" @@ -135,11 +136,21 @@ int main(int argc, char **argv) printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + enum json_tokener_error error = json_tokener_success; + new_obj = json_tokener_parse_verbose("{ foo }", &error); + assert (error == json_tokener_error_parse_object_key_name); + assert (new_obj == NULL); + new_obj = json_tokener_parse("{ foo }"); - if(is_error(new_obj)) printf("got error as expected\n"); + assert (new_obj == NULL); + + // if(is_error(new_obj)) printf("got error as expected\n"); new_obj = json_tokener_parse("foo"); - if(is_error(new_obj)) printf("got error as expected\n"); + assert (new_obj == NULL); + new_obj = json_tokener_parse_verbose("foo", &error); + assert (new_obj == NULL); + assert (error == json_tokener_error_parse_boolean); new_obj = json_tokener_parse("{ \"foo"); if(is_error(new_obj)) printf("got error as expected\n"); From ac601b5b5f9bc76200a37f39a47a62d414708aa2 Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Fri, 14 Jan 2011 17:23:06 +0000 Subject: [PATCH 053/276] update json_object_new_string_len, json_escape_str (internal). Writer handles \x00 correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added parse_null test. This does not change anything with how the parser handles \u0000 or null characters This commit is addapted from one by Adomas PaltanaviÄius git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@63 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 7 +++++-- json_object.c | 41 ++++++++++++++++++++++++++--------------- json_object.h | 10 ++++++++++ json_object_private.h | 5 ++++- test_null.c | 35 +++++++++++++++++++++++++++++++++++ test_null.expected | 2 ++ test_null.test | 12 ++++++++++++ 7 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 test_null.c create mode 100644 test_null.expected create mode 100644 test_null.test diff --git a/Makefile.am b/Makefile.am index dc920f8..dc8b348 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -46,7 +46,10 @@ test4_LDADD = $(lib_LTLIBRARIES) test_parse_int64_SOURCES = test_parse_int64.c test_parse_int64_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test +test_null_SOURCES = test_null.c +test_null_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/json_object.c b/json_object.c index 2b6dad4..8f1a67e 100644 --- a/json_object.c +++ b/json_object.c @@ -83,15 +83,13 @@ static void json_object_fini(void) { /* string escaping */ -static int json_escape_str(struct printbuf *pb, char *str) +static int json_escape_str(struct printbuf *pb, char *str, int len) { int pos = 0, start_offset = 0; unsigned char c; - do { + while (len--) { c = str[pos]; switch(c) { - case '\0': - break; case '\b': case '\n': case '\r': @@ -120,7 +118,7 @@ static int json_escape_str(struct printbuf *pb, char *str) start_offset = ++pos; } else pos++; } - } while(c); + } if(pos - start_offset > 0) printbuf_memappend(pb, str + start_offset, pos - start_offset); return 0; @@ -218,7 +216,7 @@ static int json_object_object_to_json_string(struct json_object* jso, json_object_object_foreachC(jso, iter) { if(i) sprintbuf(pb, ","); sprintbuf(pb, " \""); - json_escape_str(pb, iter.key); + 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); @@ -309,7 +307,7 @@ boolean json_object_get_boolean(struct json_object *jso) case json_type_double: return (jso->o.c_double != 0); case json_type_string: - return (strlen(jso->o.c_string) != 0); + return (jso->o.c_string.len != 0); default: return FALSE; } @@ -346,7 +344,7 @@ int32_t json_object_get_int(struct json_object *jso) * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(jso->o.c_string, &cint64) != 0) + if (json_parse_int64(jso->o.c_string.str, &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -391,7 +389,7 @@ int64_t json_object_get_int64(struct json_object *jso) case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if (json_parse_int64(jso->o.c_string, &cint) == 0) return cint; + if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint; default: return 0; } @@ -428,7 +426,7 @@ double json_object_get_double(struct json_object *jso) case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if(sscanf(jso->o.c_string, "%lf", &cdouble) == 1) return cdouble; + if(sscanf(jso->o.c_string.str, "%lf", &cdouble) == 1) return cdouble; default: return 0.0; } @@ -441,14 +439,14 @@ 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); + 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); + free(jso->o.c_string.str); json_object_generic_delete(jso); } @@ -458,7 +456,8 @@ struct json_object* json_object_new_string(const char *s) if(!jso) return NULL; jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string = strdup(s); + jso->o.c_string.str = strdup(s); + jso->o.c_string.len = strlen(s); return jso; } @@ -468,7 +467,9 @@ struct json_object* json_object_new_string_len(const char *s, int len) if(!jso) return NULL; jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string = strndup(s, len); + jso->o.c_string.str = malloc(len); + memcpy(jso->o.c_string.str, (void *)s, len); + jso->o.c_string.len = len; return jso; } @@ -477,12 +478,22 @@ 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; + 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 */ diff --git a/json_object.h b/json_object.h index 9a44c6e..d8fdc29 100644 --- a/json_object.h +++ b/json_object.h @@ -337,6 +337,16 @@ extern struct json_object* json_object_new_string_len(const char *s, int len); */ 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 diff --git a/json_object_private.h b/json_object_private.h index 04f510a..c7f604b 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -33,7 +33,10 @@ struct json_object int64_t c_int64; struct lh_table *c_object; struct array_list *c_array; - char *c_string; + struct { + char *str; + int len; + } c_string; } o; }; diff --git a/test_null.c b/test_null.c new file mode 100644 index 0000000..73729b8 --- /dev/null +++ b/test_null.c @@ -0,0 +1,35 @@ +/* +* Tests if binary strings are supported. +*/ + +#include +#include +#include "config.h" + +#include "json_inttypes.h" +#include "json_object.h" + +int main() { + // this test has a space after the null character. check that it's still included + const char *input = " \0 "; + const char *expected = "\" \\u0000 \""; + struct json_object *string = json_object_new_string_len(input, 3); + const char *json = json_object_to_json_string(string); + + int strings_match = !strcmp( expected, json); + int retval = 0; + if (strings_match) { + printf("JSON write result is correct: %s\n", json); + printf("PASS\n"); + } else { + printf("JSON write result doesn't match expected string\n"); + printf("expected string: "); + printf("%s\n", expected); + printf("parsed string: "); + printf("%s\n", json); + printf("FAIL\n"); + retval=1; + } + json_object_put(string); + return retval; +} diff --git a/test_null.expected b/test_null.expected new file mode 100644 index 0000000..fd7b479 --- /dev/null +++ b/test_null.expected @@ -0,0 +1,2 @@ +JSON write result is correct: " \u0000 " +PASS diff --git a/test_null.test b/test_null.test new file mode 100644 index 0000000..469ec64 --- /dev/null +++ b/test_null.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_null +exit $? From c096f5a7d77bcf89261cacf24d320184b4d698d1 Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Fri, 14 Jan 2011 18:02:00 +0000 Subject: [PATCH 054/276] readme updates git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@64 327403b1-1117-474d-bef2-5cb71233fd97 --- NEWS | 1 - README | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 NEWS diff --git a/NEWS b/NEWS deleted file mode 100644 index 41e843b..0000000 --- a/NEWS +++ /dev/null @@ -1 +0,0 @@ -News diff --git a/README b/README index beeba53..8eb0795 100644 --- a/README +++ b/README @@ -1,16 +1,18 @@ Building on Unix with gcc and autotools -If checking out from CVS: +If checking out from SVN (http://svn.metaparadigm.com/svn/json-c/trunk) or Git (https://github.com/jehiah/json-c): - sh autogen.sh + $ sh autogen.sh -Then configure, make, make install +Then + $ ./configure + $ make + $ make install -Test programs - -To build the test programs run 'make check' +To build and run the test programs run + $ make check Linking to libjson From d1342d6f2d79651026dc3ee4c2da5cc40a50bb5b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 19:24:07 +0000 Subject: [PATCH 055/276] Add a dummy "NEWS" file to automake doesn't complain. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@65 327403b1-1117-474d-bef2-5cb71233fd97 --- NEWS | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 From e2e16011f0839a1861754105b2268588a11776c6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 20:39:07 +0000 Subject: [PATCH 056/276] Fix a bug in json_object_get_int() where calling it on a string type object would always return 0, instead of the actual numerical value of the string. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@66 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 8f1a67e..054657a 100644 --- a/json_object.c +++ b/json_object.c @@ -349,7 +349,7 @@ int32_t json_object_get_int(struct json_object *jso) o_type = json_type_int; } - switch(jso->o_type) { + switch(o_type) { case json_type_int: /* Make sure we return the correct values for out of range numbers. */ if (cint64 <= INT32_MIN) From 886c4fbebfd0d276235277059193e6aad18fe259 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 20:40:49 +0000 Subject: [PATCH 057/276] Add a json_type_to_name() function which returns a string that describes the type. Useful for logging. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@67 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 19 +++---------------- json_object.h | 1 + json_util.c | 23 +++++++++++++++++++++++ json_util.h | 6 ++++++ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/json_object.c b/json_object.c index 054657a..f0d4324 100644 --- a/json_object.c +++ b/json_object.c @@ -34,18 +34,6 @@ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdef"; -#ifdef REFCOUNT_DEBUG -static const char* json_type_name[] = { - "null", - "boolean", - "double", - "int", - "object", - "array", - "string", -}; -#endif /* REFCOUNT_DEBUG */ - static void json_object_generic_delete(struct json_object* jso); static struct json_object* json_object_new(enum json_type o_type); @@ -71,7 +59,7 @@ static void json_object_fini(void) { 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_name[obj->o_type], obj); + MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj); } } } @@ -150,7 +138,7 @@ static void json_object_generic_delete(struct json_object* jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", - json_type_name[jso->o_type], jso); + json_type_to_name(jso->o_type), jso); lh_table_delete(json_object_table, jso); #endif /* REFCOUNT_DEBUG */ printbuf_free(jso->_pb); @@ -168,7 +156,7 @@ static struct json_object* json_object_new(enum json_type o_type) 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_name[jso->o_type], jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); #endif /* REFCOUNT_DEBUG */ return jso; } @@ -186,7 +174,6 @@ enum json_type json_object_get_type(struct json_object *jso) return jso->o_type; } - /* json_object_to_json_string */ const char* json_object_to_json_string(struct json_object *jso) diff --git a/json_object.h b/json_object.h index d8fdc29..29a408d 100644 --- a/json_object.h +++ b/json_object.h @@ -40,6 +40,7 @@ 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, diff --git a/json_util.c b/json_util.c index 9eca953..dab3d8c 100644 --- a/json_util.c +++ b/json_util.c @@ -202,3 +202,26 @@ void* rpl_realloc(void* p, size_t 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_util.h b/json_util.h index fbfcb14..a77305e 100644 --- a/json_util.h +++ b/json_util.h @@ -25,6 +25,12 @@ 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 From 41e67d0f6f371baf1f3f5678c4f362e8c7f15e3b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 20:42:25 +0000 Subject: [PATCH 058/276] Add a test_cast test case. This checks that the casting that is implied when calling the various json_object_get_FOO() functions on a differently typed object works correctly. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@68 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 7 +++-- test_cast.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ test_cast.expected | 39 ++++++++++++++++++++++++++++ test_cast.test | 12 +++++++++ 4 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 test_cast.c create mode 100644 test_cast.expected create mode 100755 test_cast.test diff --git a/Makefile.am b/Makefile.am index dc8b348..97fedd6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -49,7 +49,10 @@ test_parse_int64_LDADD = $(lib_LTLIBRARIES) test_null_SOURCES = test_null.c test_null_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test +test_cast_SOURCES = test_cast.c +test_cast_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/test_cast.c b/test_cast.c new file mode 100644 index 0000000..6459250 --- /dev/null +++ b/test_cast.c @@ -0,0 +1,64 @@ +/* + * Tests if casting within the json_object_get_* functions work correctly. + */ + +#include +#include +#include +#include "config.h" + +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + +static void getit(struct json_object *new_obj, const char *field); + +int main(int argc, char **argv) +{ + const char *input = "{\n\ + \"string_of_digits\": \"123\",\n\ + \"regular_number\": 222,\n\ + \"decimal_number\": 99.55,\n\ + \"boolean_true\": true,\n\ + \"boolean_false\": false,\n\ + \"big_number\": 2147483649,\n\ + }"; + /* Note: 2147483649 = INT_MAX + 2 */ + + struct json_object *new_obj; + + new_obj = json_tokener_parse(input); + printf("Parsed input: %s\n", input); + printf("Result is %s\n", (new_obj == NULL) ? "NULL (error!)" : "not NULL"); + if (!new_obj) + return 1; // oops, we failed. + + getit(new_obj, "string_of_digits"); + getit(new_obj, "regular_number"); + getit(new_obj, "decimal_number"); + getit(new_obj, "boolean_true"); + getit(new_obj, "boolean_false"); + getit(new_obj, "big_number"); + + json_object_put(new_obj); + + return 0; +} + +static void getit(struct json_object *new_obj, const char *field) +{ + struct json_object *o = json_object_object_get(new_obj, field); + + enum json_type o_type = json_object_get_type(o); + printf("new_obj.%s json_object_get_type()=%s\n", field, + json_type_to_name(o_type)); + printf("new_obj.%s json_object_get_int()=%d\n", field, + json_object_get_int(o)); + printf("new_obj.%s json_object_get_int64()=%" PRId64 "\n", field, + json_object_get_int64(o)); + printf("new_obj.%s json_object_get_boolean()=%d\n", field, + json_object_get_boolean(o)); + printf("new_obj.%s json_object_get_double()=%f\n", field, + json_object_get_double(o)); +} diff --git a/test_cast.expected b/test_cast.expected new file mode 100644 index 0000000..d079e04 --- /dev/null +++ b/test_cast.expected @@ -0,0 +1,39 @@ +Parsed input: { + "string_of_digits": "123", + "regular_number": 222, + "decimal_number": 99.55, + "boolean_true": true, + "boolean_false": false, + "big_number": 2147483649, + } +Result is not NULL +new_obj.string_of_digits json_object_get_type()=string +new_obj.string_of_digits json_object_get_int()=123 +new_obj.string_of_digits json_object_get_int64()=123 +new_obj.string_of_digits json_object_get_boolean()=1 +new_obj.string_of_digits json_object_get_double()=123.000000 +new_obj.regular_number json_object_get_type()=int +new_obj.regular_number json_object_get_int()=222 +new_obj.regular_number json_object_get_int64()=222 +new_obj.regular_number json_object_get_boolean()=1 +new_obj.regular_number json_object_get_double()=222.000000 +new_obj.decimal_number json_object_get_type()=double +new_obj.decimal_number json_object_get_int()=99 +new_obj.decimal_number json_object_get_int64()=99 +new_obj.decimal_number json_object_get_boolean()=1 +new_obj.decimal_number json_object_get_double()=99.550000 +new_obj.boolean_true json_object_get_type()=boolean +new_obj.boolean_true json_object_get_int()=1 +new_obj.boolean_true json_object_get_int64()=1 +new_obj.boolean_true json_object_get_boolean()=1 +new_obj.boolean_true json_object_get_double()=1.000000 +new_obj.boolean_false json_object_get_type()=boolean +new_obj.boolean_false json_object_get_int()=0 +new_obj.boolean_false json_object_get_int64()=0 +new_obj.boolean_false json_object_get_boolean()=0 +new_obj.boolean_false json_object_get_double()=0.000000 +new_obj.big_number json_object_get_type()=int +new_obj.big_number json_object_get_int()=2147483647 +new_obj.big_number json_object_get_int64()=2147483649 +new_obj.big_number json_object_get_boolean()=1 +new_obj.big_number json_object_get_double()=2147483649.000000 diff --git a/test_cast.test b/test_cast.test new file mode 100755 index 0000000..2102467 --- /dev/null +++ b/test_cast.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_cast +exit $? From 0354e19c31a82f153408195c5c0805bddfc1ac7e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 21:09:30 +0000 Subject: [PATCH 059/276] Bump the version to 0.10, since that's what we were at. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@69 327403b1-1117-474d-bef2-5cb71233fd97 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 8f0fff3..7e2bbc8 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.9, [michael@metaparadigm.com]) +AC_INIT([json-c], 0.10, [michael@metaparadigm.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 7a593a0fa755326775296b7cc4b08ace02d87948 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 21:12:17 +0000 Subject: [PATCH 060/276] Bump up the libtool library version to "1:0:1" (aka libjson.0.1.0) since the API has been extended, but is still backwards compatible.. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@70 327403b1-1117-474d-bef2-5cb71233fd97 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 97fedd6..fe4846d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ libjsoninclude_HEADERS = \ linkhash.h \ printbuf.h -libjson_la_LDFLAGS = -version-info 0:1:0 +libjson_la_LDFLAGS = -version-info 1:0:1 libjson_la_SOURCES = \ arraylist.c \ From 20707f4e1447b754136c8215602dac104b1898ed Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 21:17:50 +0000 Subject: [PATCH 061/276] Note a few recent changes in the ChangeLog. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@71 327403b1-1117-474d-bef2-5cb71233fd97 --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6f54e13..5d2c9af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ 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 From a37ddcff2d66414a023d4f550a314d08fb8819f2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 21:19:55 +0000 Subject: [PATCH 062/276] Note the json-c home page in the README file. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@72 327403b1-1117-474d-bef2-5cb71233fd97 --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index 8eb0795..09947ba 100644 --- a/README +++ b/README @@ -1,5 +1,8 @@ Building on Unix with gcc and autotools +Home page for json-c: + http://oss.metaparadigm.com/json-c/ + If checking out from SVN (http://svn.metaparadigm.com/svn/json-c/trunk) or Git (https://github.com/jehiah/json-c): $ sh autogen.sh From 1910225b7c258b5552f5e5e79458389492267953 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 May 2011 21:28:11 +0000 Subject: [PATCH 063/276] Set the svn:executable property so running the test_null test works properly. git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@73 327403b1-1117-474d-bef2-5cb71233fd97 --- test_null.test | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test_null.test diff --git a/test_null.test b/test_null.test old mode 100644 new mode 100755 From 43d2f417c70b9a9845122fd3f69708c6dc47efd1 Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Wed, 25 May 2011 04:49:20 +0000 Subject: [PATCH 064/276] move definition of json_object_iter to public header to enable external use of json_object_object_foreachC Patch from Rick Moran git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@74 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.h | 8 ++++++++ json_object_private.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/json_object.h b/json_object.h index 29a408d..9f9ca40 100644 --- a/json_object.h +++ b/json_object.h @@ -27,6 +27,14 @@ extern "C" { 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 boolean; diff --git a/json_object_private.h b/json_object_private.h index c7f604b..ceca58c 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -40,14 +40,6 @@ struct json_object } o; }; -/* CAW: added for ANSI C iteration correctness */ -struct json_object_iter -{ - char *key; - struct json_object *val; - struct lh_entry *entry; -}; - #ifdef __cplusplus } #endif From 276123efe09dde04a864317a3c273e4bd2b4fd26 Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Thu, 26 May 2011 01:34:52 +0000 Subject: [PATCH 065/276] handle NULL passed to json_objct_object_get Patch via Nikola Pajkovsky git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@75 327403b1-1117-474d-bef2-5cb71233fd97 --- json_object.c | 1 + 1 file changed, 1 insertion(+) diff --git a/json_object.c b/json_object.c index f0d4324..fc52f5c 100644 --- a/json_object.c +++ b/json_object.c @@ -256,6 +256,7 @@ void json_object_object_add(struct json_object* jso, const char *key, struct json_object* json_object_object_get(struct json_object* jso, const char *key) { + if(!jso) return NULL; return (struct json_object*) lh_table_lookup(jso->o.c_object, key); } From e6c76dab668b762418e45512cf5140eec812f9a1 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 14 Jun 2011 10:04:24 +0800 Subject: [PATCH 066/276] Update README files with pointers to new github repo and googlegroups mailing list --- README | 7 +++-- README-WIN32.html | 9 +----- README.html | 70 +++++++++++++++++++++++------------------------ 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/README b/README index 09947ba..05ec274 100644 --- a/README +++ b/README @@ -1,10 +1,13 @@ -Building on Unix with gcc and autotools +Building on Unix with git, gcc and autotools Home page for json-c: http://oss.metaparadigm.com/json-c/ -If checking out from SVN (http://svn.metaparadigm.com/svn/json-c/trunk) or Git (https://github.com/jehiah/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 diff --git a/README-WIN32.html b/README-WIN32.html index 678fc9d..28fc7d8 100644 --- a/README-WIN32.html +++ b/README-WIN32.html @@ -1,6 +1,4 @@ - + JSON-C - A JSON implementation in C - Win32 specific notes @@ -45,11 +43,6 @@ Added cast and mask to suffice size_t v. unsigned int conversion correctness -

Anonymous Subversion

-

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

-

Copyright Metaparadigm Pte. Ltd. 2004, 2005. Michael - Clark -

This program is free software; you can redistribute it and/or modify it under the terms of the MIT License. See COPYING for details.


diff --git a/README.html b/README.html index 743a4b3..dc696af 100644 --- a/README.html +++ b/README.html @@ -1,36 +1,34 @@ - - - - JSON-C - A JSON implementation in C - - - -

JSON-C - A JSON implementation in C

-

Latest release: json-c-0.9.tar.gz

-

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.

-

Minimal documentation exists here, - Although you are probably better reading the example code in test1.c.

-

To setup JSON-C to build on your system please run configure before - compiling. If you are on Win32 and are not using the VS project file, be sure - to rename config.h.win32 to config.h before building.

-

Win32 specific notes can be found here.

-

Please send bug reports to michael@metaparadigm.com

-

Please send Win32 bug reports to christopher.watford@gmail.com

-

Anonymous Subversion

-

# svn co http://svn.metaparadigm.com/svn/json-c/trunk json-c

-

This program is free software; you can redistribute it and/or modify it under - the terms of the MIT License. See COPYING for details.

-

Mailing Lists

- -
-

Copyright Metaparadigm Pte. Ltd. 2009. Michael Clark -

- - + + + + JSON-C - A JSON implementation in C + + + +

JSON-C - A JSON implementation in C

+ +

Overview

+

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.

+ +

Building

+

To setup JSON-C to build on your system please run configure and make.

+

If you are on Win32 and are not using the VS project file, be sure + to rename config.h.win32 to config.h before building.

+ +

Documentation

+

Doxygen generated documentation exists here + and Win32 specific notes can be found here.

+ +

GIT Reposository

+

git clone https://github.com/json-c/json-c.git

+ +

Mailing List

+ Send email to json-c <at> googlegroups <dot> com

+ +

License

+

This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..

+
+ + From 06e52abedb6da7193820bdbe2860aabc0dc749f2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 14 Jun 2011 09:56:00 -0500 Subject: [PATCH 067/276] Add Jehiah and myself to the list of authors. --- AUTHORS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index 38f2ce0..b389989 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,5 @@ Michael Clark +Jehiah Czebotar +Eric Haszlakiewicz C. Watford (christopher.watford@gmail.com) + From a8ffbe97b0414ce62fd2d697dcf9e76c7514362a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 14 Jun 2011 10:01:27 -0500 Subject: [PATCH 068/276] Add an initial (incomplete) release checklist. --- RELEASE_CHECKLIST.txt | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 RELEASE_CHECKLIST.txt diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt new file mode 100644 index 0000000..1a8d555 --- /dev/null +++ b/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 + From c43871c86693f34ae143da2d53a3370c670e5554 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 7 Oct 2011 21:07:18 +0200 Subject: [PATCH 069/276] Add new json_object_array_sort function - uses libc's qsort to sort the arraylist - add test in test1.c --- arraylist.c | 7 +++++++ arraylist.h | 3 +++ json_object.c | 5 +++++ json_object.h | 10 ++++++++++ test1.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ test1.expected | 14 ++++++++++++++ 6 files changed, 83 insertions(+) diff --git a/arraylist.c b/arraylist.c index cd04eea..9a673d6 100644 --- a/arraylist.c +++ b/arraylist.c @@ -87,6 +87,13 @@ 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) { diff --git a/arraylist.h b/arraylist.h index bc85c80..4f3113c 100644 --- a/arraylist.h +++ b/arraylist.h @@ -46,6 +46,9 @@ 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 diff --git a/json_object.c b/json_object.c index fc52f5c..482c5e3 100644 --- a/json_object.c +++ b/json_object.c @@ -534,6 +534,11 @@ struct array_list* json_object_get_array(struct json_object *jso) } } +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); diff --git a/json_object.h b/json_object.h index 9f9ca40..d56d12c 100644 --- a/json_object.h +++ b/json_object.h @@ -195,6 +195,16 @@ extern struct array_list* json_object_get_array(struct json_object *obj); */ 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 diff --git a/test1.c b/test1.c index ac1b882..2a4daf0 100644 --- a/test1.c +++ b/test1.c @@ -6,6 +6,29 @@ #include "json.h" +static int sort_fn (const void *j1, const void *j2) +{ + json_object **jso1, **jso2; + int i1, i2; + + jso1 = j1; + jso2 = j2; + if (!*jso1 && !*jso2) { + return 0; + } + if (!*jso1) { + return -1; + } + if (!*jso2) { + return 1; + } + + i1 = json_object_get_int(*jso1); + i2 = json_object_get_int(*jso2); + + return i1 - i2; +} + int main(int argc, char **argv) { json_tokener *tok; @@ -45,6 +68,27 @@ int main(int argc, char **argv) } printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + json_object_put(my_array); + + my_array = json_object_new_array(); + json_object_array_add(my_array, json_object_new_int(3)); + json_object_array_add(my_array, json_object_new_int(1)); + json_object_array_add(my_array, json_object_new_int(2)); + json_object_array_put_idx(my_array, 4, json_object_new_int(0)); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) { + json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + json_object_array_sort(my_array, sort_fn); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) { + json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + my_object = json_object_new_object(); json_object_object_add(my_object, "abc", json_object_new_int(12)); json_object_object_add(my_object, "foo", json_object_new_string("bar")); diff --git a/test1.expected b/test1.expected index e38ef50..aad9af0 100644 --- a/test1.expected +++ b/test1.expected @@ -13,6 +13,20 @@ my_array= [3]=null [4]=5 my_array.to_string()=[ 1, 2, 3, null, 5 ] +my_array= + [0]=3 + [1]=1 + [2]=2 + [3]=null + [4]=0 +my_array.to_string()=[ 3, 1, 2, null, 0 ] +my_array= + [0]=null + [1]=0 + [2]=1 + [3]=2 + [4]=3 +my_array.to_string()=[ null, 0, 1, 2, 3 ] my_object= abc: 12 foo: "bar" From 7ec34c9b392eb1c2ca21b3812cc6eb2b597f345d Mon Sep 17 00:00:00 2001 From: Federico Culloca Date: Sun, 30 Oct 2011 12:13:15 +0100 Subject: [PATCH 070/276] Added capitalized charaters to json_hex_chars --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 482c5e3..bc09d65 100644 --- a/json_object.c +++ b/json_object.c @@ -32,7 +32,7 @@ /* #define REFCOUNT_DEBUG 1 */ const char *json_number_chars = "0123456789.+-eE"; -const char *json_hex_chars = "0123456789abcdef"; +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); From a577ba376fcbd39ce1e5c7ca4533203386fed916 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Fri, 25 Nov 2011 23:43:25 +0200 Subject: [PATCH 071/276] Add -no-undefined to the libtool flags This allows building DLLs for windows - libtool doesn't even try to do that unless this flag is specified. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index fe4846d..0e8b303 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ libjsoninclude_HEADERS = \ linkhash.h \ printbuf.h -libjson_la_LDFLAGS = -version-info 1:0:1 +libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined libjson_la_SOURCES = \ arraylist.c \ From db050901fac07c9e46e0e606fc6ac2a6dc032560 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Wed, 18 Jan 2012 17:01:19 -0800 Subject: [PATCH 072/276] json_tokener_parse(): avoid possible NULL deref --- json_tokener.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index df106b1..1921de6 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -113,6 +113,8 @@ struct json_object* json_tokener_parse(const char *str) struct json_object* obj; tok = json_tokener_new(); + if (!tok) + return NULL; obj = json_tokener_parse_ex(tok, str, -1); if(tok->err != json_tokener_success) obj = NULL; From 6a231e4b414bc0fde02b4b6a66929302bd8ce6f6 Mon Sep 17 00:00:00 2001 From: John Arbash Meinel Date: Wed, 1 Feb 2012 09:27:49 +0100 Subject: [PATCH 073/276] Some updates to make the code compatible with VC 9 (2008) VC 9 doesn't support late variable declarations, and doesn't have inttypes so we need some direct definitions of a couple of more types. --- .gitignore | 4 +++- json_inttypes.h | 3 +++ json_object.c | 7 +++++-- json_util.c | 9 ++++++--- printbuf.c | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index a4cab25..6acd819 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,6 @@ test1 test2 test4 testSubDir -test_parse_int64 \ No newline at end of file +test_parse_int64 +Debug +Release diff --git a/json_inttypes.h b/json_inttypes.h index 1cbafc2..1f3e4d2 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -5,6 +5,9 @@ #if defined(_MSC_VER) && _MSC_VER < 1600 /* 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 PRId64 "I64d" #define SCNd64 "I64d" diff --git a/json_object.c b/json_object.c index bc09d65..65c1f6c 100644 --- a/json_object.c +++ b/json_object.c @@ -321,10 +321,13 @@ struct json_object* json_object_new_int(int32_t i) int32_t json_object_get_int(struct json_object *jso) { + int64_t cint64; + enum json_type o_type; + if(!jso) return 0; - enum json_type o_type = jso->o_type; - int64_t cint64 = jso->o.c_int64; + o_type = jso->o_type; + cint64 = jso->o.c_int64; if (o_type == json_type_string) { diff --git a/json_util.c b/json_util.c index dab3d8c..c6db882 100644 --- a/json_util.c +++ b/json_util.c @@ -130,13 +130,15 @@ int json_object_to_file(char *filename, struct json_object *obj) 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; } - const char *buf_skip_space = buf; - int orig_has_neg = 0; + buf_skip_space = buf; + orig_has_neg = 0; // Skip leading spaces while (isspace((int)*buf_skip_space) && *buf_skip_space) buf_skip_space++; @@ -156,6 +158,7 @@ int json_parse_int64(const char *buf, int64_t *retval) char buf_cmp[100]; char *buf_cmp_start = buf_cmp; int recheck_has_neg = 0; + int buf_cmp_len; snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); if (*buf_cmp_start == '-') { @@ -164,7 +167,7 @@ int json_parse_int64(const char *buf, int64_t *retval) } // No need to skip leading spaces or zeros here. - int buf_cmp_len = strlen(buf_cmp_start); + buf_cmp_len = strlen(buf_cmp_start); /** * If the sign is different, or * some of the digits are different, or diff --git a/printbuf.c b/printbuf.c index 6ed1e94..e8902c8 100644 --- a/printbuf.c +++ b/printbuf.c @@ -65,7 +65,7 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) return size; } -#if !HAVE_VSNPRINTF && defined(WIN32) +#if !HAVE_VSNPRINTF && defined(_MSC_VER) # define vsnprintf _vsnprintf #elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ # error Need vsnprintf! From 44f0f622527aa7b3801dbbe867566d5f5a8c8a29 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 15 Feb 2012 19:37:04 -0600 Subject: [PATCH 074/276] Issue#10: add some const qualifiers so test1 compiles again. --- test1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test1.c b/test1.c index 2a4daf0..1ca4db9 100644 --- a/test1.c +++ b/test1.c @@ -8,7 +8,7 @@ static int sort_fn (const void *j1, const void *j2) { - json_object **jso1, **jso2; + json_object * const *jso1, * const *jso2; int i1, i2; jso1 = j1; From b21b1378053285b3204857e87879fb3dc0197f8d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 15 Feb 2012 20:44:54 -0600 Subject: [PATCH 075/276] Include json_inttypes.h in json_object.h since we use types like int32_t in the API and some systems need that header to compile. As part of this create a public json_config.h with a custom define to decide whether to include inttypes.h to avoid conflicting with other projects config.h header. --- Makefile.am | 6 ++++++ config.h.in | 12 +++++++++++- configure.in | 2 ++ json_config.h.in | 3 +++ json_inttypes.h | 4 +++- json_object.h | 2 ++ 6 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 json_config.h.in diff --git a/Makefile.am b/Makefile.am index 0e8b303..e31da77 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,6 +13,7 @@ libjsoninclude_HEADERS = \ bits.h \ debug.h \ json.h \ + json_config.h \ json_inttypes.h \ json_object.h \ json_object_private.h \ @@ -21,6 +22,11 @@ libjsoninclude_HEADERS = \ 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 = \ diff --git a/config.h.in b/config.h.in index 83ab797..04f5dc5 100644 --- a/config.h.in +++ b/config.h.in @@ -80,6 +80,13 @@ /* 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 @@ -95,6 +102,9 @@ /* 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 @@ -113,5 +123,5 @@ /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc -/* Define to `unsigned' if does not define. */ +/* Define to `unsigned int' if does not define. */ #undef size_t diff --git a/configure.in b/configure.in index 7e2bbc8..7334319 100644 --- a/configure.in +++ b/configure.in @@ -11,8 +11,10 @@ AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) # 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 diff --git a/json_config.h.in b/json_config.h.in new file mode 100644 index 0000000..7888e02 --- /dev/null +++ b/json_config.h.in @@ -0,0 +1,3 @@ + +/* Define to 1 if you have the header file. */ +#undef JSON_C_HAVE_INTTYPES_H diff --git a/json_inttypes.h b/json_inttypes.h index 1f3e4d2..b71bb09 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -2,6 +2,8 @@ #ifndef _json_inttypes_h_ #define _json_inttypes_h_ +#include "json_config.h" + #if defined(_MSC_VER) && _MSC_VER < 1600 /* Anything less than Visual Studio C++ 10 is missing stdint.h and inttypes.h */ @@ -14,7 +16,7 @@ typedef __int64 int64_t; #else -#ifdef HAVE_INTTYPES_H +#ifdef JSON_C_HAVE_INTTYPES_H #include #endif /* inttypes.h includes stdint.h */ diff --git a/json_object.h b/json_object.h index d56d12c..e4f4c45 100644 --- a/json_object.h +++ b/json_object.h @@ -12,6 +12,8 @@ #ifndef _json_object_h_ #define _json_object_h_ +#include "json_inttypes.h" + #ifdef __cplusplus extern "C" { #endif From 2f9091f55962ac64c2aedcd3287e9b280fce0b6a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 22 Feb 2012 08:24:40 -0600 Subject: [PATCH 076/276] Add json_tokener_get_error() and json_tokener_error_desc() to better encapsulate the process of retrieving errors while parsing. Add documentation for the json_tokener_parse_ex() function. --- json_tokener.c | 13 ++++++++ json_tokener.h | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index 1921de6..6d973ec 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -43,6 +43,7 @@ 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", @@ -60,6 +61,18 @@ const char* json_tokener_errors[] = { "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) diff --git a/json_tokener.h b/json_tokener.h index 162a152..be7f87d 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -82,13 +82,102 @@ struct json_tokener 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_tokeners_errors(enum json_tokener_error jerr); + +/** + * @b XXX do not use json_tokener_errors directly. + * After v0.10 this will be removed. + * + * See json_tokeners_errors() 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_errors[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); From 37e74674769d2ae224ad52b1a866eb38c00e2821 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Mon, 26 Mar 2012 14:29:31 -0700 Subject: [PATCH 077/276] Rename boolean type to json_bool In building large systems, there are often clashes over the preferred base type to use for bool/boolean. At least one experience has been with a 3rd party proprietary library which can not be changed. In that case, boolean was a synonym for unsigned char and used widely in packed structures. --- json_object.c | 4 ++-- json_object.h | 20 ++++++++++---------- json_object_private.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/json_object.c b/json_object.c index 65c1f6c..7848630 100644 --- a/json_object.c +++ b/json_object.c @@ -275,7 +275,7 @@ static int json_object_boolean_to_json_string(struct json_object* jso, else return sprintbuf(pb, "false"); } -struct json_object* json_object_new_boolean(boolean b) +struct json_object* json_object_new_boolean(json_bool b) { struct json_object *jso = json_object_new(json_type_boolean); if(!jso) return NULL; @@ -284,7 +284,7 @@ struct json_object* json_object_new_boolean(boolean b) return jso; } -boolean json_object_get_boolean(struct json_object *jso) +json_bool json_object_get_boolean(struct json_object *jso) { if(!jso) return FALSE; switch(jso->o_type) { diff --git a/json_object.h b/json_object.h index e4f4c45..1ee9fb0 100644 --- a/json_object.h +++ b/json_object.h @@ -21,10 +21,10 @@ extern "C" { #define JSON_OBJECT_DEF_HASH_ENTRIES 16 #undef FALSE -#define FALSE ((boolean)0) +#define FALSE ((json_bool)0) #undef TRUE -#define TRUE ((boolean)1) +#define TRUE ((json_bool)1) extern const char *json_number_chars; extern const char *json_hex_chars; @@ -39,7 +39,7 @@ struct json_object_iter /* forward structure definitions */ -typedef int boolean; +typedef int json_bool; typedef struct printbuf printbuf; typedef struct lh_table lh_table; typedef struct array_list array_list; @@ -245,26 +245,26 @@ extern int json_object_array_put_idx(struct json_object *obj, int idx, extern struct json_object* json_object_array_get_idx(struct json_object *obj, int idx); -/* boolean type methods */ +/* json_bool type methods */ /** Create a new empty json_object of type json_type_boolean - * @param b a boolean TRUE or FALSE (0 or 1) + * @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(boolean b); +extern struct json_object* json_object_new_boolean(json_bool b); -/** Get the boolean value of a json_object +/** Get the json_bool value of a json_object * - * The type is coerced to a boolean if the passed object is not a boolean. + * 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 boolean + * @returns a json_bool */ -extern boolean json_object_get_boolean(struct json_object *obj); +extern json_bool json_object_get_boolean(struct json_object *obj); /* int type methods */ diff --git a/json_object_private.h b/json_object_private.h index ceca58c..112ce76 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -28,7 +28,7 @@ struct json_object int _ref_count; struct printbuf *_pb; union data { - boolean c_boolean; + json_bool c_boolean; double c_double; int64_t c_int64; struct lh_table *c_object; From 3620cba6d0fa109d9a27e1a1158438fcbff43760 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:52:59 -0500 Subject: [PATCH 078/276] Perform better error checking in json_tokener_parse_verbose and rewrite json_tokener_parse to use that instead of json_tokener_parse_ex. Fix a typo in the string represenations of the json_tokener_error_depth error (s/to deep/too deep/) --- json_tokener.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 6d973ec..04950b5 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -47,7 +47,7 @@ static const char* json_false_str = "false"; const char* json_tokener_errors[] = { "success", "continue", - "nesting to deep", + "nesting too deep", "unexpected end of data", "unexpected character", "null expected", @@ -122,17 +122,10 @@ void json_tokener_reset(struct json_tokener *tok) struct json_object* json_tokener_parse(const char *str) { - struct json_tokener* tok; - struct json_object* obj; - - tok = json_tokener_new(); - if (!tok) - return NULL; - obj = json_tokener_parse_ex(tok, str, -1); - if(tok->err != json_tokener_success) - obj = NULL; - json_tokener_free(tok); - return obj; + 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) @@ -141,9 +134,13 @@ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokene 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; } From d3c37b82a6de97c40a2403f2df0fd66f3d9fb616 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:55:52 -0500 Subject: [PATCH 079/276] Ignore several more files, include .o's, .lo's, etc... --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 6acd819..21b927d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,10 +17,16 @@ Makefile Makefile.in missing stamp-h1 +stamp-h2 test1 test2 test4 testSubDir test_parse_int64 +test_cast +test_null Debug Release +*.lo +*.o +libjson.la From aef439a1750a69c4721df50b83d696218a60db49 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 13:47:28 -0500 Subject: [PATCH 080/276] Adjust json_object_is_type and json_object_get_type so they return json_type_null for NULL objects. --- json_object.c | 4 ++++ json_object.h | 2 ++ test_cast.c | 42 ++++++++++++++++++++++++++++++++++++++++++ test_cast.expected | 17 +++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/json_object.c b/json_object.c index 7848630..ef54ecd 100644 --- a/json_object.c +++ b/json_object.c @@ -166,11 +166,15 @@ static struct json_object* json_object_new(enum json_type o_type) 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; } diff --git a/json_object.h b/json_object.h index 1ee9fb0..e9898f4 100644 --- a/json_object.h +++ b/json_object.h @@ -79,6 +79,7 @@ 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, @@ -92,6 +93,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); * Get the type of the json_object * @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, diff --git a/test_cast.c b/test_cast.c index 6459250..aad44d0 100644 --- a/test_cast.c +++ b/test_cast.c @@ -1,5 +1,6 @@ /* * Tests if casting within the json_object_get_* functions work correctly. + * Also checks the json_object_get_type and json_object_is_type functions. */ #include @@ -13,6 +14,8 @@ #include "json_util.h" static void getit(struct json_object *new_obj, const char *field); +static void checktype_header(void); +static void checktype(struct json_object *new_obj, const char *field); int main(int argc, char **argv) { @@ -23,6 +26,7 @@ int main(int argc, char **argv) \"boolean_true\": true,\n\ \"boolean_false\": false,\n\ \"big_number\": 2147483649,\n\ + \"a_null\": null,\n\ }"; /* Note: 2147483649 = INT_MAX + 2 */ @@ -40,6 +44,19 @@ int main(int argc, char **argv) getit(new_obj, "boolean_true"); getit(new_obj, "boolean_false"); getit(new_obj, "big_number"); + getit(new_obj, "a_null"); + + // Now check the behaviour of the json_object_is_type() function. + printf("\n================================\n"); + checktype_header(); + checktype(new_obj, NULL); + checktype(new_obj, "string_of_digits"); + checktype(new_obj, "regular_number"); + checktype(new_obj, "decimal_number"); + checktype(new_obj, "boolean_true"); + checktype(new_obj, "boolean_false"); + checktype(new_obj, "big_number"); + checktype(new_obj, "a_null"); json_object_put(new_obj); @@ -62,3 +79,28 @@ static void getit(struct json_object *new_obj, const char *field) printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); } + +static void checktype_header() +{ + printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n", + json_type_to_name(json_type_null), + json_type_to_name(json_type_boolean), + json_type_to_name(json_type_double), + json_type_to_name(json_type_int), + json_type_to_name(json_type_object), + json_type_to_name(json_type_array), + json_type_to_name(json_type_string)); +} +static void checktype(struct json_object *new_obj, const char *field) +{ + struct json_object *o = field ? json_object_object_get(new_obj, field) : new_obj; + printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n", + field ? "." : " ", field ? field : "", + json_object_is_type(o, json_type_null), + json_object_is_type(o, json_type_boolean), + json_object_is_type(o, json_type_double), + json_object_is_type(o, json_type_int), + json_object_is_type(o, json_type_object), + json_object_is_type(o, json_type_array), + json_object_is_type(o, json_type_string)); +} diff --git a/test_cast.expected b/test_cast.expected index d079e04..76ff823 100644 --- a/test_cast.expected +++ b/test_cast.expected @@ -5,6 +5,7 @@ Parsed input: { "boolean_true": true, "boolean_false": false, "big_number": 2147483649, + "a_null": null, } Result is not NULL new_obj.string_of_digits json_object_get_type()=string @@ -37,3 +38,19 @@ new_obj.big_number json_object_get_int()=2147483647 new_obj.big_number json_object_get_int64()=2147483649 new_obj.big_number json_object_get_boolean()=1 new_obj.big_number json_object_get_double()=2147483649.000000 +new_obj.a_null json_object_get_type()=null +new_obj.a_null json_object_get_int()=0 +new_obj.a_null json_object_get_int64()=0 +new_obj.a_null json_object_get_boolean()=0 +new_obj.a_null json_object_get_double()=0.000000 + +================================ +json_object_is_type: null,boolean,double,int,object,array,string +new_obj : 0,0,0,0,1,0,0 +new_obj.string_of_digits : 0,0,0,0,0,0,1 +new_obj.regular_number : 0,0,0,1,0,0,0 +new_obj.decimal_number : 0,0,1,0,0,0,0 +new_obj.boolean_true : 0,1,0,0,0,0,0 +new_obj.boolean_false : 0,1,0,0,0,0,0 +new_obj.big_number : 0,0,0,1,0,0,0 +new_obj.a_null : 1,0,0,0,0,0,0 From 64c0ca3690f98e978fd2fc8c6ca645243c27e3db Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 17:33:58 -0500 Subject: [PATCH 081/276] Define a LH_LOAD_FACTOR constant and note the range that it can be set to. Change the resize check from "count > size" to "count >= size" to avoid a potential infinite loop with high load factors and a full hash table. --- linkhash.c | 2 +- linkhash.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/linkhash.c b/linkhash.c index 3a9ba0e..88c0a7c 100644 --- a/linkhash.c +++ b/linkhash.c @@ -125,7 +125,7 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) unsigned long h, n; t->inserts++; - if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2); + if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); h = t->hash_fn(k); n = h % t->size; diff --git a/linkhash.h b/linkhash.h index 90f219d..9d89460 100644 --- a/linkhash.h +++ b/linkhash.h @@ -21,6 +21,13 @@ extern "C" { */ #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 */ From 6ff0817bac01f070dbae172df0bb01d617e2fae2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:47:47 -0500 Subject: [PATCH 082/276] Mention json_type_to_name() in the docs for json_object_get_type(). --- json_object.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/json_object.h b/json_object.h index e9898f4..72a8708 100644 --- a/json_object.h +++ b/json_object.h @@ -90,7 +90,9 @@ extern void json_object_put(struct json_object *obj); extern int json_object_is_type(struct json_object *obj, enum json_type type); /** - * Get the type of the json_object + * 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), From 1489b081a729d055579471d6b0906274c4e7b8af Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:49:58 -0500 Subject: [PATCH 083/276] For the prototype for json_tokener_error_desc(). --- json_tokener.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_tokener.h b/json_tokener.h index be7f87d..d104c75 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -88,13 +88,13 @@ struct json_tokener * * @return a generic error message is returned if an invalid error value is provided. */ -const char *json_tokeners_errors(enum json_tokener_error jerr); +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_tokeners_errors() instead. + * See json_tokener_error_desc() instead. */ extern const char* json_tokener_errors[]; @@ -162,7 +162,7 @@ do { } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); if (jerr != json_tokener_success) { - fprintf(stderr, "Error: %s\n", json_tokener_errors[jerr]); + 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 From c5c623a5461bbba31049b10d369f0125090bebec Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:51:39 -0500 Subject: [PATCH 084/276] Split the json_tokener_parse tests off from test1 into their own test and add several more cases to check various incremental parsing situations. --- .gitignore | 1 + Makefile.am | 7 +- test1.c | 108 ------------------ test1.expected | 23 ---- test_parse.c | 270 ++++++++++++++++++++++++++++++++++++++++++++ test_parse.expected | 46 ++++++++ test_parse.test | 12 ++ 7 files changed, 334 insertions(+), 133 deletions(-) create mode 100644 test_parse.c create mode 100644 test_parse.expected create mode 100755 test_parse.test diff --git a/.gitignore b/.gitignore index 21b927d..091ae7a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ test2 test4 testSubDir test_parse_int64 +test_parse test_cast test_null Debug diff --git a/Makefile.am b/Makefile.am index e31da77..07e610d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -58,7 +58,10 @@ test_null_LDADD = $(lib_LTLIBRARIES) test_cast_SOURCES = test_cast.c test_cast_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test +test_parse_SOURCES = test_parse.c +test_parse_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/test1.c b/test1.c index 1ca4db9..e1e411d 100644 --- a/test1.c +++ b/test1.c @@ -31,9 +31,7 @@ static int sort_fn (const void *j1, const void *j2) int main(int argc, char **argv) { - json_tokener *tok; json_object *my_string, *my_int, *my_object, *my_array; - json_object *new_obj; int i; MC_SET_DEBUG(1); @@ -104,112 +102,6 @@ int main(int argc, char **argv) } printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); - new_obj = json_tokener_parse("\"\003\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("/* hello */\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("// hello\n\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("null"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("True"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12.3"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[null]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[false]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{}"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - enum json_tokener_error error = json_tokener_success; - new_obj = json_tokener_parse_verbose("{ foo }", &error); - assert (error == json_tokener_error_parse_object_key_name); - assert (new_obj == NULL); - - new_obj = json_tokener_parse("{ foo }"); - assert (new_obj == NULL); - - // if(is_error(new_obj)) printf("got error as expected\n"); - - new_obj = json_tokener_parse("foo"); - assert (new_obj == NULL); - new_obj = json_tokener_parse_verbose("foo", &error); - assert (new_obj == NULL); - assert (error == json_tokener_error_parse_boolean); - - new_obj = json_tokener_parse("{ \"foo"); - if(is_error(new_obj)) printf("got error as expected\n"); - - /* test incremental parsing */ - tok = json_tokener_new(); - new_obj = json_tokener_parse_ex(tok, "{ \"foo", 6); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\": {\"bar", 8); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\":13}}", 6); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - json_tokener_free(tok); - json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); diff --git a/test1.expected b/test1.expected index aad9af0..6653fe0 100644 --- a/test1.expected +++ b/test1.expected @@ -33,26 +33,3 @@ my_object= bool0: false bool1: true my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } -new_obj.to_string()="\u0003" -new_obj.to_string()="foo" -new_obj.to_string()="foo" -new_obj.to_string()="ABC" -new_obj.to_string()=null -new_obj.to_string()=true -new_obj.to_string()=12 -new_obj.to_string()=12.300000 -new_obj.to_string()=[ "\n" ] -new_obj.to_string()=[ "\nabc\n" ] -new_obj.to_string()=[ null ] -new_obj.to_string()=[ ] -new_obj.to_string()=[ false ] -new_obj.to_string()=[ "abc", null, "def", 12 ] -new_obj.to_string()={ } -new_obj.to_string()={ "foo": "bar" } -new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } -new_obj.to_string()={ "foo": [ null, "foo" ] } -new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } -got error as expected -got error as expected -got error as expected -new_obj.to_string()={ "foo": { "bar": 13 } } diff --git a/test_parse.c b/test_parse.c new file mode 100644 index 0000000..0040760 --- /dev/null +++ b/test_parse.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +#include "json.h" +#include "json_tokener.h" + +static void test_basic_parse(void); +static void test_verbose_parse(void); +static void test_incremental_parse(void); + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + test_basic_parse(); + printf("==================================\n"); + test_verbose_parse(); + printf("==================================\n"); + test_incremental_parse(); + printf("==================================\n"); +} + +static void test_basic_parse() +{ + json_object *new_obj; + + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[false]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); +} + +static void test_verbose_parse() +{ + json_object *new_obj; + enum json_tokener_error error = json_tokener_success; + + new_obj = json_tokener_parse_verbose("{ foo }", &error); + assert (error == json_tokener_error_parse_object_key_name); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("{ foo }"); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("foo"); + assert (new_obj == NULL); + new_obj = json_tokener_parse_verbose("foo", &error); + assert (new_obj == NULL); + + /* b/c the string starts with 'f' parsing return a boolean error */ + assert (error == json_tokener_error_parse_boolean); + + printf("json_tokener_parse_versbose() OK\n"); +} + +struct incremental_step { + const char *string_to_parse; + int length; + int char_offset; + enum json_tokener_error expected_error; + int reset_tokener; +} incremental_steps[] = { + + /* Check that full json messages can be parsed, both w/ and w/o a reset */ + { "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 }, + { "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 }, + { "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 }, + + /* Check a basic incremental parse */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}", -1, -1, json_tokener_success, 1 }, + + /* Check that json_tokener_reset actually resets */ + { "{ \"foo", -1, -1, json_tokener_continue, 1 }, + { ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check incremental parsing with trailing characters */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}XXXX", 10, 6, json_tokener_success, 0 }, + { "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check that trailing characters can change w/o a reset */ + { "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 }, + { "\"Y\"", -1, -1, json_tokener_success, 1 }, + + /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ + { "1", 1, 1, json_tokener_continue, 0 }, + { "2", 2, 1, json_tokener_success, 0 }, + + /* Strings have a well defined end point, so we can stop at the quote */ + { "\"blue\"", -1, -1, json_tokener_success, 0 }, + + { "[1,2,3]", -1, -1, json_tokener_success, 0 }, + + /* This behaviour doesn't entirely follow the json spec, but until we have + a way to specify how strict to be we follow Postel's Law and be liberal + in what we accept (up to a point). */ + { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, + { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, + + { NULL, json_tokener_success }, +}; + +static void test_incremental_parse() +{ + json_object *new_obj; + enum json_tokener_error jerr; + json_tokener *tok; + const char *string_to_parse; + int ii; + int num_ok, num_error; + + num_ok = 0; + num_error = 0; + + printf("Starting incremental tests.\n"); + + string_to_parse = "{ \"foo"; /* } */ + printf("json_tokener_parse(%s) ... ", string_to_parse); + new_obj = json_tokener_parse(string_to_parse); + if (new_obj == NULL) printf("got error as expected\n"); + + /* test incremental parsing in various forms */ + tok = json_tokener_new(); + for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++) + { + int this_step_ok = 0; + struct incremental_step *step = &incremental_steps[ii]; + int length = step->length; + int expected_char_offset = step->char_offset; + if (length == -1) + length = strlen(step->string_to_parse); + if (expected_char_offset == -1) + expected_char_offset = length; + + printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ", + step->string_to_parse, length); + new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length); + + jerr = json_tokener_get_error(tok); + if (step->expected_error != json_tokener_success) + { + if (new_obj != NULL) + printf("ERROR: invalid object returned: %s\n", + json_object_to_json_string(new_obj)); + else if (jerr != step->expected_error) + printf("ERROR: got wrong error: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr)); + this_step_ok = 1; + } + } + else + { + if (new_obj == NULL) + printf("ERROR: expected valid object, instead: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got object of type [%s]: %s\n", + json_type_to_name(json_object_get_type(new_obj)), + json_object_to_json_string(new_obj)); + this_step_ok = 1; + } + } + + if (new_obj) + json_object_put(new_obj); + + if (step->reset_tokener) + json_tokener_reset(tok); + + if (this_step_ok) + num_ok++; + else + num_error++; + } + + json_tokener_free(tok); + + printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error); + + return; +} diff --git a/test_parse.expected b/test_parse.expected new file mode 100644 index 0000000..2481bde --- /dev/null +++ b/test_parse.expected @@ -0,0 +1,46 @@ +new_obj.to_string()="\u0003" +new_obj.to_string()="foo" +new_obj.to_string()="foo" +new_obj.to_string()="ABC" +new_obj.to_string()=null +new_obj.to_string()=true +new_obj.to_string()=12 +new_obj.to_string()=12.300000 +new_obj.to_string()=[ "\n" ] +new_obj.to_string()=[ "\nabc\n" ] +new_obj.to_string()=[ null ] +new_obj.to_string()=[ ] +new_obj.to_string()=[ false ] +new_obj.to_string()=[ "abc", null, "def", 12 ] +new_obj.to_string()={ } +new_obj.to_string()={ "foo": "bar" } +new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } +new_obj.to_string()={ "foo": [ null, "foo" ] } +new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } +================================== +json_tokener_parse_versbose() OK +================================== +Starting incremental tests. +json_tokener_parse({ "foo) ... got error as expected +json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 } +json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 } +json_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 } +json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" +json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 +json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" +json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character +End Incremental Tests OK=20 ERROR=0 +================================== diff --git a/test_parse.test b/test_parse.test new file mode 100755 index 0000000..70d1c82 --- /dev/null +++ b/test_parse.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_parse +exit $? From d809fa60c5d0bb91d1c444dfa01b9ab5cb22112e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:53:43 -0500 Subject: [PATCH 085/276] Fix a bug in json_tokener_parse_ex when re-using the same tokener to parse multiple objects. Now, json_tokener_reset() does not need to be called after a valid object is parsed. --- json_tokener.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 04950b5..1dc06e4 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -715,7 +715,17 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_eof; } - if(tok->err == json_tokener_success) return json_object_get(current); + 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; From fbd207bd6bf0b8effcda084ca027de2be97aef83 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:00 -0500 Subject: [PATCH 086/276] Remove a few more things in the distclean target to get rid of *all* generated files. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 07e610d..7f1abb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,4 +68,5 @@ TESTS_ENVIRONMENT = top_builddir=$(top_builddir) 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 From 781798ccdfbe56abd5046d3978e29adf10c74c23 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:31 -0500 Subject: [PATCH 087/276] Direct people to send bug reports to the json-c google group. --- config.h.win32 | 2 +- configure.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.h.win32 b/config.h.win32 index 7f7e6ae..ec3a84a 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -12,7 +12,7 @@ /* config.h.win32 Generated by configure. */ #define PACKAGE_STRING "JSON C Library 0.2" -#define PACKAGE_BUGREPORT "michael@metaparadigm.com" +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" #define PACKAGE_NAME "JSON C Library" #define PACKAGE_TARNAME "json-c" #define PACKAGE_VERSION "0.2" diff --git a/configure.in b/configure.in index 7334319..49b3195 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.10, [michael@metaparadigm.com]) +AC_INIT([json-c], 0.10, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 9885b30c0ef4c40117851cf54c9c7e1ee2c1f3a3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:52:59 -0500 Subject: [PATCH 088/276] Perform better error checking in json_tokener_parse_verbose and rewrite json_tokener_parse to use that instead of json_tokener_parse_ex. Fix a typo in the string represenations of the json_tokener_error_depth error (s/to deep/too deep/) --- json_tokener.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 6d973ec..04950b5 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -47,7 +47,7 @@ static const char* json_false_str = "false"; const char* json_tokener_errors[] = { "success", "continue", - "nesting to deep", + "nesting too deep", "unexpected end of data", "unexpected character", "null expected", @@ -122,17 +122,10 @@ void json_tokener_reset(struct json_tokener *tok) struct json_object* json_tokener_parse(const char *str) { - struct json_tokener* tok; - struct json_object* obj; - - tok = json_tokener_new(); - if (!tok) - return NULL; - obj = json_tokener_parse_ex(tok, str, -1); - if(tok->err != json_tokener_success) - obj = NULL; - json_tokener_free(tok); - return obj; + 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) @@ -141,9 +134,13 @@ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokene 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; } From d7db7e81a51282ffc097408aa47927af8d4a39c1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 12:55:52 -0500 Subject: [PATCH 089/276] Ignore several more files, include .o's, .lo's, etc... --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 6acd819..21b927d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,10 +17,16 @@ Makefile Makefile.in missing stamp-h1 +stamp-h2 test1 test2 test4 testSubDir test_parse_int64 +test_cast +test_null Debug Release +*.lo +*.o +libjson.la From e6668b1406de33e29a0f91bc93f448a2423230d2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 13:47:28 -0500 Subject: [PATCH 090/276] Adjust json_object_is_type and json_object_get_type so they return json_type_null for NULL objects. --- json_object.c | 4 ++++ json_object.h | 2 ++ test_cast.c | 42 ++++++++++++++++++++++++++++++++++++++++++ test_cast.expected | 17 +++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/json_object.c b/json_object.c index 7848630..ef54ecd 100644 --- a/json_object.c +++ b/json_object.c @@ -166,11 +166,15 @@ static struct json_object* json_object_new(enum json_type o_type) 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; } diff --git a/json_object.h b/json_object.h index 1ee9fb0..e9898f4 100644 --- a/json_object.h +++ b/json_object.h @@ -79,6 +79,7 @@ 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, @@ -92,6 +93,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); * Get the type of the json_object * @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, diff --git a/test_cast.c b/test_cast.c index 6459250..aad44d0 100644 --- a/test_cast.c +++ b/test_cast.c @@ -1,5 +1,6 @@ /* * Tests if casting within the json_object_get_* functions work correctly. + * Also checks the json_object_get_type and json_object_is_type functions. */ #include @@ -13,6 +14,8 @@ #include "json_util.h" static void getit(struct json_object *new_obj, const char *field); +static void checktype_header(void); +static void checktype(struct json_object *new_obj, const char *field); int main(int argc, char **argv) { @@ -23,6 +26,7 @@ int main(int argc, char **argv) \"boolean_true\": true,\n\ \"boolean_false\": false,\n\ \"big_number\": 2147483649,\n\ + \"a_null\": null,\n\ }"; /* Note: 2147483649 = INT_MAX + 2 */ @@ -40,6 +44,19 @@ int main(int argc, char **argv) getit(new_obj, "boolean_true"); getit(new_obj, "boolean_false"); getit(new_obj, "big_number"); + getit(new_obj, "a_null"); + + // Now check the behaviour of the json_object_is_type() function. + printf("\n================================\n"); + checktype_header(); + checktype(new_obj, NULL); + checktype(new_obj, "string_of_digits"); + checktype(new_obj, "regular_number"); + checktype(new_obj, "decimal_number"); + checktype(new_obj, "boolean_true"); + checktype(new_obj, "boolean_false"); + checktype(new_obj, "big_number"); + checktype(new_obj, "a_null"); json_object_put(new_obj); @@ -62,3 +79,28 @@ static void getit(struct json_object *new_obj, const char *field) printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); } + +static void checktype_header() +{ + printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n", + json_type_to_name(json_type_null), + json_type_to_name(json_type_boolean), + json_type_to_name(json_type_double), + json_type_to_name(json_type_int), + json_type_to_name(json_type_object), + json_type_to_name(json_type_array), + json_type_to_name(json_type_string)); +} +static void checktype(struct json_object *new_obj, const char *field) +{ + struct json_object *o = field ? json_object_object_get(new_obj, field) : new_obj; + printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n", + field ? "." : " ", field ? field : "", + json_object_is_type(o, json_type_null), + json_object_is_type(o, json_type_boolean), + json_object_is_type(o, json_type_double), + json_object_is_type(o, json_type_int), + json_object_is_type(o, json_type_object), + json_object_is_type(o, json_type_array), + json_object_is_type(o, json_type_string)); +} diff --git a/test_cast.expected b/test_cast.expected index d079e04..76ff823 100644 --- a/test_cast.expected +++ b/test_cast.expected @@ -5,6 +5,7 @@ Parsed input: { "boolean_true": true, "boolean_false": false, "big_number": 2147483649, + "a_null": null, } Result is not NULL new_obj.string_of_digits json_object_get_type()=string @@ -37,3 +38,19 @@ new_obj.big_number json_object_get_int()=2147483647 new_obj.big_number json_object_get_int64()=2147483649 new_obj.big_number json_object_get_boolean()=1 new_obj.big_number json_object_get_double()=2147483649.000000 +new_obj.a_null json_object_get_type()=null +new_obj.a_null json_object_get_int()=0 +new_obj.a_null json_object_get_int64()=0 +new_obj.a_null json_object_get_boolean()=0 +new_obj.a_null json_object_get_double()=0.000000 + +================================ +json_object_is_type: null,boolean,double,int,object,array,string +new_obj : 0,0,0,0,1,0,0 +new_obj.string_of_digits : 0,0,0,0,0,0,1 +new_obj.regular_number : 0,0,0,1,0,0,0 +new_obj.decimal_number : 0,0,1,0,0,0,0 +new_obj.boolean_true : 0,1,0,0,0,0,0 +new_obj.boolean_false : 0,1,0,0,0,0,0 +new_obj.big_number : 0,0,0,1,0,0,0 +new_obj.a_null : 1,0,0,0,0,0,0 From 7c4a9640028b6bf4ff635caeea75089cdad1a779 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 17:33:58 -0500 Subject: [PATCH 091/276] Define a LH_LOAD_FACTOR constant and note the range that it can be set to. Change the resize check from "count > size" to "count >= size" to avoid a potential infinite loop with high load factors and a full hash table. --- linkhash.c | 2 +- linkhash.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/linkhash.c b/linkhash.c index 3a9ba0e..88c0a7c 100644 --- a/linkhash.c +++ b/linkhash.c @@ -125,7 +125,7 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) unsigned long h, n; t->inserts++; - if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2); + if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); h = t->hash_fn(k); n = h % t->size; diff --git a/linkhash.h b/linkhash.h index 90f219d..9d89460 100644 --- a/linkhash.h +++ b/linkhash.h @@ -21,6 +21,13 @@ extern "C" { */ #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 */ From 23d0da5870001b6faff76f21ab6dc57a00ae92e3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:47:47 -0500 Subject: [PATCH 092/276] Mention json_type_to_name() in the docs for json_object_get_type(). --- json_object.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/json_object.h b/json_object.h index e9898f4..72a8708 100644 --- a/json_object.h +++ b/json_object.h @@ -90,7 +90,9 @@ extern void json_object_put(struct json_object *obj); extern int json_object_is_type(struct json_object *obj, enum json_type type); /** - * Get the type of the json_object + * 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), From bb7978c95ffbb1afd78767309ef3c30a93ee62ab Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:49:58 -0500 Subject: [PATCH 093/276] For the prototype for json_tokener_error_desc(). --- json_tokener.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_tokener.h b/json_tokener.h index be7f87d..d104c75 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -88,13 +88,13 @@ struct json_tokener * * @return a generic error message is returned if an invalid error value is provided. */ -const char *json_tokeners_errors(enum json_tokener_error jerr); +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_tokeners_errors() instead. + * See json_tokener_error_desc() instead. */ extern const char* json_tokener_errors[]; @@ -162,7 +162,7 @@ do { } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); if (jerr != json_tokener_success) { - fprintf(stderr, "Error: %s\n", json_tokener_errors[jerr]); + 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 From 30c6c4a1be41a59ea9335bc3566371276a72763f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:51:39 -0500 Subject: [PATCH 094/276] Split the json_tokener_parse tests off from test1 into their own test and add several more cases to check various incremental parsing situations. --- .gitignore | 1 + Makefile.am | 7 +- test1.c | 108 ------------------ test1.expected | 23 ---- test_parse.c | 270 ++++++++++++++++++++++++++++++++++++++++++++ test_parse.expected | 46 ++++++++ test_parse.test | 12 ++ 7 files changed, 334 insertions(+), 133 deletions(-) create mode 100644 test_parse.c create mode 100644 test_parse.expected create mode 100755 test_parse.test diff --git a/.gitignore b/.gitignore index 21b927d..091ae7a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ test2 test4 testSubDir test_parse_int64 +test_parse test_cast test_null Debug diff --git a/Makefile.am b/Makefile.am index e31da77..07e610d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse test1_SOURCES = test1.c test1_LDADD = $(lib_LTLIBRARIES) @@ -58,7 +58,10 @@ test_null_LDADD = $(lib_LTLIBRARIES) test_cast_SOURCES = test_cast.c test_cast_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test +test_parse_SOURCES = test_parse.c +test_parse_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/test1.c b/test1.c index 1ca4db9..e1e411d 100644 --- a/test1.c +++ b/test1.c @@ -31,9 +31,7 @@ static int sort_fn (const void *j1, const void *j2) int main(int argc, char **argv) { - json_tokener *tok; json_object *my_string, *my_int, *my_object, *my_array; - json_object *new_obj; int i; MC_SET_DEBUG(1); @@ -104,112 +102,6 @@ int main(int argc, char **argv) } printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); - new_obj = json_tokener_parse("\"\003\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("/* hello */\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("// hello\n\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("null"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("True"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12.3"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[null]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[false]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{}"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - enum json_tokener_error error = json_tokener_success; - new_obj = json_tokener_parse_verbose("{ foo }", &error); - assert (error == json_tokener_error_parse_object_key_name); - assert (new_obj == NULL); - - new_obj = json_tokener_parse("{ foo }"); - assert (new_obj == NULL); - - // if(is_error(new_obj)) printf("got error as expected\n"); - - new_obj = json_tokener_parse("foo"); - assert (new_obj == NULL); - new_obj = json_tokener_parse_verbose("foo", &error); - assert (new_obj == NULL); - assert (error == json_tokener_error_parse_boolean); - - new_obj = json_tokener_parse("{ \"foo"); - if(is_error(new_obj)) printf("got error as expected\n"); - - /* test incremental parsing */ - tok = json_tokener_new(); - new_obj = json_tokener_parse_ex(tok, "{ \"foo", 6); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\": {\"bar", 8); - if(is_error(new_obj)) printf("got error as expected\n"); - new_obj = json_tokener_parse_ex(tok, "\":13}}", 6); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - json_tokener_free(tok); - json_object_put(my_string); json_object_put(my_int); json_object_put(my_object); diff --git a/test1.expected b/test1.expected index aad9af0..6653fe0 100644 --- a/test1.expected +++ b/test1.expected @@ -33,26 +33,3 @@ my_object= bool0: false bool1: true my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } -new_obj.to_string()="\u0003" -new_obj.to_string()="foo" -new_obj.to_string()="foo" -new_obj.to_string()="ABC" -new_obj.to_string()=null -new_obj.to_string()=true -new_obj.to_string()=12 -new_obj.to_string()=12.300000 -new_obj.to_string()=[ "\n" ] -new_obj.to_string()=[ "\nabc\n" ] -new_obj.to_string()=[ null ] -new_obj.to_string()=[ ] -new_obj.to_string()=[ false ] -new_obj.to_string()=[ "abc", null, "def", 12 ] -new_obj.to_string()={ } -new_obj.to_string()={ "foo": "bar" } -new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } -new_obj.to_string()={ "foo": [ null, "foo" ] } -new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } -got error as expected -got error as expected -got error as expected -new_obj.to_string()={ "foo": { "bar": 13 } } diff --git a/test_parse.c b/test_parse.c new file mode 100644 index 0000000..0040760 --- /dev/null +++ b/test_parse.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include + +#include "json.h" +#include "json_tokener.h" + +static void test_basic_parse(void); +static void test_verbose_parse(void); +static void test_incremental_parse(void); + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + test_basic_parse(); + printf("==================================\n"); + test_verbose_parse(); + printf("==================================\n"); + test_incremental_parse(); + printf("==================================\n"); +} + +static void test_basic_parse() +{ + json_object *new_obj; + + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[false]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); +} + +static void test_verbose_parse() +{ + json_object *new_obj; + enum json_tokener_error error = json_tokener_success; + + new_obj = json_tokener_parse_verbose("{ foo }", &error); + assert (error == json_tokener_error_parse_object_key_name); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("{ foo }"); + assert (new_obj == NULL); + + new_obj = json_tokener_parse("foo"); + assert (new_obj == NULL); + new_obj = json_tokener_parse_verbose("foo", &error); + assert (new_obj == NULL); + + /* b/c the string starts with 'f' parsing return a boolean error */ + assert (error == json_tokener_error_parse_boolean); + + printf("json_tokener_parse_versbose() OK\n"); +} + +struct incremental_step { + const char *string_to_parse; + int length; + int char_offset; + enum json_tokener_error expected_error; + int reset_tokener; +} incremental_steps[] = { + + /* Check that full json messages can be parsed, both w/ and w/o a reset */ + { "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 }, + { "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 }, + { "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 }, + + /* Check a basic incremental parse */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}", -1, -1, json_tokener_success, 1 }, + + /* Check that json_tokener_reset actually resets */ + { "{ \"foo", -1, -1, json_tokener_continue, 1 }, + { ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check incremental parsing with trailing characters */ + { "{ \"foo", -1, -1, json_tokener_continue, 0 }, + { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, + { "\":13}}XXXX", 10, 6, json_tokener_success, 0 }, + { "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 }, + + /* Check that trailing characters can change w/o a reset */ + { "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 }, + { "\"Y\"", -1, -1, json_tokener_success, 1 }, + + /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ + { "1", 1, 1, json_tokener_continue, 0 }, + { "2", 2, 1, json_tokener_success, 0 }, + + /* Strings have a well defined end point, so we can stop at the quote */ + { "\"blue\"", -1, -1, json_tokener_success, 0 }, + + { "[1,2,3]", -1, -1, json_tokener_success, 0 }, + + /* This behaviour doesn't entirely follow the json spec, but until we have + a way to specify how strict to be we follow Postel's Law and be liberal + in what we accept (up to a point). */ + { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, + { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, + + { NULL, json_tokener_success }, +}; + +static void test_incremental_parse() +{ + json_object *new_obj; + enum json_tokener_error jerr; + json_tokener *tok; + const char *string_to_parse; + int ii; + int num_ok, num_error; + + num_ok = 0; + num_error = 0; + + printf("Starting incremental tests.\n"); + + string_to_parse = "{ \"foo"; /* } */ + printf("json_tokener_parse(%s) ... ", string_to_parse); + new_obj = json_tokener_parse(string_to_parse); + if (new_obj == NULL) printf("got error as expected\n"); + + /* test incremental parsing in various forms */ + tok = json_tokener_new(); + for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++) + { + int this_step_ok = 0; + struct incremental_step *step = &incremental_steps[ii]; + int length = step->length; + int expected_char_offset = step->char_offset; + if (length == -1) + length = strlen(step->string_to_parse); + if (expected_char_offset == -1) + expected_char_offset = length; + + printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ", + step->string_to_parse, length); + new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length); + + jerr = json_tokener_get_error(tok); + if (step->expected_error != json_tokener_success) + { + if (new_obj != NULL) + printf("ERROR: invalid object returned: %s\n", + json_object_to_json_string(new_obj)); + else if (jerr != step->expected_error) + printf("ERROR: got wrong error: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr)); + this_step_ok = 1; + } + } + else + { + if (new_obj == NULL) + printf("ERROR: expected valid object, instead: %s\n", + json_tokener_error_desc(jerr)); + else if (tok->char_offset != expected_char_offset) + printf("ERROR: wrong char_offset %d != expected %d\n", + tok->char_offset, + expected_char_offset); + else + { + printf("OK: got object of type [%s]: %s\n", + json_type_to_name(json_object_get_type(new_obj)), + json_object_to_json_string(new_obj)); + this_step_ok = 1; + } + } + + if (new_obj) + json_object_put(new_obj); + + if (step->reset_tokener) + json_tokener_reset(tok); + + if (this_step_ok) + num_ok++; + else + num_error++; + } + + json_tokener_free(tok); + + printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error); + + return; +} diff --git a/test_parse.expected b/test_parse.expected new file mode 100644 index 0000000..2481bde --- /dev/null +++ b/test_parse.expected @@ -0,0 +1,46 @@ +new_obj.to_string()="\u0003" +new_obj.to_string()="foo" +new_obj.to_string()="foo" +new_obj.to_string()="ABC" +new_obj.to_string()=null +new_obj.to_string()=true +new_obj.to_string()=12 +new_obj.to_string()=12.300000 +new_obj.to_string()=[ "\n" ] +new_obj.to_string()=[ "\nabc\n" ] +new_obj.to_string()=[ null ] +new_obj.to_string()=[ ] +new_obj.to_string()=[ false ] +new_obj.to_string()=[ "abc", null, "def", 12 ] +new_obj.to_string()={ } +new_obj.to_string()={ "foo": "bar" } +new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } +new_obj.to_string()={ "foo": [ null, "foo" ] } +new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } +================================== +json_tokener_parse_versbose() OK +================================== +Starting incremental tests. +json_tokener_parse({ "foo) ... got error as expected +json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 } +json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 } +json_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 } +json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" +json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 +json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" +json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] +json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character +End Incremental Tests OK=20 ERROR=0 +================================== diff --git a/test_parse.test b/test_parse.test new file mode 100755 index 0000000..70d1c82 --- /dev/null +++ b/test_parse.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_parse +exit $? From f30a9ace77fd87d08b326688919abbeb3c8717d4 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 22:53:43 -0500 Subject: [PATCH 095/276] Fix a bug in json_tokener_parse_ex when re-using the same tokener to parse multiple objects. Now, json_tokener_reset() does not need to be called after a valid object is parsed. --- json_tokener.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 04950b5..1dc06e4 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -715,7 +715,17 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_eof; } - if(tok->err == json_tokener_success) return json_object_get(current); + 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; From a7bd85caba88db2e91e7a4f74ca655c995d12df0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:00 -0500 Subject: [PATCH 096/276] Remove a few more things in the distclean target to get rid of *all* generated files. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 07e610d..7f1abb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,4 +68,5 @@ TESTS_ENVIRONMENT = top_builddir=$(top_builddir) 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 From 2b5929bb13eb2086466a8dfa5266ad5d6ff8c9d6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 31 Mar 2012 23:17:31 -0500 Subject: [PATCH 097/276] Direct people to send bug reports to the json-c google group. --- config.h.win32 | 2 +- configure.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.h.win32 b/config.h.win32 index 7f7e6ae..ec3a84a 100644 --- a/config.h.win32 +++ b/config.h.win32 @@ -12,7 +12,7 @@ /* config.h.win32 Generated by configure. */ #define PACKAGE_STRING "JSON C Library 0.2" -#define PACKAGE_BUGREPORT "michael@metaparadigm.com" +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" #define PACKAGE_NAME "JSON C Library" #define PACKAGE_TARNAME "json-c" #define PACKAGE_VERSION "0.2" diff --git a/configure.in b/configure.in index 7334319..49b3195 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.10, [michael@metaparadigm.com]) +AC_INIT([json-c], 0.10, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) From 2d48543f2ef8caadcbdbd9b3b779664038bf6a2b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 2 Apr 2012 15:39:55 -0500 Subject: [PATCH 098/276] Add a printbuf_memset() function to provide an effecient way to set and append things like whitespace indentation. --- printbuf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++---------- printbuf.h | 13 +++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/printbuf.c b/printbuf.c index e8902c8..b4f7955 100644 --- a/printbuf.c +++ b/printbuf.c @@ -29,6 +29,8 @@ #include "debug.h" #include "printbuf.h" +static int printbuf_extend(struct printbuf *p, int min_size); + struct printbuf* printbuf_new(void) { struct printbuf *p; @@ -45,19 +47,32 @@ struct printbuf* printbuf_new(void) } +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, p->bpos + min_size + 8); +#ifdef PRINTBUF_DEBUG + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d wrsize=%d old_size=%d new_size=%d\n", + p->bpos, 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) { - char *t; if(p->size - p->bpos <= size) { - int new_size = json_max(p->size * 2, p->bpos + size + 8); -#ifdef PRINTBUF_DEBUG - MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, 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; + if (printbuf_extend(p, size) < 0) + return -1; } memcpy(p->buf + p->bpos, buf, size); p->bpos += size; @@ -65,6 +80,26 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) 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 - pb->bpos <= 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 */ diff --git a/printbuf.h b/printbuf.h index 5d4963f..fc8ac61 100644 --- a/printbuf.h +++ b/printbuf.h @@ -50,6 +50,19 @@ do { \ } 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, ...); From 61a154e58b0a13f4d9e4cfb74bd1a8b9655baa3d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:48:15 -0500 Subject: [PATCH 099/276] Remove the "#undef PRINTBUF_DEBUG" from printbuf.h so it can be more easily turned on in the Makefile. --- printbuf.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/printbuf.h b/printbuf.h index fc8ac61..b1bde7f 100644 --- a/printbuf.h +++ b/printbuf.h @@ -20,8 +20,6 @@ extern "C" { #endif -#undef PRINTBUF_DEBUG - struct printbuf { char *buf; int bpos; From 0d79b534568f609a9444c3466ae1f5a2864f702f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:54:25 -0500 Subject: [PATCH 100/276] Fix some bugs with how buffer sizes were being calcuated in printbuf_memset and an off-by-one error in printbuf_memappend. --- printbuf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/printbuf.c b/printbuf.c index b4f7955..b951c7b 100644 --- a/printbuf.c +++ b/printbuf.c @@ -47,6 +47,14 @@ struct printbuf* printbuf_new(void) } +/** + * 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; @@ -55,11 +63,11 @@ static int printbuf_extend(struct printbuf *p, int min_size) if (p->size >= min_size) return 0; - new_size = json_max(p->size * 2, p->bpos + min_size + 8); + new_size = json_max(p->size * 2, min_size + 8); #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, size, p->size, new_size); + "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; @@ -70,8 +78,8 @@ static int printbuf_extend(struct printbuf *p, int min_size) int printbuf_memappend(struct printbuf *p, const char *buf, int size) { - if(p->size - p->bpos <= size) { - if (printbuf_extend(p, size) < 0) + 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); @@ -87,7 +95,7 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) if (offset == -1) offset = pb->bpos; size_needed = offset + len; - if(pb->size - pb->bpos <= size_needed) + if (pb->size < size_needed) { if (printbuf_extend(pb, size_needed) < 0) return -1; From 8310d3634cb3316cc71d0042282574788189e46b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 2 Apr 2012 15:39:55 -0500 Subject: [PATCH 101/276] Add a printbuf_memset() function to provide an effecient way to set and append things like whitespace indentation. --- printbuf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++---------- printbuf.h | 13 +++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/printbuf.c b/printbuf.c index e8902c8..b4f7955 100644 --- a/printbuf.c +++ b/printbuf.c @@ -29,6 +29,8 @@ #include "debug.h" #include "printbuf.h" +static int printbuf_extend(struct printbuf *p, int min_size); + struct printbuf* printbuf_new(void) { struct printbuf *p; @@ -45,19 +47,32 @@ struct printbuf* printbuf_new(void) } +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, p->bpos + min_size + 8); +#ifdef PRINTBUF_DEBUG + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d wrsize=%d old_size=%d new_size=%d\n", + p->bpos, 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) { - char *t; if(p->size - p->bpos <= size) { - int new_size = json_max(p->size * 2, p->bpos + size + 8); -#ifdef PRINTBUF_DEBUG - MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, 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; + if (printbuf_extend(p, size) < 0) + return -1; } memcpy(p->buf + p->bpos, buf, size); p->bpos += size; @@ -65,6 +80,26 @@ int printbuf_memappend(struct printbuf *p, const char *buf, int size) 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 - pb->bpos <= 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 */ diff --git a/printbuf.h b/printbuf.h index 5d4963f..fc8ac61 100644 --- a/printbuf.h +++ b/printbuf.h @@ -50,6 +50,19 @@ do { \ } 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, ...); From 7f3298da8519a1f4be73957ae1eebb3b433dd0ae Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:48:15 -0500 Subject: [PATCH 102/276] Remove the "#undef PRINTBUF_DEBUG" from printbuf.h so it can be more easily turned on in the Makefile. --- printbuf.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/printbuf.h b/printbuf.h index fc8ac61..b1bde7f 100644 --- a/printbuf.h +++ b/printbuf.h @@ -20,8 +20,6 @@ extern "C" { #endif -#undef PRINTBUF_DEBUG - struct printbuf { char *buf; int bpos; From e0fa94ba3151b839104e6b344583ea3385d95daa Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 3 Apr 2012 14:54:25 -0500 Subject: [PATCH 103/276] Fix some bugs with how buffer sizes were being calcuated in printbuf_memset and an off-by-one error in printbuf_memappend. --- printbuf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/printbuf.c b/printbuf.c index b4f7955..b951c7b 100644 --- a/printbuf.c +++ b/printbuf.c @@ -47,6 +47,14 @@ struct printbuf* printbuf_new(void) } +/** + * 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; @@ -55,11 +63,11 @@ static int printbuf_extend(struct printbuf *p, int min_size) if (p->size >= min_size) return 0; - new_size = json_max(p->size * 2, p->bpos + min_size + 8); + new_size = json_max(p->size * 2, min_size + 8); #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " - "bpos=%d wrsize=%d old_size=%d new_size=%d\n", - p->bpos, size, p->size, new_size); + "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; @@ -70,8 +78,8 @@ static int printbuf_extend(struct printbuf *p, int min_size) int printbuf_memappend(struct printbuf *p, const char *buf, int size) { - if(p->size - p->bpos <= size) { - if (printbuf_extend(p, size) < 0) + 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); @@ -87,7 +95,7 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) if (offset == -1) offset = pb->bpos; size_needed = offset + len; - if(pb->size - pb->bpos <= size_needed) + if (pb->size < size_needed) { if (printbuf_extend(pb, size_needed) < 0) return -1; From 21d37061928a494ea629e1b47ccf9f4d7e01f4ee Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 5 Apr 2012 19:33:09 -0700 Subject: [PATCH 104/276] Added explanatory notes to documentation. --- json_object.h | 64 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/json_object.h b/json_object.h index 72a8708..72b1829 100644 --- a/json_object.h +++ b/json_object.h @@ -115,7 +115,14 @@ extern const char* json_object_to_json_string(struct json_object *obj); /* object type methods */ -/** Create a new empty object +/** 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); @@ -130,7 +137,13 @@ extern struct lh_table* json_object_get_object(struct json_object *obj); * * 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 + * 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) @@ -140,6 +153,17 @@ 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 @@ -149,7 +173,9 @@ extern struct json_object* json_object_object_get(struct json_object* obj, /** Delete the given json_object field * - * The reference count will be decremented for the deleted object + * 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 @@ -159,7 +185,8 @@ 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 + * @param val the local name for the json_object* object variable defined in + * the body */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) @@ -293,7 +320,8 @@ extern struct json_object* json_object_new_int64(int64_t i); * * 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. + * 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 @@ -310,6 +338,10 @@ extern int32_t json_object_get_int(struct json_object *obj); * 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 */ @@ -324,14 +356,28 @@ extern int64_t json_object_get_int64(struct json_object *obj); */ extern struct json_object* json_object_new_double(double d); -/** Get the double value of a json_object +/** 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 dboule conversion. Strings will be - * parsed as a double. If no conversion exists then 0.0 is returned. + * 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 an double + * @returns a double floating point number */ extern double json_object_get_double(struct json_object *obj); From 30dd367c0a2467dc292f653ea3afd6ad4c6e034b Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Fri, 30 Mar 2012 12:28:32 -0700 Subject: [PATCH 105/276] Modify install names for library and include files Changing root name of library to json-c, and also the directory where header files are installed to .../jsdon-c/*. This avoids clashes with other implementations of JSON libraries. --- Makefile.am | 10 +++++----- configure.in | 2 +- json.pc.in => json-c.pc.in | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename json.pc.in => json-c.pc.in (67%) diff --git a/Makefile.am b/Makefile.am index 7f1abb1..eafaf6a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,12 +2,12 @@ AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj -lib_LTLIBRARIES = libjson.la +lib_LTLIBRARIES = libjson-c.la pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = json.pc +pkgconfig_DATA = json-c.pc -libjsonincludedir = $(includedir)/json +libjsonincludedir = $(includedir)/json-c libjsoninclude_HEADERS = \ arraylist.h \ bits.h \ @@ -27,9 +27,9 @@ libjsoninclude_HEADERS = \ #libjsonx_include_HEADERS = \ # json_config.h -libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined +libjson_c_la_LDFLAGS = -version-info 1:0:1 -no-undefined -libjson_la_SOURCES = \ +libjson_c_la_SOURCES = \ arraylist.c \ debug.c \ json_object.c \ diff --git a/configure.in b/configure.in index 49b3195..df0d82b 100644 --- a/configure.in +++ b/configure.in @@ -31,5 +31,5 @@ AM_PROG_LIBTOOL AC_OUTPUT([ Makefile -json.pc +json-c.pc ]) diff --git a/json.pc.in b/json-c.pc.in similarity index 67% rename from json.pc.in rename to json-c.pc.in index b3d140b..037739d 100644 --- a/json.pc.in +++ b/json-c.pc.in @@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -Name: json +Name: json-c Description: JSON implementation in C Version: @VERSION@ Requires: -Libs: -L${libdir} -ljson -Cflags: -I${includedir}/json +Libs: -L${libdir} -ljson-c +Cflags: -I${includedir}/json-c From 65f649b7ba6bde1d42d8d9b4051eff47aec04099 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Fri, 30 Mar 2012 12:34:01 -0700 Subject: [PATCH 106/276] Ignoring additional build products --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 091ae7a..5ccc37a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ Release *.lo *.o libjson.la +json-c.pc +json_config.h From ca519fb81735bf8eb7a6cf4ddb77f036efcaac61 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 5 Apr 2012 19:33:09 -0700 Subject: [PATCH 107/276] Added explanatory notes to documentation. --- json_object.h | 73 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/json_object.h b/json_object.h index 72a8708..7b2c4ee 100644 --- a/json_object.h +++ b/json_object.h @@ -63,13 +63,18 @@ typedef enum json_type { /* reference counting functions */ /** - * Increment the reference count of json_object + * 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 + * 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); @@ -115,7 +120,14 @@ extern const char* json_object_to_json_string(struct json_object *obj); /* object type methods */ -/** Create a new empty object +/** 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); @@ -130,7 +142,13 @@ extern struct lh_table* json_object_get_object(struct json_object *obj); * * 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 + * 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) @@ -140,6 +158,17 @@ 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 @@ -149,7 +178,9 @@ extern struct json_object* json_object_object_get(struct json_object* obj, /** Delete the given json_object field * - * The reference count will be decremented for the deleted object + * 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 @@ -159,7 +190,8 @@ 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 + * @param val the local name for the json_object* object variable defined in + * the body */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) @@ -293,7 +325,8 @@ extern struct json_object* json_object_new_int64(int64_t i); * * 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. + * 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 @@ -310,6 +343,10 @@ extern int32_t json_object_get_int(struct json_object *obj); * 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 */ @@ -324,14 +361,28 @@ extern int64_t json_object_get_int64(struct json_object *obj); */ extern struct json_object* json_object_new_double(double d); -/** Get the double value of a json_object +/** 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 dboule conversion. Strings will be - * parsed as a double. If no conversion exists then 0.0 is returned. + * 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 an double + * @returns a double floating point number */ extern double json_object_get_double(struct json_object *obj); From 74d830dc035db05e2d7c4fecc4aff69c2c6d17e7 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 12 Apr 2012 11:40:44 -0700 Subject: [PATCH 108/276] Add JASSERT macro to guarantee aborts --- debug.h | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/debug.h b/debug.h index 59a4dfc..1e09701 100644 --- a/debug.h +++ b/debug.h @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -12,6 +13,8 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ +#include + #ifdef __cplusplus extern "C" { #endif @@ -25,21 +28,40 @@ 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_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) #define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) -#define MC_ERROR(x, ...) mc_error(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_ABORT(x, ...) if (0) mc_abort(x, ##__VA_ARGS__) #define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) -#define MC_ERROR(x, ...) if (0) mc_error(x, ##__VA_ARGS__) #define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) #endif From 4a2cd966f5ef267545ec57f2490e3ec14f47d70f Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 12 Apr 2012 11:43:34 -0700 Subject: [PATCH 109/276] Add NULL-safe lookup function New lh_table_lookup_ex() method protects itself against null pointers and invalid objects being passed in. --- linkhash.c | 17 ++++++++++++++--- linkhash.h | 12 ++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/linkhash.c b/linkhash.c index 88c0a7c..ddedc12 100644 --- a/linkhash.c +++ b/linkhash.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -174,11 +175,21 @@ struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) const void* lh_table_lookup(struct lh_table *t, const void *k) { - struct lh_entry *e = lh_table_lookup_entry(t, k); - if(e) return e->v; - return NULL; + 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) { diff --git a/linkhash.h b/linkhash.h index 9d89460..bbb5488 100644 --- a/linkhash.h +++ b/linkhash.h @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -12,6 +13,8 @@ #ifndef _linkhash_h_ #define _linkhash_h_ +#include "json_object.h" + #ifdef __cplusplus extern "C" { #endif @@ -241,9 +244,18 @@ extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) * @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. From 6917586acfb49d976b9a8a441aaef694a9e2d774 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 12 Apr 2012 11:44:13 -0700 Subject: [PATCH 110/276] Add NULL-safe get object method New json_object_object_get_ex() method protects itself against null pointers and invalid objects being passed in. --- json_object.c | 23 +++++++++++++++++++++-- json_object.h | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index ef54ecd..842ca22 100644 --- a/json_object.c +++ b/json_object.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -24,11 +25,13 @@ #include "json_object.h" #include "json_object_private.h" #include "json_util.h" +#include "json_tokener.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"; @@ -260,8 +263,24 @@ void json_object_object_add(struct json_object* jso, const char *key, struct json_object* json_object_object_get(struct json_object* jso, const char *key) { - if(!jso) return NULL; - return (struct json_object*) lh_table_lookup(jso->o.c_object, 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) diff --git a/json_object.h b/json_object.h index 7b2c4ee..f7ec9ea 100644 --- a/json_object.h +++ b/json_object.h @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -172,10 +173,33 @@ extern void json_object_object_add(struct json_object* obj, const char *key, * @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 From bcfd1f57ac3aeb6b2ce7af89c3130e617ab6e5c0 Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Thu, 12 Apr 2012 09:54:21 -0700 Subject: [PATCH 111/276] Add alternative iterator implementation --- json.h | 2 + json_object_iterator.c | 169 +++++++++++++++++++++++++++ json_object_iterator.h | 254 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+) create mode 100644 json_object_iterator.c create mode 100644 json_object_iterator.h diff --git a/json.h b/json.h index a5a3432..d49715b 100644 --- a/json.h +++ b/json.h @@ -3,6 +3,7 @@ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark + * 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. @@ -23,6 +24,7 @@ extern "C" { #include "json_util.h" #include "json_object.h" #include "json_tokener.h" +#include "json_object_iterator.h" #ifdef __cplusplus } diff --git a/json_object_iterator.c b/json_object_iterator.c new file mode 100644 index 0000000..b887eb2 --- /dev/null +++ b/json_object_iterator.c @@ -0,0 +1,169 @@ +/** +******************************************************************************* +* @file cjson_object_iterator.c +* +* 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. +* +* @brief cjson forces clients to use its private data +* structures for JSON Object iteration. This API +* implementation corrects that by abstracting the +* private cjson details. +* +******************************************************************************* +*/ + +#include +#include + +#include "json.h" +#include "json_object_private.h" + +#include "json_object_iterator.h" + +/** + * How It Works + * + * For each JSON Object, cjson 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 cjson'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); +} + + +/** + * **************************************************************************** + */ +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_object_iterator.h b/json_object_iterator.h new file mode 100644 index 0000000..21feaf5 --- /dev/null +++ b/json_object_iterator.h @@ -0,0 +1,254 @@ +/** +******************************************************************************* +* @file json_object_iterator.h +* +* 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. +* +* @brief cjson forces clients to use its private data +* structures for JSON Object iteration. This API +* corrects that by abstracting the private cjson +* details. +* +* The intention is to add this API (and its +* implementation) to Palm's version of the cjson +* library, at which point it can be removed from the +* Wireless System Framework library implementation. +* +* API attributes: +* * Thread-safe: NO +* * Re-entrant: NO +* +******************************************************************************* +*/ + + +#ifndef JSON_OBJECT_ITERATOR_H +#define JSON_OBJECT_ITERATOR_H + +#include +#include + +#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 intance or the "end" iterator value. + */ +struct json_object_iterator { + const void* opaque_; +}; + + +/** + * forward declaration of cjson'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 cjson 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. + * + * @note WARNING: Any modification of the underlying pair + * invalidates all iterators to that pair. + * + * @param obj JSON Object instance (MUST be of type + * json_type_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 = json_tokener_parse( + * "{'first':'george', 'age':100}"); + * json_object_iter_begin(obj, &it); + * json_object_iter_end(obj, &itEnd); + * while (!json_object_iter_equal(&it, &itEnd)) { + * printf("%s\n", + * json_object_iter_peek_name(&it)); + * json_object_iter_next(&it); + * } + * + * struct json_object* obj = json_tokener_parse( + * "{'first':'george', 'age':100}"); + * struct json_object_iterator it; + * bool iterable = json_object_iter_begin(&it); + * if (iterable) { + * do { + * printf("%s\n", json_object_iter_peek_name(&it)); + * } while (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. + * + * @note 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, memoize the "end" iterator prior + * to any loop. + * + * @param obj JSON Object instance (MUST be of type + * json_type_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 + * + * @note WARNING: Any modification of the underlying pair + * invalidates all iterators to that pair. + * + * @param iter Iterator that references a name/value 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 invalid or + * "end" iterator is passed. + * + * @return const char* Pointer to the name of the rerferenced + * 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 cjson 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 cjson 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 cjson node, + * take a look at json_object_get() and + * json_object_put(). IMPORTANT: cjson 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 + * + * @note 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 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. + */ +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 From 1e89ba68afbf8310b0fa34226a5e730e4118a465 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 10:27:50 -0500 Subject: [PATCH 112/276] Create a tests subdirectory and move one of the test to there. --- Makefile.am | 10 ++++------ Makefile.am.inc | 2 ++ configure.in | 8 +++++++- tests/Makefile.am | 22 ++++++++++++++++++++++ test1.c => tests/test1.c | 0 test1.expected => tests/test1.expected | 0 test1.test => tests/test1.test | 0 7 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 Makefile.am.inc create mode 100644 tests/Makefile.am rename test1.c => tests/test1.c (100%) rename test1.expected => tests/test1.expected (100%) rename test1.test => tests/test1.test (100%) diff --git a/Makefile.am b/Makefile.am index 7f1abb1..cec14fd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ -AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +include Makefile.am.inc EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj +SUBDIRS = . tests lib_LTLIBRARIES = libjson.la @@ -38,10 +39,7 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse - -test1_SOURCES = test1.c -test1_LDADD = $(lib_LTLIBRARIES) +check_PROGRAMS = test2 test4 test_parse_int64 test_null test_cast test_parse test2_SOURCES = test2.c test2_LDADD = $(lib_LTLIBRARIES) @@ -61,7 +59,7 @@ test_cast_LDADD = $(lib_LTLIBRARIES) test_parse_SOURCES = test_parse.c test_parse_LDADD = $(lib_LTLIBRARIES) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test +TESTS = test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST += $(TESTS) testsubdir=testSubDir TESTS_ENVIRONMENT = top_builddir=$(top_builddir) diff --git a/Makefile.am.inc b/Makefile.am.inc new file mode 100644 index 0000000..b1ebce8 --- /dev/null +++ b/Makefile.am.inc @@ -0,0 +1,2 @@ +AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT + diff --git a/configure.in b/configure.in index 49b3195..b2c3cbe 100644 --- a/configure.in +++ b/configure.in @@ -5,6 +5,8 @@ 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. @@ -29,7 +31,11 @@ AC_CHECK_FUNCS(strndup strerror vsnprintf vasprintf open vsyslog strncasecmp) AM_PROG_LIBTOOL -AC_OUTPUT([ +AC_CONFIG_FILES([ Makefile json.pc +tests/Makefile ]) + +AC_OUTPUT + diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..ed5d2a5 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,22 @@ + +include ../Makefile.am.inc + +#lib_LTLIBRARIES = ../libjson.la + +#check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse +check_PROGRAMS = test1 + +#test1_SOURCES = test1.c +#test1_LDADD = $(lib_LTLIBRARIES) +test1_LDADD = $(top_builddir)/libjson.la + +#TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test +TESTS = test1.test +EXTRA_DIST= +EXTRA_DIST += $(TESTS) + +testsubdir=testSubDir +TESTS_ENVIRONMENT = top_builddir=$(top_builddir) + +distclean-local: + -rm -rf $(testsubdir) diff --git a/test1.c b/tests/test1.c similarity index 100% rename from test1.c rename to tests/test1.c diff --git a/test1.expected b/tests/test1.expected similarity index 100% rename from test1.expected rename to tests/test1.expected diff --git a/test1.test b/tests/test1.test similarity index 100% rename from test1.test rename to tests/test1.test From c1b8891a133c64bd46dfee382a47045171e5cdcd Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 10:33:41 -0500 Subject: [PATCH 113/276] Move the rest of the tests into the tests subdirectory. --- Makefile.am | 24 ------------------- tests/Makefile.am | 24 ++++++++++++------- parse_int64.test => tests/parse_int64.test | 0 test-defs.sh => tests/test-defs.sh | 5 ++-- test2.c => tests/test2.c | 0 test2.expected => tests/test2.expected | 0 test2.test => tests/test2.test | 0 test4.c => tests/test4.c | 0 test4.expected => tests/test4.expected | 0 test4.test => tests/test4.test | 0 test_cast.c => tests/test_cast.c | 0 .../test_cast.expected | 0 test_cast.test => tests/test_cast.test | 0 test_null.c => tests/test_null.c | 0 .../test_null.expected | 0 test_null.test => tests/test_null.test | 0 test_parse.c => tests/test_parse.c | 0 .../test_parse.expected | 0 test_parse.test => tests/test_parse.test | 0 .../test_parse_int64.c | 0 .../test_parse_int64.expected | 0 21 files changed, 19 insertions(+), 34 deletions(-) rename parse_int64.test => tests/parse_int64.test (100%) rename test-defs.sh => tests/test-defs.sh (98%) rename test2.c => tests/test2.c (100%) rename test2.expected => tests/test2.expected (100%) rename test2.test => tests/test2.test (100%) rename test4.c => tests/test4.c (100%) rename test4.expected => tests/test4.expected (100%) rename test4.test => tests/test4.test (100%) rename test_cast.c => tests/test_cast.c (100%) rename test_cast.expected => tests/test_cast.expected (100%) rename test_cast.test => tests/test_cast.test (100%) rename test_null.c => tests/test_null.c (100%) rename test_null.expected => tests/test_null.expected (100%) rename test_null.test => tests/test_null.test (100%) rename test_parse.c => tests/test_parse.c (100%) rename test_parse.expected => tests/test_parse.expected (100%) rename test_parse.test => tests/test_parse.test (100%) rename test_parse_int64.c => tests/test_parse_int64.c (100%) rename test_parse_int64.expected => tests/test_parse_int64.expected (100%) diff --git a/Makefile.am b/Makefile.am index cec14fd..d4a7bbb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,30 +39,6 @@ libjson_la_SOURCES = \ linkhash.c \ printbuf.c -check_PROGRAMS = test2 test4 test_parse_int64 test_null test_cast test_parse - -test2_SOURCES = test2.c -test2_LDADD = $(lib_LTLIBRARIES) - -test4_SOURCES = test4.c -test4_LDADD = $(lib_LTLIBRARIES) - -test_parse_int64_SOURCES = test_parse_int64.c -test_parse_int64_LDADD = $(lib_LTLIBRARIES) - -test_null_SOURCES = test_null.c -test_null_LDADD = $(lib_LTLIBRARIES) - -test_cast_SOURCES = test_cast.c -test_cast_LDADD = $(lib_LTLIBRARIES) - -test_parse_SOURCES = test_parse.c -test_parse_LDADD = $(lib_LTLIBRARIES) - -TESTS = test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test -EXTRA_DIST += $(TESTS) -testsubdir=testSubDir -TESTS_ENVIRONMENT = top_builddir=$(top_builddir) distclean-local: -rm -rf $(testsubdir) diff --git a/tests/Makefile.am b/tests/Makefile.am index ed5d2a5..d899c54 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,17 +1,25 @@ include ../Makefile.am.inc -#lib_LTLIBRARIES = ../libjson.la +lib_LTLIBRARIES = $(top_builddir)/libjson.la -#check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse -check_PROGRAMS = test1 +check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse -#test1_SOURCES = test1.c -#test1_LDADD = $(lib_LTLIBRARIES) -test1_LDADD = $(top_builddir)/libjson.la +test1_LDADD = $(lib_LTLIBRARIES) -#TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test -TESTS = test1.test +test2_LDADD = $(lib_LTLIBRARIES) + +test4_LDADD = $(lib_LTLIBRARIES) + +test_parse_int64_LDADD = $(lib_LTLIBRARIES) + +test_null_LDADD = $(lib_LTLIBRARIES) + +test_cast_LDADD = $(lib_LTLIBRARIES) + +test_parse_LDADD = $(lib_LTLIBRARIES) + +TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST= EXTRA_DIST += $(TESTS) diff --git a/parse_int64.test b/tests/parse_int64.test similarity index 100% rename from parse_int64.test rename to tests/parse_int64.test diff --git a/test-defs.sh b/tests/test-defs.sh similarity index 98% rename from test-defs.sh rename to tests/test-defs.sh index 2014b37..b9b0f60 100755 --- a/test-defs.sh +++ b/tests/test-defs.sh @@ -1,5 +1,4 @@ - -#! /bin/sh +#!/bin/sh # Make sure srcdir is an absolute path. Supply the variable # if it does not exist. We want to be able to run the tests @@ -22,6 +21,8 @@ case "$top_builddir" in *) top_builddir=`\cd ${top_builddir-..} && pwd` ;; esac +top_builddir=${top_builddir}/tests + progname=`echo "$0" | sed 's,^.*/,,'` testname=`echo "$progname" | sed 's,-.*$,,'` testsubdir=${testsubdir-testSubDir} diff --git a/test2.c b/tests/test2.c similarity index 100% rename from test2.c rename to tests/test2.c diff --git a/test2.expected b/tests/test2.expected similarity index 100% rename from test2.expected rename to tests/test2.expected diff --git a/test2.test b/tests/test2.test similarity index 100% rename from test2.test rename to tests/test2.test diff --git a/test4.c b/tests/test4.c similarity index 100% rename from test4.c rename to tests/test4.c diff --git a/test4.expected b/tests/test4.expected similarity index 100% rename from test4.expected rename to tests/test4.expected diff --git a/test4.test b/tests/test4.test similarity index 100% rename from test4.test rename to tests/test4.test diff --git a/test_cast.c b/tests/test_cast.c similarity index 100% rename from test_cast.c rename to tests/test_cast.c diff --git a/test_cast.expected b/tests/test_cast.expected similarity index 100% rename from test_cast.expected rename to tests/test_cast.expected diff --git a/test_cast.test b/tests/test_cast.test similarity index 100% rename from test_cast.test rename to tests/test_cast.test diff --git a/test_null.c b/tests/test_null.c similarity index 100% rename from test_null.c rename to tests/test_null.c diff --git a/test_null.expected b/tests/test_null.expected similarity index 100% rename from test_null.expected rename to tests/test_null.expected diff --git a/test_null.test b/tests/test_null.test similarity index 100% rename from test_null.test rename to tests/test_null.test diff --git a/test_parse.c b/tests/test_parse.c similarity index 100% rename from test_parse.c rename to tests/test_parse.c diff --git a/test_parse.expected b/tests/test_parse.expected similarity index 100% rename from test_parse.expected rename to tests/test_parse.expected diff --git a/test_parse.test b/tests/test_parse.test similarity index 100% rename from test_parse.test rename to tests/test_parse.test diff --git a/test_parse_int64.c b/tests/test_parse_int64.c similarity index 100% rename from test_parse_int64.c rename to tests/test_parse_int64.c diff --git a/test_parse_int64.expected b/tests/test_parse_int64.expected similarity index 100% rename from test_parse_int64.expected rename to tests/test_parse_int64.expected From b80772a0f58506f461c27e26ba46d9faf3e9213a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 10:48:30 -0500 Subject: [PATCH 114/276] Use a different variable when referring to the json.la file, since the original lib_LTLIBRARIES means something special to automake. --- tests/Makefile.am | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index d899c54..c54144c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,23 +1,23 @@ include ../Makefile.am.inc -lib_LTLIBRARIES = $(top_builddir)/libjson.la +LIBJSON_LA=$(top_builddir)/libjson.la check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse -test1_LDADD = $(lib_LTLIBRARIES) +test1_LDADD = $(LIBJSON_LA) -test2_LDADD = $(lib_LTLIBRARIES) +test2_LDADD = $(LIBJSON_LA) -test4_LDADD = $(lib_LTLIBRARIES) +test4_LDADD = $(LIBJSON_LA) -test_parse_int64_LDADD = $(lib_LTLIBRARIES) +test_parse_int64_LDADD = $(LIBJSON_LA) -test_null_LDADD = $(lib_LTLIBRARIES) +test_null_LDADD = $(LIBJSON_LA) -test_cast_LDADD = $(lib_LTLIBRARIES) +test_cast_LDADD = $(LIBJSON_LA) -test_parse_LDADD = $(lib_LTLIBRARIES) +test_parse_LDADD = $(LIBJSON_LA) TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test EXTRA_DIST= From e5c1e87f05a8126911aa891b81d5499697188fd9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 14:13:01 -0500 Subject: [PATCH 115/276] Add a test for the printbuf functions. --- tests/Makefile.am | 5 ++ tests/test_printbuf.c | 165 +++++++++++++++++++++++++++++++++++++++ tests/test_printbuf.test | 12 +++ 3 files changed, 182 insertions(+) create mode 100644 tests/test_printbuf.c create mode 100755 tests/test_printbuf.test diff --git a/tests/Makefile.am b/tests/Makefile.am index c54144c..1de7723 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,6 +20,11 @@ test_cast_LDADD = $(LIBJSON_LA) test_parse_LDADD = $(LIBJSON_LA) TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test + +TESTS+= test_printbuf.test +check_PROGRAMS+=test_printbuf +test_printbuf_LDADD = $(LIBJSON_LA) + EXTRA_DIST= EXTRA_DIST += $(TESTS) diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c new file mode 100644 index 0000000..3676b54 --- /dev/null +++ b/tests/test_printbuf.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "printbuf.h" + +static void test_basic_printbuf_memset(void); +static void test_printbuf_memset_length(void); + +static void test_basic_printbuf_memset() +{ + struct printbuf *pb; + + printf("%s: starting test\n", __func__); + pb = printbuf_new(); + sprintbuf(pb, "blue:%d", 1); + printbuf_memset(pb, -1, 'x', 52); + printf("Buffer contents:%.*s\n", printbuf_length(pb), pb->buf); + printbuf_free(pb); + printf("%s: end test\n", __func__); +} + +static void test_printbuf_memset_length() +{ + struct printbuf *pb; + + printf("%s: starting test\n", __func__); + pb = printbuf_new(); + printbuf_memset(pb, -1, ' ', 0); + printbuf_memset(pb, -1, ' ', 0); + printbuf_memset(pb, -1, ' ', 0); + printbuf_memset(pb, -1, ' ', 0); + printbuf_memset(pb, -1, ' ', 0); + printf("Buffer length: %d\n", printbuf_length(pb)); + printbuf_memset(pb, -1, ' ', 2); + printbuf_memset(pb, -1, ' ', 4); + printbuf_memset(pb, -1, ' ', 6); + printf("Buffer length: %d\n", printbuf_length(pb)); + printbuf_memset(pb, -1, ' ', 6); + printf("Buffer length: %d\n", printbuf_length(pb)); + printbuf_memset(pb, -1, ' ', 8); + printbuf_memset(pb, -1, ' ', 10); + printbuf_memset(pb, -1, ' ', 10); + printbuf_memset(pb, -1, ' ', 10); + printbuf_memset(pb, -1, ' ', 20); + printf("Buffer length: %d\n", printbuf_length(pb)); + + // No length change should occur + printbuf_memset(pb, 0, 'x', 30); + printf("Buffer length: %d\n", printbuf_length(pb)); + + // This should extend it by one. + printbuf_memset(pb, 0, 'x', printbuf_length(pb) + 1); + printf("Buffer length: %d\n", printbuf_length(pb)); + + printbuf_free(pb); + printf("%s: end test\n", __func__); +} + +static void test_printbuf_memappend(int *before_resize); +static void test_printbuf_memappend(int *before_resize) +{ + struct printbuf *pb; + int initial_size; + + printf("%s: starting test\n", __func__); + pb = printbuf_new(); + printf("Buffer length: %d\n", printbuf_length(pb)); + + initial_size = pb->size; + + while(pb->size == initial_size) + { + printbuf_memappend_fast(pb, "x", 1); + } + *before_resize = printbuf_length(pb) - 1; + printf("Appended %d bytes for resize: [%s]\n", *before_resize + 1, pb->buf); + + printbuf_reset(pb); + printbuf_memappend_fast(pb, "bluexyz123", 3); + printf("Partial append: %d, [%s]\n", printbuf_length(pb), pb->buf); + + char with_nulls[] = { 'a', 'b', '\0', 'c' }; + printbuf_reset(pb); + printbuf_memappend_fast(pb, with_nulls, sizeof(with_nulls)); + printf("With embedded \\0 character: %d, [%s]\n", printbuf_length(pb), pb->buf); + + printbuf_free(pb); + pb = printbuf_new(); + char *data = malloc(*before_resize); + memset(data, 'X', *before_resize); + printbuf_memappend_fast(pb, data, *before_resize); + printf("Append to just before resize: %d, [%s]\n", printbuf_length(pb), pb->buf); + + free(data); + printbuf_free(pb); + + pb = printbuf_new(); + data = malloc(*before_resize + 1); + memset(data, 'X', *before_resize + 1); + printbuf_memappend_fast(pb, data, *before_resize + 1); + printf("Append to just after resize: %d, [%s]\n", printbuf_length(pb), pb->buf); + + free(data); + + printbuf_free(pb); + printf("%s: end test\n", __func__); +} + +static void test_sprintbuf(int before_resize); +static void test_sprintbuf(int before_resize) +{ + struct printbuf *pb; + + printf("%s: starting test\n", __func__); + pb = printbuf_new(); + printf("Buffer length: %d\n", printbuf_length(pb)); + + char *data = malloc(before_resize + 1 + 1); + memset(data, 'X', before_resize + 1 + 1); + data[before_resize + 1] = '\0'; + sprintbuf(pb, "%s", data); + printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, strlen(pb->buf)); + + printbuf_reset(pb); + sprintbuf(pb, "plain"); + printf("%d, [%s]\n", printbuf_length(pb), pb->buf); + + sprintbuf(pb, "%d", 1); + printf("%d, [%s]\n", printbuf_length(pb), pb->buf); + + sprintbuf(pb, "%d", INT_MAX); + printf("%d, [%s]\n", printbuf_length(pb), pb->buf); + + sprintbuf(pb, "%d", INT_MIN); + printf("%d, [%s]\n", printbuf_length(pb), pb->buf); + + sprintbuf(pb, "%s", "%s"); + printf("%d, [%s]\n", printbuf_length(pb), pb->buf); + + printbuf_free(pb); + printf("%s: end test\n", __func__); +} + +int main(int argc, char **argv) +{ + int before_resize = 0; + + mc_set_debug(1); + + test_basic_printbuf_memset(); + printf("========================================\n"); + test_printbuf_memset_length(); + printf("========================================\n"); + test_printbuf_memappend(&before_resize); + printf("========================================\n"); + test_sprintbuf(before_resize); + printf("========================================\n"); + + return 0; +} diff --git a/tests/test_printbuf.test b/tests/test_printbuf.test new file mode 100755 index 0000000..09d27c2 --- /dev/null +++ b/tests/test_printbuf.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_printbuf +exit $? From 37cfe6bc4c9567a52d85b4c016c293512e974801 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 14:21:27 -0500 Subject: [PATCH 116/276] Update the list of files to ignore. --- .gitignore | 66 +++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index 091ae7a..5534d69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,37 @@ -.deps -.libs -aclocal.m4 -autom4te.cache -config.guess -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 -test1 -test2 -test4 -testSubDir -test_parse_int64 -test_parse -test_cast -test_null -Debug -Release +.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 +/libjson.la From 3d8817978c62c410aa00658710bf4ee1a20eb712 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 22 Apr 2012 14:25:08 -0500 Subject: [PATCH 117/276] Actually save the expected output for the test_printbuf test so it passes. --- tests/test_printbuf.expected | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/test_printbuf.expected diff --git a/tests/test_printbuf.expected b/tests/test_printbuf.expected new file mode 100644 index 0000000..142db0b --- /dev/null +++ b/tests/test_printbuf.expected @@ -0,0 +1,32 @@ +test_basic_printbuf_memset: starting test +Buffer contents:blue:1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +test_basic_printbuf_memset: end test +======================================== +test_printbuf_memset_length: starting test +Buffer length: 0 +Buffer length: 12 +Buffer length: 18 +Buffer length: 76 +Buffer length: 76 +Buffer length: 77 +test_printbuf_memset_length: end test +======================================== +test_printbuf_memappend: starting test +Buffer length: 0 +Appended 32 bytes for resize: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] +Partial append: 3, [blu] +With embedded \0 character: 4, [ab] +Append to just before resize: 31, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX] +Append to just after resize: 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX] +test_printbuf_memappend: end test +======================================== +test_sprintbuf: starting test +Buffer length: 0 +sprintbuf to just after resize(31+1): 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX], strlen(buf)=32 +5, [plain] +6, [plain1] +16, [plain12147483647] +27, [plain12147483647-2147483648] +29, [plain12147483647-2147483648%s] +test_sprintbuf: end test +======================================== From 8409dc039a22d0d008a15a259e83ce5b91abd18b Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Mon, 23 Apr 2012 13:11:11 +0100 Subject: [PATCH 118/276] Fix missing inttypes.h definitions for Visual Studio 2010 and earliers. Related to issue #22. --- json_inttypes.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/json_inttypes.h b/json_inttypes.h index b71bb09..2f84ade 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -4,13 +4,15 @@ #include "json_config.h" -#if defined(_MSC_VER) && _MSC_VER < 1600 +#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" From ded667a6126f0a97146d2a4e88693a6e9bae191c Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Mon, 23 Apr 2012 15:34:44 -0700 Subject: [PATCH 119/276] Clean up documentation and correct sample code --- json_object_iterator.c | 32 ++++----- json_object_iterator.h | 148 +++++++++++++++++++---------------------- 2 files changed, 83 insertions(+), 97 deletions(-) diff --git a/json_object_iterator.c b/json_object_iterator.c index b887eb2..7191b53 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -1,17 +1,17 @@ -/** +/** ******************************************************************************* -* @file cjson_object_iterator.c -* -* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. +* @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 cjson forces clients to use its private data +* @brief json-c forces clients to use its private data * structures for JSON Object iteration. This API * implementation corrects that by abstracting the -* private cjson details. -* +* private json-c details. +* ******************************************************************************* */ @@ -25,30 +25,30 @@ /** * How It Works - * - * For each JSON Object, cjson maintains a linked list of zero + * + * 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 cjson's current pair list representation by + * + * 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 @@ -57,7 +57,7 @@ */ /// Our current representation of the "end" iterator; -/// +/// /// @note May not always be NULL static const void* kObjectEndIterValue = NULL; diff --git a/json_object_iterator.h b/json_object_iterator.h index 21feaf5..3221a15 100644 --- a/json_object_iterator.h +++ b/json_object_iterator.h @@ -1,26 +1,21 @@ -/** +/** ******************************************************************************* * @file json_object_iterator.h -* -* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. +* +* 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 cjson forces clients to use its private data +* +* @brief json-c forces clients to use its private data * structures for JSON Object iteration. This API -* corrects that by abstracting the private cjson +* corrects that by abstracting the private json-c * details. -* -* The intention is to add this API (and its -* implementation) to Palm's version of the cjson -* library, at which point it can be removed from the -* Wireless System Framework library implementation. -* -* API attributes: -* * Thread-safe: NO -* * Re-entrant: NO -* +* +* API attributes:
+* * Thread-safe: NO
+* * Reentrant: NO +* ******************************************************************************* */ @@ -31,7 +26,7 @@ #include #include -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -42,7 +37,7 @@ struct json_object_iter_info_; /** * The opaque iterator that references a name/value pair within - * a JSON Object intance or the "end" iterator value. + * a JSON Object instance or the "end" iterator value. */ struct json_object_iterator { const void* opaque_; @@ -50,7 +45,7 @@ struct json_object_iterator { /** - * forward declaration of cjson's JSON value instance structure + * forward declaration of json-c's JSON value instance structure */ struct json_object; @@ -60,33 +55,32 @@ struct json_object; * is convenient for initializing an iterator variable to a * default state (e.g., initialization list in a class' * constructor). - * - * @code + * + * @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 cjson API that expects a valid + * 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. - * - * @note WARNING: Any modification of the underlying pair - * invalidates all iterators to that pair. - * - * @param obj JSON Object instance (MUST be of type - * json_type_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 @@ -94,29 +88,22 @@ json_object_iter_init_default(void); * have any pairs, the returned iterator is * equivalent to the "end" iterator for the same * JSON Object instance. - * - * @code + * + * @code * struct json_object_iterator it; * struct json_object_iterator itEnd; - * struct json_object* obj = json_tokener_parse( - * "{'first':'george', 'age':100}"); - * json_object_iter_begin(obj, &it); - * json_object_iter_end(obj, &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); * } * - * struct json_object* obj = json_tokener_parse( - * "{'first':'george', 'age':100}"); - * struct json_object_iterator it; - * bool iterable = json_object_iter_begin(&it); - * if (iterable) { - * do { - * printf("%s\n", json_object_iter_peek_name(&it)); - * } while (json_object_iter_next(&it)); - * } * @endcode */ struct json_object_iterator @@ -124,11 +111,11 @@ 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. - * - * @note WARNING: Do NOT write code that assumes that the "end" + * + * @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 @@ -140,11 +127,10 @@ json_object_iter_begin(struct json_object* obj); * representation without burdening the iterator * structure with unnecessary data. * - * @note For performance reasons, memoize the "end" iterator prior + * @note For performance reasons, memorize the "end" iterator prior * to any loop. - * - * @param obj JSON Object instance (MUST be of type - * json_type_object) + * + * @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 @@ -155,12 +141,10 @@ struct json_object_iterator json_object_iter_end(const struct json_object* obj); /** Returns an iterator to the next pair, if any - * - * @note WARNING: Any modification of the underlying pair - * invalidates all iterators to that pair. - * - * @param iter Iterator that references a name/value pair; - * + * + * @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" @@ -177,13 +161,14 @@ 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 invalid or - * "end" iterator is passed. - * - * @return const char* Pointer to the name of the rerferenced + * + * @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 @@ -193,21 +178,22 @@ const char* json_object_iter_peek_name(const struct json_object_iterator* iter); -/** Returns a pointer to the cjson instance representing the +/** 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 + * + * @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 cjson value + * + * @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 cjson node, + * function: if you plan to hold on to this json-c node, * take a look at json_object_get() and - * json_object_put(). IMPORTANT: cjson API represents + * json_object_put(). IMPORTANT: json-c API represents * the JSON Null value as a NULL json_object instance * pointer. */ @@ -219,7 +205,7 @@ json_object_iter_peek_value(const struct json_object_iterator* iter); * 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 @@ -228,15 +214,15 @@ json_object_iter_peek_value(const struct json_object_iterator* iter); * 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 - * - * @note 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! - * + * + * @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 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. From 4e000a65e671588749a670c5d954ffa8d2d41b0a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 24 Apr 2012 21:54:07 -0500 Subject: [PATCH 120/276] Since we already use a local json_bool type, replace any stdbool.h usage with that, since not all environments actually have a stdbool.h to use. --- json_object.c | 1 - json_object_iterator.c | 3 +-- json_object_iterator.h | 5 ++--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/json_object.c b/json_object.c index 842ca22..84af414 100644 --- a/json_object.c +++ b/json_object.c @@ -25,7 +25,6 @@ #include "json_object.h" #include "json_object_private.h" #include "json_util.h" -#include "json_tokener.h" #if !HAVE_STRNDUP char* strndup(const char* str, size_t n); diff --git a/json_object_iterator.c b/json_object_iterator.c index 7191b53..7066649 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -16,7 +16,6 @@ */ #include -#include #include "json.h" #include "json_object_private.h" @@ -139,7 +138,7 @@ json_object_iter_peek_value(const struct json_object_iterator* iter) /** * **************************************************************************** */ -bool +json_bool json_object_iter_equal(const struct json_object_iterator* iter1, const struct json_object_iterator* iter2) { diff --git a/json_object_iterator.h b/json_object_iterator.h index 3221a15..f6e7ca6 100644 --- a/json_object_iterator.h +++ b/json_object_iterator.h @@ -24,7 +24,6 @@ #define JSON_OBJECT_ITERATOR_H #include -#include #ifdef __cplusplus extern "C" { @@ -223,11 +222,11 @@ json_object_iter_peek_value(const struct json_object_iterator* iter); * different JSON Object instances are passed, bad things * will happen! * - * @return bool non-zero if iterators are equal (i.e., both + * @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. */ -bool +json_bool json_object_iter_equal(const struct json_object_iterator* iter1, const struct json_object_iterator* iter2); From f931f61851c949f8ab943dee8935b0d775346178 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 24 Apr 2012 22:17:13 -0500 Subject: [PATCH 121/276] Fixed parsing numbers in E notation. ` --- json_tokener.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 1dc06e4..1c82484 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -562,7 +562,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, int case_len=0; while(c && strchr(json_number_chars, c)) { ++case_len; - if(c == '.' || c == 'e') tok->is_double = 1; + 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; From cb29a77c94f813bb6f11f3abebb06b3a2dc039a2 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 20 Jan 2012 12:59:30 +0530 Subject: [PATCH 122/276] Add a pkgconfig file for uninstalled builds This allows systems certain types of build setups to work. Specifically, this will help when building on Android and using json-c as a dependency for another package. --- configure.in | 1 + json-uninstalled.pc.in | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 json-uninstalled.pc.in diff --git a/configure.in b/configure.in index b2c3cbe..8b3b19b 100644 --- a/configure.in +++ b/configure.in @@ -35,6 +35,7 @@ AC_CONFIG_FILES([ Makefile json.pc tests/Makefile +json-uninstalled.pc ]) AC_OUTPUT diff --git a/json-uninstalled.pc.in b/json-uninstalled.pc.in new file mode 100644 index 0000000..967f771 --- /dev/null +++ b/json-uninstalled.pc.in @@ -0,0 +1,11 @@ +prefix= +exec_prefix= +libdir=@abs_top_builddir@ +includedir=@abs_top_srcdir@ + +Name: json +Description: JSON implementation in C +Version: @VERSION@ +Requires: +Libs: -L@abs_top_builddir@ -ljson +Cflags: -I@abs_top_srcdir@ From 17caddc0ab7ae953bcbc79b5ca98a2e7abf01e00 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 20 Jan 2012 12:59:59 +0530 Subject: [PATCH 123/276] Run configure in the autogen.sh script This is convention in most open source projects. --- autogen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/autogen.sh b/autogen.sh index c67b903..990096c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1 +1,2 @@ autoreconf -v --install || exit 1 +exec ./configure "$@" From a1221eba70a0590a23088c365710a6d35289d04e Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 20 Jan 2012 13:00:45 +0530 Subject: [PATCH 124/276] Add an Android-friendly build system This dependson the Androgenizer project, which helps keep autofoo-based build systems in sync with the Android build. --- Android.configure.mk | 39 +++++++++++++++++++++++++++++++++++++++ Makefile.am | 14 ++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 Android.configure.mk diff --git a/Android.configure.mk b/Android.configure.mk new file mode 100644 index 0000000..a6265ad --- /dev/null +++ b/Android.configure.mk @@ -0,0 +1,39 @@ +# This file is the top android makefile for all sub-modules. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +json_c_TOP := $(LOCAL_PATH) + +JSON_C_BUILT_SOURCES := Android.mk + +JSON_C_BUILT_SOURCES := $(patsubst %, $(abspath $(json_c_TOP))/%, $(JSON_C_BUILT_SOURCES)) + +.PHONY: json-c-configure json-c-configure-real +json-c-configure-real: + echo $(JSON_C_BUILT_SOURCES) + cd $(json_c_TOP) ; \ + $(abspath $(json_c_TOP))/autogen.sh && \ + CC="$(CONFIGURE_CC)" \ + CFLAGS="$(CONFIGURE_CFLAGS)" \ + LD=$(TARGET_LD) \ + LDFLAGS="$(CONFIGURE_LDFLAGS)" \ + CPP=$(CONFIGURE_CPP) \ + CPPFLAGS="$(CONFIGURE_CPPFLAGS)" \ + PKG_CONFIG_LIBDIR=$(CONFIGURE_PKG_CONFIG_LIBDIR) \ + PKG_CONFIG_TOP_BUILD_DIR=/ \ + ac_cv_func_malloc_0_nonnull=yes \ + ac_cv_func_realloc_0_nonnull=yes \ + $(abspath $(json_c_TOP))/$(CONFIGURE) --host=$(CONFIGURE_HOST) \ + --prefix=/system \ + && \ + for file in $(JSON_C_BUILT_SOURCES); do \ + rm -f $$file && \ + make -C $$(dirname $$file) $$(basename $$file) ; \ + done + +json-c-configure: json-c-configure-real + +PA_CONFIGURE_TARGETS += json-c-configure + +-include $(json_c_TOP)/Android.mk diff --git a/Makefile.am b/Makefile.am index d4a7bbb..3c53b93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,3 +44,17 @@ 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 +ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H + +Android.mk: Makefile.am + androgenizer -:PROJECT json-c \ + -:SHARED libjson \ + -:TAGS eng debug \ + -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \ + -:SOURCES $(libjson_la_SOURCES) $(nodist_libjson_la_SOURCES) \ + -:CFLAGS $(DEFS) $(ANDROID_CFLAGS) $(libjson_la_CFLAGS) \ + -:LDFLAGS $(libjson_la_LDFLAGS) $(libjson_la_LIBADD) \ + -:HEADER_TARGET json \ + -:HEADERS $(libjsoninclude_HEADERS) \ + -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ + > $@ From 3fcffe1bb01de6978f4516abd49a3b3c9e2cd2f2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 28 Apr 2012 13:26:09 -0500 Subject: [PATCH 125/276] Add a json_object_to_json_string_ext() function to allow the formatting of output to be selected. There are now three options: JSON_C_TO_STRING_SPACED, JSON_C_TO_STRING_PLAIN and JSON_C_TO_STRING_PRETTY. This also add a json_object_to_file_ext() that takes the same flags. Existing output of json_object_to_json_string() is unchanged, and uses JSON_C_TO_STRING_SPACED. Thanks fo Grant Edwards for the initial patches. --- json_object.c | 156 +++++++++++++++++++++++++++++++----------- json_object.h | 33 ++++++++- json_object_private.h | 4 +- json_util.c | 19 +++-- json_util.h | 2 + 5 files changed, 167 insertions(+), 47 deletions(-) diff --git a/json_object.c b/json_object.c index 84af414..825630f 100644 --- a/json_object.c +++ b/json_object.c @@ -180,45 +180,88 @@ enum json_type json_object_get_type(struct json_object *jso) return jso->o_type; } -/* json_object_to_json_string */ +/* extended conversion to string */ + +const char* json_object_to_json_string_ext(struct json_object *jso, int flags) +{ + if (!jso) + return "null"; + + if ((!jso->_pb) && !(jso->_pb = printbuf_new())) + return NULL; + + printbuf_reset(jso->_pb); + + if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0) + return NULL; + + return jso->_pb->buf; +} + +/* backwards-compatible conversion to string */ const char* json_object_to_json_string(struct json_object *jso) { - 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; + return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); } +static void indent(struct printbuf *pb, int level, int flags) +{ + if (flags & JSON_C_TO_STRING_PRETTY) + { + printbuf_memset(pb, -1, ' ', level * 2); + } +} /* json_object_object */ static int json_object_object_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { - int i=0; - struct json_object_iter iter; - sprintbuf(pb, "{"); + int had_children = 0; + struct json_object_iter iter; - /* 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 (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + json_object_object_foreachC(jso, iter) + { + if (had_children) + { + sprintbuf(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + sprintbuf(pb, " "); + indent(pb, level+1, flags); + sprintbuf(pb, "\""); + json_escape_str(pb, iter.key, strlen(iter.key)); + if (flags & JSON_C_TO_STRING_SPACED) sprintbuf(pb, "\": "); - if(iter.val == NULL) sprintbuf(pb, "null"); - else iter.val->_to_json_string(iter.val, pb); - i++; + else + sprintbuf(pb, "\":"); + if(iter.val == NULL) + sprintbuf(pb, "null"); + else + iter.val->_to_json_string(iter.val, pb, level+1,flags); } - - return sprintbuf(pb, " }"); + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + sprintbuf(pb, "\n"); + indent(pb,level,flags); + } + if (flags & JSON_C_TO_STRING_SPACED) + return sprintbuf(pb, /*{*/ " }"); + else + return sprintbuf(pb, /*{*/ "}"); } + static void json_object_lh_entry_free(struct lh_entry *ent) { free(ent->k); @@ -291,7 +334,9 @@ void json_object_object_del(struct json_object* jso, const char *key) /* json_object_boolean */ static int json_object_boolean_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { if(jso->o.c_boolean) return sprintbuf(pb, "true"); else return sprintbuf(pb, "false"); @@ -327,7 +372,9 @@ json_bool json_object_get_boolean(struct json_object *jso) /* json_object_int */ static int json_object_int_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { return sprintbuf(pb, "%"PRId64, jso->o.c_int64); } @@ -412,7 +459,9 @@ int64_t json_object_get_int64(struct json_object *jso) /* json_object_double */ static int json_object_double_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { return sprintbuf(pb, "%lf", jso->o.c_double); } @@ -449,7 +498,9 @@ double json_object_get_double(struct json_object *jso) /* json_object_string */ static int json_object_string_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { sprintbuf(pb, "\""); json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); @@ -511,20 +562,45 @@ int json_object_get_string_len(struct json_object *jso) { /* json_object_array */ static int json_object_array_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { - 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, " "); } + int had_children = 0; + int ii; + sprintbuf(pb, "["); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + for(ii=0; ii < json_object_array_length(jso); ii++) + { + struct json_object *val; + if (had_children) + { + sprintbuf(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + sprintbuf(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + sprintbuf(pb, " "); + indent(pb, level + 1, flags); + val = json_object_array_get_idx(jso, ii); + if(val == NULL) + sprintbuf(pb, "null"); + else + val->_to_json_string(val, pb, level+1, flags); + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + sprintbuf(pb, "\n"); + indent(pb,level,flags); + } - val = json_object_array_get_idx(jso, i); - if(val == NULL) { sprintbuf(pb, "null"); } - else { val->_to_json_string(val, pb); } - } - return sprintbuf(pb, " ]"); + if (flags & JSON_C_TO_STRING_SPACED) + return sprintbuf(pb, " ]"); + else + return sprintbuf(pb, "]"); } static void json_object_array_entry_free(void *data) diff --git a/json_object.h b/json_object.h index f7ec9ea..6520a9a 100644 --- a/json_object.h +++ b/json_object.h @@ -21,6 +21,28 @@ extern "C" { #define JSON_OBJECT_DEF_HASH_ENTRIES 16 +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output + * to have no extra whitespace or formatting applied. + */ +#define JSON_C_TO_STRING_PLAIN 0 +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output to have + * minimal whitespace inserted to make things slightly more readable. + */ +#define JSON_C_TO_STRING_SPACED (1<<0) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ + * for an example of the format. + */ +#define JSON_C_TO_STRING_PRETTY (1<<1) + #undef FALSE #define FALSE ((json_bool)0) @@ -112,12 +134,21 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); extern enum json_type json_object_get_type(struct json_object *obj); -/** Stringify object to json format +/** Stringify object to json format. + * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) * @param obj the json_object instance * @returns a string in JSON format */ extern const char* json_object_to_json_string(struct json_object *obj); +/** Stringify object to json format + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @returns a string in JSON format + */ +extern const char* json_object_to_json_string_ext(struct json_object *obj, int +flags); + /* object type methods */ diff --git a/json_object_private.h b/json_object_private.h index 112ce76..597332b 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -18,7 +18,9 @@ extern "C" { 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 printbuf *pb, + int level, + int flags); struct json_object { diff --git a/json_util.c b/json_util.c index c6db882..e551d2d 100644 --- a/json_util.c +++ b/json_util.c @@ -65,12 +65,12 @@ struct json_object* json_object_from_file(const char *filename) 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); + return NULL; // XAX this is an API change! } if(!(pb = printbuf_new())) { close(fd); MC_ERROR("json_object_from_file: printbuf_new failed\n"); - return (struct json_object*)error_ptr(-1); + return NULL; } while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { printbuf_memappend(pb, buf, ret); @@ -80,14 +80,16 @@ struct json_object* json_object_from_file(const char *filename) 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); + return NULL; } obj = json_tokener_parse(pb->buf); printbuf_free(pb); return obj; } -int json_object_to_file(char *filename, struct json_object *obj) +/* extended "format and write to file" function */ + +int json_object_to_file_ext(char *filename, struct json_object *obj, int flags) { const char *json_str; int fd, ret; @@ -104,7 +106,7 @@ int json_object_to_file(char *filename, struct json_object *obj) return -1; } - if(!(json_str = json_object_to_json_string(obj))) { + if(!(json_str = json_object_to_json_string_ext(obj,flags))) { close(fd); return -1; } @@ -127,6 +129,13 @@ int json_object_to_file(char *filename, struct json_object *obj) return 0; } +// backwards compatible "format and write to file" function + +int json_object_to_file(char *filename, struct json_object *obj) +{ + return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); +} + int json_parse_int64(const char *buf, int64_t *retval) { int64_t num64; diff --git a/json_util.h b/json_util.h index a77305e..277c3a7 100644 --- a/json_util.h +++ b/json_util.h @@ -23,8 +23,10 @@ extern "C" { /* utility functions */ extern struct json_object* json_object_from_file(const char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); +extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags); extern int json_parse_int64(const char *buf, int64_t *retval); + /** * Return a string describing the type of the object. * e.g. "int", or "object", etc... From 4c7f38eb9b4cb09aef7a8c6e73bf49d602cd0476 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 28 Apr 2012 14:14:26 -0500 Subject: [PATCH 126/276] Extend test1 and test2 to run using json_object_to_json_string_ext() based on an additional command line parameter. Extend the run_output_test() function so we actually can pass command line parameters and so we can support different output files for the same test executable. Also provide some hints about what to do if a test fails (i.e. set VERBOSE=1). --- tests/Makefile.am | 16 +++++++- tests/parse_flags.c | 42 ++++++++++++++++++++ tests/parse_flags.h | 4 ++ tests/test-defs.sh | 45 +++++++++++++-------- tests/test1.c | 14 +++++++ tests/test1.test | 12 +++++- tests/test1Formatted_plain.expected | 35 +++++++++++++++++ tests/test1Formatted_pretty.expected | 58 ++++++++++++++++++++++++++++ tests/test1Formatted_spaced.expected | 35 +++++++++++++++++ tests/test2.c | 14 +++++++ tests/test2.test | 12 +++++- tests/test2Formatted_plain.expected | 1 + tests/test2Formatted_pretty.expected | 23 +++++++++++ tests/test2Formatted_spaced.expected | 1 + 14 files changed, 293 insertions(+), 19 deletions(-) create mode 100644 tests/parse_flags.c create mode 100644 tests/parse_flags.h create mode 100644 tests/test1Formatted_plain.expected create mode 100644 tests/test1Formatted_pretty.expected create mode 100644 tests/test1Formatted_spaced.expected create mode 100644 tests/test2Formatted_plain.expected create mode 100644 tests/test2Formatted_pretty.expected create mode 100644 tests/test2Formatted_spaced.expected diff --git a/tests/Makefile.am b/tests/Makefile.am index 1de7723..e2854dd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,12 +3,26 @@ include ../Makefile.am.inc LIBJSON_LA=$(top_builddir)/libjson.la -check_PROGRAMS = test1 test2 test4 test_parse_int64 test_null test_cast test_parse +check_PROGRAMS = test1 test1Formatted +check_PROGRAMS += test2 test2Formatted +check_PROGRAMS += test4 +check_PROGRAMS += test_parse_int64 +check_PROGRAMS += test_null +check_PROGRAMS += test_cast +check_PROGRAMS += test_parse test1_LDADD = $(LIBJSON_LA) +test1Formatted_LDADD= $(LIBJSON_LA) +test1Formatted_SOURCES = test1.c parse_flags.c +test1Formatted_CPPFLAGS = -DTEST_FORMATTED + test2_LDADD = $(LIBJSON_LA) +test2Formatted_LDADD= $(LIBJSON_LA) +test2Formatted_SOURCES = test2.c parse_flags.c +test2Formatted_CPPFLAGS = -DTEST_FORMATTED + test4_LDADD = $(LIBJSON_LA) test_parse_int64_LDADD = $(LIBJSON_LA) diff --git a/tests/parse_flags.c b/tests/parse_flags.c new file mode 100644 index 0000000..fafabc8 --- /dev/null +++ b/tests/parse_flags.c @@ -0,0 +1,42 @@ +#include +#include + +#include "json.h" +#include "parse_flags.h" + +static struct { + const char *arg; + int flag; +} format_args[] = { + { "plain", JSON_C_TO_STRING_PLAIN }, + { "spaced", JSON_C_TO_STRING_SPACED }, + { "pretty", JSON_C_TO_STRING_PRETTY }, +}; + +#ifndef NELEM +#define NELEM(x) (sizeof(x) / sizeof(&x[0])) +#endif + +int parse_flags(int argc, char **argv) +{ + int arg_idx; + int sflags = 0; + for (arg_idx = 1; arg_idx < argc ; arg_idx++) + { + int jj; + for (jj = 0; jj < NELEM(format_args); jj++) + { + if (strcasecmp(argv[arg_idx], format_args[jj].arg) == 0) + { + sflags |= format_args[jj].flag; + break; + } + } + if (jj == NELEM(format_args)) + { + printf("Unknown arg: %s\n", argv[arg_idx]); + exit(1); + } + } + return sflags; +} diff --git a/tests/parse_flags.h b/tests/parse_flags.h new file mode 100644 index 0000000..c5e2f41 --- /dev/null +++ b/tests/parse_flags.h @@ -0,0 +1,4 @@ +#ifndef __parse_flags_h +#define __parse_flags_h +int parse_flags(int argc, char **argv); +#endif diff --git a/tests/test-defs.sh b/tests/test-defs.sh index b9b0f60..658a75d 100755 --- a/tests/test-defs.sh +++ b/tests/test-defs.sh @@ -26,22 +26,24 @@ top_builddir=${top_builddir}/tests progname=`echo "$0" | sed 's,^.*/,,'` testname=`echo "$progname" | sed 's,-.*$,,'` testsubdir=${testsubdir-testSubDir} +testsubdir=${testsubdir}/${progname} # User can set VERBOSE to cause output redirection case "$VERBOSE" in [Nn]|[Nn][Oo]|0|"") VERBOSE=0 - exec > /dev/null 2>&1 + exec > /dev/null ;; [Yy]|[Yy][Ee][Ss]) VERBOSE=1 ;; esac -rm -rf "$testsubdir/$progname" > /dev/null 2>&1 -mkdir -p "$testsubdir/$progname" -cd "$testsubdir/$progname" \ - || { echo "Cannot make or change into $testsubdir/$progname"; exit 1; } +rm -rf "$testsubdir" > /dev/null 2>&1 +mkdir -p "$testsubdir" +CURDIR=$(pwd) +cd "$testsubdir" \ + || { echo "Cannot make or change into $testsubdir"; exit 1; } echo "=== Running test $progname" @@ -68,44 +70,55 @@ fi # run_output_test() { + if [ "$1" = "-o" ] ; then + TEST_OUTPUT="$2" + shift + shift + fi TEST_COMMAND="$1" + shift + if [ -z "${TEST_OUTPUT}" ] ; then + TEST_OUTPUT=${TEST_COMMAND} + fi - REDIR_OUTPUT="> \"${TEST_COMMAND}.out\"" + REDIR_OUTPUT="> \"${TEST_OUTPUT}.out\"" if [ $VERBOSE -gt 1 ] ; then - REDIR_OUTPUT="| tee \"${TEST_COMMAND}.out\"" + REDIR_OUTPUT="| tee \"${TEST_OUTPUT}.out\"" fi if [ $use_valgrind -eq 1 ] ; then eval valgrind --tool=memcheck \ --trace-children=yes \ --demangle=yes \ - --log-file=vg.out \ + --log-file="${TEST_OUTPUT}.vg.out" \ --leak-check=full \ --show-reachable=yes \ --run-libc-freeres=yes \ - "\"${top_builddir}/${TEST_COMMAND}\"" ${REDIR_OUTPUT} + "\"${top_builddir}/${TEST_COMMAND}\"" \"\$@\" ${REDIR_OUTPUT} err=$? else - eval "\"${top_builddir}/${TEST_COMMAND}"\" ${REDIR_OUTPUT} + eval "\"${top_builddir}/${TEST_COMMAND}"\" \"\$@\" ${REDIR_OUTPUT} err=$? fi if [ $err -ne 0 ] ; then - echo "ERROR: ${TEST_COMMAND} exited with non-zero exit status: $err" 1>&2 + echo "ERROR: \"${TEST_COMMAND} $@\" exited with non-zero exit status: $err" 1>&2 fi if [ $use_valgrind -eq 1 ] ; then - if ! tail -1 "vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then + if ! tail -1 "${TEST_OUTPUT}.vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then echo "ERROR: valgrind found errors during execution:" 1>&2 - cat vg.out + cat "${TEST_OUTPUT}.vg.out" err=1 fi fi - if ! "$CMP" -s "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" ; then - echo "ERROR: ${TEST_COMMAND} failed:" 1>&2 - diff "${top_builddir}/${TEST_COMMAND}.expected" "${TEST_COMMAND}.out" 1>&2 + if ! "$CMP" -s "${top_builddir}/${TEST_OUTPUT}.expected" "${TEST_OUTPUT}.out" ; then + echo "ERROR: \"${TEST_COMMAND} $@\" (${TEST_OUTPUT}) failed (set VERBOSE=1 to see full output):" 1>&2 + (cd "${CURDIR}" ; set -x ; diff "${top_builddir}/${TEST_OUTPUT}.expected" "$testsubdir/${TEST_OUTPUT}.out") + echo "cp \"$testsubdir/${TEST_OUTPUT}.out\" \"${top_builddir}/${TEST_OUTPUT}.expected\"" 1>&2 + err=1 fi diff --git a/tests/test1.c b/tests/test1.c index e1e411d..9802eb1 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -5,6 +5,7 @@ #include #include "json.h" +#include "parse_flags.h" static int sort_fn (const void *j1, const void *j2) { @@ -29,13 +30,26 @@ static int sort_fn (const void *j1, const void *j2) return i1 - i2; } +#ifdef TEST_FORMATTED +#define json_object_to_json_string(obj) json_object_to_json_string_ext(obj,sflags) +#else +/* no special define */ +#endif + int main(int argc, char **argv) { json_object *my_string, *my_int, *my_object, *my_array; int i; +#ifdef TEST_FORMATTED + int sflags = 0; +#endif MC_SET_DEBUG(1); +#ifdef TEST_FORMATTED + sflags = parse_flags(argc, argv); +#endif + my_string = json_object_new_string("\t"); printf("my_string=%s\n", json_object_get_string(my_string)); printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); diff --git a/tests/test1.test b/tests/test1.test index 6074fac..79d2e09 100755 --- a/tests/test1.test +++ b/tests/test1.test @@ -9,4 +9,14 @@ fi . "$srcdir/test-defs.sh" run_output_test test1 -exit $? +_err=$? + +for flag in plain spaced pretty ; do + run_output_test -o test1Formatted_${flag} test1Formatted ${flag} + _err2=$? + if [ $_err -eq 0 ] ; then + _err=$_err2 + fi +done + +exit $_err diff --git a/tests/test1Formatted_plain.expected b/tests/test1Formatted_plain.expected new file mode 100644 index 0000000..65b19ed --- /dev/null +++ b/tests/test1Formatted_plain.expected @@ -0,0 +1,35 @@ +my_string= +my_string.to_string()="\t" +my_string=\ +my_string.to_string()="\\" +my_string=foo +my_string.to_string()="foo" +my_int=9 +my_int.to_string()=9 +my_array= + [0]=1 + [1]=2 + [2]=3 + [3]=null + [4]=5 +my_array.to_string()=[1,2,3,null,5] +my_array= + [0]=3 + [1]=1 + [2]=2 + [3]=null + [4]=0 +my_array.to_string()=[3,1,2,null,0] +my_array= + [0]=null + [1]=0 + [2]=1 + [3]=2 + [4]=3 +my_array.to_string()=[null,0,1,2,3] +my_object= + abc: 12 + foo: "bar" + bool0: false + bool1: true +my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true} diff --git a/tests/test1Formatted_pretty.expected b/tests/test1Formatted_pretty.expected new file mode 100644 index 0000000..f2334c4 --- /dev/null +++ b/tests/test1Formatted_pretty.expected @@ -0,0 +1,58 @@ +my_string= +my_string.to_string()="\t" +my_string=\ +my_string.to_string()="\\" +my_string=foo +my_string.to_string()="foo" +my_int=9 +my_int.to_string()=9 +my_array= + [0]=1 + [1]=2 + [2]=3 + [3]=null + [4]=5 +my_array.to_string()=[ + 1, + 2, + 3, + null, + 5 +] +my_array= + [0]=3 + [1]=1 + [2]=2 + [3]=null + [4]=0 +my_array.to_string()=[ + 3, + 1, + 2, + null, + 0 +] +my_array= + [0]=null + [1]=0 + [2]=1 + [3]=2 + [4]=3 +my_array.to_string()=[ + null, + 0, + 1, + 2, + 3 +] +my_object= + abc: 12 + foo: "bar" + bool0: false + bool1: true +my_object.to_string()={ + "abc":12, + "foo":"bar", + "bool0":false, + "bool1":true +} diff --git a/tests/test1Formatted_spaced.expected b/tests/test1Formatted_spaced.expected new file mode 100644 index 0000000..6653fe0 --- /dev/null +++ b/tests/test1Formatted_spaced.expected @@ -0,0 +1,35 @@ +my_string= +my_string.to_string()="\t" +my_string=\ +my_string.to_string()="\\" +my_string=foo +my_string.to_string()="foo" +my_int=9 +my_int.to_string()=9 +my_array= + [0]=1 + [1]=2 + [2]=3 + [3]=null + [4]=5 +my_array.to_string()=[ 1, 2, 3, null, 5 ] +my_array= + [0]=3 + [1]=1 + [2]=2 + [3]=null + [4]=0 +my_array.to_string()=[ 3, 1, 2, null, 0 ] +my_array= + [0]=null + [1]=0 + [2]=1 + [3]=2 + [4]=3 +my_array.to_string()=[ null, 0, 1, 2, 3 ] +my_object= + abc: 12 + foo: "bar" + bool0: false + bool1: true +my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } diff --git a/tests/test2.c b/tests/test2.c index 5f95565..4a6b660 100644 --- a/tests/test2.c +++ b/tests/test2.c @@ -4,14 +4,28 @@ #include #include "json.h" +#include "parse_flags.h" + +#ifdef TEST_FORMATTED +#define json_object_to_json_string(obj) json_object_to_json_string_ext(obj,sflags) +#else +/* no special define */ +#endif int main(int argc, char **argv) { json_object *new_obj; +#ifdef TEST_FORMATTED + int sflags = 0; +#endif MC_SET_DEBUG(1); +#ifdef TEST_FORMATTED + sflags = parse_flags(argc, argv); +#endif + new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); diff --git a/tests/test2.test b/tests/test2.test index cbb3830..d4a4e79 100755 --- a/tests/test2.test +++ b/tests/test2.test @@ -9,4 +9,14 @@ fi . "$srcdir/test-defs.sh" run_output_test test2 -exit $? +_err=$? + +for flag in plain spaced pretty ; do + run_output_test -o test2Formatted_${flag} test2Formatted ${flag} + _err2=$? + if [ $_err -eq 0 ] ; then + _err=$_err2 + fi +done + +exit $_err diff --git a/tests/test2Formatted_plain.expected b/tests/test2Formatted_plain.expected new file mode 100644 index 0000000..cc587e9 --- /dev/null +++ b/tests/test2Formatted_plain.expected @@ -0,0 +1 @@ +new_obj.to_string()={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":[{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML","markup"]}]}}} diff --git a/tests/test2Formatted_pretty.expected b/tests/test2Formatted_pretty.expected new file mode 100644 index 0000000..8d6d740 --- /dev/null +++ b/tests/test2Formatted_pretty.expected @@ -0,0 +1,23 @@ +new_obj.to_string()={ + "glossary":{ + "title":"example glossary", + "GlossDiv":{ + "title":"S", + "GlossList":[ + { + "ID":"SGML", + "SortAs":"SGML", + "GlossTerm":"Standard Generalized Markup Language", + "Acronym":"SGML", + "Abbrev":"ISO 8879:1986", + "GlossDef":"A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso":[ + "GML", + "XML", + "markup" + ] + } + ] + } + } +} diff --git a/tests/test2Formatted_spaced.expected b/tests/test2Formatted_spaced.expected new file mode 100644 index 0000000..0b740a9 --- /dev/null +++ b/tests/test2Formatted_spaced.expected @@ -0,0 +1 @@ +new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } } From 31faa49bd8ce3a6335ae313990e69572808a96a2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 28 Apr 2012 14:17:09 -0500 Subject: [PATCH 127/276] Ignore the new test1Formatted and test2Formatted executables. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5534d69..6dfd3fd 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,9 @@ /tests/Makefile /tests/Makefile.in /tests/test1 +/tests/test1Formatted /tests/test2 +/tests/test2Formatted /tests/test4 /tests/testSubDir /tests/test_parse_int64 From 0cc1db6459035fd071371281daff030e5a0e9b8e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Apr 2012 11:04:33 -0500 Subject: [PATCH 128/276] Change the format used for sprintbuf (but not scanf) to use %f instead of %lf because the "l" is unnecessary and some compilers behave differently with it present (e.g. MinGW). Thanks for Mateusz Loskot for the fix. --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 825630f..5a35938 100644 --- a/json_object.c +++ b/json_object.c @@ -463,7 +463,7 @@ static int json_object_double_to_json_string(struct json_object* jso, int level, int flags) { - return sprintbuf(pb, "%lf", jso->o.c_double); + return sprintbuf(pb, "%f", jso->o.c_double); } struct json_object* json_object_new_double(double d) From e7bd2e97f311b2941ced6fa65696ecdb273cd152 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Apr 2012 12:54:04 -0500 Subject: [PATCH 129/276] Fill in the missing pieces of the release checklist. --- RELEASE_CHECKLIST.txt | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 1a8d555..28f5b89 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -6,20 +6,43 @@ git clone https://github.com/json-c/json-c json-c-${release} cd json-c-${release} Check that the compile works on Linux +Check that the compile works on NetBSD Check that the compile works on Windows Check ChangeLog to see if anything should be added. -git branch json-c-${release} -git checkout json-c-${release} -sh autogen.sh -XXX doxygen + git branch json-c-${release} + git checkout json-c-${release} -XXX Add generated files to git? +Generate the configure script and other files: + sh autogen.sh + git add -f Makefile.in aclocal.m4 config.guess \ + config.sub configure depcomp install-sh \ + ltmain.sh missing tests/Makefile.in + + # check for anything else to be added: + git status --ignored + git commit + +Generate the doxygen documentation: + doxygen + git add doc + git commit doc cd .. -tar czf json-c-${release}.tar.gz json-c-${release} +echo .git > excludes +echo autom4te.cache >> excludes +tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} + +echo doc >> excludes +tar -czf json-c-${release}-doc.tar.gz -X excludes json-c-${release} + +Tag the branch: +cd json-c-${release} +git tag json-c-${release}-$(date +%Y%m%d) + +Go to https://github.com/json-c/json-c/downloads +Upload the two tarballs. -XXX upload tarball to ??? =================================== From 1abaaee658389037ba016b7ba7eca65755d53b07 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Apr 2012 12:54:14 -0500 Subject: [PATCH 130/276] Update the ChangeLog with the rest of the changes that will be included in the 0.10 release. --- ChangeLog | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index 5d2c9af..e0fd4a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,26 @@ 0.10 + + * Add a json_object_to_json_string_ext() function to allow output to be + formatted in a more human readable form. + * Add json_object_object_get_ex(), a NULL-safe get object method, to be able + to distinguish between a key not present and the value being NULL. + * Add an alternative iterator implementation, see json_object_iterator.h + * Make json_object_iter public to enable external use of the + json_object_object_foreachC macro. + * Add a printbuf_memset() function to provide an effecient way to set and + append things like whitespace indentation. + * Adjust json_object_is_type and json_object_get_type so they return + json_type_null for NULL objects and handle NULL passed to + json_objct_object_get(). + * Rename boolean type to json_bool. + * Fix various compile issues for Visual Studio and MinGW. + * Allow json_tokener_parse_ex() to be re-used to parse multiple object. + Also, fix some parsing issues with capitalized hexadecimal numbers and + number in E notation. + * Add json_tokener_get_error() and json_tokener_error_desc() to better + encapsulate the process of retrieving errors while parsing. + * Various improvements to the documentation of many functions. + * Add new json_object_array_sort() function. * Fix a bug in json_object_get_int(), which would incorrectly return 0 when called on a string type object. Eric Haszlakiewicz From b6ff1c2f71d937383367a3ae6579c21f19061c08 Mon Sep 17 00:00:00 2001 From: OBI-1 Date: Wed, 9 May 2012 13:52:17 +0300 Subject: [PATCH 131/276] array_list_expand_internal needs length, not index. (The current implementation will fail when adding index 65.) --- arraylist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arraylist.c b/arraylist.c index 9a673d6..bcc695c 100644 --- a/arraylist.c +++ b/arraylist.c @@ -74,7 +74,7 @@ static int array_list_expand_internal(struct array_list *arr, int max) int array_list_put_idx(struct array_list *arr, int idx, void *data) { - if(array_list_expand_internal(arr, idx)) return -1; + if(array_list_expand_internal(arr, idx+1)) return -1; if(arr->array[idx]) arr->free_fn(arr->array[idx]); arr->array[idx] = data; if(arr->length <= idx) arr->length = idx + 1; From a6f39a3c0ce09aec1f947479e7c441f5c2b99f01 Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Mon, 21 May 2012 23:22:36 +0100 Subject: [PATCH 132/276] Replaced #if HAVE_X with #ifdef HAVE_X as the former test is troublemaker with #define HAVE_X where #define HAVE_X 1|0 is meant. --- arraylist.c | 4 ++-- json_object.c | 9 ++++++++- json_tokener.c | 8 +++++++- json_util.c | 18 ++++++++++++------ printbuf.c | 8 ++++---- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/arraylist.c b/arraylist.c index 9a673d6..2d44a18 100644 --- a/arraylist.c +++ b/arraylist.c @@ -11,12 +11,12 @@ #include "config.h" -#if STDC_HEADERS +#ifdef STDC_HEADERS # include # include #endif /* STDC_HEADERS */ -#if defined HAVE_STRINGS_H && !defined _STRING_H && !defined __USE_BSD +#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) # include #endif /* HAVE_STRINGS_H */ diff --git a/json_object.c b/json_object.c index 5a35938..8e399de 100644 --- a/json_object.c +++ b/json_object.c @@ -26,7 +26,14 @@ #include "json_object_private.h" #include "json_util.h" -#if !HAVE_STRNDUP +#if !defined(HAVE_STRDUP) && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !defined(HAVE_STRDUP) +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#if !defined(HAVE_STRNDUP) char* strndup(const char* str, size_t n); #endif /* !HAVE_STRNDUP */ diff --git a/json_tokener.c b/json_tokener.c index 1c82484..47768f4 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -31,6 +31,13 @@ #include "json_tokener.h" #include "json_util.h" +#if !HAVE_STRDUP && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !HAVE_STRDUP +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + #if !HAVE_STRNCASECMP && defined(_MSC_VER) /* MSC has the version as _strnicmp */ # define strncasecmp _strnicmp @@ -38,7 +45,6 @@ # 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"; diff --git a/json_util.c b/json_util.c index e551d2d..03fb24b 100644 --- a/json_util.c +++ b/json_util.c @@ -20,19 +20,19 @@ #include #include -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H #include #endif /* HAVE_SYS_TYPES_H */ -#if HAVE_SYS_STAT_H +#ifdef HAVE_SYS_STAT_H #include #endif /* HAVE_SYS_STAT_H */ -#if HAVE_FCNTL_H +#ifdef HAVE_FCNTL_H #include #endif /* HAVE_FCNTL_H */ -#if HAVE_UNISTD_H +#ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ @@ -42,10 +42,16 @@ # include #endif /* defined(WIN32) */ -#if !HAVE_OPEN && defined(WIN32) +#if !defined(HAVE_OPEN) && defined(WIN32) # define open _open #endif +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) + /* MSC has the version as _snprintf */ +# define snprintf _snprintf +#elif !defined(HAVE_SNPRINTF) +# error You do not have snprintf on your system. +#endif /* HAVE_SNPRINTF */ #include "bits.h" #include "debug.h" @@ -204,7 +210,7 @@ int json_parse_int64(const char *buf, int64_t *retval) return 0; } -#if HAVE_REALLOC == 0 +#ifndef HAVE_REALLOC void* rpl_realloc(void* p, size_t n) { if (n == 0) diff --git a/printbuf.c b/printbuf.c index b951c7b..9d56522 100644 --- a/printbuf.c +++ b/printbuf.c @@ -19,7 +19,7 @@ #include #include -#if HAVE_STDARG_H +#ifdef HAVE_STDARG_H # include #else /* !HAVE_STDARG_H */ # error Not enough var arg support! @@ -108,13 +108,13 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) return 0; } -#if !HAVE_VSNPRINTF && defined(_MSC_VER) +#if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) # define vsnprintf _vsnprintf -#elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ +#elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ # error Need vsnprintf! #endif /* !HAVE_VSNPRINTF && defined(WIN32) */ -#if !HAVE_VASPRINTF +#if !defined(HAVE_VASPRINTF) /* CAW: compliant version of vasprintf */ static int vasprintf(char **buf, const char *fmt, va_list ap) { From 271c53ebdd6ca995a6feec6dd67881e15b7a9eb0 Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Tue, 22 May 2012 23:51:44 +0100 Subject: [PATCH 133/276] Missing explicit casts from void* to specific pointers required. Added #define strcasecmp for Visual C++. --- json_object.c | 2 +- tests/parse_flags.c | 8 ++++++++ tests/test1.c | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index 8e399de..2258c02 100644 --- a/json_object.c +++ b/json_object.c @@ -538,7 +538,7 @@ struct json_object* json_object_new_string_len(const char *s, int len) 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); + jso->o.c_string.str = (char*)malloc(len); memcpy(jso->o.c_string.str, (void *)s, len); jso->o.c_string.len = len; return jso; diff --git a/tests/parse_flags.c b/tests/parse_flags.c index fafabc8..e33ffee 100644 --- a/tests/parse_flags.c +++ b/tests/parse_flags.c @@ -1,9 +1,17 @@ +#include "config.h" + #include #include #include "json.h" #include "parse_flags.h" +#if !defined(HAVE_STRCASECMP) && defined(_MSC_VER) +# define strcasecmp _stricmp +#elif !defined(HAVE_STRCASECMP) +# error You do not have strcasecmp on your system. +#endif /* HAVE_STRNCASECMP */ + static struct { const char *arg; int flag; diff --git a/tests/test1.c b/tests/test1.c index 9802eb1..87d7ea4 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -12,8 +12,8 @@ static int sort_fn (const void *j1, const void *j2) json_object * const *jso1, * const *jso2; int i1, i2; - jso1 = j1; - jso2 = j2; + jso1 = (json_object* const*)j1; + jso2 = (json_object* const*)j2; if (!*jso1 && !*jso2) { return 0; } From 837d685d787366a9bf5266c91a9867dd1cafc420 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 30 May 2012 23:03:34 -0500 Subject: [PATCH 134/276] Use "nodoc", not "doc", for the name of the tarball w/o docs. --- RELEASE_CHECKLIST.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 28f5b89..c803449 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -34,7 +34,7 @@ echo autom4te.cache >> excludes tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} echo doc >> excludes -tar -czf json-c-${release}-doc.tar.gz -X excludes json-c-${release} +tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} Tag the branch: cd json-c-${release} From 984303dfe590eb448ad319564057d4f7c6a97aa2 Mon Sep 17 00:00:00 2001 From: Mateusz Loskot Date: Tue, 19 Jun 2012 20:15:44 +0100 Subject: [PATCH 135/276] Added a bunch of missing HAVE_* defines tested with ./configure script to fix compilation on Linux with GCC 4.7.1. The issue likely caused by my previous commits related to Visual C++ port of the code. --- config.h.in | 9 +++++++++ configure.in | 2 +- tests/test_printbuf.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/config.h.in b/config.h.in index 04f5dc5..2dad0d9 100644 --- a/config.h.in +++ b/config.h.in @@ -29,6 +29,9 @@ and to 0 otherwise. */ #undef HAVE_REALLOC +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H @@ -38,6 +41,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR diff --git a/configure.in b/configure.in index b2c3cbe..bcb9027 100644 --- a/configure.in +++ b/configure.in @@ -27,7 +27,7 @@ AC_FUNC_VPRINTF AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS(strndup strerror vsnprintf vasprintf open vsyslog strncasecmp) +AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp) AM_PROG_LIBTOOL diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index 3676b54..ee3f80d 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -124,7 +124,7 @@ static void test_sprintbuf(int before_resize) memset(data, 'X', before_resize + 1 + 1); data[before_resize + 1] = '\0'; sprintbuf(pb, "%s", data); - printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, strlen(pb->buf)); + printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, (int)strlen(pb->buf)); printbuf_reset(pb); sprintbuf(pb, "plain"); From eead1a7dc42d9f6c781ce5eb5eed1ec0e053cc07 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Jul 2012 20:32:12 -0500 Subject: [PATCH 136/276] Remove unnecessary comment from json_util.c --- json_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_util.c b/json_util.c index 03fb24b..bab772b 100644 --- a/json_util.c +++ b/json_util.c @@ -71,7 +71,7 @@ struct json_object* json_object_from_file(const char *filename) if((fd = open(filename, O_RDONLY)) < 0) { MC_ERROR("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); - return NULL; // XAX this is an API change! + return NULL; } if(!(pb = printbuf_new())) { close(fd); From 9791c3896e6b2c30dc762013af41dd62ad1421bb Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Jul 2012 20:33:25 -0500 Subject: [PATCH 137/276] Fix git commands for tagging a release. --- RELEASE_CHECKLIST.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index c803449..1eccac8 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -38,7 +38,9 @@ tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} Tag the branch: cd json-c-${release} -git tag json-c-${release}-$(date +%Y%m%d) +git tag -a json-c-${release}-$(date +%Y%m%d) +git push +git push --tags Go to https://github.com/json-c/json-c/downloads Upload the two tarballs. From 4154c55edae6f6b34d6ef4fcc331055fdf8e1a23 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Jul 2012 20:38:53 -0500 Subject: [PATCH 138/276] Add json_object_iterator.h to installed headers. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index d4a7bbb..8f09ca8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,6 +17,7 @@ libjsoninclude_HEADERS = \ json_config.h \ json_inttypes.h \ json_object.h \ + json_object_iterator.h \ json_object_private.h \ json_tokener.h \ json_util.h \ From 6d9437725acbeaf9619beb326d6363e7dd96f1e2 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 11 Jul 2012 15:33:49 -0400 Subject: [PATCH 139/276] autogen.sh: Add /bin/sh interpreter, honor NOCONFIGURE=1 First, we should be able to execute as "./autogen.sh". Second, add support for NOCONFIGURE=1. For more information, see http://people.gnome.org/~walters/docs/build-api.txt --- autogen.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 990096c..169d689 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,2 +1,5 @@ +#!/bin/sh autoreconf -v --install || exit 1 -exec ./configure "$@" +if test -z "$NOCONFIGURE"; then + exec ./configure "$@" +fi From 6988f53fcb05c13d99dd846494d79ea3bb3b1d4c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 24 Jul 2012 23:27:41 -0500 Subject: [PATCH 140/276] Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. This is particularly useful when replacing values in a loop, since it allows the key used by json_object_object_foreach to continue to be used. --- json_object.c | 16 +++++++-- tests/Makefile.am | 5 ++- tests/testReplaceExisting.c | 56 ++++++++++++++++++++++++++++++ tests/testReplaceExisting.expected | 9 +++++ tests/testReplaceExisting.test | 12 +++++++ 5 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 tests/testReplaceExisting.c create mode 100644 tests/testReplaceExisting.expected create mode 100755 tests/testReplaceExisting.test diff --git a/json_object.c b/json_object.c index 2258c02..8dd13b0 100644 --- a/json_object.c +++ b/json_object.c @@ -306,8 +306,20 @@ struct lh_table* json_object_get_object(struct json_object *jso) 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); + // We lookup the entry and replace the value, rather than just deleting + // and re-adding it, so the existing key remains valid. + json_object *existing_value = NULL; + struct lh_entry *existing_entry; + existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); + if (!existing_entry) + { + lh_table_insert(jso->o.c_object, strdup(key), val); + return; + } + existing_value = (void *)existing_entry->v; + if (existing_value) + json_object_put(existing_value); + existing_entry->v = val; } struct json_object* json_object_object_get(struct json_object* jso, const char *key) diff --git a/tests/Makefile.am b/tests/Makefile.am index e2854dd..635ce55 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,6 +6,7 @@ LIBJSON_LA=$(top_builddir)/libjson.la check_PROGRAMS = test1 test1Formatted check_PROGRAMS += test2 test2Formatted check_PROGRAMS += test4 +check_PROGRAMS += testReplaceExisting check_PROGRAMS += test_parse_int64 check_PROGRAMS += test_null check_PROGRAMS += test_cast @@ -25,6 +26,8 @@ test2Formatted_CPPFLAGS = -DTEST_FORMATTED test4_LDADD = $(LIBJSON_LA) +testReplaceExisting_LDADD = $(LIBJSON_LA) + test_parse_int64_LDADD = $(LIBJSON_LA) test_null_LDADD = $(LIBJSON_LA) @@ -33,7 +36,7 @@ test_cast_LDADD = $(LIBJSON_LA) test_parse_LDADD = $(LIBJSON_LA) -TESTS = test1.test test2.test test4.test parse_int64.test test_null.test test_cast.test test_parse.test +TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c new file mode 100644 index 0000000..8c8c4b2 --- /dev/null +++ b/tests/testReplaceExisting.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include "json.h" + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + /* + * Check that replacing an existing object keeps the key valid, + * and that it keeps the order the same. + */ + json_object *my_object = json_object_new_object(); + json_object_object_add(my_object, "foo1", json_object_new_string("bar1")); + json_object_object_add(my_object, "foo2", json_object_new_string("bar2")); + json_object_object_add(my_object, "foo3", json_object_new_string("bar3")); + const char *original_key = NULL; + int orig_count = 0; + json_object_object_foreach(my_object, key, val) + { + printf("Key at index %d is [%s]\n", orig_count, key); + orig_count++; + if (strcmp(key, "foo2") != 0) + continue; + printf("replacing value for key [%s]\n", key); + original_key = key; + json_object_object_add(my_object, key, json_object_new_string("zzz")); + } + + printf("==== second loop starting ====\n"); + + int new_count = 0; + int retval = 0; + json_object_object_foreach(my_object, key2, val2) + { + printf("Key at index %d is [%s]\n", new_count, key2); + new_count++; + if (strcmp(key2, "foo2") != 0) + continue; + printf("pointer for key [%s] does %smatch\n", key2, + (key2 == original_key) ? "" : "NOT "); + if (key2 != original_key) + retval = 1; + } + if (new_count != orig_count) + { + printf("mismatch between original count (%d) and new count (%d)\n", + orig_count, new_count); + retval = 1; + } + + return 0; +} diff --git a/tests/testReplaceExisting.expected b/tests/testReplaceExisting.expected new file mode 100644 index 0000000..4d1c509 --- /dev/null +++ b/tests/testReplaceExisting.expected @@ -0,0 +1,9 @@ +Key at index 0 is [foo1] +Key at index 1 is [foo2] +replacing value for key [foo2] +Key at index 2 is [foo3] +==== second loop starting ==== +Key at index 0 is [foo1] +Key at index 1 is [foo2] +pointer for key [foo2] does match +Key at index 2 is [foo3] diff --git a/tests/testReplaceExisting.test b/tests/testReplaceExisting.test new file mode 100755 index 0000000..ec5cbf1 --- /dev/null +++ b/tests/testReplaceExisting.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test testReplaceExisting +exit $? From 77c623946517cdfe2eb80ea1e7b0ad6752216667 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 12:13:54 -0500 Subject: [PATCH 141/276] Initialize errno before calling sscanf in json_parse_int64() so parsing valid numbers after parsing an out of range number works. --- json_util.c | 9 ++++++--- tests/test_parse_int64.c | 10 ++++++++++ tests/test_parse_int64.expected | 3 +++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/json_util.c b/json_util.c index bab772b..79ae5c7 100644 --- a/json_util.c +++ b/json_util.c @@ -147,11 +147,14 @@ int json_parse_int64(const char *buf, int64_t *retval) int64_t num64; const char *buf_skip_space; int orig_has_neg; + int _errno; + errno = 0; // sscanf won't always set errno, so initialize if (sscanf(buf, "%" SCNd64, &num64) != 1) { MC_DEBUG("Failed to parse, sscanf != 1\n"); return 1; } + _errno = errno; buf_skip_space = buf; orig_has_neg = 0; // Skip leading spaces @@ -168,7 +171,7 @@ int json_parse_int64(const char *buf, int64_t *retval) 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) + if (_errno != ERANGE) { char buf_cmp[100]; char *buf_cmp_start = buf_cmp; @@ -196,10 +199,10 @@ int json_parse_int64(const char *buf, int64_t *retval) ) ) { - errno = ERANGE; + _errno = ERANGE; } } - if (errno == ERANGE) + if (_errno == ERANGE) { if (orig_has_neg) num64 = INT64_MIN; diff --git a/tests/test_parse_int64.c b/tests/test_parse_int64.c index 0893356..c251e01 100644 --- a/tests/test_parse_int64.c +++ b/tests/test_parse_int64.c @@ -80,6 +80,9 @@ int main() strcpy(buf, "-21474836480"); // INT32_MIN * 10 checkit(buf); + strcpy(buf, "9223372036854775806"); // INT64_MAX - 1 + checkit(buf); + strcpy(buf, "9223372036854775807"); // INT64_MAX checkit(buf); @@ -92,6 +95,9 @@ int main() strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1 checkit(buf); + strcpy(buf, "18446744073709551614"); // UINT64_MAX - 1 + checkit(buf); + strcpy(buf, "18446744073709551615"); // UINT64_MAX checkit(buf); @@ -101,5 +107,9 @@ int main() strcpy(buf, "-18446744073709551616"); // -UINT64_MAX checkit(buf); + // Ensure we can still parse valid numbers after parsing out of range ones. + strcpy(buf, "123"); + checkit(buf); + return 0; } diff --git a/tests/test_parse_int64.expected b/tests/test_parse_int64.expected index 23a9803..d9cdf5a 100644 --- a/tests/test_parse_int64.expected +++ b/tests/test_parse_int64.expected @@ -17,10 +17,13 @@ buf=-2147483647 parseit=0, value=-2147483647 buf=-2147483648 parseit=0, value=-2147483648 buf=-2147483649 parseit=0, value=-2147483649 buf=-21474836480 parseit=0, value=-21474836480 +buf=9223372036854775806 parseit=0, value=9223372036854775806 buf=9223372036854775807 parseit=0, value=9223372036854775807 buf=9223372036854775808 parseit=0, value=9223372036854775807 buf=-9223372036854775808 parseit=0, value=-9223372036854775808 buf=-9223372036854775809 parseit=0, value=-9223372036854775808 +buf=18446744073709551614 parseit=0, value=9223372036854775807 buf=18446744073709551615 parseit=0, value=9223372036854775807 buf=18446744073709551616 parseit=0, value=9223372036854775807 buf=-18446744073709551616 parseit=0, value=-9223372036854775808 +buf=123 parseit=0, value=123 From 8fcfeb63ec28e5184309cf249d6a6e81c0c53e34 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 12:18:37 -0500 Subject: [PATCH 142/276] Default autogen.sh to not running configure, unless some command line options are specified. --- autogen.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 169d689..69e765a 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,13 @@ #!/bin/sh autoreconf -v --install || exit 1 -if test -z "$NOCONFIGURE"; then + +# If there are any options, assume the user wants to run configure. +# To run configure w/o any options, use ./autogen.sh --configure +if [ $# -gt 0 ] ; then + case "$1" in + --conf*) + shift 1 + ;; + esac exec ./configure "$@" fi From 92f31bd99a3c5f7d7ea7c2fd1ab56d83caf786b0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 12:31:07 -0500 Subject: [PATCH 143/276] Handle the \f escape sequence (the two characters: backslash followed by an f, not a literal formfeed) and extend the test_parse test to check all valid escape sequences. --- json_tokener.c | 2 ++ tests/test_parse.c | 11 +++++++++++ tests/test_parse.expected | 11 ++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 47768f4..f5fa8d6 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -423,10 +423,12 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case 'n': case 'r': case 't': + case 'f': if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1); else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1); else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1); else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1); + else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1); state = saved_state; break; case 'u': diff --git a/tests/test_parse.c b/tests/test_parse.c index 0040760..975fb52 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -166,6 +166,15 @@ struct incremental_step { /* Strings have a well defined end point, so we can stop at the quote */ { "\"blue\"", -1, -1, json_tokener_success, 0 }, + /* Check each of the escape sequences defined by the spec */ + { "\"\\\"\"", -1, -1, json_tokener_success, 0 }, + { "\"\\\\\"", -1, -1, json_tokener_success, 0 }, + { "\"\\b\"", -1, -1, json_tokener_success, 0 }, + { "\"\\f\"", -1, -1, json_tokener_success, 0 }, + { "\"\\n\"", -1, -1, json_tokener_success, 0 }, + { "\"\\r\"", -1, -1, json_tokener_success, 0 }, + { "\"\\t\"", -1, -1, json_tokener_success, 0 }, + { "[1,2,3]", -1, -1, json_tokener_success, 0 }, /* This behaviour doesn't entirely follow the json spec, but until we have @@ -190,6 +199,8 @@ static void test_incremental_parse() num_error = 0; printf("Starting incremental tests.\n"); + printf("Note: quotes and backslashes seen in the output here are literal values passed\n"); + printf(" to the parse functions. e.g. this is 4 characters: \"\\f\"\n"); string_to_parse = "{ \"foo"; /* } */ printf("json_tokener_parse(%s) ... ", string_to_parse); diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 2481bde..97910dc 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -21,6 +21,8 @@ new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "a json_tokener_parse_versbose() OK ================================== Starting incremental tests. +Note: quotes and backslashes seen in the output here are literal values passed + to the parse functions. e.g. this is 4 characters: "\f" json_tokener_parse({ "foo) ... got error as expected json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 } json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 } @@ -39,8 +41,15 @@ json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" +json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\"" +json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\" +json_tokener_parse_ex(tok, "\b" , 4) ... OK: got object of type [string]: "\b" +json_tokener_parse_ex(tok, "\f" , 4) ... OK: got object of type [string]: "\u000c" +json_tokener_parse_ex(tok, "\n" , 4) ... OK: got object of type [string]: "\n" +json_tokener_parse_ex(tok, "\r" , 4) ... OK: got object of type [string]: "\r" +json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string]: "\t" json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character -End Incremental Tests OK=20 ERROR=0 +End Incremental Tests OK=27 ERROR=0 ================================== From ba1c3810cb95218821b2cd5168fa0984a37e584a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 14:08:26 -0500 Subject: [PATCH 144/276] Remove test_parse from the top level directory. (accidentally re-introduced with the last merge) --- test_parse.c | 270 -------------------------------------------- test_parse.expected | 46 -------- test_parse.test | 12 -- 3 files changed, 328 deletions(-) delete mode 100644 test_parse.c delete mode 100644 test_parse.expected delete mode 100755 test_parse.test diff --git a/test_parse.c b/test_parse.c deleted file mode 100644 index 0040760..0000000 --- a/test_parse.c +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include -#include -#include -#include - -#include "json.h" -#include "json_tokener.h" - -static void test_basic_parse(void); -static void test_verbose_parse(void); -static void test_incremental_parse(void); - -int main(int argc, char **argv) -{ - MC_SET_DEBUG(1); - - test_basic_parse(); - printf("==================================\n"); - test_verbose_parse(); - printf("==================================\n"); - test_incremental_parse(); - printf("==================================\n"); -} - -static void test_basic_parse() -{ - json_object *new_obj; - - new_obj = json_tokener_parse("\"\003\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("/* hello */\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("// hello\n\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("null"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("True"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("12.3"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[null]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[false]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{}"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); - - new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); -} - -static void test_verbose_parse() -{ - json_object *new_obj; - enum json_tokener_error error = json_tokener_success; - - new_obj = json_tokener_parse_verbose("{ foo }", &error); - assert (error == json_tokener_error_parse_object_key_name); - assert (new_obj == NULL); - - new_obj = json_tokener_parse("{ foo }"); - assert (new_obj == NULL); - - new_obj = json_tokener_parse("foo"); - assert (new_obj == NULL); - new_obj = json_tokener_parse_verbose("foo", &error); - assert (new_obj == NULL); - - /* b/c the string starts with 'f' parsing return a boolean error */ - assert (error == json_tokener_error_parse_boolean); - - printf("json_tokener_parse_versbose() OK\n"); -} - -struct incremental_step { - const char *string_to_parse; - int length; - int char_offset; - enum json_tokener_error expected_error; - int reset_tokener; -} incremental_steps[] = { - - /* Check that full json messages can be parsed, both w/ and w/o a reset */ - { "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 }, - { "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 }, - { "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 }, - - /* Check a basic incremental parse */ - { "{ \"foo", -1, -1, json_tokener_continue, 0 }, - { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, - { "\":13}}", -1, -1, json_tokener_success, 1 }, - - /* Check that json_tokener_reset actually resets */ - { "{ \"foo", -1, -1, json_tokener_continue, 1 }, - { ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 }, - - /* Check incremental parsing with trailing characters */ - { "{ \"foo", -1, -1, json_tokener_continue, 0 }, - { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, - { "\":13}}XXXX", 10, 6, json_tokener_success, 0 }, - { "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 }, - - /* Check that trailing characters can change w/o a reset */ - { "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 }, - { "\"Y\"", -1, -1, json_tokener_success, 1 }, - - /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ - { "1", 1, 1, json_tokener_continue, 0 }, - { "2", 2, 1, json_tokener_success, 0 }, - - /* Strings have a well defined end point, so we can stop at the quote */ - { "\"blue\"", -1, -1, json_tokener_success, 0 }, - - { "[1,2,3]", -1, -1, json_tokener_success, 0 }, - - /* This behaviour doesn't entirely follow the json spec, but until we have - a way to specify how strict to be we follow Postel's Law and be liberal - in what we accept (up to a point). */ - { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, - { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, - - { NULL, json_tokener_success }, -}; - -static void test_incremental_parse() -{ - json_object *new_obj; - enum json_tokener_error jerr; - json_tokener *tok; - const char *string_to_parse; - int ii; - int num_ok, num_error; - - num_ok = 0; - num_error = 0; - - printf("Starting incremental tests.\n"); - - string_to_parse = "{ \"foo"; /* } */ - printf("json_tokener_parse(%s) ... ", string_to_parse); - new_obj = json_tokener_parse(string_to_parse); - if (new_obj == NULL) printf("got error as expected\n"); - - /* test incremental parsing in various forms */ - tok = json_tokener_new(); - for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++) - { - int this_step_ok = 0; - struct incremental_step *step = &incremental_steps[ii]; - int length = step->length; - int expected_char_offset = step->char_offset; - if (length == -1) - length = strlen(step->string_to_parse); - if (expected_char_offset == -1) - expected_char_offset = length; - - printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ", - step->string_to_parse, length); - new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length); - - jerr = json_tokener_get_error(tok); - if (step->expected_error != json_tokener_success) - { - if (new_obj != NULL) - printf("ERROR: invalid object returned: %s\n", - json_object_to_json_string(new_obj)); - else if (jerr != step->expected_error) - printf("ERROR: got wrong error: %s\n", - json_tokener_error_desc(jerr)); - else if (tok->char_offset != expected_char_offset) - printf("ERROR: wrong char_offset %d != expected %d\n", - tok->char_offset, - expected_char_offset); - else - { - printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr)); - this_step_ok = 1; - } - } - else - { - if (new_obj == NULL) - printf("ERROR: expected valid object, instead: %s\n", - json_tokener_error_desc(jerr)); - else if (tok->char_offset != expected_char_offset) - printf("ERROR: wrong char_offset %d != expected %d\n", - tok->char_offset, - expected_char_offset); - else - { - printf("OK: got object of type [%s]: %s\n", - json_type_to_name(json_object_get_type(new_obj)), - json_object_to_json_string(new_obj)); - this_step_ok = 1; - } - } - - if (new_obj) - json_object_put(new_obj); - - if (step->reset_tokener) - json_tokener_reset(tok); - - if (this_step_ok) - num_ok++; - else - num_error++; - } - - json_tokener_free(tok); - - printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error); - - return; -} diff --git a/test_parse.expected b/test_parse.expected deleted file mode 100644 index 2481bde..0000000 --- a/test_parse.expected +++ /dev/null @@ -1,46 +0,0 @@ -new_obj.to_string()="\u0003" -new_obj.to_string()="foo" -new_obj.to_string()="foo" -new_obj.to_string()="ABC" -new_obj.to_string()=null -new_obj.to_string()=true -new_obj.to_string()=12 -new_obj.to_string()=12.300000 -new_obj.to_string()=[ "\n" ] -new_obj.to_string()=[ "\nabc\n" ] -new_obj.to_string()=[ null ] -new_obj.to_string()=[ ] -new_obj.to_string()=[ false ] -new_obj.to_string()=[ "abc", null, "def", 12 ] -new_obj.to_string()={ } -new_obj.to_string()={ "foo": "bar" } -new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true } -new_obj.to_string()={ "foo": [ null, "foo" ] } -new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] } -================================== -json_tokener_parse_versbose() OK -================================== -Starting incremental tests. -json_tokener_parse({ "foo) ... got error as expected -json_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 } -json_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 } -json_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 } -json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue -json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue -json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } } -json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue -json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character -json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue -json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue -json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } } -json_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character -json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 } -json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" -json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue -json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 -json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" -json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] -json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] -json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character -End Incremental Tests OK=20 ERROR=0 -================================== diff --git a/test_parse.test b/test_parse.test deleted file mode 100755 index 70d1c82..0000000 --- a/test_parse.test +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# Common definitions -if test -z "$srcdir"; then - srcdir="${0%/*}" - test "$srcdir" = "$0" && srcdir=. - test -z "$srcdir" && srcdir=. -fi -. "$srcdir/test-defs.sh" - -run_output_test test_parse -exit $? From eb37094aa604634fa8e838a2aca78e5c3d1d6d55 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 14:57:59 -0500 Subject: [PATCH 145/276] Check for the sys/cdefs.h header which on some systems defines the __warn_references macro. --- config.h.in | 3 +++ configure.in | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config.h.in b/config.h.in index 2dad0d9..34ad9a8 100644 --- a/config.h.in +++ b/config.h.in @@ -65,6 +65,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CDEFS_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H diff --git a/configure.in b/configure.in index 79eafd1..90255c1 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ AC_PROG_MAKE_SET 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_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.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. From b98aa6eaa3a0ac6ee8c4c7239bddc972abebe8ab Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 14:59:01 -0500 Subject: [PATCH 146/276] Create an additional libjson.so library that simply links against libjson-c, but emits a warning encouraging the use of the new library. --- Makefile.am | 6 +++++- libjson.c | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 libjson.c diff --git a/Makefile.am b/Makefile.am index 868cf97..ecd4097 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,7 @@ include Makefile.am.inc EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj SUBDIRS = . tests -lib_LTLIBRARIES = libjson-c.la +lib_LTLIBRARIES = libjson-c.la libjson.la pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = json-c.pc @@ -30,6 +30,10 @@ libjsoninclude_HEADERS = \ # json_config.h libjson_c_la_LDFLAGS = -version-info 1:0:1 -no-undefined +libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c + +# Temporary libjson library. This will be removed after one release. +libjson_la_LIBADD = -ljson-c libjson_c_la_SOURCES = \ arraylist.c \ diff --git a/libjson.c b/libjson.c new file mode 100644 index 0000000..48fc3a4 --- /dev/null +++ b/libjson.c @@ -0,0 +1,27 @@ + +/* dummy source file for compatibility purposes */ + +#if defined(HAVE_CDEFS_H) +#include +#endif + +#ifndef __warn_references + +#ifdef __GNUC__ +#define __warn_references(sym,msg) \ + __asm(".pushsection .gnu.warning." #sym "\n" \ + ".ascii \"" msg "\"\n" \ + ".popsection"); + +#else +#define __warn_references(sym,msg) /* nothing */ +#endif + +#endif + +#include "json_object.h" + +__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); + +/* __asm__(".section .gnu.warning." __STRING(sym) \ + " ; .ascii \"" msg "\" ; .text") */ From 082419edf91c84cdd78510652173dfe5127ecec3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 15:09:59 -0500 Subject: [PATCH 147/276] Fix the Libs line in json-uninstalled.pc to use -ljson-c --- json-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-uninstalled.pc.in b/json-uninstalled.pc.in index 967f771..dab2bab 100644 --- a/json-uninstalled.pc.in +++ b/json-uninstalled.pc.in @@ -7,5 +7,5 @@ Name: json Description: JSON implementation in C Version: @VERSION@ Requires: -Libs: -L@abs_top_builddir@ -ljson +Libs: -L@abs_top_builddir@ -ljson-c Cflags: -I@abs_top_srcdir@ From c7a21203de9cf9c232a36c8e68e25aca5247d662 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 15:10:30 -0500 Subject: [PATCH 148/276] Ignore a couple more generated files. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6da095d..8e60343 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ /depcomp /install-sh /json-c.pc +/json-uninstalled.pc /libtool /ltmain.sh /Makefile @@ -36,4 +37,5 @@ /Release *.lo *.o +/libjson-c.la /libjson.la From 075b783631c320bce55deb6c9a0fa2b35fa4cd65 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 17:48:22 -0500 Subject: [PATCH 149/276] Add a --disable-oldname-compat option to configure to turn off the creation of the libjson.so library, and only include libjson-c.so --- Makefile.am | 13 ++++++++++--- configure.in | 8 ++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index ecd4097..0de3d21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,13 +3,16 @@ include Makefile.am.inc EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj SUBDIRS = . tests -lib_LTLIBRARIES = libjson-c.la libjson.la +lib_LTLIBRARIES = libjson-c.la +if ENABLE_OLDNAME_COMPAT +lib_LTLIBRARIES+=libjson.la +endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = json-c.pc -libjsonincludedir = $(includedir)/json-c -libjsoninclude_HEADERS = \ +libjson_cincludedir = $(includedir)/json-c +libjson_cinclude_HEADERS = \ arraylist.h \ bits.h \ debug.h \ @@ -30,10 +33,14 @@ libjsoninclude_HEADERS = \ # json_config.h libjson_c_la_LDFLAGS = -version-info 1:0:1 -no-undefined + +if ENABLE_OLDNAME_COMPAT libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c # Temporary libjson library. This will be removed after one release. libjson_la_LIBADD = -ljson-c +endif + libjson_c_la_SOURCES = \ arraylist.c \ diff --git a/configure.in b/configure.in index 90255c1..032dc8d 100644 --- a/configure.in +++ b/configure.in @@ -7,6 +7,14 @@ AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) AC_PROG_MAKE_SET +AC_ARG_ENABLE(oldname-compat, + AS_HELP_STRING([--disable-oldname-compat], + [Don't include the old libjson.so library and include/json directory.]), +[], +[enable_oldname_compat=yes] +) +AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno"]) + # Checks for programs. # Checks for libraries. From 943b7a4de78b7c9c0765d157df0d4db0adabbf26 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 18:05:08 -0500 Subject: [PATCH 150/276] Add a compatibility symlink json->json-c in the include directory. --- Makefile.am | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile.am b/Makefile.am index 0de3d21..41ea9fb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,17 @@ 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 +if ENABLE_OLDNAME_COMPAT +install-data-hook: + test \! -d "$(includedir)/json" || rmdir "$(includedir)/json" + test \! -e "$(includedir)/json" || rm "$(includedir)/json" + $(LN_S) json-c "$(includedir)/json" + +uninstall-local: + rm -f "$(includedir)/json" + +endif + ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H Android.mk: Makefile.am From 9f16e25a3e7bb38d89f6f92758da905dd3476db7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 18:05:34 -0500 Subject: [PATCH 151/276] Bump the version of the new library since programs will need to be re-linked to use it. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 41ea9fb..ee6ca16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ libjson_cinclude_HEADERS = \ #libjsonx_include_HEADERS = \ # json_config.h -libjson_c_la_LDFLAGS = -version-info 1:0:1 -no-undefined +libjson_c_la_LDFLAGS = -version-info 2:0:0 -no-undefined if ENABLE_OLDNAME_COMPAT libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c From 1f9d199522af1b6fb61df3f60dc1a68d6c7e0e72 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 18:25:09 -0500 Subject: [PATCH 152/276] Re-add the "json" pkg-config file as a compatibility shim. Also rename the json-c-uninstalled.pc file. --- .gitignore | 3 ++- Makefile.am | 3 +++ configure.in | 3 ++- json-uninstalled.pc.in => json-c-uninstalled.pc.in | 0 json.pc.in | 11 +++++++++++ 5 files changed, 18 insertions(+), 2 deletions(-) rename json-uninstalled.pc.in => json-c-uninstalled.pc.in (100%) create mode 100644 json.pc.in diff --git a/.gitignore b/.gitignore index 8e60343..c3b5f80 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,9 @@ /configure /depcomp /install-sh +/json.pc /json-c.pc -/json-uninstalled.pc +/json-c-uninstalled.pc /libtool /ltmain.sh /Makefile diff --git a/Makefile.am b/Makefile.am index ee6ca16..83bacd4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,6 +10,9 @@ endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = json-c.pc +if ENABLE_OLDNAME_COMPAT +pkgconfig_DATA += json.pc +endif libjson_cincludedir = $(includedir)/json-c libjson_cinclude_HEADERS = \ diff --git a/configure.in b/configure.in index 032dc8d..5b2eea3 100644 --- a/configure.in +++ b/configure.in @@ -41,9 +41,10 @@ AM_PROG_LIBTOOL AC_CONFIG_FILES([ Makefile +json.pc json-c.pc tests/Makefile -json-uninstalled.pc +json-c-uninstalled.pc ]) AC_OUTPUT diff --git a/json-uninstalled.pc.in b/json-c-uninstalled.pc.in similarity index 100% rename from json-uninstalled.pc.in rename to json-c-uninstalled.pc.in diff --git a/json.pc.in b/json.pc.in new file mode 100644 index 0000000..80e75d1 --- /dev/null +++ b/json.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: json-c +Description: JSON implementation in C, compat shim. Use json-c instead. +Version: @VERSION@ +Requires: json-c +Libs: +Cflags: From 2f2180b70d262c6a58d0744e10b9b5ad4a226c6d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 18:29:38 -0500 Subject: [PATCH 153/276] Take a guess as to the rename changes changes needed to the Android part of the build. I think this should work, but I can't test it. --- Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 83bacd4..09221a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -74,13 +74,13 @@ ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H Android.mk: Makefile.am androgenizer -:PROJECT json-c \ - -:SHARED libjson \ + -:SHARED libjson-c \ -:TAGS eng debug \ -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \ - -:SOURCES $(libjson_la_SOURCES) $(nodist_libjson_la_SOURCES) \ - -:CFLAGS $(DEFS) $(ANDROID_CFLAGS) $(libjson_la_CFLAGS) \ - -:LDFLAGS $(libjson_la_LDFLAGS) $(libjson_la_LIBADD) \ - -:HEADER_TARGET json \ - -:HEADERS $(libjsoninclude_HEADERS) \ + -:SOURCES $(libjson_c_la_SOURCES) $(nodist_libjson_c_la_SOURCES) \ + -:CFLAGS $(DEFS) $(ANDROID_CFLAGS) $(libjson_c_la_CFLAGS) \ + -:LDFLAGS $(libjson_c_la_LDFLAGS) $(libjson_c_la_LIBADD) \ + -:HEADER_TARGET json-c \ + -:HEADERS $(libjson_cinclude_HEADERS) \ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ > $@ From 8ce53f9d1e019995e3e08b20112b88b0262dc883 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 18:43:55 -0500 Subject: [PATCH 154/276] Note the rename in the ChangeLog, and update the instructions in the README file. --- ChangeLog | 10 ++++++++++ README | 14 +++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0fd4a3..42a3da9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ + +NEXT.VERSION + + * IMPORTANT: the name of the library has changed to libjson-c.so and + the header files are now in include/json-c. + The pkgconfig name has also changed from json to json-c. + You should change your build to use appropriate -I and -l options. + A compatibility shim is in place so builds using the old name will + continue to work, but that will be removed in the next release. + 0.10 * Add a json_object_to_json_string_ext() function to allow output to be diff --git a/README b/README index 05ec274..20adddc 100644 --- a/README +++ b/README @@ -3,6 +3,8 @@ Building on Unix with git, gcc and autotools Home page for json-c: http://oss.metaparadigm.com/json-c/ + Caution: do NOT use sources from svn.metaparadigm.com, they are old. + Github repo for json-c: https://github.com/json-c/json-c @@ -20,9 +22,15 @@ To build and run the test programs run $ make check -Linking to libjson +Linking to libjson-c 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) +CFLAGS += $(shell pkg-config --cflags json-c) +LDFLAGS += $(shell pkg-config --libs json-c) + +Without pkgconfig, you would do something like this: + +JSON_C_DIR=/path/to/json_c/install +CFLAGS += -I$(JSON_C_DIR)/include/json-c +LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c From d305cae12c77200b46ac1d4a2b31966c0772e49c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 20:00:28 -0500 Subject: [PATCH 155/276] Ignore the tests/testReplaceExisting binary. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c3b5f80..a5034a9 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /tests/test2 /tests/test2Formatted /tests/test4 +/tests/testReplaceExisting /tests/testSubDir /tests/test_parse_int64 /tests/test_parse From f74e8f8f9b1314293623c293e10fc838b89c7ddb Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 29 Jul 2012 20:02:00 -0500 Subject: [PATCH 156/276] Add my copyright. --- COPYING | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/COPYING b/COPYING index f8ff2e1..740d125 100644 --- a/COPYING +++ b/COPYING @@ -1,3 +1,26 @@ + +Copyright (c) 2009-2012 Eric Haszlakiewicz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------- + Copyright (c) 2004, 2005 Metaparadigm Pte Ltd Permission is hereby granted, free of charge, to any person obtaining a From 38f421a2e7f4453bdc7f206681dbcbfb1b00de4c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 2 Sep 2012 15:21:56 -0500 Subject: [PATCH 157/276] Add a json_set_serializer() function to allow the string output of a json_object to be customized. --- .gitignore | 1 + json_object.c | 72 ++++++++++++++++++++++++++++-- json_object.h | 45 +++++++++++++++++++ json_object_private.h | 10 ++--- tests/Makefile.am | 4 ++ tests/test_set_serializer.c | 71 +++++++++++++++++++++++++++++ tests/test_set_serializer.expected | 9 ++++ tests/test_set_serializer.test | 12 +++++ 8 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 tests/test_set_serializer.c create mode 100644 tests/test_set_serializer.expected create mode 100755 tests/test_set_serializer.test diff --git a/.gitignore b/.gitignore index a5034a9..843fb3c 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ /tests/test_cast /tests/test_null /tests/test_printbuf +/tests/test_set_serializer /Debug /Release *.lo diff --git a/json_object.c b/json_object.c index 8dd13b0..d11efc5 100644 --- a/json_object.c +++ b/json_object.c @@ -46,6 +46,13 @@ const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object* jso); static struct json_object* json_object_new(enum json_type o_type); +static json_object_to_json_string_fn json_object_object_to_json_string; +static json_object_to_json_string_fn json_object_boolean_to_json_string; +static json_object_to_json_string_fn json_object_int_to_json_string; +static json_object_to_json_string_fn json_object_double_to_json_string; +static json_object_to_json_string_fn json_object_string_to_json_string; +static json_object_to_json_string_fn json_object_array_to_json_string; + /* ref count debugging */ @@ -134,10 +141,16 @@ extern struct json_object* json_object_get(struct json_object *jso) extern void json_object_put(struct json_object *jso) { - if(jso) { - jso->_ref_count--; - if(!jso->_ref_count) jso->_delete(jso); - } + if(jso) + { + jso->_ref_count--; + if(!jso->_ref_count) + { + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + jso->_delete(jso); + } + } } @@ -187,6 +200,57 @@ enum json_type json_object_get_type(struct json_object *jso) return jso->o_type; } +/* set a custom conversion to string */ + +void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn to_string_func, + void *userdata, + json_object_delete_fn *user_delete) +{ + // First, clean up any previously existing user info + if (jso->_user_delete) + { + jso->_user_delete(jso, jso->_userdata); + } + jso->_userdata = NULL; + jso->_user_delete = NULL; + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch(jso->o_type) + { + case json_type_null: + jso->_to_json_string = NULL; + break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string; + break; + case json_type_int: + jso->_to_json_string = &json_object_int_to_json_string; + break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; + jso->_userdata = userdata; + jso->_user_delete = user_delete; +} + + /* extended conversion to string */ const char* json_object_to_json_string_ext(struct json_object *jso, int flags) diff --git a/json_object.h b/json_object.h index 6520a9a..f264629 100644 --- a/json_object.h +++ b/json_object.h @@ -70,6 +70,19 @@ typedef struct json_object json_object; typedef struct json_object_iter json_object_iter; typedef struct json_tokener json_tokener; +/** + * Type of custom user delete functions. See json_object_set_serializer. + */ +typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata); + +/** + * Type of a custom serialization function. See json_object_set_serializer. + */ +typedef int (json_object_to_json_string_fn)(struct json_object *jso, + struct printbuf *pb, + int level, + int flags); + /* supported object types */ typedef enum json_type { @@ -149,6 +162,38 @@ extern const char* json_object_to_json_string(struct json_object *obj); extern const char* json_object_to_json_string_ext(struct json_object *obj, int flags); +/** + * Set a custom serialization function to be used when this particular object + * is converted to a string by json_object_to_json_string. + * + * If a custom serializer is already set on this object, any existing + * user_delete function is called before the new one is set. + * + * If to_string_func is NULL, the other parameters are ignored + * and the default behaviour is reset. + * + * The userdata parameter is optional and may be passed as NULL. If provided, + * it is passed to to_string_func as-is. This parameter may be NULL even + * if user_delete is non-NULL. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * @param jso the object to customize + * @param to_string_func the custom serialization function + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn to_string_func, + void *userdata, + json_object_delete_fn *user_delete); + + /* object type methods */ diff --git a/json_object_private.h b/json_object_private.h index 597332b..5ed791b 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -16,16 +16,12 @@ 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, - int level, - int flags); +typedef void (json_object_private_delete_fn)(struct json_object *o); struct json_object { enum json_type o_type; - json_object_delete_fn *_delete; + json_object_private_delete_fn *_delete; json_object_to_json_string_fn *_to_json_string; int _ref_count; struct printbuf *_pb; @@ -40,6 +36,8 @@ struct json_object int len; } c_string; } o; + json_object_delete_fn *_user_delete; + void *_userdata; }; #ifdef __cplusplus diff --git a/tests/Makefile.am b/tests/Makefile.am index 635ce55..8057acd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,6 +42,10 @@ TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf test_printbuf_LDADD = $(LIBJSON_LA) +TESTS+= test_set_serializer.test +check_PROGRAMS += test_set_serializer +test_set_serializer_LDADD = $(LIBJSON_LA) + EXTRA_DIST= EXTRA_DIST += $(TESTS) diff --git a/tests/test_set_serializer.c b/tests/test_set_serializer.c new file mode 100644 index 0000000..ae0121b --- /dev/null +++ b/tests/test_set_serializer.c @@ -0,0 +1,71 @@ +#include +#include +#include + +#include "json.h" +#include "printbuf.h" + +struct myinfo { + int value; +}; + +static int freeit_was_called = 0; +static void freeit(json_object *jso, void *userdata) +{ + struct myinfo *info = userdata; + printf("freeit, value=%d\n", info->value); + // Don't actually free anything here, the userdata is stack allocated. + freeit_was_called = 1; +} +static int custom_serializer(struct json_object *o, + struct printbuf *pb, + int level, + int flags) +{ + sprintbuf(pb, "Custom Output"); + return 0; +} + +int main(int argc, char **argv) +{ + json_object *my_object; + + MC_SET_DEBUG(1); + + printf("Test setting, then resetting a custom serializer:\n"); + my_object = json_object_new_object(); + json_object_object_add(my_object, "abc", json_object_new_int(12)); + json_object_object_add(my_object, "foo", json_object_new_string("bar")); + + printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object)); + + struct myinfo userdata = { .value = 123 }; + json_object_set_serializer(my_object, custom_serializer, &userdata, freeit); + + printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object)); + + printf("Next line of output should be from the custom freeit function:\n"); + freeit_was_called = 0; + json_object_set_serializer(my_object, NULL, NULL, NULL); + assert(freeit_was_called); + + printf("my_object.to_string(standard)=%s\n", json_object_to_json_string(my_object)); + + json_object_put(my_object); + + // ============================================ + + my_object = json_object_new_object(); + printf("Check that the custom serializer isn't free'd until the last json_object_put:\n"); + json_object_set_serializer(my_object, custom_serializer, &userdata, freeit); + json_object_get(my_object); + json_object_put(my_object); + printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object)); + printf("Next line of output should be from the custom freeit function:\n"); + + freeit_was_called = 0; + json_object_put(my_object); + assert(freeit_was_called); + + return 0; +} diff --git a/tests/test_set_serializer.expected b/tests/test_set_serializer.expected new file mode 100644 index 0000000..b91a081 --- /dev/null +++ b/tests/test_set_serializer.expected @@ -0,0 +1,9 @@ +my_object.to_string(standard)={ "abc": 12, "foo": "bar" } +my_object.to_string(custom serializer)=Custom Output +Next line of output should be from the custom freeit function: +freeit, value=123 +my_object.to_string(standard)={ "abc": 12, "foo": "bar" } +Check that the custom serializer isn't free'd until the last json_object_put: +my_object.to_string(custom serializer)=Custom Output +Next line of output should be from the custom freeit function: +freeit, value=123 diff --git a/tests/test_set_serializer.test b/tests/test_set_serializer.test new file mode 100755 index 0000000..728dfed --- /dev/null +++ b/tests/test_set_serializer.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_set_serializer +exit $? From 4b1a0668a8b0a77de7a99ba5f2307ea907da041d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 9 Sep 2012 13:53:12 -0500 Subject: [PATCH 158/276] Update the set_serializer test to match the actual output. --- tests/test_set_serializer.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_set_serializer.expected b/tests/test_set_serializer.expected index b91a081..ad44a90 100644 --- a/tests/test_set_serializer.expected +++ b/tests/test_set_serializer.expected @@ -1,3 +1,4 @@ +Test setting, then resetting a custom serializer: my_object.to_string(standard)={ "abc": 12, "foo": "bar" } my_object.to_string(custom serializer)=Custom Output Next line of output should be from the custom freeit function: From e7e0600405b1f06f0b1f3ad3c174de4832f9756e Mon Sep 17 00:00:00 2001 From: Lin Xu Date: Sun, 9 Sep 2012 17:33:35 -0700 Subject: [PATCH 159/276] Add an autoconf test to test whether the .section .gnu works with the linker on the system, and define _warn_references to nothing if not. --- config.h.in | 6 +++--- configure.in | 18 ++++++++++++++++++ libjson.c | 9 ++++----- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/config.h.in b/config.h.in index 34ad9a8..8263c08 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.in by autoheader. */ +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -114,9 +117,6 @@ /* 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 diff --git a/configure.in b/configure.in index 5b2eea3..387b422 100644 --- a/configure.in +++ b/configure.in @@ -37,6 +37,24 @@ AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp) +#check if .section.gnu.warning accepts long strings (for __warn_references) +AC_LANG_PUSH([C]) + +AC_MSG_CHECKING([if .gnu.warning accepts long strings]) +AC_LINK_IFELSE([[ +extern void json_object_get(); +__asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libjson-c instead of libjson\"\n\t.text"); + +int main(int c,char* v) {return 0;} +]], [ + AC_DEFINE(HAS_GNU_WARNING_LONG, 1, [Define if .gnu.warning accepts long strings.]) + AC_MSG_RESULT(yes) +], [ + AC_MSG_RESULT(no) +]) + +AC_LANG_POP([C]) + AM_PROG_LIBTOOL AC_CONFIG_FILES([ diff --git a/libjson.c b/libjson.c index 48fc3a4..5284fd0 100644 --- a/libjson.c +++ b/libjson.c @@ -7,11 +7,10 @@ #ifndef __warn_references -#ifdef __GNUC__ -#define __warn_references(sym,msg) \ - __asm(".pushsection .gnu.warning." #sym "\n" \ - ".ascii \"" msg "\"\n" \ - ".popsection"); +#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) + +#define __warn_references(sym,msg) \ + __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); #else #define __warn_references(sym,msg) /* nothing */ From d1f237e28ab5f7dce91968d5b89f8d04732c52e6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 10 Sep 2012 17:32:14 -0500 Subject: [PATCH 160/276] Fix the home page in the README, and add a list of prerequisites. --- README | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README b/README index 20adddc..ac1e812 100644 --- a/README +++ b/README @@ -1,10 +1,18 @@ Building on Unix with git, gcc and autotools Home page for json-c: - http://oss.metaparadigm.com/json-c/ + https://github.com/json-c/json-c/wiki Caution: do NOT use sources from svn.metaparadigm.com, they are old. +Prerequisites: + gcc (or another C compiler) + libtool + + If you're not using a release tarball, you'll also need: + autoconf (autoreconf) + automake + Github repo for json-c: https://github.com/json-c/json-c From c3068bfd097c035bd5a1cc1252f8164195f4a90b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 16 Sep 2012 20:43:29 -0500 Subject: [PATCH 161/276] Reformat the test sources. No functional change. --- tests/test1.c | 165 ++++++++++++++++++------------------ tests/test2.c | 12 +-- tests/test4.c | 64 +++++++------- tests/test_cast.c | 4 +- tests/test_null.c | 46 +++++----- tests/test_parse.c | 118 +++++++++++++------------- tests/test_printbuf.c | 4 +- tests/test_set_serializer.c | 2 +- 8 files changed, 211 insertions(+), 204 deletions(-) diff --git a/tests/test1.c b/tests/test1.c index 87d7ea4..8157846 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -9,25 +9,22 @@ static int sort_fn (const void *j1, const void *j2) { - json_object * const *jso1, * const *jso2; - int i1, i2; + json_object * const *jso1, * const *jso2; + int i1, i2; - jso1 = (json_object* const*)j1; - jso2 = (json_object* const*)j2; - if (!*jso1 && !*jso2) { - return 0; - } - if (!*jso1) { - return -1; - } - if (!*jso2) { - return 1; - } + jso1 = (json_object* const*)j1; + jso2 = (json_object* const*)j2; + if (!*jso1 && !*jso2) + return 0; + if (!*jso1) + return -1; + if (!*jso2) + return 1; - i1 = json_object_get_int(*jso1); - i2 = json_object_get_int(*jso2); + i1 = json_object_get_int(*jso1); + i2 = json_object_get_int(*jso2); - return i1 - i2; + return i1 - i2; } #ifdef TEST_FORMATTED @@ -38,88 +35,92 @@ static int sort_fn (const void *j1, const void *j2) int main(int argc, char **argv) { - json_object *my_string, *my_int, *my_object, *my_array; - int i; + json_object *my_string, *my_int, *my_object, *my_array; + int i; #ifdef TEST_FORMATTED int sflags = 0; #endif - MC_SET_DEBUG(1); + MC_SET_DEBUG(1); #ifdef TEST_FORMATTED sflags = parse_flags(argc, argv); #endif - my_string = json_object_new_string("\t"); - printf("my_string=%s\n", json_object_get_string(my_string)); - printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); - json_object_put(my_string); + my_string = json_object_new_string("\t"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + json_object_put(my_string); - my_string = json_object_new_string("\\"); - printf("my_string=%s\n", json_object_get_string(my_string)); - printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); - json_object_put(my_string); + my_string = json_object_new_string("\\"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + json_object_put(my_string); - my_string = json_object_new_string("foo"); - printf("my_string=%s\n", json_object_get_string(my_string)); - printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + my_string = json_object_new_string("foo"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); - my_int = json_object_new_int(9); - printf("my_int=%d\n", json_object_get_int(my_int)); - printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int)); + my_int = json_object_new_int(9); + printf("my_int=%d\n", json_object_get_int(my_int)); + printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int)); - my_array = json_object_new_array(); - json_object_array_add(my_array, json_object_new_int(1)); - json_object_array_add(my_array, json_object_new_int(2)); - json_object_array_add(my_array, json_object_new_int(3)); - json_object_array_put_idx(my_array, 4, json_object_new_int(5)); - printf("my_array=\n"); - for(i=0; i < json_object_array_length(my_array); i++) { - json_object *obj = json_object_array_get_idx(my_array, i); - printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); - } - printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + my_array = json_object_new_array(); + json_object_array_add(my_array, json_object_new_int(1)); + json_object_array_add(my_array, json_object_new_int(2)); + json_object_array_add(my_array, json_object_new_int(3)); + json_object_array_put_idx(my_array, 4, json_object_new_int(5)); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) + { + json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); - json_object_put(my_array); + json_object_put(my_array); - my_array = json_object_new_array(); - json_object_array_add(my_array, json_object_new_int(3)); - json_object_array_add(my_array, json_object_new_int(1)); - json_object_array_add(my_array, json_object_new_int(2)); - json_object_array_put_idx(my_array, 4, json_object_new_int(0)); - printf("my_array=\n"); - for(i=0; i < json_object_array_length(my_array); i++) { - json_object *obj = json_object_array_get_idx(my_array, i); - printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); - } - printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); - json_object_array_sort(my_array, sort_fn); - printf("my_array=\n"); - for(i=0; i < json_object_array_length(my_array); i++) { - json_object *obj = json_object_array_get_idx(my_array, i); - printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); - } - printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + my_array = json_object_new_array(); + json_object_array_add(my_array, json_object_new_int(3)); + json_object_array_add(my_array, json_object_new_int(1)); + json_object_array_add(my_array, json_object_new_int(2)); + json_object_array_put_idx(my_array, 4, json_object_new_int(0)); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) + { + json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + json_object_array_sort(my_array, sort_fn); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) + { + json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); - my_object = json_object_new_object(); - json_object_object_add(my_object, "abc", json_object_new_int(12)); - json_object_object_add(my_object, "foo", json_object_new_string("bar")); - json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); - json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); - json_object_object_add(my_object, "baz", json_object_new_string("bang")); - json_object_object_add(my_object, "baz", json_object_new_string("fark")); - json_object_object_del(my_object, "baz"); - /*json_object_object_add(my_object, "arr", my_array);*/ - printf("my_object=\n"); - json_object_object_foreach(my_object, key, val) { - printf("\t%s: %s\n", key, json_object_to_json_string(val)); - } - printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); + my_object = json_object_new_object(); + json_object_object_add(my_object, "abc", json_object_new_int(12)); + json_object_object_add(my_object, "foo", json_object_new_string("bar")); + json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); + json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); + json_object_object_add(my_object, "baz", json_object_new_string("bang")); + json_object_object_add(my_object, "baz", json_object_new_string("fark")); + json_object_object_del(my_object, "baz"); + /*json_object_object_add(my_object, "arr", my_array);*/ + printf("my_object=\n"); + json_object_object_foreach(my_object, key, val) + { + printf("\t%s: %s\n", key, json_object_to_json_string(val)); + } + printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); - json_object_put(my_string); - json_object_put(my_int); - json_object_put(my_object); - json_object_put(my_array); + json_object_put(my_string); + json_object_put(my_int); + json_object_put(my_object); + json_object_put(my_array); - return 0; + return 0; } diff --git a/tests/test2.c b/tests/test2.c index 4a6b660..ce44e46 100644 --- a/tests/test2.c +++ b/tests/test2.c @@ -15,20 +15,20 @@ int main(int argc, char **argv) { - json_object *new_obj; + json_object *new_obj; #ifdef TEST_FORMATTED int sflags = 0; #endif - MC_SET_DEBUG(1); + MC_SET_DEBUG(1); #ifdef TEST_FORMATTED sflags = parse_flags(argc, argv); #endif - new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - return 0; + return 0; } diff --git a/tests/test4.c b/tests/test4.c index 555afd1..23e97da 100644 --- a/tests/test4.c +++ b/tests/test4.c @@ -1,6 +1,6 @@ /* * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson -*/ + */ #include #include @@ -10,40 +10,44 @@ #include "json_object.h" #include "json_tokener.h" -void print_hex( const char* s) { - const char *iter = s; - unsigned char ch; - while ((ch = *iter++) != 0) { - if( ',' != ch) - printf("%x ", ch); - else - printf( ","); - } - printf("\n"); +void print_hex( const char* s) +{ + const char *iter = s; + unsigned char ch; + while ((ch = *iter++) != 0) + { + if( ',' != ch) + printf("%x ", ch); + else + printf( ","); + } + printf("\n"); } -int main() { - const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; - const char *expected = "\xF0\xA0\x84\xA6,\xF0\xA0\x84\xA7,\xF0\x90\x84\xA6,\xF0\x90\x84\xA7"; - struct json_object *parse_result = json_tokener_parse((char*)input); - const char *unjson = json_object_get_string(parse_result); +int main() +{ + const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; + const char *expected = "\xF0\xA0\x84\xA6,\xF0\xA0\x84\xA7,\xF0\x90\x84\xA6,\xF0\x90\x84\xA7"; + struct json_object *parse_result = json_tokener_parse((char*)input); + const char *unjson = json_object_get_string(parse_result); - printf("input: %s\n", input); + printf("input: %s\n", input); - int strings_match = !strcmp( expected, unjson); + int strings_match = !strcmp( expected, unjson); int retval = 0; - if (strings_match) { - printf("JSON parse result is correct: %s\n", unjson); - printf("PASS\n"); - } else { - printf("JSON parse result doesn't match expected string\n"); - printf("expected string bytes: "); - print_hex( expected); - printf("parsed string bytes: "); - print_hex( unjson); - printf("FAIL\n"); - retval = 1; - } + if (strings_match) + { + printf("JSON parse result is correct: %s\n", unjson); + printf("PASS\n"); + } else { + printf("JSON parse result doesn't match expected string\n"); + printf("expected string bytes: "); + print_hex( expected); + printf("parsed string bytes: "); + print_hex( unjson); + printf("FAIL\n"); + retval = 1; + } json_object_put(parse_result); return retval; } diff --git a/tests/test_cast.c b/tests/test_cast.c index aad44d0..72c8cc4 100644 --- a/tests/test_cast.c +++ b/tests/test_cast.c @@ -58,9 +58,9 @@ int main(int argc, char **argv) checktype(new_obj, "big_number"); checktype(new_obj, "a_null"); - json_object_put(new_obj); + json_object_put(new_obj); - return 0; + return 0; } static void getit(struct json_object *new_obj, const char *field) diff --git a/tests/test_null.c b/tests/test_null.c index 73729b8..675eab5 100644 --- a/tests/test_null.c +++ b/tests/test_null.c @@ -9,27 +9,29 @@ #include "json_inttypes.h" #include "json_object.h" -int main() { - // this test has a space after the null character. check that it's still included - const char *input = " \0 "; - const char *expected = "\" \\u0000 \""; - struct json_object *string = json_object_new_string_len(input, 3); - const char *json = json_object_to_json_string(string); +int main() +{ + // this test has a space after the null character. check that it's still included + const char *input = " \0 "; + const char *expected = "\" \\u0000 \""; + struct json_object *string = json_object_new_string_len(input, 3); + const char *json = json_object_to_json_string(string); - int strings_match = !strcmp( expected, json); - int retval = 0; - if (strings_match) { - printf("JSON write result is correct: %s\n", json); - printf("PASS\n"); - } else { - printf("JSON write result doesn't match expected string\n"); - printf("expected string: "); - printf("%s\n", expected); - printf("parsed string: "); - printf("%s\n", json); - printf("FAIL\n"); - retval=1; - } - json_object_put(string); - return retval; + int strings_match = !strcmp( expected, json); + int retval = 0; + if (strings_match) + { + printf("JSON write result is correct: %s\n", json); + printf("PASS\n"); + } else { + printf("JSON write result doesn't match expected string\n"); + printf("expected string: "); + printf("%s\n", expected); + printf("parsed string: "); + printf("%s\n", json); + printf("FAIL\n"); + retval=1; + } + json_object_put(string); + return retval; } diff --git a/tests/test_parse.c b/tests/test_parse.c index 975fb52..3e86c5a 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -25,83 +25,83 @@ int main(int argc, char **argv) static void test_basic_parse() { - json_object *new_obj; + json_object *new_obj; - new_obj = json_tokener_parse("\"\003\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("/* hello */\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("// hello\n\"foo\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("null"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("True"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("12"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("12.3"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[\"\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[null]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[false]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[false]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("{}"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); - new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); - printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); - json_object_put(new_obj); + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); } static void test_verbose_parse() @@ -121,7 +121,7 @@ static void test_verbose_parse() new_obj = json_tokener_parse_verbose("foo", &error); assert (new_obj == NULL); - /* b/c the string starts with 'f' parsing return a boolean error */ + /* b/c the string starts with 'f' parsing return a boolean error */ assert (error == json_tokener_error_parse_boolean); printf("json_tokener_parse_versbose() OK\n"); diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index ee3f80d..9a46566 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -14,7 +14,7 @@ static void test_printbuf_memset_length(void); static void test_basic_printbuf_memset() { struct printbuf *pb; - + printf("%s: starting test\n", __func__); pb = printbuf_new(); sprintbuf(pb, "blue:%d", 1); @@ -104,7 +104,7 @@ static void test_printbuf_memappend(int *before_resize) memset(data, 'X', *before_resize + 1); printbuf_memappend_fast(pb, data, *before_resize + 1); printf("Append to just after resize: %d, [%s]\n", printbuf_length(pb), pb->buf); - + free(data); printbuf_free(pb); diff --git a/tests/test_set_serializer.c b/tests/test_set_serializer.c index ae0121b..0f122af 100644 --- a/tests/test_set_serializer.c +++ b/tests/test_set_serializer.c @@ -63,7 +63,7 @@ int main(int argc, char **argv) printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string(my_object)); printf("Next line of output should be from the custom freeit function:\n"); - freeit_was_called = 0; + freeit_was_called = 0; json_object_put(my_object); assert(freeit_was_called); From c3d1d597abb6261a6c874bd6315a73fe4dbb8e7f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 16 Sep 2012 20:49:22 -0500 Subject: [PATCH 162/276] Fix a memory leak in test1 with respect to how json_object_object_del was used. --- tests/test1.c | 9 ++++++++- tests/test1.expected | 1 + tests/test1Formatted_plain.expected | 1 + tests/test1Formatted_pretty.expected | 1 + tests/test1Formatted_spaced.expected | 1 + 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test1.c b/tests/test1.c index 8157846..0c483a5 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -107,8 +107,15 @@ int main(int argc, char **argv) json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); json_object_object_add(my_object, "baz", json_object_new_string("bang")); - json_object_object_add(my_object, "baz", json_object_new_string("fark")); + + json_object *baz_obj = json_object_new_string("fark"); + json_object_object_add(my_object, "baz", baz_obj); json_object_object_del(my_object, "baz"); + + /* baz_obj should still be valid */ + printf("baz_obj.to_string()=%s\n", json_object_to_json_string(baz_obj)); + json_object_put(baz_obj); + /*json_object_object_add(my_object, "arr", my_array);*/ printf("my_object=\n"); json_object_object_foreach(my_object, key, val) diff --git a/tests/test1.expected b/tests/test1.expected index 6653fe0..e36aaa4 100644 --- a/tests/test1.expected +++ b/tests/test1.expected @@ -27,6 +27,7 @@ my_array= [3]=2 [4]=3 my_array.to_string()=[ null, 0, 1, 2, 3 ] +baz_obj.to_string()="fark" my_object= abc: 12 foo: "bar" diff --git a/tests/test1Formatted_plain.expected b/tests/test1Formatted_plain.expected index 65b19ed..edcc1b9 100644 --- a/tests/test1Formatted_plain.expected +++ b/tests/test1Formatted_plain.expected @@ -27,6 +27,7 @@ my_array= [3]=2 [4]=3 my_array.to_string()=[null,0,1,2,3] +baz_obj.to_string()="fark" my_object= abc: 12 foo: "bar" diff --git a/tests/test1Formatted_pretty.expected b/tests/test1Formatted_pretty.expected index f2334c4..95e48ed 100644 --- a/tests/test1Formatted_pretty.expected +++ b/tests/test1Formatted_pretty.expected @@ -45,6 +45,7 @@ my_array.to_string()=[ 2, 3 ] +baz_obj.to_string()="fark" my_object= abc: 12 foo: "bar" diff --git a/tests/test1Formatted_spaced.expected b/tests/test1Formatted_spaced.expected index 6653fe0..e36aaa4 100644 --- a/tests/test1Formatted_spaced.expected +++ b/tests/test1Formatted_spaced.expected @@ -27,6 +27,7 @@ my_array= [3]=2 [4]=3 my_array.to_string()=[ null, 0, 1, 2, 3 ] +baz_obj.to_string()="fark" my_object= abc: 12 foo: "bar" From 5f4739e2eb6407a6fae898802d165daab1ad7986 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 18 Oct 2012 17:10:09 -0500 Subject: [PATCH 163/276] Change json_object_put to return 1 if the object passed was actually freed. (or 0 if only the reference count was decremented) --- json_object.c | 6 ++++-- json_object.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/json_object.c b/json_object.c index d11efc5..bb344af 100644 --- a/json_object.c +++ b/json_object.c @@ -139,7 +139,7 @@ extern struct json_object* json_object_get(struct json_object *jso) return jso; } -extern void json_object_put(struct json_object *jso) +int json_object_put(struct json_object *jso) { if(jso) { @@ -149,8 +149,10 @@ extern void json_object_put(struct json_object *jso) if (jso->_user_delete) jso->_user_delete(jso, jso->_userdata); jso->_delete(jso); + return 1; } } + return 0; } @@ -410,7 +412,7 @@ json_bool json_object_object_get_ex(struct json_object* jso, const char *key, st void json_object_object_del(struct json_object* jso, const char *key) { - lh_table_delete(jso->o.c_object, key); + lh_table_delete(jso->o.c_object, key); } diff --git a/json_object.h b/json_object.h index f264629..6c42fc3 100644 --- a/json_object.h +++ b/json_object.h @@ -112,9 +112,9 @@ extern struct json_object* json_object_get(struct json_object *obj); * imbalance in the reference count. * * @param obj the json_object instance + * @returns 1 if the object was freed. */ -extern void json_object_put(struct json_object *obj); - +int json_object_put(struct json_object *obj); /** * Check if the json_object is of a given type From 5450bed05147c5d80e3c8c7f79d893d4a22dae4e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 18 Oct 2012 17:14:41 -0500 Subject: [PATCH 164/276] Fix json_object_object_get() so it returns NULL if the incoming json_object is NULL. --- json_object.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index bb344af..4c179ab 100644 --- a/json_object.c +++ b/json_object.c @@ -390,13 +390,16 @@ void json_object_object_add(struct json_object* jso, const char *key, struct json_object* json_object_object_get(struct json_object* jso, const char *key) { - struct json_object *result; + struct json_object *result = NULL; json_object_object_get_ex(jso, key, &result); return result; } json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) { + if (value != NULL) + *value = NULL; + if (NULL == jso) return FALSE; switch(jso->o_type) { From e36e56287272e45456afd5a315dc7ce770f5df8d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 18 Oct 2012 17:16:36 -0500 Subject: [PATCH 165/276] Reformat json_object_object_get() and json_object_object_get_ex(). --- json_object.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/json_object.c b/json_object.c index 4c179ab..5b60a06 100644 --- a/json_object.c +++ b/json_object.c @@ -390,9 +390,9 @@ void json_object_object_add(struct json_object* jso, const char *key, struct json_object* json_object_object_get(struct json_object* jso, const char *key) { - struct json_object *result = NULL; - json_object_object_get_ex(jso, key, &result); - return result; + struct json_object *result = NULL; + json_object_object_get_ex(jso, key, &result); + return result; } json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) @@ -400,17 +400,18 @@ json_bool json_object_object_get_ex(struct json_object* jso, const char *key, st if (value != NULL) *value = NULL; - if (NULL == jso) return FALSE; + 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; - } + 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) From 5abc0ea4443e46f8e508f17e3768c6404dee0d09 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 20 Oct 2012 20:10:15 -0500 Subject: [PATCH 166/276] Reformat the json_object_object_foreach macro so it is readable, and document what is allowed to be done with the object while iterating. --- json_object.h | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/json_object.h b/json_object.h index 6c42fc3..3f0ec6a 100644 --- a/json_object.h +++ b/json_object.h @@ -287,7 +287,13 @@ extern json_bool json_object_object_get_ex(struct json_object* obj, */ extern void json_object_object_del(struct json_object* obj, const char *key); -/** Iterate through all keys and values of an object +/** + * Iterate through all keys and values of an object. + * + * Adding or deleting keys to the object while iterating is NOT allowed. + * + * Replacing an existing key with a new value IS allowed. + * * @param obj the json_object instance * @param key the local name for the char* key variable defined in the body * @param val the local name for the json_object* object variable defined in @@ -296,14 +302,27 @@ extern void json_object_object_del(struct json_object* obj, const char *key); #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 ) + 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) + 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__) */ From f6b27cbb6cd2797641e71247e59299d771f13530 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 20 Oct 2012 20:26:37 -0500 Subject: [PATCH 167/276] Make it safe to delete keys while iterating with the json_object_object_foreach macro. --- json_object.h | 14 +++++++++----- tests/testReplaceExisting.c | 22 +++++++++++++++++++++- tests/testReplaceExisting.expected | 6 ++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/json_object.h b/json_object.h index 3f0ec6a..2621112 100644 --- a/json_object.h +++ b/json_object.h @@ -290,9 +290,10 @@ extern void json_object_object_del(struct json_object* obj, const char *key); /** * Iterate through all keys and values of an object. * - * Adding or deleting keys to the object while iterating is NOT allowed. + * Adding keys to the object while iterating is NOT allowed. * - * Replacing an existing key with a new value IS allowed. + * Deleting an existing key, or replacing an existing key with a + * new value IS allowed. * * @param obj the json_object instance * @param key the local name for the char* key variable defined in the body @@ -304,12 +305,13 @@ extern void json_object_object_del(struct json_object* obj, const char *key); # 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; \ + for(struct lh_entry *entry = json_object_get_object(obj)->head, *entry_next = NULL; \ ({ if(entry) { \ key = (char*)entry->k; \ val = (struct json_object*)entry->v; \ + entry_next = entry->next; \ } ; entry; }); \ - entry = entry->next ) + entry = entry_next ) #else /* ANSI C or MSC */ @@ -317,12 +319,14 @@ extern void json_object_object_del(struct json_object* obj, const char *key); char *key;\ struct json_object *val; \ struct lh_entry *entry; \ + struct lh_entry *entry_next = NULL; \ for(entry = json_object_get_object(obj)->head; \ (entry ? ( \ key = (char*)entry->k, \ val = (struct json_object*)entry->v, \ + entry_next = entry->next, \ entry) : 0); \ - entry = entry->next) + entry = entry_next) #endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c index 8c8c4b2..69a7145 100644 --- a/tests/testReplaceExisting.c +++ b/tests/testReplaceExisting.c @@ -16,9 +16,29 @@ int main(int argc, char **argv) json_object *my_object = json_object_new_object(); json_object_object_add(my_object, "foo1", json_object_new_string("bar1")); json_object_object_add(my_object, "foo2", json_object_new_string("bar2")); + json_object_object_add(my_object, "deleteme", json_object_new_string("bar2")); json_object_object_add(my_object, "foo3", json_object_new_string("bar3")); - const char *original_key = NULL; + + printf("==== delete-in-loop test starting ====\n"); + int orig_count = 0; + json_object_object_foreach(my_object, key0, val0) + { + printf("Key at index %d is [%s]", orig_count, key0); + if (strcmp(key0, "deleteme") == 0) + { + json_object_object_del(my_object, key0); + printf(" (deleted)\n"); + } + else + printf(" (kept)\n"); + orig_count++; + } + + printf("==== replace-value first loop starting ====\n"); + + const char *original_key = NULL; + orig_count = 0; json_object_object_foreach(my_object, key, val) { printf("Key at index %d is [%s]\n", orig_count, key); diff --git a/tests/testReplaceExisting.expected b/tests/testReplaceExisting.expected index 4d1c509..b1d4461 100644 --- a/tests/testReplaceExisting.expected +++ b/tests/testReplaceExisting.expected @@ -1,3 +1,9 @@ +==== delete-in-loop test starting ==== +Key at index 0 is [foo1] (kept) +Key at index 1 is [foo2] (kept) +Key at index 2 is [deleteme] (deleted) +Key at index 3 is [foo3] (kept) +==== replace-value first loop starting ==== Key at index 0 is [foo1] Key at index 1 is [foo2] replacing value for key [foo2] From 197cb1d1c1aecd5084b705eee0fafbd4d8da812d Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 27 Nov 2012 09:01:45 +0100 Subject: [PATCH 168/276] Make maximum recursion depth a runtime option --- ChangeLog | 3 +++ json_tokener.c | 21 ++++++++++++++++----- json_tokener.h | 7 ++++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42a3da9..2d55020 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ NEXT.VERSION You should change your build to use appropriate -I and -l options. A compatibility shim is in place so builds using the old name will continue to work, but that will be removed in the next release. + * Maximum recursion depth is now a runtime option. + json_tokener_new() is provided for compatibility. + json_tokener_new_ex(depth) 0.10 diff --git a/json_tokener.c b/json_tokener.c index f5fa8d6..72cfe2a 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -85,22 +85,33 @@ enum json_tokener_error json_tokener_get_error(json_tokener *tok) #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* json_tokener_new_ex(int depth) { struct json_tokener *tok; tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); if (!tok) return NULL; + tok->stack = (struct json_tokener*)calloc(depth, sizeof(struct json_tokener_srec)); + if (!tok->stack) { + free(tok); + return NULL; + } tok->pb = printbuf_new(); + tok->max_depth = depth; json_tokener_reset(tok); return tok; } +struct json_tokener* json_tokener_new(void) +{ + return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH); +} + void json_tokener_free(struct json_tokener *tok) { json_tokener_reset(tok); - if(tok) printbuf_free(tok->pb); + if (tok->pb) printbuf_free(tok->pb); + if (tok->stack) free(tok->stack); free(tok); } @@ -602,7 +613,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else { - if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) { + if(tok->depth >= tok->max_depth-1) { tok->err = json_tokener_error_depth; goto out; } @@ -682,7 +693,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_object_value: - if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) { + if(tok->depth >= tok->max_depth-1) { tok->err = json_tokener_error_depth; goto out; } diff --git a/json_tokener.h b/json_tokener.h index d104c75..3da520a 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -69,17 +69,17 @@ struct json_tokener_srec char *obj_field_name; }; -#define JSON_TOKENER_MAX_DEPTH 32 +#define JSON_TOKENER_DEFAULT_DEPTH 32 struct json_tokener { char *str; struct printbuf *pb; - int depth, is_double, st_pos, char_offset; + int max_depth, depth, is_double, st_pos, char_offset; enum json_tokener_error err; unsigned int ucs_char; char quote_char; - struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; + struct json_tokener_srec *stack; }; /** @@ -110,6 +110,7 @@ extern const char* json_tokener_errors[]; enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); extern struct json_tokener* json_tokener_new(void); +extern struct json_tokener* json_tokener_new_ex(int depth); extern void json_tokener_free(struct json_tokener *tok); extern void json_tokener_reset(struct json_tokener *tok); extern struct json_object* json_tokener_parse(const char *str); From 16a4a32e294e80ca8c89ec83e62baa0c59947ac9 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 27 Nov 2012 11:06:49 +0100 Subject: [PATCH 169/276] float parsing must be locale independent --- configure.in | 4 ++-- json_tokener.c | 2 +- json_util.c | 25 +++++++++++++++++++++++++ json_util.h | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 387b422..ea3ed67 100644 --- a/configure.in +++ b/configure.in @@ -23,7 +23,7 @@ AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno" 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/cdefs.h] [sys/param.h] stdarg.h) +AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h) AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public define for json_inttypes.h])]) # Checks for typedefs, structures, and compiler characteristics. @@ -35,7 +35,7 @@ AC_FUNC_VPRINTF AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp) +AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) #check if .section.gnu.warning accepts long strings (for __warn_references) AC_LANG_PUSH([C]) diff --git a/json_tokener.c b/json_tokener.c index f5fa8d6..85c530b 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -585,7 +585,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, 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) { + } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) { current = json_object_new_double(numd); } else { tok->err = json_tokener_error_parse_number; diff --git a/json_util.c b/json_util.c index 79ae5c7..c144059 100644 --- a/json_util.c +++ b/json_util.c @@ -36,6 +36,10 @@ # include #endif /* HAVE_UNISTD_H */ +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ + #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include @@ -142,6 +146,27 @@ int json_object_to_file(char *filename, struct json_object *obj) return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); } +int json_parse_double(const char *buf, double *retval) +{ + int ret; +#ifdef HAVE_SETLOCALE + char *old=NULL, *tmp; + + tmp = setlocale(LC_NUMERIC, NULL); + if (tmp) old = strdup(tmp); + setlocale(LC_NUMERIC, "C"); +#endif + + ret = sscanf(buf, "%lf", retval); + +#ifdef HAVE_SETLOCALE + setlocale(LC_NUMERIC, old); + if (old) free(old); +#endif + + return (ret==1 ? 0 : 1); +} + int json_parse_int64(const char *buf, int64_t *retval) { int64_t num64; diff --git a/json_util.h b/json_util.h index 277c3a7..b9a69c8 100644 --- a/json_util.h +++ b/json_util.h @@ -25,6 +25,7 @@ extern struct json_object* json_object_from_file(const char *filename); extern int json_object_to_file(char *filename, struct json_object *obj); extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags); extern int json_parse_int64(const char *buf, int64_t *retval); +extern int json_parse_double(const char *buf, double *retval); /** From 23461c75dd12af93d6979f5c6cce42b8fa017a80 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 29 Nov 2012 13:23:06 -0600 Subject: [PATCH 170/276] Include json_object_iterator.c in the list of sources. --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 09221a3..9353b7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,6 +49,7 @@ libjson_c_la_SOURCES = \ arraylist.c \ debug.c \ json_object.c \ + json_object_iterator.c \ json_tokener.c \ json_util.c \ linkhash.c \ From 447b88a115cc98589625742a21e5d7475c4dba2e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 29 Nov 2012 13:29:55 -0600 Subject: [PATCH 171/276] Fix a memory leak in the test_printbuf test. --- tests/test_printbuf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index 9a46566..fed185e 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -124,6 +124,7 @@ static void test_sprintbuf(int before_resize) memset(data, 'X', before_resize + 1 + 1); data[before_resize + 1] = '\0'; sprintbuf(pb, "%s", data); + free(data); printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, (int)strlen(pb->buf)); printbuf_reset(pb); From aec876357c3207585d3378d2b47cfaa824c5dde4 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 29 Nov 2012 15:06:17 -0500 Subject: [PATCH 172/276] Add a missing json_object_get() so we don't try to use a freed object in test1. --- tests/test1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test1.c b/tests/test1.c index 0c483a5..7acea62 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -109,6 +109,7 @@ int main(int argc, char **argv) json_object_object_add(my_object, "baz", json_object_new_string("bang")); json_object *baz_obj = json_object_new_string("fark"); + json_object_get(baz_obj); json_object_object_add(my_object, "baz", baz_obj); json_object_object_del(my_object, "baz"); From 7653d4952a577adce514be3a4f16678efb6cfc40 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 9 Dec 2012 15:46:23 -0600 Subject: [PATCH 173/276] Add PACKAGE_URL to config.h.in --- config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.h.in b/config.h.in index 8263c08..f44c8ed 100644 --- a/config.h.in +++ b/config.h.in @@ -117,6 +117,9 @@ /* 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 From 7a4506d6df902001a4261358ed0e04f66ac092d7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 9 Dec 2012 15:46:35 -0600 Subject: [PATCH 174/276] Remove configure as part of maintainer-clean instead of distclean. Addresses issue #48. --- Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 9353b7a..3ffc15f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,7 +58,10 @@ libjson_c_la_SOURCES = \ 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 + -rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub depcomp install-sh ltmain.sh missing + +maintainer-clean-local: + -rm -rf configure if ENABLE_OLDNAME_COMPAT install-data-hook: From 4e4af93d667ae0d3cb9779f5a3c3f964cc9d7d81 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 9 Dec 2012 16:32:11 -0600 Subject: [PATCH 175/276] Fix issue #53 - ensure explicit length string are still NUL terminated, and fix json_tokener_parse() to work properly with embedded unicode \u0000 values in strings. Adjust test_null to check for this case. See also http://bugs.debian.org/687269 --- json_object.c | 3 ++- json_tokener.c | 2 +- tests/test_null.c | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index 5b60a06..a84785c 100644 --- a/json_object.c +++ b/json_object.c @@ -620,8 +620,9 @@ struct json_object* json_object_new_string_len(const char *s, int len) if(!jso) return NULL; jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = (char*)malloc(len); + jso->o.c_string.str = (char*)malloc(len + 1); memcpy(jso->o.c_string.str, (void *)s, len); + jso->o.c_string.str[len] = '\0'; jso->o.c_string.len = len; return jso; } diff --git a/json_tokener.c b/json_tokener.c index f5fa8d6..05357fb 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -393,7 +393,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, 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); + current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; break; diff --git a/tests/test_null.c b/tests/test_null.c index 675eab5..1f07910 100644 --- a/tests/test_null.c +++ b/tests/test_null.c @@ -8,6 +8,7 @@ #include "json_inttypes.h" #include "json_object.h" +#include "json_tokener.h" int main() { @@ -33,5 +34,24 @@ int main() retval=1; } json_object_put(string); + + struct json_object *parsed_str = json_tokener_parse(expected); + if (parsed_str) + { + int parsed_len = json_object_get_string_len(parsed_str); + const char *parsed_cstr = json_object_get_string(parsed_str); + int ii; + printf("Re-parsed object string len=%d, chars=[", parsed_len); + for (ii = 0; ii < parsed_len ; ii++) + { + printf("%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]); + } + printf("]\n"); + json_object_put(parsed_str); + } + else + { + printf("ERROR: failed to parse\n"); + } return retval; } From a01b659ace168d85a3e9e47848eaaba2bea31078 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 13 Dec 2012 09:47:33 +0100 Subject: [PATCH 176/276] move locale change to be global for perf --- json_tokener.c | 16 ++++++++++++++++ json_util.c | 22 +--------------------- tests/Makefile.am | 3 +++ tests/test_locale.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 tests/test_locale.c diff --git a/json_tokener.c b/json_tokener.c index 85c530b..63bb41b 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -31,6 +31,10 @@ #include "json_tokener.h" #include "json_util.h" +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ + #if !HAVE_STRDUP && defined(_MSC_VER) /* MSC has the version as _strdup */ # define strdup _strdup @@ -227,6 +231,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, { struct json_object *obj = NULL; char c = '\1'; +#ifdef HAVE_SETLOCALE + char *oldlocale=NULL, *tmplocale; + + tmplocale = setlocale(LC_NUMERIC, NULL); + if (tmplocale) oldlocale = strdup(tmplocale); + setlocale(LC_NUMERIC, "C"); +#endif tok->char_offset = 0; tok->err = json_tokener_success; @@ -724,6 +735,11 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_eof; } +#ifdef HAVE_SETLOCALE + setlocale(LC_NUMERIC, oldlocale); + if (oldlocale) free(oldlocale); +#endif + if (tok->err == json_tokener_success) { json_object *ret = json_object_get(current); diff --git a/json_util.c b/json_util.c index c144059..0a59811 100644 --- a/json_util.c +++ b/json_util.c @@ -36,10 +36,6 @@ # include #endif /* HAVE_UNISTD_H */ -#ifdef HAVE_LOCALE_H -#include -#endif /* HAVE_LOCALE_H */ - #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include @@ -148,23 +144,7 @@ int json_object_to_file(char *filename, struct json_object *obj) int json_parse_double(const char *buf, double *retval) { - int ret; -#ifdef HAVE_SETLOCALE - char *old=NULL, *tmp; - - tmp = setlocale(LC_NUMERIC, NULL); - if (tmp) old = strdup(tmp); - setlocale(LC_NUMERIC, "C"); -#endif - - ret = sscanf(buf, "%lf", retval); - -#ifdef HAVE_SETLOCALE - setlocale(LC_NUMERIC, old); - if (old) free(old); -#endif - - return (ret==1 ? 0 : 1); + return (sscanf(buf, "%lf", retval)==1 ? 0 : 1); } int json_parse_int64(const char *buf, int64_t *retval) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8057acd..90222ba 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,6 +11,7 @@ check_PROGRAMS += test_parse_int64 check_PROGRAMS += test_null check_PROGRAMS += test_cast check_PROGRAMS += test_parse +check_PROGRAMS += test_locale test1_LDADD = $(LIBJSON_LA) @@ -36,6 +37,8 @@ test_cast_LDADD = $(LIBJSON_LA) test_parse_LDADD = $(LIBJSON_LA) +test_locale_LDADD = $(LIBJSON_LA) + TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test TESTS+= test_printbuf.test diff --git a/tests/test_locale.c b/tests/test_locale.c new file mode 100644 index 0000000..6926a5d --- /dev/null +++ b/tests/test_locale.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "json.h" +#include "json_tokener.h" + +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ + +int main(int argc, char **argv) +{ + json_object *new_obj; +#ifdef HAVE_SETLOCALE + setlocale(LC_NUMERIC, "de_DE"); +#else + printf("No locale\n"); +#endif + + MC_SET_DEBUG(1); + + new_obj = json_tokener_parse("[1.2,3.4,123456.78,5.0]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); +} + From 4014fe86d96d850271a1bd724ccf5a83d27dceb8 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 13 Dec 2012 11:16:03 +0100 Subject: [PATCH 177/276] Simple fix to double encode --- json_object.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 5b60a06..eeba91b 100644 --- a/json_object.c +++ b/json_object.c @@ -552,7 +552,16 @@ static int json_object_double_to_json_string(struct json_object* jso, int level, int flags) { - return sprintbuf(pb, "%f", jso->o.c_double); + char buf[128], *p; + int size; + + size = snprintf(buf, 128, "%f", jso->o.c_double); + p = strchr(buf, ','); + if (p) { + *p = '.'; + } + printbuf_memappend(pb, buf, size); + return size; } struct json_object* json_object_new_double(double d) From 8c847968c7de17be6cf3878a4e6adca8ab8d8f14 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 13 Dec 2012 11:22:31 +0100 Subject: [PATCH 178/276] Save space, drop unuseful trailing zeroes --- json_object.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index eeba91b..b078017 100644 --- a/json_object.c +++ b/json_object.c @@ -552,13 +552,25 @@ static int json_object_double_to_json_string(struct json_object* jso, int level, int flags) { - char buf[128], *p; + char buf[128], *p, *q; int size; size = snprintf(buf, 128, "%f", jso->o.c_double); p = strchr(buf, ','); if (p) { *p = '.'; + } else { + p = strchr(buf, '.'); + } + if (p) { + /* last useful digit, always keep 1 zero */ + p++; + for (q=p ; *q ; q++) { + if (*q!='0') p=q; + } + /* drop trailing zeroes */ + *(++p) = 0; + size = p-buf; } printbuf_memappend(pb, buf, size); return size; From 32d149c8f60a5bdad4f678013a83d052ffd8ad43 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 13 Dec 2012 11:46:04 +0100 Subject: [PATCH 179/276] probably worth an option for this --- json_object.c | 2 +- json_object.h | 4 ++++ tests/test_locale.c | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index b078017..9161b00 100644 --- a/json_object.c +++ b/json_object.c @@ -562,7 +562,7 @@ static int json_object_double_to_json_string(struct json_object* jso, } else { p = strchr(buf, '.'); } - if (p) { + if (p && (flags & JSON_C_TO_STRING_NOZERO)) { /* last useful digit, always keep 1 zero */ p++; for (q=p ; *q ; q++) { diff --git a/json_object.h b/json_object.h index 2621112..1f70461 100644 --- a/json_object.h +++ b/json_object.h @@ -42,6 +42,10 @@ extern "C" { * for an example of the format. */ #define JSON_C_TO_STRING_PRETTY (1<<1) +/** + * A flag to drop trailing zero for float values + */ +#define JSON_C_TO_STRING_NOZERO (1<<2) #undef FALSE #define FALSE ((json_bool)0) diff --git a/tests/test_locale.c b/tests/test_locale.c index 6926a5d..da070cf 100644 --- a/tests/test_locale.c +++ b/tests/test_locale.c @@ -23,8 +23,9 @@ int main(int argc, char **argv) MC_SET_DEBUG(1); - new_obj = json_tokener_parse("[1.2,3.4,123456.78,5.0]"); + new_obj = json_tokener_parse("[1.2,3.4,123456.78,5.0,2.3e10]"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + printf("new_obj.to_string()=%s\n", json_object_to_json_string_ext(new_obj,JSON_C_TO_STRING_NOZERO)); json_object_put(new_obj); } From e176965c1c7db7e7a5310deafbcc9f061b21e384 Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Tue, 18 Dec 2012 18:27:39 +0100 Subject: [PATCH 180/276] Ignore valgrind output files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 843fb3c..4a8ace2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ /tests/test_null /tests/test_printbuf /tests/test_set_serializer +/tests/*.vg.out /Debug /Release *.lo From b670f6f99208c085abaf1713b2b92ea66f9a5d2b Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Tue, 18 Dec 2012 18:44:52 +0100 Subject: [PATCH 181/276] -d test is useless as symlinks are dereferenced --- Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 3ffc15f..17d5837 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,7 +65,6 @@ maintainer-clean-local: if ENABLE_OLDNAME_COMPAT install-data-hook: - test \! -d "$(includedir)/json" || rmdir "$(includedir)/json" test \! -e "$(includedir)/json" || rm "$(includedir)/json" $(LN_S) json-c "$(includedir)/json" From a3a0f5b28d628bd9d4fcd390fa842536c99a023c Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Tue, 18 Dec 2012 18:45:39 +0100 Subject: [PATCH 182/276] Need to explicitly remove include/json-c directory --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 17d5837..fc4479f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,6 +70,7 @@ install-data-hook: uninstall-local: rm -f "$(includedir)/json" + rm -rf "$(includedir)/json-c" endif From b1d61d10e1720495bfd0d31c9c95dc6e1d298502 Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Tue, 18 Dec 2012 18:46:24 +0100 Subject: [PATCH 183/276] Library is now called libjson-c --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8057acd..0f06590 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ include ../Makefile.am.inc -LIBJSON_LA=$(top_builddir)/libjson.la +LIBJSON_LA=$(top_builddir)/libjson-c.la check_PROGRAMS = test1 test1Formatted check_PROGRAMS += test2 test2Formatted From 54d551c8103cae1b45dc1fa6accf6bb1ffcbfc4e Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Tue, 18 Dec 2012 18:53:04 +0100 Subject: [PATCH 184/276] Ignore doc dir for now --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4a8ace2..ce87c33 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /config.sub /configure /depcomp +/doc /install-sh /json.pc /json-c.pc From 8f58f09c69db2a8396b4f9d952731eda1dd365cb Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 09:38:45 +0100 Subject: [PATCH 185/276] Ignore editor swap files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ce87c33..a056b11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*~ +*.swp .deps/ .libs/ /aclocal.m4 From 20ef1bd9808ffbe91198a50210479955b69c044a Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 09:40:10 +0100 Subject: [PATCH 186/276] Remove and ignore autogenerated installation instructions --- .gitignore | 1 + INSTALL | 229 ----------------------------------------------------- 2 files changed, 1 insertion(+), 229 deletions(-) delete mode 100644 INSTALL diff --git a/.gitignore b/.gitignore index a056b11..f3b18f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *~ *.swp +/INSTALL .deps/ .libs/ /aclocal.m4 diff --git a/INSTALL b/INSTALL deleted file mode 100644 index a4b3414..0000000 --- a/INSTALL +++ /dev/null @@ -1,229 +0,0 @@ -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. - From beb12d49e1b7ee4f4adc12d8ea31f543b6ca4823 Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 10:31:39 +0100 Subject: [PATCH 187/276] Make macro json_object_object_foreach multiple-use safe --- json_object.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/json_object.h b/json_object.h index 2621112..0ff6584 100644 --- a/json_object.h +++ b/json_object.h @@ -305,28 +305,28 @@ extern void json_object_object_del(struct json_object* obj, const char *key); # 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, *entry_next = NULL; \ - ({ if(entry) { \ - key = (char*)entry->k; \ - val = (struct json_object*)entry->v; \ - entry_next = entry->next; \ - } ; entry; }); \ - entry = entry_next ) + for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ + ({ if(entry ## key) { \ + key = (char*)entry ## key->k; \ + val = (struct json_object*)entry ## key->v; \ + entry_next ## key = entry ## key->next; \ + } ; entry ## key; }); \ + entry ## key = entry_next ## key ) #else /* ANSI C or MSC */ # define json_object_object_foreach(obj,key,val) \ char *key;\ struct json_object *val; \ - struct lh_entry *entry; \ - struct lh_entry *entry_next = NULL; \ - for(entry = json_object_get_object(obj)->head; \ - (entry ? ( \ - key = (char*)entry->k, \ - val = (struct json_object*)entry->v, \ - entry_next = entry->next, \ - entry) : 0); \ - entry = entry_next) + struct lh_entry *entry ## key; \ + struct lh_entry *entry_next ## key = NULL; \ + for(entry ## key = json_object_get_object(obj)->head; \ + (entry ## key ? ( \ + key = (char*)entry ## key->k, \ + val = (struct json_object*)entry ## key->v, \ + entry_next ## key = entry ## key->next, \ + entry ## key) : 0); \ + entry ## key = entry_next ## key) #endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ From 827a4a97b9ddf6a04ad5a3d7a3c9350edcd00df0 Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 10:46:35 +0100 Subject: [PATCH 188/276] Fixed memory leak in testReplaceExisting --- tests/testReplaceExisting.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c index 69a7145..8cc6924 100644 --- a/tests/testReplaceExisting.c +++ b/tests/testReplaceExisting.c @@ -72,5 +72,7 @@ int main(int argc, char **argv) retval = 1; } + json_object_put( my_object ); + return 0; } From 57f36ed32a1e679d2ac4c90d12b88e7e2c183b6b Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 10:52:50 +0100 Subject: [PATCH 189/276] Write additional test info to stderr instead of stdout so as not to mar the expected output --- tests/test_null.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_null.c b/tests/test_null.c index 1f07910..d017c7a 100644 --- a/tests/test_null.c +++ b/tests/test_null.c @@ -41,12 +41,12 @@ int main() int parsed_len = json_object_get_string_len(parsed_str); const char *parsed_cstr = json_object_get_string(parsed_str); int ii; - printf("Re-parsed object string len=%d, chars=[", parsed_len); + fprintf( stderr, "Re-parsed object string len=%d, chars=[", parsed_len); for (ii = 0; ii < parsed_len ; ii++) { - printf("%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]); + fprintf( stderr, "%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]); } - printf("]\n"); + fprintf( stderr, "]\n"); json_object_put(parsed_str); } else From 024d86c07ffcd8fef1ba19ac821416281ffb1f8d Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 13:16:38 +0100 Subject: [PATCH 190/276] Prepend DESTDIR to paths for staged installs --- Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index fc4479f..36272f4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,12 +65,12 @@ maintainer-clean-local: if ENABLE_OLDNAME_COMPAT install-data-hook: - test \! -e "$(includedir)/json" || rm "$(includedir)/json" - $(LN_S) json-c "$(includedir)/json" + test \! -e "$(DESTDIR)@includedir@json" || rm "$(DESTDIR)@includedir@/json" + $(LN_S) json-c "$(DESTDIR)@includedir@/json" uninstall-local: - rm -f "$(includedir)/json" - rm -rf "$(includedir)/json-c" + rm -f "$(DESTDIR)@includedir@/json" + rm -rf "$(DESTDIR)@includedir@/json-c" endif From 18abf6e5092175e7de27e73c6bb643b2bf57ec7d Mon Sep 17 00:00:00 2001 From: Alexander Klauer Date: Wed, 19 Dec 2012 13:55:02 +0100 Subject: [PATCH 191/276] More warnings, fewer errors, C99 --- Makefile.am.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am.inc b/Makefile.am.inc index b1ebce8..7882fd7 100644 --- a/Makefile.am.inc +++ b/Makefile.am.inc @@ -1,2 +1,2 @@ -AM_CFLAGS = -Wall -Wwrite-strings -Werror -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -Wextra -Wwrite-strings -Wno-unused-parameter -std=c99 -D_GNU_SOURCE -D_REENTRANT From 2e9fef38c26a3321105ebda1efed4320b85a8688 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Dec 2012 10:25:03 -0600 Subject: [PATCH 192/276] Revert the test_null test back to emitted to stdout, and update the expected output to match. --- tests/test_null.c | 6 +++--- tests/test_null.expected | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_null.c b/tests/test_null.c index d017c7a..1f07910 100644 --- a/tests/test_null.c +++ b/tests/test_null.c @@ -41,12 +41,12 @@ int main() int parsed_len = json_object_get_string_len(parsed_str); const char *parsed_cstr = json_object_get_string(parsed_str); int ii; - fprintf( stderr, "Re-parsed object string len=%d, chars=[", parsed_len); + printf("Re-parsed object string len=%d, chars=[", parsed_len); for (ii = 0; ii < parsed_len ; ii++) { - fprintf( stderr, "%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]); + printf("%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]); } - fprintf( stderr, "]\n"); + printf("]\n"); json_object_put(parsed_str); } else diff --git a/tests/test_null.expected b/tests/test_null.expected index fd7b479..52d2890 100644 --- a/tests/test_null.expected +++ b/tests/test_null.expected @@ -1,2 +1,3 @@ JSON write result is correct: " \u0000 " PASS +Re-parsed object string len=3, chars=[32, 0, 32] From d7de3aa24b2255ebe52b43e654d0a87e5c5a09a0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Dec 2012 10:27:14 -0600 Subject: [PATCH 193/276] Update the release checklist to include the INSTALL file, and adjust the git command to add the doc directory. --- RELEASE_CHECKLIST.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 1eccac8..d086592 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -17,7 +17,8 @@ Generate the configure script and other files: sh autogen.sh git add -f Makefile.in aclocal.m4 config.guess \ config.sub configure depcomp install-sh \ - ltmain.sh missing tests/Makefile.in + ltmain.sh missing tests/Makefile.in \ + INSTALL # check for anything else to be added: git status --ignored @@ -25,7 +26,7 @@ Generate the configure script and other files: Generate the doxygen documentation: doxygen - git add doc + git add -f doc git commit doc cd .. From 1461b49385c6aa86e8426f91e8d608cb83bad241 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Dec 2012 10:57:44 -0600 Subject: [PATCH 194/276] Add a json_c_version.h header (included from json.h), and several macros and functions for retrieving the json-c version at compile-time and run-time. --- Makefile.am | 2 ++ json.h | 1 + json_c_version.c | 20 ++++++++++++++++++++ json_c_version.h | 22 ++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 json_c_version.c create mode 100644 json_c_version.h diff --git a/Makefile.am b/Makefile.am index 36272f4..147d957 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,7 @@ libjson_cinclude_HEADERS = \ debug.h \ json.h \ json_config.h \ + json_c_version.h \ json_inttypes.h \ json_object.h \ json_object_iterator.h \ @@ -48,6 +49,7 @@ endif libjson_c_la_SOURCES = \ arraylist.c \ debug.c \ + json_c_version.c \ json_object.c \ json_object_iterator.c \ json_tokener.c \ diff --git a/json.h b/json.h index d49715b..4339b20 100644 --- a/json.h +++ b/json.h @@ -25,6 +25,7 @@ extern "C" { #include "json_object.h" #include "json_tokener.h" #include "json_object_iterator.h" +#include "json_c_version.h" #ifdef __cplusplus } diff --git a/json_c_version.c b/json_c_version.c new file mode 100644 index 0000000..13eb188 --- /dev/null +++ b/json_c_version.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ +#include "config.h" + +#include "json_c_version.h" + +const char *json_c_version(void) +{ + return JSON_C_VERSION; +} + +int json_c_version_num(void) +{ + return JSON_C_VERSION_NUM; +} + diff --git a/json_c_version.h b/json_c_version.h new file mode 100644 index 0000000..3e35aff --- /dev/null +++ b/json_c_version.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#ifndef _json_c_version_h_ +#define _json_c_version_h_ + +#define JSON_C_MAJOR_VERSION 0 +#define JSON_C_MINOR_VERSION 10 +#define JSON_C_MICRO_VERSION 0 +#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ + (JSON_C_MINOR_VERSION << 8) | \ + JSON_C_MICRO_VERSION) +#define JSON_C_VERSION "0.10" + +const char *json_c_version(void); /* Returns JSON_C_VERSION */ +int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ + +#endif From fcc768e6679076ef90ea263569a36ca29a85a544 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Dec 2012 11:09:20 -0600 Subject: [PATCH 195/276] Bump the version up to 0.10.99 to make it clear that the master branch is beyond anything on the 0.10 branch. --- Doxyfile | 2 +- Makefile.am | 2 +- RELEASE_CHECKLIST.txt | 1 + configure.in | 2 +- json_c_version.h | 4 ++-- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doxyfile b/Doxyfile index 3ff27eb..91c9434 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.10 +PROJECT_NUMBER = 0.10.99 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/Makefile.am b/Makefile.am index 147d957..51159b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,7 +67,7 @@ maintainer-clean-local: if ENABLE_OLDNAME_COMPAT install-data-hook: - test \! -e "$(DESTDIR)@includedir@json" || rm "$(DESTDIR)@includedir@/json" + test \! -e "$(DESTDIR)@includedir@/json" || rm "$(DESTDIR)@includedir@/json" $(LN_S) json-c "$(DESTDIR)@includedir@/json" uninstall-local: diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index d086592..bdc547a 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -53,6 +53,7 @@ Post-release checklist: git branch master Add new section to CHANGES +Update the version in json_c_version.h Update the version in Doxyfile Update the version in configure.in Update the libjson_la_LDFLAGS line in Makefile.am to the new version. diff --git a/configure.in b/configure.in index 387b422..5a3c0df 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.10, [json-c@googlegroups.com]) +AC_INIT([json-c], 0.10.99, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) diff --git a/json_c_version.h b/json_c_version.h index 3e35aff..72bbbae 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -10,11 +10,11 @@ #define JSON_C_MAJOR_VERSION 0 #define JSON_C_MINOR_VERSION 10 -#define JSON_C_MICRO_VERSION 0 +#define JSON_C_MICRO_VERSION 99 #define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ (JSON_C_MINOR_VERSION << 8) | \ JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.10" +#define JSON_C_VERSION "0.10.99" const char *json_c_version(void); /* Returns JSON_C_VERSION */ int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ From 7eaa849e9a386da30a05d41ef77e4d047897e80a Mon Sep 17 00:00:00 2001 From: Abioy Date: Mon, 24 Dec 2012 22:22:05 +0800 Subject: [PATCH 196/276] escape '\f' in json_escape_str '\f' is a llegal char and should be escape in printbuf --- json_object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/json_object.c b/json_object.c index a84785c..6060554 100644 --- a/json_object.c +++ b/json_object.c @@ -98,6 +98,7 @@ static int json_escape_str(struct printbuf *pb, char *str, int len) case '\n': case '\r': case '\t': + case '\f': case '"': case '\\': case '/': @@ -107,6 +108,7 @@ static int json_escape_str(struct printbuf *pb, char *str, int len) else if(c == '\n') printbuf_memappend(pb, "\\n", 2); else if(c == '\r') printbuf_memappend(pb, "\\r", 2); else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '\f') printbuf_memappend(pb, "\\f", 2); else if(c == '"') printbuf_memappend(pb, "\\\"", 2); else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); else if(c == '/') printbuf_memappend(pb, "\\/", 2); From 77d0493b7062ac0c811a92dea98cf094737e3957 Mon Sep 17 00:00:00 2001 From: Greg Hazel Date: Thu, 3 Jan 2013 16:54:04 -0800 Subject: [PATCH 197/276] rename _errno --- json_util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json_util.c b/json_util.c index 79ae5c7..4030cbe 100644 --- a/json_util.c +++ b/json_util.c @@ -147,14 +147,14 @@ int json_parse_int64(const char *buf, int64_t *retval) int64_t num64; const char *buf_skip_space; int orig_has_neg; - int _errno; + int saved_errno; errno = 0; // sscanf won't always set errno, so initialize if (sscanf(buf, "%" SCNd64, &num64) != 1) { MC_DEBUG("Failed to parse, sscanf != 1\n"); return 1; } - _errno = errno; + saved_errno = errno; buf_skip_space = buf; orig_has_neg = 0; // Skip leading spaces @@ -171,7 +171,7 @@ int json_parse_int64(const char *buf, int64_t *retval) 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) + if (saved_errno != ERANGE) { char buf_cmp[100]; char *buf_cmp_start = buf_cmp; @@ -199,10 +199,10 @@ int json_parse_int64(const char *buf, int64_t *retval) ) ) { - _errno = ERANGE; + saved_errno = ERANGE; } } - if (_errno == ERANGE) + if (saved_errno == ERANGE) { if (orig_has_neg) num64 = INT64_MIN; From cca74c6de6e0d7ea397f50c8f16bbdbff2aeae78 Mon Sep 17 00:00:00 2001 From: Greg Hazel Date: Fri, 11 Jan 2013 01:36:55 -0800 Subject: [PATCH 198/276] add json_object_object_length --- json_object.c | 5 +++++ json_object.h | 2 ++ linkhash.c | 4 ++++ linkhash.h | 1 + 4 files changed, 12 insertions(+) diff --git a/json_object.c b/json_object.c index 6060554..9dc6637 100644 --- a/json_object.c +++ b/json_object.c @@ -390,6 +390,11 @@ void json_object_object_add(struct json_object* jso, const char *key, existing_entry->v = val; } +int json_object_object_length(struct json_object *jso) +{ + return lh_table_length(jso->o.c_object); +} + struct json_object* json_object_object_get(struct json_object* jso, const char *key) { struct json_object *result = NULL; diff --git a/json_object.h b/json_object.h index 0ff6584..336ce96 100644 --- a/json_object.h +++ b/json_object.h @@ -215,6 +215,8 @@ extern struct json_object* json_object_new_object(void); */ extern struct lh_table* json_object_get_object(struct json_object *obj); +extern int json_object_object_length(struct json_object* obj); + /** Add an object field to a json_object of type json_type_object * * The reference count will *not* be incremented. This is to make adding diff --git a/linkhash.c b/linkhash.c index ddedc12..2661823 100644 --- a/linkhash.c +++ b/linkhash.c @@ -227,3 +227,7 @@ int lh_table_delete(struct lh_table *t, const void *k) return lh_table_delete_entry(t, e); } +int lh_table_length(struct lh_table *t) +{ + return t->count; +} diff --git a/linkhash.h b/linkhash.h index bbb5488..378de0b 100644 --- a/linkhash.h +++ b/linkhash.h @@ -280,6 +280,7 @@ extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); */ extern int lh_table_delete(struct lh_table *t, const void *k); +extern int lh_table_length(struct lh_table *t); void lh_abort(const char *msg, ...); void lh_table_resize(struct lh_table *t, int new_size); From 78b089bc1e5a06af2be355260ff8d028d3dcd23f Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Mon, 28 Jan 2013 19:06:49 -0800 Subject: [PATCH 199/276] Fixed test_parse for \f --- tests/test_parse.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 97910dc..814dc62 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -44,7 +44,7 @@ json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\"" json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\" json_tokener_parse_ex(tok, "\b" , 4) ... OK: got object of type [string]: "\b" -json_tokener_parse_ex(tok, "\f" , 4) ... OK: got object of type [string]: "\u000c" +json_tokener_parse_ex(tok, "\f" , 4) ... OK: got object of type [string]: "\f" json_tokener_parse_ex(tok, "\n" , 4) ... OK: got object of type [string]: "\n" json_tokener_parse_ex(tok, "\r" , 4) ... OK: got object of type [string]: "\r" json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string]: "\t" From 92d289f5d366058284b69180c3c32ea10ef51610 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 9 Feb 2013 16:18:05 -0600 Subject: [PATCH 200/276] Add a comment briefly describing json_object_object_length() --- json_object.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/json_object.h b/json_object.h index 336ce96..c97850a 100644 --- a/json_object.h +++ b/json_object.h @@ -215,6 +215,9 @@ extern struct json_object* json_object_new_object(void); */ extern struct lh_table* json_object_get_object(struct json_object *obj); +/** Get the size of an object in terms of the number of fields it has. + * @param obj the json_object whose length to return + */ extern int json_object_object_length(struct json_object* obj); /** Add an object field to a json_object of type json_type_object From ca8b27d1836ff97935d2eb212f762f63b9258cbd Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 9 Feb 2013 16:35:24 -0600 Subject: [PATCH 201/276] Enable -Werror and fix a number of minor warnings that existed. --- Makefile.am.inc | 2 +- json_tokener.c | 17 +++++++++-------- json_util.c | 5 +++-- linkhash.c | 4 ++-- tests/parse_flags.c | 2 +- tests/test_parse.c | 2 +- tests/test_printbuf.c | 2 +- 7 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Makefile.am.inc b/Makefile.am.inc index 7882fd7..96a791a 100644 --- a/Makefile.am.inc +++ b/Makefile.am.inc @@ -1,2 +1,2 @@ -AM_CFLAGS = -Wall -Wextra -Wwrite-strings -Wno-unused-parameter -std=c99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=c99 -D_GNU_SOURCE -D_REENTRANT diff --git a/json_tokener.c b/json_tokener.c index 6c5924b..e0edca0 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -69,7 +69,8 @@ const char* json_tokener_errors[] = { const char *json_tokener_error_desc(enum json_tokener_error jerr) { - if (jerr < 0 || jerr > sizeof(json_tokener_errors)) + int jerr_int = (int)jerr; + if (jerr_int < 0 || jerr_int > (int)sizeof(json_tokener_errors)) return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; return json_tokener_errors[jerr]; } @@ -91,7 +92,7 @@ struct json_tokener* json_tokener_new_ex(int depth) tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); if (!tok) return NULL; - tok->stack = (struct json_tokener*)calloc(depth, sizeof(struct json_tokener_srec)); + tok->stack = (struct json_tokener_srec *)calloc(depth, sizeof(struct json_tokener_srec)); if (!tok->stack) { free(tok); return NULL; @@ -330,8 +331,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, 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)) { + json_min(tok->st_pos+1, (int)strlen(json_null_str))) == 0) { + if(tok->st_pos == (int)strlen(json_null_str)) { current = NULL; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; @@ -552,16 +553,16 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, 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)) { + json_min(tok->st_pos+1, (int)strlen(json_true_str))) == 0) { + if(tok->st_pos == (int)strlen(json_true_str)) { current = json_object_new_boolean(1); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; } } else if(strncasecmp(json_false_str, tok->pb->buf, - json_min(tok->st_pos+1, strlen(json_false_str))) == 0) { - if(tok->st_pos == strlen(json_false_str)) { + json_min(tok->st_pos+1, (int)strlen(json_false_str))) == 0) { + if(tok->st_pos == (int)strlen(json_false_str)) { current = json_object_new_boolean(0); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; diff --git a/json_util.c b/json_util.c index 4030cbe..4e4e00c 100644 --- a/json_util.c +++ b/json_util.c @@ -194,7 +194,7 @@ int json_parse_int64(const char *buf, int64_t *retval) */ 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 && + ((int)strlen(buf_skip_space) != buf_cmp_len && isdigit((int)buf_skip_space[buf_cmp_len]) ) ) @@ -238,7 +238,8 @@ static const char* json_type_name[] = { const char *json_type_to_name(enum json_type o_type) { - if (o_type < 0 || o_type >= NELEM(json_type_name)) + int o_type_int = (int)o_type; + if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) { MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); return NULL; diff --git a/linkhash.c b/linkhash.c index 2661823..5043148 100644 --- a/linkhash.c +++ b/linkhash.c @@ -134,7 +134,7 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) while( 1 ) { if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; t->collisions++; - if(++n == t->size) n = 0; + if ((int)++n == t->size) n = 0; } t->table[n].k = k; @@ -166,7 +166,7 @@ struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) 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; + if ((int)++n == t->size) n = 0; count++; } return NULL; diff --git a/tests/parse_flags.c b/tests/parse_flags.c index e33ffee..1af61ea 100644 --- a/tests/parse_flags.c +++ b/tests/parse_flags.c @@ -32,7 +32,7 @@ int parse_flags(int argc, char **argv) for (arg_idx = 1; arg_idx < argc ; arg_idx++) { int jj; - for (jj = 0; jj < NELEM(format_args); jj++) + for (jj = 0; jj < (int)NELEM(format_args); jj++) { if (strcasecmp(argv[arg_idx], format_args[jj].arg) == 0) { diff --git a/tests/test_parse.c b/tests/test_parse.c index 3e86c5a..481cb12 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -183,7 +183,7 @@ struct incremental_step { { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, - { NULL, json_tokener_success }, + { NULL, -1, -1, json_tokener_success, 0 }, }; static void test_incremental_parse() diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index fed185e..c8b8ad0 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -86,7 +86,7 @@ static void test_printbuf_memappend(int *before_resize) char with_nulls[] = { 'a', 'b', '\0', 'c' }; printbuf_reset(pb); - printbuf_memappend_fast(pb, with_nulls, sizeof(with_nulls)); + printbuf_memappend_fast(pb, with_nulls, (int)sizeof(with_nulls)); printf("With embedded \\0 character: %d, [%s]\n", printbuf_length(pb), pb->buf); printbuf_free(pb); From bfb329223aecf7f47da2b8ece4bd8e421c7bfc6d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 9 Feb 2013 17:35:33 -0600 Subject: [PATCH 202/276] Add a runtime check to see if parse_int64 needs to workaround sscanf bugs. If that workaround is not needed parsing is nearly twice as fast. --- json_util.c | 81 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/json_util.c b/json_util.c index 4e4e00c..194f290 100644 --- a/json_util.c +++ b/json_util.c @@ -61,6 +61,10 @@ #include "json_tokener.h" #include "json_util.h" +static int sscanf_is_broken = 0; +static int sscanf_is_broken_testdone = 0; +static void sscanf_is_broken_test(void); + struct json_object* json_object_from_file(const char *filename) { struct printbuf *pb; @@ -142,41 +146,78 @@ int json_object_to_file(char *filename, struct json_object *obj) return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); } +/* + * Not all implementations of sscanf actually work properly. + * Check whether the one we're currently using does, and if + * it's broken, enable the workaround code. + */ +static void sscanf_is_broken_test() +{ + int64_t num64; + + (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64); + int ret_errno = errno; + int is_int64_min = (num64 == INT64_MIN); + + (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64); + int ret_errno2 = errno; + int is_int64_max = (num64 == INT64_MAX); + + if (ret_errno != ERANGE || !is_int64_min || + ret_errno2 != ERANGE || !is_int64_max) + { + MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); + sscanf_is_broken = 1; + } +} + int json_parse_int64(const char *buf, int64_t *retval) { int64_t num64; - const char *buf_skip_space; + const char *buf_sig_digits; int orig_has_neg; int saved_errno; + + if (!sscanf_is_broken_testdone) + { + sscanf_is_broken_test(); + sscanf_is_broken_testdone = 1; + } + + // Skip leading spaces + while (isspace((int)*buf) && *buf) + buf++; + errno = 0; // sscanf won't always set errno, so initialize if (sscanf(buf, "%" SCNd64, &num64) != 1) { MC_DEBUG("Failed to parse, sscanf != 1\n"); return 1; } + saved_errno = errno; - buf_skip_space = buf; + buf_sig_digits = buf; orig_has_neg = 0; - // Skip leading spaces - while (isspace((int)*buf_skip_space) && *buf_skip_space) - buf_skip_space++; - if (*buf_skip_space == '-') + if (*buf_sig_digits == '-') { - buf_skip_space++; + buf_sig_digits++; 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 (saved_errno != ERANGE) + + // Not all sscanf implementations actually work + if (sscanf_is_broken && saved_errno != ERANGE) { char buf_cmp[100]; char *buf_cmp_start = buf_cmp; int recheck_has_neg = 0; int buf_cmp_len; + + // Skip leading zeros, but keep at least one digit + while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') + buf_sig_digits++; + if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 + orig_has_neg = 0; // "-0" is the same as just plain "0" + snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); if (*buf_cmp_start == '-') { @@ -190,18 +231,22 @@ int json_parse_int64(const char *buf, int64_t *retval) * 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. + * then we have NOT successfully parsed the value. */ if (orig_has_neg != recheck_has_neg || - strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 || - ((int)strlen(buf_skip_space) != buf_cmp_len && - isdigit((int)buf_skip_space[buf_cmp_len]) + strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || + ((int)strlen(buf_sig_digits) != buf_cmp_len && + isdigit((int)buf_sig_digits[buf_cmp_len]) ) ) { saved_errno = ERANGE; } } + + // Not all sscanf impl's set the value properly when out of range. + // Always do this, even for properly functioning implementations, + // since it shouldn't slow things down much. if (saved_errno == ERANGE) { if (orig_has_neg) From 9b64c05ff9feb1cdb1e5ae5e134e5e6ff85dbb1b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 21 Feb 2013 12:32:29 -0600 Subject: [PATCH 203/276] Mark the "val" variable in json_object_object_foreach as unused so the compiler doesn't complain. Fix warnings in the testReplaceExisting test. --- json_object.h | 2 +- tests/testReplaceExisting.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/json_object.h b/json_object.h index c97850a..e18af8a 100644 --- a/json_object.h +++ b/json_object.h @@ -309,7 +309,7 @@ extern void json_object_object_del(struct json_object* obj, const char *key); # define json_object_object_foreach(obj,key,val) \ char *key; \ - struct json_object *val; \ + struct json_object *val __attribute__((__unused__)); \ for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ ({ if(entry ## key) { \ key = (char*)entry ## key->k; \ diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c index 8cc6924..6db7b98 100644 --- a/tests/testReplaceExisting.c +++ b/tests/testReplaceExisting.c @@ -74,5 +74,5 @@ int main(int argc, char **argv) json_object_put( my_object ); - return 0; + return retval; } From 94aeed2ecd5b65e46434cde5ba5f5a17ffd5f4c1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 26 Feb 2013 21:14:07 -0600 Subject: [PATCH 204/276] Include the test_locale test in the tests that run. --- tests/Makefile.am | 2 +- tests/test_locale.expected | 2 ++ tests/test_locale.test | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/test_locale.expected create mode 100755 tests/test_locale.test diff --git a/tests/Makefile.am b/tests/Makefile.am index 881c7e7..c6123ed 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,7 +39,7 @@ test_parse_LDADD = $(LIBJSON_LA) test_locale_LDADD = $(LIBJSON_LA) -TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test +TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf diff --git a/tests/test_locale.expected b/tests/test_locale.expected new file mode 100644 index 0000000..8031785 --- /dev/null +++ b/tests/test_locale.expected @@ -0,0 +1,2 @@ +new_obj.to_string()=[ 1.200000, 3.400000, 123456.780000, 5.000000, 23000000000.000000 ] +new_obj.to_string()=[1.2,3.4,123456.78,5.0,23000000000.0] diff --git a/tests/test_locale.test b/tests/test_locale.test new file mode 100755 index 0000000..e4b6c6d --- /dev/null +++ b/tests/test_locale.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_locale +exit $? From 36ec47db49277f4a5eda30823cf6d1f238f34991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Gst=C3=A4dtner?= Date: Sun, 3 Mar 2013 00:17:25 +0100 Subject: [PATCH 205/276] configure.in: mv AM_CONFIG_HEADER to AC_CONFIG_HEADER the former has been deprecated and does not work on newer autoconf versions. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 1a428b6..d68d7a1 100644 --- a/configure.in +++ b/configure.in @@ -20,8 +20,8 @@ AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno" # Checks for libraries. # Checks for header files. -AM_CONFIG_HEADER(config.h) -AM_CONFIG_HEADER(json_config.h) +AC_CONFIG_HEADER(config.h) +AC_CONFIG_HEADER(json_config.h) AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h) AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public define for json_inttypes.h])]) From 1aa29b655a26f3bc49d7b67a9fa983bffb1cca52 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 3 Mar 2013 22:26:28 -0600 Subject: [PATCH 206/276] Issue #68: use -std=gnu99 because some versions of gcc seem to think that -std=c99 also implies -ansi, which causes warnings and build breakage. --- Makefile.am.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am.inc b/Makefile.am.inc index 96a791a..fd68a25 100644 --- a/Makefile.am.inc +++ b/Makefile.am.inc @@ -1,2 +1,2 @@ -AM_CFLAGS = -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=c99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT From bb492d4d69f50f09191705f7e32204f99ca31c1b Mon Sep 17 00:00:00 2001 From: William Dignazio Date: Wed, 6 Mar 2013 12:29:33 -0500 Subject: [PATCH 207/276] Rename misnomer POP_CHAR to PEEK_CHAR. While parsing token data, we use the POP_CHAR macro to 'peek' at character data. This behaviour is noted in the comments for the macro, yet the definition is left as 'pop'. Changing to PEEK_CHAR does not imply that the character being observed is removed. --- json_tokener.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 8040fea..afb7bb2 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -202,21 +202,21 @@ char* strndup(const char* str, size_t n) * 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 + * 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 + * PEEK_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. +/* PEEK_CHAR(dest, tok) macro: + * Peeks at the current char and stores it in dest. * Returns 1 on success, sets tok->err and returns 0 if no more chars. * Implicit inputs: str, len vars */ -#define POP_CHAR(dest, tok) \ +#define PEEK_CHAR(dest, tok) \ (((tok)->char_offset == len) ? \ (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \ (((tok)->err = json_tokener_success), 0) \ @@ -225,7 +225,7 @@ char* strndup(const char* str, size_t n) ) : \ (((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) @@ -254,7 +254,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->char_offset = 0; tok->err = json_tokener_success; - while (POP_CHAR(c, tok)) { + while (PEEK_CHAR(c, tok)) { redo_char: switch(state) { @@ -262,7 +262,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_eatws: /* Advance until we change state */ while (isspace((int)c)) { - if ((!ADVANCE_CHAR(str, tok)) || (!POP_CHAR(c, tok))) + if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) goto out; } if(c == '/') { @@ -373,10 +373,10 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, /* Advance until we change state */ const char *case_start = str; while(c != '*') { - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); goto out; - } + } } printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start); state = json_tokener_state_comment_end; @@ -388,7 +388,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, /* Advance until we change state */ const char *case_start = str; while(c != '\n') { - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); goto out; } @@ -426,7 +426,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, state = json_tokener_state_string_escape; break; } - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); goto out; } @@ -513,7 +513,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *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)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); goto out; } @@ -552,7 +552,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->err = json_tokener_error_parse_string; goto out; } - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { if (got_hi_surrogate) /* Clean up any pending chars */ printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); goto out; @@ -595,7 +595,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, ++case_len; if(c == '.' || c == 'e' || c == 'E') tok->is_double = 1; - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, case_len); goto out; } @@ -686,7 +686,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, state = json_tokener_state_string_escape; break; } - if (!ADVANCE_CHAR(str, tok) || !POP_CHAR(c, tok)) { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); goto out; } @@ -752,7 +752,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if (oldlocale) free(oldlocale); #endif - if (tok->err == json_tokener_success) + if (tok->err == json_tokener_success) { json_object *ret = json_object_get(current); int ii; From 32eddd66f510fb13ef61d4ecab5296bcb771f111 Mon Sep 17 00:00:00 2001 From: William Dignazio Date: Wed, 6 Mar 2013 20:18:14 -0500 Subject: [PATCH 208/276] Fix broken build by using ADVANCE_CHAR macro return. We forget to check or use the return value of the ADVANCE_CHAR macro, and upon compilation an error is thrown because of its lack of use. This patch checks to see if the macro was successful, and if not replaces the offending character with a replacement. --- json_tokener.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index afb7bb2..6d50bc2 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -507,9 +507,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, (str[1] == '\\') && (str[2] == 'u')) { - ADVANCE_CHAR(str, tok); - ADVANCE_CHAR(str, tok); - + /* Advance through the 16 bit surrogate, and move on to the + * next sequence. The next step is to process the following + * characters. + */ + if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) { + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } /* Advance to the first char of the next sequence and * continue processing with the next sequence. */ From 88bf1c996013f2f733a3b21822aa73669eb8cdf5 Mon Sep 17 00:00:00 2001 From: Greg Hazel Date: Tue, 19 Mar 2013 16:26:12 -0700 Subject: [PATCH 209/276] one definition of json_object_object_foreach only works on c99 and later --- json_object.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json_object.h b/json_object.h index 7085d0a..6270309 100644 --- a/json_object.h +++ b/json_object.h @@ -309,7 +309,7 @@ extern void json_object_object_del(struct json_object* obj, const char *key); * @param val the local name for the json_object* object variable defined in * the body */ -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L # define json_object_object_foreach(obj,key,val) \ char *key; \ @@ -337,7 +337,7 @@ extern void json_object_object_del(struct json_object* obj, const char *key); entry ## key) : 0); \ entry ## key = entry_next ## key) -#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */ /** Iterate through all keys and values of an object (ANSI C Safe) * @param obj the json_object instance From e8161a11bbc2d34c459c5ae9b91750e49a8963e3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 31 Mar 2013 20:05:36 -0500 Subject: [PATCH 210/276] Issue #15: add a way to set a JSON_TOKENER_STRICT flag to forbid commas at the end of arrays and objects. --- json_tokener.c | 23 +++++++++++++++++++++-- json_tokener.h | 22 +++++++++++++++++++++- tests/test_parse.c | 11 ++++++++++- tests/test_parse.expected | 4 +++- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 6d50bc2..b2b47f9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -624,8 +624,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } break; + case json_tokener_state_array_after_sep: case json_tokener_state_array: if(c == ']') { + if (state == json_tokener_state_array_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else { @@ -651,7 +658,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if(c == ',') { - saved_state = json_tokener_state_array; + saved_state = json_tokener_state_array_after_sep; state = json_tokener_state_eatws; } else { tok->err = json_tokener_error_parse_array; @@ -660,7 +667,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_object_field_start: + case json_tokener_state_object_field_start_after_sep: if(c == '}') { + if (state == json_tokener_state_object_field_start_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if (c == '"' || c == '\'') { @@ -731,7 +745,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } else if(c == ',') { - saved_state = json_tokener_state_object_field_start; + saved_state = json_tokener_state_object_field_start_after_sep; state = json_tokener_state_eatws; } else { tok->err = json_tokener_error_parse_object_value_sep; @@ -771,3 +785,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, json_tokener_errors[tok->err], tok->char_offset); return NULL; } + +void json_tokener_set_flags(struct json_tokener *tok, int flags) +{ + tok->flags = flags; +} diff --git a/json_tokener.h b/json_tokener.h index 3da520a..08e5ff7 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -58,7 +58,9 @@ enum json_tokener_state { json_tokener_state_object_field_end, json_tokener_state_object_value, json_tokener_state_object_value_add, - json_tokener_state_object_sep + json_tokener_state_object_sep, + json_tokener_state_array_after_sep, + json_tokener_state_object_field_start_after_sep }; struct json_tokener_srec @@ -80,8 +82,21 @@ struct json_tokener unsigned int ucs_char; char quote_char; struct json_tokener_srec *stack; + int flags; }; +/** + * Be strict when parsing JSON input. Use caution with + * this flag as what is considered valid may become more + * restrictive from one release to the next, causing your + * code to fail on previously working input. + * + * This flag is not set by default. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_STRICT 0x01 + /** * Given an error previously returned by json_tokener_get_error(), * return a human readable description of the error. @@ -116,6 +131,11 @@ extern void json_tokener_reset(struct json_tokener *tok); extern struct json_object* json_tokener_parse(const char *str); extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); +/** + * Set flags that control how parsing will be done. + */ +extern void json_tokener_set_flags(struct json_tokener *tok, int flags); + /** * Parse a string and return a non-NULL json_object if a valid JSON value * is found. The string does not need to be a JSON object or array; diff --git a/tests/test_parse.c b/tests/test_parse.c index 481cb12..1a59a6b 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -183,6 +183,9 @@ struct incremental_step { { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, + { "[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 3 }, + { "{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 3 }, + { NULL, -1, -1, json_tokener_success, 0 }, }; @@ -215,6 +218,12 @@ static void test_incremental_parse() struct incremental_step *step = &incremental_steps[ii]; int length = step->length; int expected_char_offset = step->char_offset; + + if (step->reset_tokener & 2) + json_tokener_set_flags(tok, JSON_TOKENER_STRICT); + else + json_tokener_set_flags(tok, 0); + if (length == -1) length = strlen(step->string_to_parse); if (expected_char_offset == -1) @@ -264,7 +273,7 @@ static void test_incremental_parse() if (new_obj) json_object_put(new_obj); - if (step->reset_tokener) + if (step->reset_tokener & 1) json_tokener_reset(tok); if (this_step_ok) diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 814dc62..f0af0fa 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -51,5 +51,7 @@ json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character -End Incremental Tests OK=27 ERROR=0 +json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character +json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character +End Incremental Tests OK=29 ERROR=0 ================================== From f1b684971dd9fe2ab15c1973a0b7d0d563258cd1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 31 Mar 2013 20:34:28 -0500 Subject: [PATCH 211/276] Update config.h.in to add the HAVE_SETLOCALE and HAVE_LOCALE_H lines. --- config.h.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.h.in b/config.h.in index f44c8ed..b8b2d17 100644 --- a/config.h.in +++ b/config.h.in @@ -18,6 +18,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC @@ -32,6 +35,9 @@ and to 0 otherwise. */ #undef HAVE_REALLOC +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF From eee744cd7e8e10e754a3a3dc8efebb22e74e9d07 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 31 Mar 2013 20:57:08 -0500 Subject: [PATCH 212/276] Update the changelog with changes since the 0.10 release. --- ChangeLog | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2d55020..4e74c90 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ -NEXT.VERSION +0.11 * IMPORTANT: the name of the library has changed to libjson-c.so and the header files are now in include/json-c. @@ -10,6 +10,17 @@ NEXT.VERSION * Maximum recursion depth is now a runtime option. json_tokener_new() is provided for compatibility. json_tokener_new_ex(depth) + * Include json_object_iterator.h in the installed headers. + * Add support for building on Android. + * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. + * Make it safe to delete keys while iterating with the json_object_object_foreach macro. + * Add a json_set_serializer() function to allow the string output of a json_object to be customized. + * Make float parsing locale independent. + * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag. + * Enable -Werror when building. + * speed improvements to parsing 64-bit integers on systems with working sscanf + * Add a json_object_object_length function. + * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries. 0.10 From 0e81b21dc8f2be26d2b21b31b39e5df6f72e2d4d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 31 Mar 2013 20:58:30 -0500 Subject: [PATCH 213/276] Bump up the version in the release checklist to 0.11 --- RELEASE_CHECKLIST.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index bdc547a..2e901c3 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -1,7 +1,7 @@ Release checklist: -release=0.10 +release=0.11 git clone https://github.com/json-c/json-c json-c-${release} cd json-c-${release} From 20db5a4e848bbc8e0bf79ebea17a7eef9988c785 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 2 Apr 2013 21:21:38 -0500 Subject: [PATCH 214/276] Fill in a number of missing steps in the release process. --- RELEASE_CHECKLIST.txt | 55 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 2e901c3..3156d8c 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -9,10 +9,26 @@ Check that the compile works on Linux Check that the compile works on NetBSD Check that the compile works on Windows Check ChangeLog to see if anything should be added. +Make any fixes/changes *before* branching. git branch json-c-${release} git checkout json-c-${release} +------------ + +Update the version in json_c_version.h +Update the version in Doxyfile +Update the version in configure.in + Use ${release}. + +Update the libjson_la_LDFLAGS line in Makefile.am to the new version. + Generally, unless we're doing a major release, change: + -version-info x:y:z + to + -version-info x:y+1:z + +------------ + Generate the configure script and other files: sh autogen.sh git add -f Makefile.in aclocal.m4 config.guess \ @@ -24,11 +40,15 @@ Generate the configure script and other files: git status --ignored git commit +------------ + Generate the doxygen documentation: doxygen git add -f doc git commit doc +------------ + cd .. echo .git > excludes echo autom4te.cache >> excludes @@ -37,25 +57,46 @@ tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} echo doc >> excludes tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} +------------ + Tag the branch: cd json-c-${release} -git tag -a json-c-${release}-$(date +%Y%m%d) -git push +git tag -a json-c-${release}-$(date +%Y%m%d) -m "Release json-c-${release}" + +git push origin json-c-${release} git push --tags -Go to https://github.com/json-c/json-c/downloads -Upload the two tarballs. +------------ +Go to Amazon S3 service at: + https://console.aws.amazon.com/s3/ + +Upload the two tarballs in the json-c_releases folder. + When uploading, use "Reduced Redundancy", and make the uploaded files publicly accessible. + +Logout of Amazon S3, and verify that the files are visible. + https://s3.amazonaws.com/json-c_releases/releases/index.html =================================== Post-release checklist: -git branch master -Add new section to CHANGES +git checkout master +Add new section to ChangeLog Update the version in json_c_version.h Update the version in Doxyfile Update the version in configure.in -Update the libjson_la_LDFLAGS line in Makefile.am to the new version. + Use ${release}.99 to indicate a version "newer" than anything on the branch. + +Leave the libjson_la_LDFLAGS line in Makefile.am alone. + For more details see: http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +------------ + +XXX Update gh-pages branch, index.html: + Link to current release. + Add new docs. + +Send an email to the mailing list. + From 4207147c24c53115bdf3be378941e4269291ed0a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 2 Apr 2013 21:22:59 -0500 Subject: [PATCH 215/276] Bump the versions for the non-release branch; add a placeholder section to the change log. --- ChangeLog | 4 ++++ Doxyfile | 2 +- configure.in | 2 +- json_c_version.h | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e74c90..578ebc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ +NEXT.VERSION + + * Nothing yet... + 0.11 * IMPORTANT: the name of the library has changed to libjson-c.so and diff --git a/Doxyfile b/Doxyfile index 91c9434..cf52c48 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.10.99 +PROJECT_NUMBER = 0.11.99 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/configure.in b/configure.in index d68d7a1..c5494a9 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.10.99, [json-c@googlegroups.com]) +AC_INIT([json-c], 0.11.99, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) diff --git a/json_c_version.h b/json_c_version.h index 72bbbae..5d3db8f 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -9,12 +9,12 @@ #define _json_c_version_h_ #define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 10 +#define JSON_C_MINOR_VERSION 11 #define JSON_C_MICRO_VERSION 99 #define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ (JSON_C_MINOR_VERSION << 8) | \ JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.10.99" +#define JSON_C_VERSION "0.11.99" const char *json_c_version(void); /* Returns JSON_C_VERSION */ int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ From e843616cc62c2f170486539b59538cdbaf76c81d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 2 Apr 2013 21:36:28 -0500 Subject: [PATCH 216/276] Fill in the instructions for update the gh-pages branch. --- RELEASE_CHECKLIST.txt | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 3156d8c..a05b8a3 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -94,9 +94,24 @@ Leave the libjson_la_LDFLAGS line in Makefile.am alone. ------------ -XXX Update gh-pages branch, index.html: - Link to current release. - Add new docs. +Update the gh-pages branch with new docs: + +cd json-c-${release} +git checkout json-c-${release} +cd .. + +git clone -b gh-pages https://github.com/json-c/json-c json-c-pages +cd json-c-pages +mkdir json-c-${release} +cp -R ../json-c-${release}/doc json-c-${release}/. +cp ../json-c-${release}/README-WIN32.html json-c-${release}/. +git add json-c-${release} +git commit + +vi index.html + Add/change links to current release. + +------------ Send an email to the mailing list. From e48a25cfbb18449505edf6205cb069e346dce0f8 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 30 Apr 2013 09:47:19 -0500 Subject: [PATCH 217/276] Issue #76: use old style comment to allow json_object_iterator.h to build in ansi mode. --- json_object_iterator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object_iterator.h b/json_object_iterator.h index f6e7ca6..44c9fb2 100644 --- a/json_object_iterator.h +++ b/json_object_iterator.h @@ -236,4 +236,4 @@ json_object_iter_equal(const struct json_object_iterator* iter1, #endif -#endif // JSON_OBJECT_ITERATOR_H +#endif /* JSON_OBJECT_ITERATOR_H */ From 48ba6b8c0639e8b9fc1b81ce3e7b8c62191fb639 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 4 Jun 2013 20:17:12 +0200 Subject: [PATCH 218/276] fixe int32_t definition for VC11 int32_t is nowhere in msvc, so the version check could be even removed --- json_inttypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_inttypes.h b/json_inttypes.h index 2f84ade..bfe1060 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -4,7 +4,7 @@ #include "json_config.h" -#if defined(_MSC_VER) && _MSC_VER < 1700 +#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; From ed819fb9268535589c2302277f4d80afa6d38d79 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 4 Jun 2013 20:18:05 +0200 Subject: [PATCH 219/276] snprintf definition is needed here, too --- json_object.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/json_object.c b/json_object.c index f2b5ce0..facb824 100644 --- a/json_object.c +++ b/json_object.c @@ -37,6 +37,13 @@ char* strndup(const char* str, size_t n); #endif /* !HAVE_STRNDUP */ +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) + /* MSC has the version as _snprintf */ +# define snprintf _snprintf +#elif !defined(HAVE_SNPRINTF) +# error You do not have snprintf on your system. +#endif /* HAVE_SNPRINTF */ + // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ From 990fa8e3ee84195c35c3c68d9f8a1435ddf97d59 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 4 Jun 2013 20:18:28 +0200 Subject: [PATCH 220/276] Fix C89 compat needed by MSVC --- json_util.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/json_util.c b/json_util.c index 111fa01..d62d54e 100644 --- a/json_util.c +++ b/json_util.c @@ -159,14 +159,15 @@ int json_parse_double(const char *buf, double *retval) static void sscanf_is_broken_test() { int64_t num64; + int ret_errno, is_int64_min, ret_errno2, is_int64_max; (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64); - int ret_errno = errno; - int is_int64_min = (num64 == INT64_MIN); + ret_errno = errno; + is_int64_min = (num64 == INT64_MIN); (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64); - int ret_errno2 = errno; - int is_int64_max = (num64 == INT64_MAX); + ret_errno2 = errno; + is_int64_max = (num64 == INT64_MAX); if (ret_errno != ERANGE || !is_int64_min || ret_errno2 != ERANGE || !is_int64_max) From d086e2018c7938b0038db714335213a2ad91fa91 Mon Sep 17 00:00:00 2001 From: Adrian Yanes Date: Fri, 7 Jun 2013 13:14:54 -0700 Subject: [PATCH 221/276] Fixes for Infinity and NaN Although JSON RFC does not support NaN or Infinity as numeric values ECMA 262 section 9.8.1 defines how to handle these cases as strings --- json_object.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index f2b5ce0..b955f6d 100644 --- a/json_object.c +++ b/json_object.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "debug.h" #include "printbuf.h" @@ -561,8 +562,19 @@ static int json_object_double_to_json_string(struct json_object* jso, { char buf[128], *p, *q; int size; + /* Although JSON RFC does not support + NaN or Infinity as numeric values + ECMA 262 section 9.8.1 defines + how to handle these cases as strings */ + if(isnan(jso->o.c_double)) + size = snprintf(buf, 128, "NaN"); + else if(isinf(jso->o.c_double) == 1) + size = snprintf(buf, 128, "Infinity"); + else if(isinf(jso->o.c_double) == -1) + size = snprintf(buf, 128, "-Infinity"); + else + size = snprintf(buf, 128, "%f", jso->o.c_double); - size = snprintf(buf, 128, "%f", jso->o.c_double); p = strchr(buf, ','); if (p) { *p = '.'; From e9ee4ae18a9fca8c31eac44669364034658b3d51 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 13 Jun 2013 13:40:01 +0200 Subject: [PATCH 222/276] in strick mode, number must not start with 0 --- json_tokener.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index b2b47f9..4491cec 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -611,6 +611,11 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, int64_t num64; double numd; if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { + if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) { + /* in strick mode, number must not start with 0 */ + tok->err = json_tokener_error_parse_number; + goto out; + } current = json_object_new_int64(num64); } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) { current = json_object_new_double(numd); From d032aad1f4dff2b49c2a4f0e4b2aafc96a9f728e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 19 Jun 2013 09:14:19 -0500 Subject: [PATCH 223/276] Minor spell check. --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 4491cec..a6924a1 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -612,7 +612,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, double numd; if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { if (num64 && tok->pb->buf[0]=='0' && (tok->flags & JSON_TOKENER_STRICT)) { - /* in strick mode, number must not start with 0 */ + /* in strict mode, number must not start with 0 */ tok->err = json_tokener_error_parse_number; goto out; } From 5e8df40523e59c57017a2d160cca06c3503f68c1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Jun 2013 18:55:02 -0500 Subject: [PATCH 224/276] Mention that libtoolize is needed if you're not using a release tarball. --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index ac1e812..8c7301f 100644 --- a/README +++ b/README @@ -12,6 +12,7 @@ Prerequisites: If you're not using a release tarball, you'll also need: autoconf (autoreconf) automake + Make sure you have a complete libtool install, including libtoolize Github repo for json-c: https://github.com/json-c/json-c From c62965660b10d76671116986189c2d5cbba5c0d9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 23 Jun 2013 19:12:14 -0500 Subject: [PATCH 225/276] Fix the _MSC_VER check so it compiles on non-windows compilers. Issue#91 --- json_inttypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_inttypes.h b/json_inttypes.h index bfe1060..9de8d24 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -4,7 +4,7 @@ #include "json_config.h" -#if defined(_MSC_VER) && _MSC_VER =< 1700 +#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; From be002fbb96c484f89aee2c843b89bdd00b0a5e46 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 29 Jun 2013 15:21:04 -0500 Subject: [PATCH 226/276] Issue#84: explicitly remove old headers and include/json directory so creating the compat symlink can work. --- Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am index 51159b0..73e8116 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,13 @@ maintainer-clean-local: -rm -rf configure if ENABLE_OLDNAME_COMPAT +# Remove old headers and create a compatibility link install-data-hook: + if test -d "$(DESTDIR)@includedir@/json" ; then \ + (cd "$(DESTDIR)@includedir@/json" && \ + rm -f $(libjson_cinclude_HEADERS)) ; \ + rmdir "$(DESTDIR)@includedir@/json" ; \ + fi test \! -e "$(DESTDIR)@includedir@/json" || rm "$(DESTDIR)@includedir@/json" $(LN_S) json-c "$(DESTDIR)@includedir@/json" From b3bce4d5943774b59d7fa653da89f48db70d013e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 29 Jun 2013 15:31:18 -0500 Subject: [PATCH 227/276] Eliminate use of MC_ABORT in json-c code, and mark MC_ABORT/mc_abort deprecated. Also adjust an error message in json_util to make it unique. Fixes #87. --- debug.h | 7 +++++++ json_util.c | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/debug.h b/debug.h index 1e09701..f2dc541 100644 --- a/debug.h +++ b/debug.h @@ -23,6 +23,10 @@ extern void mc_set_debug(int debug); extern int mc_get_debug(void); extern void mc_set_syslog(int syslog); + +/** + * @deprecated Use mc_error(), and return an appropriate error. + */ extern void mc_abort(const char *msg, ...); extern void mc_debug(const char *msg, ...); extern void mc_error(const char *msg, ...); @@ -48,6 +52,9 @@ extern void mc_info(const char *msg, ...); #endif +/** + * @deprecated Use MC_ERROR(), and return an appropriate error. + */ #define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) #define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) diff --git a/json_util.c b/json_util.c index d62d54e..cab2f1e 100644 --- a/json_util.c +++ b/json_util.c @@ -73,7 +73,7 @@ struct json_object* json_object_from_file(const char *filename) int fd, ret; if((fd = open(filename, O_RDONLY)) < 0) { - MC_ERROR("json_object_from_file: error reading file %s: %s\n", + MC_ERROR("json_object_from_file: error opening file %s: %s\n", filename, strerror(errno)); return NULL; } @@ -87,7 +87,7 @@ struct json_object* json_object_from_file(const char *filename) } close(fd); if(ret < 0) { - MC_ABORT("json_object_from_file: error reading file %s: %s\n", + MC_ERROR("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); printbuf_free(pb); return NULL; From c5523a17e8dfd1da47716586bf85c3d0619d15c7 Mon Sep 17 00:00:00 2001 From: Taneli Mielikainen Date: Sun, 4 Aug 2013 00:21:58 +0300 Subject: [PATCH 228/276] fixing problem that isinf(-Inf) can be 1 or -1 --- json_object.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/json_object.c b/json_object.c index e12c440..b63faa4 100644 --- a/json_object.c +++ b/json_object.c @@ -575,10 +575,11 @@ static int json_object_double_to_json_string(struct json_object* jso, how to handle these cases as strings */ if(isnan(jso->o.c_double)) size = snprintf(buf, 128, "NaN"); - else if(isinf(jso->o.c_double) == 1) - size = snprintf(buf, 128, "Infinity"); - else if(isinf(jso->o.c_double) == -1) - size = snprintf(buf, 128, "-Infinity"); + else if(isinf(jso->o.c_double)) + if(jso->o.c_double > 0) + size = snprintf(buf, 128, "Infinity"); + else + size = snprintf(buf, 128, "-Infinity"); else size = snprintf(buf, 128, "%f", jso->o.c_double); From a07ef3d19763094ab35cc009657c85bcbb9dd9ae Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 6 Aug 2013 10:41:14 +0200 Subject: [PATCH 229/276] no single-quote string in strict mode --- json_tokener.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index a6924a1..45390ac 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -293,8 +293,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, printbuf_reset(tok->pb); tok->st_pos = 0; goto redo_char; - case '"': case '\'': + if (tok->flags & JSON_TOKENER_STRICT) { + /* in STRICT mode only double-quote are allowed */ + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + case '"': state = json_tokener_state_string; printbuf_reset(tok->pb); tok->quote_char = c; From 6c4bb3840c3541406893a9026ba2300bb3f009b3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 11 Aug 2013 01:18:17 +0200 Subject: [PATCH 230/276] Add extern to json_object_set_serializer so that it gets exported (Windows fix) --- json_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.h b/json_object.h index 6270309..df958bf 100644 --- a/json_object.h +++ b/json_object.h @@ -192,7 +192,7 @@ flags); * @param userdata an optional opaque cookie * @param user_delete an optional function from freeing userdata */ -void json_object_set_serializer(json_object *jso, +extern void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn to_string_func, void *userdata, json_object_delete_fn *user_delete); From 1a957c2edc4df1ae3ac5396209e19ba8355a624b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 12 Aug 2013 20:49:19 +0200 Subject: [PATCH 231/276] Remove redefinition of strndup() which is no longer used in the codebase --- config.h.in | 3 --- configure.in | 2 +- json_object.c | 4 ---- json_tokener.c | 23 ----------------------- 4 files changed, 1 insertion(+), 31 deletions(-) diff --git a/config.h.in b/config.h.in index b8b2d17..a912bb0 100644 --- a/config.h.in +++ b/config.h.in @@ -68,9 +68,6 @@ /* 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 header file. */ #undef HAVE_SYSLOG_H diff --git a/configure.in b/configure.in index c5494a9..64f9cbe 100644 --- a/configure.in +++ b/configure.in @@ -35,7 +35,7 @@ AC_FUNC_VPRINTF AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) +AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) #check if .section.gnu.warning accepts long strings (for __warn_references) AC_LANG_PUSH([C]) diff --git a/json_object.c b/json_object.c index e12c440..df1a62e 100644 --- a/json_object.c +++ b/json_object.c @@ -34,10 +34,6 @@ # error You do not have strdup on your system. #endif /* HAVE_STRDUP */ -#if !defined(HAVE_STRNDUP) - char* strndup(const char* str, size_t n); -#endif /* !HAVE_STRNDUP */ - #if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) /* MSC has the version as _snprintf */ # define snprintf _snprintf diff --git a/json_tokener.c b/json_tokener.c index a6924a1..24eddb2 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -170,29 +170,6 @@ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokene 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 From 20e4708c8a28dabfc6b55e926b0c47f9b454550d Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Tue, 13 Aug 2013 18:24:23 +0200 Subject: [PATCH 232/276] Update json_util filename should be passed as const char* to functions json_object_to_file and json_object_to_file --- json_util.c | 4 ++-- json_util.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/json_util.c b/json_util.c index cab2f1e..531f9af 100644 --- a/json_util.c +++ b/json_util.c @@ -99,7 +99,7 @@ struct json_object* json_object_from_file(const char *filename) /* extended "format and write to file" function */ -int json_object_to_file_ext(char *filename, struct json_object *obj, int flags) +int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) { const char *json_str; int fd, ret; @@ -141,7 +141,7 @@ int json_object_to_file_ext(char *filename, struct json_object *obj, int flags) // backwards compatible "format and write to file" function -int json_object_to_file(char *filename, struct json_object *obj) +int json_object_to_file(const char *filename, struct json_object *obj) { return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); } diff --git a/json_util.h b/json_util.h index b9a69c8..1005e58 100644 --- a/json_util.h +++ b/json_util.h @@ -22,8 +22,8 @@ extern "C" { /* utility functions */ extern struct json_object* json_object_from_file(const char *filename); -extern int json_object_to_file(char *filename, struct json_object *obj); -extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags); +extern int json_object_to_file(const char *filename, struct json_object *obj); +extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); extern int json_parse_int64(const char *buf, int64_t *retval); extern int json_parse_double(const char *buf, double *retval); From 87fa32dfe013d961ced5252ffacef0beefc8f62f Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Wed, 21 Aug 2013 15:41:40 +0200 Subject: [PATCH 233/276] no comment in strict mode --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 45390ac..7ce53ca 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -265,7 +265,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) goto out; } - if(c == '/') { + if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) { printbuf_reset(tok->pb); printbuf_memappend_fast(tok->pb, &c, 1); state = json_tokener_state_comment_start; From 4039f91cab283b483094dbe59202818bb1733d66 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Fri, 23 Aug 2013 13:40:01 +0200 Subject: [PATCH 234/276] trailing char not allowed in strict mode --- json_tokener.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index 7ce53ca..def6e10 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -769,6 +769,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } /* while(POP_CHAR) */ out: + if (c && + (state == json_tokener_state_finish) && + (tok->depth == 0) && + (tok->flags & JSON_TOKENER_STRICT)) { + /* unexpected char after JSON data */ + tok->err = json_tokener_error_parse_unexpected; + } if (!c) { /* We hit an eof char (0) */ if(state != json_tokener_state_finish && saved_state != json_tokener_state_finish) From 86dd55a74a6634a1018feac7f5ef5579d033ce2a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 8 Sep 2013 11:31:38 +0200 Subject: [PATCH 235/276] Fix potential out-of-bounds read in json_tokener_error_desc Found by Coverity. The number of elements of an array 'ar' is found by sizeof(ar)/sizeof(ar[0]) and not sizeof(ar) 76const char *json_tokener_error_desc(enum json_tokener_error jerr) 77{ 78 int jerr_int = (int)jerr; 1. Condition "jerr_int < 0", taking false branch 2. Condition "jerr_int > 112 /* (int)sizeof (gdal_json_tokener_errors) */", taking false branch 79 if (jerr_int < 0 || jerr_int > (int)sizeof(json_tokener_errors)) 80 return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; CID 1076806 (#1 of 1): Out-of-bounds read (OVERRUN)3. overrun-local: Overrunning array "gdal_json_tokener_errors" of 14 8-byte elements at element index 112 (byte offset 896) using index "jerr" (which evaluates to 112). 81 return json_tokener_errors[jerr]; 82} --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index a6924a1..7b3a097 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -74,7 +74,7 @@ const char* json_tokener_errors[] = { const char *json_tokener_error_desc(enum json_tokener_error jerr) { int jerr_int = (int)jerr; - if (jerr_int < 0 || jerr_int > (int)sizeof(json_tokener_errors)) + if (jerr_int < 0 || jerr_int > (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; return json_tokener_errors[jerr]; } From 8d18815f8aab102c707f63933dd56b352ca8a65e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Sep 2013 17:21:52 -0500 Subject: [PATCH 236/276] strndup is gone, remove it from the README file. --- README-WIN32.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-WIN32.html b/README-WIN32.html index 28fc7d8..abdb39e 100644 --- a/README-WIN32.html +++ b/README-WIN32.html @@ -13,7 +13,7 @@ Various functions have been redefined to their Win32 version (i.e. open on win32 is _open)
  • - Implemented missing functions from MS's libc (i.e. vasprintf and strndup)
  • + Implemented missing functions from MS's libc (i.e. vasprintf)
  • Added code to allow Win64 support without integer resizing issues, this probably makes it much nicer on 64bit machines everywhere (i.e. using ptrdiff_t From 60e4990d1d7feca862bf6daeac2a268f6c8bda69 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Sep 2013 17:23:24 -0500 Subject: [PATCH 237/276] The updated test driver creates .log and .trs files; ignore them. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f3b18f1..a920d40 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ /tests/test_printbuf /tests/test_set_serializer /tests/*.vg.out +/tests/*.log +/tests/*.trs /Debug /Release *.lo From b83e0f11826e86747885fc066fa5b06d50f60520 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 8 Sep 2013 17:30:54 -0500 Subject: [PATCH 238/276] Ignore the test-driver script that is now created, and the script for the test_locale test. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a920d40..4644691 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ /missing /stamp-h1 /stamp-h2 +/test-driver /tests/Makefile /tests/Makefile.in /tests/test1 @@ -37,6 +38,7 @@ /tests/test_parse_int64 /tests/test_parse /tests/test_cast +/tests/test_locale /tests/test_null /tests/test_printbuf /tests/test_set_serializer From 51993c28c2721b00340e1ddbd9bb133fdedf1bf4 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 11 Sep 2013 20:27:39 -0500 Subject: [PATCH 239/276] Added a json_object_new_double_s() convenience function to allow an exact string representation of a double to be specified when creating the object and use it in json_tokener_parse_ex() so a re-serialized object more exactly matches the input. Add json_object_free_userdata() and json_object_userdata_to_json_string() too. --- ChangeLog | 5 ++++- json_object.c | 35 ++++++++++++++++++++++++++----- json_object.h | 42 ++++++++++++++++++++++++++++++++++++++ json_tokener.c | 6 ++++-- tests/test_locale.expected | 4 ++-- tests/test_parse.expected | 2 +- 6 files changed, 83 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 578ebc7..1f16787 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,10 @@ NEXT.VERSION - * Nothing yet... + * Added a json_object_new_double_s() convenience function to allow + an exact string representation of a double to be specified when + creating the object and use it in json_tokener_parse_ex() so + a re-serialized object more exactly matches the input. 0.11 diff --git a/json_object.c b/json_object.c index 1b3fc76..f65ae52 100644 --- a/json_object.c +++ b/json_object.c @@ -601,11 +601,36 @@ static int json_object_double_to_json_string(struct json_object* jso, 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; + 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; +} + +struct json_object* json_object_new_double_s(double d, const char *ds) +{ + struct json_object *jso = json_object_new_double(d); + if (!jso) + return NULL; + + json_object_set_serializer(jso, json_object_userdata_to_json_string, + strdup(ds), json_object_free_userdata); + return jso; +} + +int json_object_userdata_to_json_string(struct json_object *jso, + struct printbuf *pb, int level, int flags) +{ + int userdata_len = strlen(jso->_userdata); + printbuf_memappend(pb, jso->_userdata, userdata_len); + return userdata_len; +} + +void json_object_free_userdata(struct json_object *jso, void *userdata) +{ + free(userdata); } double json_object_get_double(struct json_object *jso) diff --git a/json_object.h b/json_object.h index df958bf..1005734 100644 --- a/json_object.h +++ b/json_object.h @@ -197,6 +197,25 @@ extern void json_object_set_serializer(json_object *jso, void *userdata, json_object_delete_fn *user_delete); +/** + * Simply call free on the userdata pointer. + * Can be used with json_object_set_serializer(). + * + * @param jso unused + * @param userdata the pointer that is passed to free(). + */ +json_object_delete_fn json_object_free_userdata; + +/** + * Copy the jso->_userdata string over to pb as-is. + * Can be used with json_object_set_serializer(). + * + * @param jso The object whose _userdata is used. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +json_object_to_json_string_fn json_object_userdata_to_json_string; /* object type methods */ @@ -493,6 +512,29 @@ extern int64_t json_object_get_int64(struct json_object *obj); */ extern struct json_object* json_object_new_double(double d); +/** + * Create a new json_object of type json_type_double, using + * the exact serialized representation of the value. + * + * This allows for numbers that would otherwise get displayed + * inefficiently (e.g. 12.3 => "12.300000000000001") to be + * serialized with the more convenient form. + * + * Note: this is used by json_tokener_parse_ex() to allow for + * an exact re-serialization of a parsed object. + * + * An equivalent sequence of calls is: + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(d, json_object_userdata_to_json_string, + * strdup(ds), json_object_free_userdata) + * @endcode + * + * @param d the numeric value of the double. + * @param ds the string representation of the double. This will be copied. + */ +extern struct json_object* json_object_new_double_s(double d, const char *ds); + /** 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. diff --git a/json_tokener.c b/json_tokener.c index 7e1fb68..a2a598b 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -599,8 +599,10 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto out; } current = json_object_new_int64(num64); - } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) { - current = json_object_new_double(numd); + } + else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) + { + current = json_object_new_double_s(numd, tok->pb->buf); } else { tok->err = json_tokener_error_parse_number; goto out; diff --git a/tests/test_locale.expected b/tests/test_locale.expected index 8031785..0068be4 100644 --- a/tests/test_locale.expected +++ b/tests/test_locale.expected @@ -1,2 +1,2 @@ -new_obj.to_string()=[ 1.200000, 3.400000, 123456.780000, 5.000000, 23000000000.000000 ] -new_obj.to_string()=[1.2,3.4,123456.78,5.0,23000000000.0] +new_obj.to_string()=[ 1.2, 3.4, 123456.78, 5.0, 2.3e10 ] +new_obj.to_string()=[1.2,3.4,123456.78,5.0,2.3e10] diff --git a/tests/test_parse.expected b/tests/test_parse.expected index f0af0fa..5ea99d8 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -5,7 +5,7 @@ new_obj.to_string()="ABC" new_obj.to_string()=null new_obj.to_string()=true new_obj.to_string()=12 -new_obj.to_string()=12.300000 +new_obj.to_string()=12.3 new_obj.to_string()=[ "\n" ] new_obj.to_string()=[ "\nabc\n" ] new_obj.to_string()=[ null ] From a23caf677c107b7cfe5ad52c73a932c706aaa7f5 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 11 Sep 2013 20:28:56 -0500 Subject: [PATCH 240/276] Use sizeof instead of hard coded values when calling snprintf. --- json_object.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/json_object.c b/json_object.c index f65ae52..118def7 100644 --- a/json_object.c +++ b/json_object.c @@ -570,14 +570,14 @@ static int json_object_double_to_json_string(struct json_object* jso, ECMA 262 section 9.8.1 defines how to handle these cases as strings */ if(isnan(jso->o.c_double)) - size = snprintf(buf, 128, "NaN"); + size = snprintf(buf, sizeof(buf), "NaN"); else if(isinf(jso->o.c_double)) if(jso->o.c_double > 0) - size = snprintf(buf, 128, "Infinity"); + size = snprintf(buf, sizeof(buf), "Infinity"); else - size = snprintf(buf, 128, "-Infinity"); + size = snprintf(buf, sizeof(buf), "-Infinity"); else - size = snprintf(buf, 128, "%f", jso->o.c_double); + size = snprintf(buf, sizeof(buf), "%f", jso->o.c_double); p = strchr(buf, ','); if (p) { From 06450206c4f3de4af8d81bb6d93e9db1d5fedec1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 11 Sep 2013 21:09:43 -0500 Subject: [PATCH 241/276] Issue #59: change the floating point output format to %.17g so values with more than 6 digits show up in the output. --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 118def7..faf6193 100644 --- a/json_object.c +++ b/json_object.c @@ -577,7 +577,7 @@ static int json_object_double_to_json_string(struct json_object* jso, else size = snprintf(buf, sizeof(buf), "-Infinity"); else - size = snprintf(buf, sizeof(buf), "%f", jso->o.c_double); + size = snprintf(buf, sizeof(buf), "%.17g", jso->o.c_double); p = strchr(buf, ','); if (p) { From 311686f63ed26e510c50808977c31883fe7bc23d Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 17 Sep 2013 13:08:14 +0100 Subject: [PATCH 242/276] Add a check for the -Bsymbolic-functions linker flag The -Bsymbolic-functions linker flag reduces the amount of PLT jumps in a shared object, and has a side effect of preventing symbol collisions in libraries and applications linking against two different shared objects exposing the same symbol. While the former is (generally) a performance win, the latter is less rare than expected. For instance, PulseAudio started linking against json-c a while ago; now, every project linking against PulseAudio is leaking json-c symbols. In the GNOME platform, this means that projects linking against PulseAudio cannot be safely linked against other libraries depending on the GLib-based JSON parsing libraries JSON-GLib, because of a symbol conflict. Nominally, this conflict would not be an issue: libraries and applications do not need to depend on two different JSON parsing libraries; the symbol leakage, though, ends up causing either segmentation faults, or weird errors. For further reference, please see: https://bugzilla.gnome.org/show_bug.cgi?id=703734 JSON-GLib already switched to using -Bsymbolic-functions, but it would be safe if json-c did the same, wherever the linker flag is available. --- Makefile.am | 4 ++-- configure.in | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 73e8116..cc6f005 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,10 +36,10 @@ libjson_cinclude_HEADERS = \ #libjsonx_include_HEADERS = \ # json_config.h -libjson_c_la_LDFLAGS = -version-info 2:0:0 -no-undefined +libjson_c_la_LDFLAGS = -version-info 2:0:0 -no-undefined @JSON_BSYMBOLIC_LDFLAGS@ if ENABLE_OLDNAME_COMPAT -libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c +libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c @JSON_BSYMBOLIC_LDFLAGS@ # Temporary libjson library. This will be removed after one release. libjson_la_LIBADD = -ljson-c diff --git a/configure.in b/configure.in index 64f9cbe..7697be5 100644 --- a/configure.in +++ b/configure.in @@ -57,6 +57,32 @@ AC_LANG_POP([C]) AM_PROG_LIBTOOL +# Check for the -Bsymbolic-functions linker flag +AC_ARG_ENABLE([Bsymbolic], + [AS_HELP_STRING([--disable-Bsymbolic], [Avoid linking with -Bsymbolic-function])], + [], + [enable_Bsymbolic=check]) + +AS_IF([test "x$enable_Bsymbolic" = "xcheck"], + [ + saved_LDFLAGS="${LDFLAGS}" + AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) + LDFLAGS=-Wl,-Bsymbolic-functions + AC_TRY_LINK([], [int main (void) { return 0; }], + [ + AC_MSG_RESULT([yes]) + enable_Bsymbolic=yes + ], + [ + AC_MSG_RESULT([no]) + enable_Bsymbolic=no + ]) + LDFLAGS="${saved_LDFLAGS}" + ]) + +AS_IF([test "x$enable_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions]) +AC_SUBST(JSON_BSYMBOLIC_LDFLAGS) + AC_CONFIG_FILES([ Makefile json.pc From c51b88d69a3bb70f7bfed3f78a9283726cc827dd Mon Sep 17 00:00:00 2001 From: Keith Derrick Date: Tue, 1 Oct 2013 09:18:51 -0700 Subject: [PATCH 243/276] Avoid potential overflow in json_object_get_double sscanf is always a potential problem when converting numeric values as it does not correctly handle over- and underflow (or at least gives no indication that it has done so). This change converts json_object_get_double() to use strtod() according to CERT guidelines. --- json_object.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index faf6193..377ab59 100644 --- a/json_object.c +++ b/json_object.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "debug.h" #include "printbuf.h" @@ -636,6 +637,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(struct json_object *jso) { double cdouble; + char *errPtr = NULL; if(!jso) return 0.0; switch(jso->o_type) { @@ -646,7 +648,36 @@ double json_object_get_double(struct json_object *jso) 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; + errno = 0; + cdouble = strtod(jso->o.c_string.str,&errPtr); + + /* if conversion stopped at the first character, return 0.0 */ + if (errPtr == jso->o.c_string.str) + return 0.0; + + /* + * Check that the conversion terminated on something sensible + * + * For example, { "pay" : 123AB } would parse as 123. + */ + if (*errPtr != '\0') + return 0.0; + + /* + * If strtod encounters a string which would exceed the + * capacity of a double, it returns +/- HUGE_VAL and sets + * errno to ERANGE. But +/- HUGE_VAL is also a valid result + * from a conversion, so we need to check errno. + * + * Underflow also sets errno to ERANGE, but it returns 0 in + * that case, which is what we will return anyway. + * + * See CERT guideline ERR30-C + */ + if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && + (ERANGE == errno)) + cdouble = 0.0; + return cdouble; default: return 0.0; } From bda0540cb990b56fea7903f93e3829a02bf7b42e Mon Sep 17 00:00:00 2001 From: Andrea Faulds Date: Thu, 14 Nov 2013 21:13:32 +0000 Subject: [PATCH 244/276] Only allow lowercase literals in STRICT mode --- json_tokener.c | 78 ++++++++++++++++++++++++++++------------------- tests/Makefile.am | 5 ++- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index a2a598b..7c59603 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -322,20 +322,26 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto redo_char; case json_tokener_state_null: - printbuf_memappend_fast(tok->pb, &c, 1); - if(strncasecmp(json_null_str, tok->pb->buf, - json_min(tok->st_pos+1, (int)strlen(json_null_str))) == 0) { - if(tok->st_pos == (int)strlen(json_null_str)) { - current = NULL; - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; + { + int size; + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, (int)strlen(json_null_str)); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_null_str, tok->pb->buf, size) == 0) + || (strncmp(json_null_str, tok->pb->buf, size) == 0) + ) { + if(tok->st_pos == (int)strlen(json_null_str)) { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_null; + goto out; } - } else { - tok->err = json_tokener_error_parse_null; - goto out; + tok->st_pos++; } - tok->st_pos++; break; case json_tokener_state_comment_start: @@ -548,28 +554,36 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_boolean: - printbuf_memappend_fast(tok->pb, &c, 1); - if(strncasecmp(json_true_str, tok->pb->buf, - json_min(tok->st_pos+1, (int)strlen(json_true_str))) == 0) { - if(tok->st_pos == (int)strlen(json_true_str)) { - current = json_object_new_boolean(1); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; + { + int size1, size2; + printbuf_memappend_fast(tok->pb, &c, 1); + size1 = json_min(tok->st_pos+1, (int)strlen(json_true_str)); + size2 = json_min(tok->st_pos+1, (int)strlen(json_false_str)); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_true_str, tok->pb->buf, size1) == 0) + || (strncmp(json_true_str, tok->pb->buf, size1) == 0) + ) { + if(tok->st_pos == (int)strlen(json_true_str)) { + current = json_object_new_boolean(1); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_false_str, tok->pb->buf, size2) == 0) + || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { + if(tok->st_pos == (int)strlen(json_false_str)) { + current = json_object_new_boolean(0); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_boolean; + goto out; } - } else if(strncasecmp(json_false_str, tok->pb->buf, - json_min(tok->st_pos+1, (int)strlen(json_false_str))) == 0) { - if(tok->st_pos == (int)strlen(json_false_str)) { - current = json_object_new_boolean(0); - saved_state = json_tokener_state_finish; - state = json_tokener_state_eatws; - goto redo_char; - } - } else { - tok->err = json_tokener_error_parse_boolean; - goto out; + tok->st_pos++; } - tok->st_pos++; break; case json_tokener_state_number: diff --git a/tests/Makefile.am b/tests/Makefile.am index c6123ed..4fb3cb8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,6 +12,7 @@ check_PROGRAMS += test_null check_PROGRAMS += test_cast check_PROGRAMS += test_parse check_PROGRAMS += test_locale +check_PROGRAMS += test_case test1_LDADD = $(LIBJSON_LA) @@ -39,7 +40,9 @@ test_parse_LDADD = $(LIBJSON_LA) test_locale_LDADD = $(LIBJSON_LA) -TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test +test_case_LDADD = $(LIBJSON_LA) + +TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test test_case.test TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf From 89535bb1fff73edac43b153ee4721f44179f0469 Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Mon, 18 Nov 2013 16:25:14 +0000 Subject: [PATCH 245/276] build: call AM_PROG_CC_C_O as requested by autoreconf --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 64f9cbe..da50fdd 100644 --- a/configure.in +++ b/configure.in @@ -20,6 +20,7 @@ AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno" # Checks for libraries. # Checks for header files. +AM_PROG_CC_C_O AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(json_config.h) AC_HEADER_STDC From c8ee9196420c4b7c295a38c397a4e315df1baa03 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 11 Feb 2014 22:49:59 -0500 Subject: [PATCH 246/276] Remove the old libjson.so name compatibility support. The library is only created as libjson-c.so now and headers are only installed into the ${prefix}/json-c directory. --- Makefile.am | 29 +---------------------------- configure.in | 9 --------- json.pc.in | 11 ----------- 3 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 json.pc.in diff --git a/Makefile.am b/Makefile.am index 73e8116..8f76acb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,15 +4,9 @@ EXTRA_DIST = README.html README-WIN32.html config.h.win32 doc json-c.vcproj SUBDIRS = . tests lib_LTLIBRARIES = libjson-c.la -if ENABLE_OLDNAME_COMPAT -lib_LTLIBRARIES+=libjson.la -endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = json-c.pc -if ENABLE_OLDNAME_COMPAT -pkgconfig_DATA += json.pc -endif libjson_cincludedir = $(includedir)/json-c libjson_cinclude_HEADERS = \ @@ -38,14 +32,6 @@ libjson_cinclude_HEADERS = \ libjson_c_la_LDFLAGS = -version-info 2:0:0 -no-undefined -if ENABLE_OLDNAME_COMPAT -libjson_la_LDFLAGS = -version-info 1:0:1 -no-undefined -ljson-c - -# Temporary libjson library. This will be removed after one release. -libjson_la_LIBADD = -ljson-c -endif - - libjson_c_la_SOURCES = \ arraylist.c \ debug.c \ @@ -65,22 +51,9 @@ distclean-local: maintainer-clean-local: -rm -rf configure -if ENABLE_OLDNAME_COMPAT -# Remove old headers and create a compatibility link -install-data-hook: - if test -d "$(DESTDIR)@includedir@/json" ; then \ - (cd "$(DESTDIR)@includedir@/json" && \ - rm -f $(libjson_cinclude_HEADERS)) ; \ - rmdir "$(DESTDIR)@includedir@/json" ; \ - fi - test \! -e "$(DESTDIR)@includedir@/json" || rm "$(DESTDIR)@includedir@/json" - $(LN_S) json-c "$(DESTDIR)@includedir@/json" - uninstall-local: - rm -f "$(DESTDIR)@includedir@/json" rm -rf "$(DESTDIR)@includedir@/json-c" - -endif + rm -f "$(DESTDIR)@includedir@/json" ANDROID_CFLAGS = -I$(top_srcdir) -DHAVE_CONFIG_H diff --git a/configure.in b/configure.in index 64f9cbe..b6eae8c 100644 --- a/configure.in +++ b/configure.in @@ -7,14 +7,6 @@ AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) AC_PROG_MAKE_SET -AC_ARG_ENABLE(oldname-compat, - AS_HELP_STRING([--disable-oldname-compat], - [Don't include the old libjson.so library and include/json directory.]), -[], -[enable_oldname_compat=yes] -) -AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno"]) - # Checks for programs. # Checks for libraries. @@ -59,7 +51,6 @@ AM_PROG_LIBTOOL AC_CONFIG_FILES([ Makefile -json.pc json-c.pc tests/Makefile json-c-uninstalled.pc diff --git a/json.pc.in b/json.pc.in deleted file mode 100644 index 80e75d1..0000000 --- a/json.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: json-c -Description: JSON implementation in C, compat shim. Use json-c instead. -Version: @VERSION@ -Requires: json-c -Libs: -Cflags: From a2c078fc6eaf92dfe68d11bc2089e9e7c91f47c0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 11 Feb 2014 22:55:52 -0500 Subject: [PATCH 247/276] Issue#105: Rename configure.in to configure.ac --- configure.in => configure.ac | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename configure.in => configure.ac (100%) diff --git a/configure.in b/configure.ac similarity index 100% rename from configure.in rename to configure.ac From 295bea21d0c91c46c484922da4d85801c3be889e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 11 Feb 2014 23:03:46 -0500 Subject: [PATCH 248/276] Ignore and cleanup a few more files that automake creates. --- .gitignore | 1 + Makefile.am | 1 + config.h.in | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4644691..d3e748e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /autom4te.cache /config.guess /json_config.h +/compile /config.h /config.log /config.status diff --git a/Makefile.am b/Makefile.am index 8f76acb..d85d776 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ libjson_c_la_SOURCES = \ distclean-local: -rm -rf $(testsubdir) -rm -rf config.h.in~ Makefile.in aclocal.m4 autom4te.cache/ config.guess config.sub depcomp install-sh ltmain.sh missing + -rm -f INSTALL test-driver tests/Makefile.in compile maintainer-clean-local: -rm -rf configure diff --git a/config.h.in b/config.h.in index a912bb0..e59a5a3 100644 --- a/config.h.in +++ b/config.h.in @@ -1,4 +1,4 @@ -/* config.h.in. Generated from configure.in by autoheader. */ +/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if .gnu.warning accepts long strings. */ #undef HAS_GNU_WARNING_LONG From 56df93d12857fb3d13f7e14391954e3b59708261 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 11 Feb 2014 23:16:53 -0500 Subject: [PATCH 249/276] Fix Issue #111: Fix off-by-one error when range checking the input to json_tokener_error_desc(). --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index a2a598b..4ebe712 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -74,7 +74,7 @@ const char* json_tokener_errors[] = { const char *json_tokener_error_desc(enum json_tokener_error jerr) { int jerr_int = (int)jerr; - if (jerr_int < 0 || jerr_int > (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) + if (jerr_int < 0 || jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()"; return json_tokener_errors[jerr]; } From 1d6f9140ba9f9200f23b5b91dafafd749d61241c Mon Sep 17 00:00:00 2001 From: Andrea Faulds Date: Wed, 12 Feb 2014 09:51:51 +0000 Subject: [PATCH 250/276] Missing tests --- tests/test_case.c | 40 ++++++++++++++++++++++++++++++++++++++++ tests/test_case.expected | 1 + tests/test_case.test | 12 ++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/test_case.c create mode 100644 tests/test_case.expected create mode 100755 tests/test_case.test diff --git a/tests/test_case.c b/tests/test_case.c new file mode 100644 index 0000000..936afee --- /dev/null +++ b/tests/test_case.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +#include "json.h" +#include "json_tokener.h" + +static void test_case_parse(void); + +int main(int argc, char **argv) +{ + MC_SET_DEBUG(1); + + test_case_parse(); +} + +/* make sure only lowercase forms are parsed in strict mode */ +static void test_case_parse() +{ + struct json_tokener *tok; + json_object *new_obj; + + tok = json_tokener_new(); + json_tokener_set_flags(tok, JSON_TOKENER_STRICT); + + new_obj = json_tokener_parse_ex(tok, "True", 4); + assert (new_obj == NULL); + + new_obj = json_tokener_parse_ex(tok, "False", 5); + assert (new_obj == NULL); + + new_obj = json_tokener_parse_ex(tok, "Null", 4); + assert (new_obj == NULL); + + printf("OK\n"); + + json_tokener_free(tok); +} diff --git a/tests/test_case.expected b/tests/test_case.expected new file mode 100644 index 0000000..d86bac9 --- /dev/null +++ b/tests/test_case.expected @@ -0,0 +1 @@ +OK diff --git a/tests/test_case.test b/tests/test_case.test new file mode 100755 index 0000000..ad0a099 --- /dev/null +++ b/tests/test_case.test @@ -0,0 +1,12 @@ +#!/bin/sh + +# Common definitions +if test -z "$srcdir"; then + srcdir="${0%/*}" + test "$srcdir" = "$0" && srcdir=. + test -z "$srcdir" && srcdir=. +fi +. "$srcdir/test-defs.sh" + +run_output_test test_case +exit $? From e6f1322b5e0fbbd5b8767b60c5fe34ff4468ec42 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 2 Mar 2014 12:16:37 -0500 Subject: [PATCH 251/276] Issue#114: check for the presence of isnan and isinf, and provide compat macros on MSCV where _isnan and _finite exist instead. --- config.h.in | 16 ++++++++++++++++ configure.ac | 6 +++++- json_object.c | 1 + math_compat.h | 20 ++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 math_compat.h diff --git a/config.h.in b/config.h.in index e59a5a3..d612636 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,22 @@ /* Define if .gnu.warning accepts long strings. */ #undef HAS_GNU_WARNING_LONG +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#undef HAVE_DECL_ISINF + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#undef HAVE_DECL_ISNAN + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you + don't. */ +#undef HAVE_DECL__FINITE + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. + */ +#undef HAVE_DECL__ISNAN + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H diff --git a/configure.ac b/configure.ac index 5c0a0e8..a7d2d7b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. AC_INIT([json-c], 0.11.99, [json-c@googlegroups.com]) -AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) +AM_INIT_AUTOMAKE AC_PROG_MAKE_SET @@ -29,6 +29,10 @@ AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) +AC_CHECK_DECLS([isnan], [], [], [[#include ]]) +AC_CHECK_DECLS([isinf], [], [], [[#include ]]) +AC_CHECK_DECLS([_isnan], [], [], [[#include ]]) +AC_CHECK_DECLS([_finite], [], [], [[#include ]]) #check if .section.gnu.warning accepts long strings (for __warn_references) AC_LANG_PUSH([C]) diff --git a/json_object.c b/json_object.c index 377ab59..6cc73bc 100644 --- a/json_object.c +++ b/json_object.c @@ -27,6 +27,7 @@ #include "json_object.h" #include "json_object_private.h" #include "json_util.h" +#include "math_compat.h" #if !defined(HAVE_STRDUP) && defined(_MSC_VER) /* MSC has the version as _strdup */ diff --git a/math_compat.h b/math_compat.h new file mode 100644 index 0000000..4a2721e --- /dev/null +++ b/math_compat.h @@ -0,0 +1,20 @@ +#ifndef __math_compat_h +#define __math_compat_h + +/* Define isnan and isinf on Windows/MSVC */ + +#ifndef HAVE_DECL_ISNAN +# ifdef HAVE_DECL__ISNAN +#include +#define isnan(x) _isnan(x) +# endif +#endif + +#ifndef HAVE_DECL_ISINF +# ifdef HAVE_DECL__FINITE +#include +#define isinf(x) (!_finite(x)) +# endif +#endif + +#endif From 0eedf3802fad2d41e45eecd92af529440f0d7d3a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 9 Mar 2014 16:41:33 -0400 Subject: [PATCH 252/276] Issue#102 - add support for parsing "NaN". --- config.h.in | 3 +++ configure.ac | 1 + json_tokener.c | 41 +++++++++++++++++++++++++++++---------- math_compat.h | 4 ++++ tests/test_parse.c | 4 ++++ tests/test_parse.expected | 1 + 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/config.h.in b/config.h.in index d612636..f24bfbc 100644 --- a/config.h.in +++ b/config.h.in @@ -11,6 +11,9 @@ */ #undef HAVE_DECL_ISNAN +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#undef HAVE_DECL_NAN + /* Define to 1 if you have the declaration of `_finite', and to 0 if you don't. */ #undef HAVE_DECL__FINITE diff --git a/configure.ac b/configure.ac index a7d2d7b..96e2466 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) +AC_CHECK_DECLS([nan], [], [], [[#include ]]) AC_CHECK_DECLS([isnan], [], [], [[#include ]]) AC_CHECK_DECLS([isinf], [], [], [[#include ]]) AC_CHECK_DECLS([_isnan], [], [], [[#include ]]) diff --git a/json_tokener.c b/json_tokener.c index 74fd27a..0c800d8 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -15,6 +15,7 @@ #include "config.h" +#include #include #include #include @@ -49,9 +50,14 @@ # 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"; +static const char json_null_str[] = "null"; +static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_nan_str[] = "NaN"; +static const int json_nan_str_len = sizeof(json_nan_str) - 1; +static const char json_true_str[] = "true"; +static const int json_true_str_len = sizeof(json_true_str) - 1; +static const char json_false_str[] = "false"; +static const int json_false_str_len = sizeof(json_false_str) - 1; // XXX after v0.10 this array will become static: const char* json_tokener_errors[] = { @@ -266,7 +272,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case 'N': case 'n': - state = json_tokener_state_null; + state = json_tokener_state_null; // or NaN printbuf_reset(tok->pb); tok->st_pos = 0; goto redo_char; @@ -324,18 +330,33 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_null: { int size; + int size_nan; printbuf_memappend_fast(tok->pb, &c, 1); - size = json_min(tok->st_pos+1, (int)strlen(json_null_str)); + size = json_min(tok->st_pos+1, json_null_str_len); + size_nan = json_min(tok->st_pos+1, json_nan_str_len); if((!(tok->flags & JSON_TOKENER_STRICT) && strncasecmp(json_null_str, tok->pb->buf, size) == 0) || (strncmp(json_null_str, tok->pb->buf, size) == 0) ) { - if(tok->st_pos == (int)strlen(json_null_str)) { + if (tok->st_pos == json_null_str_len) { current = NULL; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; } + } + else if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) || + (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0) + ) + { + if (tok->st_pos == json_nan_str_len) + { + current = json_object_new_double(nan("")); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } } else { tok->err = json_tokener_error_parse_null; goto out; @@ -557,13 +578,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, { int size1, size2; printbuf_memappend_fast(tok->pb, &c, 1); - size1 = json_min(tok->st_pos+1, (int)strlen(json_true_str)); - size2 = json_min(tok->st_pos+1, (int)strlen(json_false_str)); + size1 = json_min(tok->st_pos+1, json_true_str_len); + size2 = json_min(tok->st_pos+1, json_false_str_len); if((!(tok->flags & JSON_TOKENER_STRICT) && strncasecmp(json_true_str, tok->pb->buf, size1) == 0) || (strncmp(json_true_str, tok->pb->buf, size1) == 0) ) { - if(tok->st_pos == (int)strlen(json_true_str)) { + if(tok->st_pos == json_true_str_len) { current = json_object_new_boolean(1); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; @@ -572,7 +593,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } else if((!(tok->flags & JSON_TOKENER_STRICT) && strncasecmp(json_false_str, tok->pb->buf, size2) == 0) || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { - if(tok->st_pos == (int)strlen(json_false_str)) { + if(tok->st_pos == json_false_str_len) { current = json_object_new_boolean(0); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; diff --git a/math_compat.h b/math_compat.h index 4a2721e..d94a4da 100644 --- a/math_compat.h +++ b/math_compat.h @@ -17,4 +17,8 @@ # endif #endif +#ifndef HAVE_DECL_NAN +#error This platform does not have nan() +#endif + #endif diff --git a/tests/test_parse.c b/tests/test_parse.c index 1a59a6b..f0f2550 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -47,6 +47,10 @@ static void test_basic_parse() printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + new_obj = json_tokener_parse("NaN"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + new_obj = json_tokener_parse("True"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 5ea99d8..378a82b 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -3,6 +3,7 @@ new_obj.to_string()="foo" new_obj.to_string()="foo" new_obj.to_string()="ABC" new_obj.to_string()=null +new_obj.to_string()=NaN new_obj.to_string()=true new_obj.to_string()=12 new_obj.to_string()=12.3 From a1c8991e135f7fbdb7d4254c699b1cf0085c23e8 Mon Sep 17 00:00:00 2001 From: Markus Stenberg Date: Tue, 18 Mar 2014 16:29:49 +0200 Subject: [PATCH 253/276] nan function requires -lm on some platforms; use of NAN is better, if available. --- json_tokener.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 0c800d8..9862f9e 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -50,6 +50,11 @@ # error You do not have strncasecmp on your system. #endif /* HAVE_STRNCASECMP */ +/* Use C99 NAN by default; if not available, nan("") should work too. */ +#ifndef NAN +#define NAN nan("") +#endif /* !NAN */ + static const char json_null_str[] = "null"; static const int json_null_str_len = sizeof(json_null_str) - 1; static const char json_nan_str[] = "NaN"; @@ -352,7 +357,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, { if (tok->st_pos == json_nan_str_len) { - current = json_object_new_double(nan("")); + current = json_object_new_double(NAN); saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; From 05da316b9ceee79fa98575133d9f4c9e2abe59d0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 17:28:40 -0400 Subject: [PATCH 254/276] Issue #103: allow Infinity and -Infinity to be parsed. --- config.h.in | 4 +++ configure.ac | 1 + json_tokener.c | 52 ++++++++++++++++++++++++++++++++++++++- json_tokener.h | 3 ++- math_compat.h | 4 +++ tests/test_parse.c | 28 +++++++++++++++++++++ tests/test_parse.expected | 7 ++++++ 7 files changed, 97 insertions(+), 2 deletions(-) diff --git a/config.h.in b/config.h.in index f24bfbc..7c8973f 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,10 @@ /* Define if .gnu.warning accepts long strings. */ #undef HAS_GNU_WARNING_LONG +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#undef HAVE_DECL_INFINITY + /* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. */ #undef HAVE_DECL_ISINF diff --git a/configure.ac b/configure.ac index 96e2466..20ad715 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) +AC_CHECK_DECLS([INFINITY], [], [], [[#include ]]) AC_CHECK_DECLS([nan], [], [], [[#include ]]) AC_CHECK_DECLS([isnan], [], [], [[#include ]]) AC_CHECK_DECLS([isinf], [], [], [[#include ]]) diff --git a/json_tokener.c b/json_tokener.c index 9862f9e..e4710e4 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -57,6 +57,8 @@ static const char json_null_str[] = "null"; static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_inf_str[] = "Infinity"; +static const int json_inf_str_len = sizeof(json_inf_str) - 1; static const char json_nan_str[] = "NaN"; static const int json_nan_str_len = sizeof(json_nan_str) - 1; static const char json_true_str[] = "true"; @@ -275,6 +277,12 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, saved_state = json_tokener_state_array; current = json_object_new_array(); break; + case 'I': + case 'i': + state = json_tokener_state_inf; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; case 'N': case 'n': state = json_tokener_state_null; // or NaN @@ -332,7 +340,41 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->depth--; goto redo_char; - case json_tokener_state_null: + case json_tokener_state_inf: /* aka starts with 'i' */ + { + int size; + int size_inf; + int is_negative = 0; + + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, json_null_str_len); + size_inf = json_min(tok->st_pos+1, json_inf_str_len); + char *infbuf = tok->pb->buf; + if (*infbuf == '-') + { + infbuf++; + is_negative = 1; + } + if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_inf_str, infbuf, size_inf) == 0) || + (strncmp(json_inf_str, infbuf, size_inf) == 0) + ) + { + if (tok->st_pos == json_inf_str_len) + { + current = json_object_new_double(is_negative ? -INFINITY : INFINITY); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + } + break; + case json_tokener_state_null: /* aka starts with 'n' */ { int size; int size_nan; @@ -628,6 +670,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } if (case_len>0) printbuf_memappend_fast(tok->pb, case_start, case_len); + + // Check for -Infinity + if (tok->pb->buf[0] == '-' && case_len == 1 && + (c == 'i' || c == 'I')) + { + state = json_tokener_state_inf; + goto redo_char; + } } { int64_t num64; diff --git a/json_tokener.h b/json_tokener.h index 08e5ff7..61f73d2 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -60,7 +60,8 @@ enum json_tokener_state { json_tokener_state_object_value_add, json_tokener_state_object_sep, json_tokener_state_array_after_sep, - json_tokener_state_object_field_start_after_sep + json_tokener_state_object_field_start_after_sep, + json_tokener_state_inf }; struct json_tokener_srec diff --git a/math_compat.h b/math_compat.h index d94a4da..f40b8fa 100644 --- a/math_compat.h +++ b/math_compat.h @@ -21,4 +21,8 @@ #error This platform does not have nan() #endif +#ifndef HAVE_DECL_INFINITY +#error This platform does not have INFINITY +#endif + #endif diff --git a/tests/test_parse.c b/tests/test_parse.c index f0f2550..8808d0f 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -51,6 +51,34 @@ static void test_basic_parse() printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + new_obj = json_tokener_parse("-NaN"); /* non-sensical, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("Inf"); /* must use full string, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("inf"); /* must use full string, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("Infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("-Infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("-infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + new_obj = json_tokener_parse("True"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 378a82b..d49cbbb 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -4,6 +4,13 @@ new_obj.to_string()="foo" new_obj.to_string()="ABC" new_obj.to_string()=null new_obj.to_string()=NaN +new_obj.to_string()=null +new_obj.to_string()=null +new_obj.to_string()=null +new_obj.to_string()=Infinity +new_obj.to_string()=Infinity +new_obj.to_string()=-Infinity +new_obj.to_string()=-Infinity new_obj.to_string()=true new_obj.to_string()=12 new_obj.to_string()=12.3 From 9f26d96f0979efb8c8acf4901fd77265c9bf7e8d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 19:15:01 -0400 Subject: [PATCH 255/276] Fix warnings from autoconf about "...no AC_LANG_SOURCE call detected..." by adding that call within the AC_LINK_IFELSE call. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 20ad715..6ad10ad 100644 --- a/configure.ac +++ b/configure.ac @@ -40,12 +40,12 @@ AC_CHECK_DECLS([_finite], [], [], [[#include ]]) AC_LANG_PUSH([C]) AC_MSG_CHECKING([if .gnu.warning accepts long strings]) -AC_LINK_IFELSE([[ +AC_LINK_IFELSE([AC_LANG_SOURCE([[ extern void json_object_get(); __asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libjson-c instead of libjson\"\n\t.text"); int main(int c,char* v) {return 0;} -]], [ +]])], [ AC_DEFINE(HAS_GNU_WARNING_LONG, 1, [Define if .gnu.warning accepts long strings.]) AC_MSG_RESULT(yes) ], [ From e2bbb5664c96d73f85fce6dbd44cd35aea5c1904 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 21:15:41 -0400 Subject: [PATCH 256/276] Rename the "test_case" test to "test_charcase" to make it slightly less confusing. --- .gitignore | 1 + tests/Makefile.am | 29 ++----------------- tests/{test_case.c => test_charcase.c} | 0 ...t_case.expected => test_charcase.expected} | 0 tests/{test_case.test => test_charcase.test} | 2 +- 5 files changed, 5 insertions(+), 27 deletions(-) rename tests/{test_case.c => test_charcase.c} (100%) rename tests/{test_case.expected => test_charcase.expected} (100%) rename tests/{test_case.test => test_charcase.test} (86%) diff --git a/.gitignore b/.gitignore index d3e748e..15000ba 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ /tests/test_parse_int64 /tests/test_parse /tests/test_cast +/tests/test_charcase /tests/test_locale /tests/test_null /tests/test_printbuf diff --git a/tests/Makefile.am b/tests/Makefile.am index 4fb3cb8..70f1fc1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,6 @@ include ../Makefile.am.inc +LDADD= $(LIBJSON_LA) LIBJSON_LA=$(top_builddir)/libjson-c.la @@ -12,45 +13,21 @@ check_PROGRAMS += test_null check_PROGRAMS += test_cast check_PROGRAMS += test_parse check_PROGRAMS += test_locale -check_PROGRAMS += test_case +check_PROGRAMS += test_charcase -test1_LDADD = $(LIBJSON_LA) - -test1Formatted_LDADD= $(LIBJSON_LA) test1Formatted_SOURCES = test1.c parse_flags.c test1Formatted_CPPFLAGS = -DTEST_FORMATTED -test2_LDADD = $(LIBJSON_LA) - -test2Formatted_LDADD= $(LIBJSON_LA) test2Formatted_SOURCES = test2.c parse_flags.c test2Formatted_CPPFLAGS = -DTEST_FORMATTED -test4_LDADD = $(LIBJSON_LA) - -testReplaceExisting_LDADD = $(LIBJSON_LA) - -test_parse_int64_LDADD = $(LIBJSON_LA) - -test_null_LDADD = $(LIBJSON_LA) - -test_cast_LDADD = $(LIBJSON_LA) - -test_parse_LDADD = $(LIBJSON_LA) - -test_locale_LDADD = $(LIBJSON_LA) - -test_case_LDADD = $(LIBJSON_LA) - -TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test test_case.test +TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test test_charcase.test TESTS+= test_printbuf.test check_PROGRAMS+=test_printbuf -test_printbuf_LDADD = $(LIBJSON_LA) TESTS+= test_set_serializer.test check_PROGRAMS += test_set_serializer -test_set_serializer_LDADD = $(LIBJSON_LA) EXTRA_DIST= EXTRA_DIST += $(TESTS) diff --git a/tests/test_case.c b/tests/test_charcase.c similarity index 100% rename from tests/test_case.c rename to tests/test_charcase.c diff --git a/tests/test_case.expected b/tests/test_charcase.expected similarity index 100% rename from tests/test_case.expected rename to tests/test_charcase.expected diff --git a/tests/test_case.test b/tests/test_charcase.test similarity index 86% rename from tests/test_case.test rename to tests/test_charcase.test index ad0a099..c967475 100755 --- a/tests/test_case.test +++ b/tests/test_charcase.test @@ -8,5 +8,5 @@ if test -z "$srcdir"; then fi . "$srcdir/test-defs.sh" -run_output_test test_case +run_output_test test_charcase exit $? From 936d036ea3cd77cf3215e580f074a4d8d4d1f82c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 21:40:37 -0400 Subject: [PATCH 257/276] Simplify the tests Makefile to avoid repeating the name of each test. --- tests/Makefile.am | 38 ++++++++++--------- ...parse_int64.test => test_parse_int64.test} | 0 2 files changed, 20 insertions(+), 18 deletions(-) rename tests/{parse_int64.test => test_parse_int64.test} (100%) diff --git a/tests/Makefile.am b/tests/Makefile.am index 70f1fc1..a388eeb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,31 +4,33 @@ LDADD= $(LIBJSON_LA) LIBJSON_LA=$(top_builddir)/libjson-c.la -check_PROGRAMS = test1 test1Formatted -check_PROGRAMS += test2 test2Formatted -check_PROGRAMS += test4 -check_PROGRAMS += testReplaceExisting -check_PROGRAMS += test_parse_int64 -check_PROGRAMS += test_null -check_PROGRAMS += test_cast -check_PROGRAMS += test_parse -check_PROGRAMS += test_locale -check_PROGRAMS += test_charcase +TESTS= +TESTS+= test1.test +TESTS+= test2.test +TESTS+= test4.test +TESTS+= testReplaceExisting.test +TESTS+= test_parse_int64.test +TESTS+= test_null.test +TESTS+= test_cast.test +TESTS+= test_parse.test +TESTS+= test_locale.test +TESTS+= test_charcase.test +TESTS+= test_printbuf.test +TESTS+= test_set_serializer.test +check_PROGRAMS= +check_PROGRAMS += $(TESTS:.test=) + +# Note: handled by test1.test +check_PROGRAMS += test1Formatted test1Formatted_SOURCES = test1.c parse_flags.c test1Formatted_CPPFLAGS = -DTEST_FORMATTED +# Note: handled by test2.test +check_PROGRAMS += test2Formatted test2Formatted_SOURCES = test2.c parse_flags.c test2Formatted_CPPFLAGS = -DTEST_FORMATTED -TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test test_locale.test test_charcase.test - -TESTS+= test_printbuf.test -check_PROGRAMS+=test_printbuf - -TESTS+= test_set_serializer.test -check_PROGRAMS += test_set_serializer - EXTRA_DIST= EXTRA_DIST += $(TESTS) diff --git a/tests/parse_int64.test b/tests/test_parse_int64.test similarity index 100% rename from tests/parse_int64.test rename to tests/test_parse_int64.test From f9136f68520db4761f05810f97922900ba459f46 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 21:41:24 -0400 Subject: [PATCH 258/276] Make the json_tokener_errors array local. It has been deprecated for a while, and json_tokener_error_desc() should be used instead. --- json_tokener.c | 3 +-- json_tokener.h | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index e4710e4..a1019c0 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -66,8 +66,7 @@ static const int json_true_str_len = sizeof(json_true_str) - 1; static const char json_false_str[] = "false"; static const int json_false_str_len = sizeof(json_false_str) - 1; -// XXX after v0.10 this array will become static: -const char* json_tokener_errors[] = { +static const char* json_tokener_errors[] = { "success", "continue", "nesting too deep", diff --git a/json_tokener.h b/json_tokener.h index 61f73d2..5471d97 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -106,14 +106,6 @@ struct json_tokener */ 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. From 784534a31f301466d9ab6f8d5b5ccd39a3b9f156 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 22 Mar 2014 21:48:34 -0400 Subject: [PATCH 259/276] Eliminate the deprecated mc_abort() function and MC_ABORT macro. --- debug.c | 15 --------------- debug.h | 8 -------- 2 files changed, 23 deletions(-) diff --git a/debug.c b/debug.c index e0294ca..3b64b59 100644 --- a/debug.c +++ b/debug.c @@ -41,21 +41,6 @@ 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; diff --git a/debug.h b/debug.h index f2dc541..80ca3e4 100644 --- a/debug.h +++ b/debug.h @@ -24,10 +24,6 @@ extern int mc_get_debug(void); extern void mc_set_syslog(int syslog); -/** - * @deprecated Use mc_error(), and return an appropriate error. - */ -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, ...); @@ -52,10 +48,6 @@ extern void mc_info(const char *msg, ...); #endif -/** - * @deprecated Use MC_ERROR(), and return an appropriate error. - */ -#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) #define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) #ifdef MC_MAINTAINER_MODE From 64e36901a0614bf64a19bc3396469c66dcd0b015 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Wed, 9 Apr 2014 13:48:21 +0800 Subject: [PATCH 260/276] Patch to address the following issues: * CVE-2013-6371: hash collision denial of service * CVE-2013-6370: buffer overflow if size_t is larger than int --- Makefile.am | 6 +- Makefile.am.inc | 2 +- config.h.in | 6 + configure.ac | 16 +- json_object.h | 12 +- json_tokener.c | 11 ++ json_tokener.h | 8 +- linkhash.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++- linkhash.h | 2 +- random_seed.c | 237 ++++++++++++++++++++++++++++++ random_seed.h | 25 ++++ 11 files changed, 691 insertions(+), 13 deletions(-) create mode 100644 random_seed.c create mode 100644 random_seed.h diff --git a/Makefile.am b/Makefile.am index 24b9bdf..26ced27 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,8 @@ libjson_cinclude_HEADERS = \ json_tokener.h \ json_util.h \ linkhash.h \ - printbuf.h + printbuf.h \ + random_seed.h #libjsonx_includedir = $(libdir)/json-c-@VERSION@ # @@ -41,7 +42,8 @@ libjson_c_la_SOURCES = \ json_tokener.c \ json_util.c \ linkhash.c \ - printbuf.c + printbuf.c \ + random_seed.c distclean-local: diff --git a/Makefile.am.inc b/Makefile.am.inc index fd68a25..fec591b 100644 --- a/Makefile.am.inc +++ b/Makefile.am.inc @@ -1,2 +1,2 @@ -AM_CFLAGS = -Wall -Werror -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT +AM_CFLAGS = -Wall -Werror -Wno-error=deprecated-declarations -Wextra -Wwrite-strings -Wno-unused-parameter -std=gnu99 -D_GNU_SOURCE -D_REENTRANT diff --git a/config.h.in b/config.h.in index 7c8973f..0dcab1a 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Enable RDRANR Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND + /* Define if .gnu.warning accepts long strings. */ #undef HAS_GNU_WARNING_LONG @@ -32,6 +35,9 @@ /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H diff --git a/configure.ac b/configure.ac index 6ad10ad..48c8e5f 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,20 @@ AM_INIT_AUTOMAKE AC_PROG_MAKE_SET +AC_ARG_ENABLE(rdrand, + AS_HELP_STRING([--enable-rdrand], + [Enable RDRAND Hardware RNG Hash Seed generation on supported x86/x64 platforms.]), +[if test x$enableval = xyes; then + enable_rdrand=yes + AC_DEFINE(ENABLE_RDRAND, 1, [Enable RDRANR Hardware RNG Hash Seed]) +fi]) + +if test "x$enable_rdrand" = "xyes"; then + AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed enabled on supported x86/x64 platforms]) +else + AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed disabled. Use --enable-rdrand to enable]) +fi + # Checks for programs. # Checks for libraries. @@ -16,7 +30,7 @@ AM_PROG_CC_C_O AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(json_config.h) AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h) +AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h endian.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. diff --git a/json_object.h b/json_object.h index 1005734..200ac40 100644 --- a/json_object.h +++ b/json_object.h @@ -13,6 +13,14 @@ #ifndef _json_object_h_ #define _json_object_h_ +#ifdef __GNUC__ +#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func +#else +#define THIS_FUNCTION_IS_DEPRECATED(func) func +#endif + #include "json_inttypes.h" #ifdef __cplusplus @@ -279,8 +287,8 @@ extern void json_object_object_add(struct json_object* obj, const char *key, * @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); +THIS_FUNCTION_IS_DEPRECATED(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. * diff --git a/json_tokener.c b/json_tokener.c index a1019c0..19de8ef 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -81,6 +81,7 @@ static const char* json_tokener_errors[] = { "object value separator ',' expected", "invalid string sequence", "expected comment", + "buffer size overflow" }; const char *json_tokener_error_desc(enum json_tokener_error jerr) @@ -243,6 +244,16 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->char_offset = 0; tok->err = json_tokener_success; + /* this interface is presently not 64-bit clean due to the int len argument + and the internal printbuf interface that takes 32-bit int len arguments + so the function limits the maximum string size to INT32_MAX (2GB). + If the function is called with len == -1 then strlen is called to check + the string length is less than INT32_MAX (2GB) */ + if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) { + tok->err = json_tokener_error_size; + return NULL; + } + while (PEEK_CHAR(c, tok)) { redo_char: diff --git a/json_tokener.h b/json_tokener.h index 5471d97..a72d2bd 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -33,7 +33,8 @@ enum json_tokener_error { json_tokener_error_parse_object_key_sep, json_tokener_error_parse_object_value_sep, json_tokener_error_parse_string, - json_tokener_error_parse_comment + json_tokener_error_parse_comment, + json_tokener_error_size }; enum json_tokener_state { @@ -163,6 +164,11 @@ extern void json_tokener_set_flags(struct json_tokener *tok, int flags); * responsible for calling json_tokener_parse_ex with an appropriate str * parameter starting with the extra characters. * + * This interface is presently not 64-bit clean due to the int len argument + * so the function limits the maximum string size to INT32_MAX (2GB). + * If the function is called with len == -1 then strlen is called to check + * the string length is less than INT32_MAX (2GB) + * * Example: * @code json_object *jobj = NULL; diff --git a/linkhash.c b/linkhash.c index 5043148..712c387 100644 --- a/linkhash.c +++ b/linkhash.c @@ -17,6 +17,11 @@ #include #include +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +#include "random_seed.h" #include "linkhash.h" void lh_abort(const char *msg, ...) @@ -39,14 +44,378 @@ int lh_ptr_equal(const void *k1, const void *k2) return (k1 == k2); } +/* + * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * http://burtleburtle.net/bob/c/lookup3.c + * minor modifications to make functions static so no symbols are exported + * minor mofifications to compile with -Werror + */ + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + 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; + static volatile int random_seed = -1; - return h; + if (random_seed == -1) { + int seed; + /* we can't use -1 as it is the unitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1); +#if defined __GNUC__ + __sync_val_compare_and_swap(&random_seed, -1, seed); +#elif defined _MSC_VER + InterlockedCompareExchange(&random_seed, seed, -1); +#else +#warning "racy random seed initializtion if used by multiple threads" + random_seed = seed; /* potentially racy */ +#endif + } + + return hashlittle((const char*)k, strlen((const char*)k), random_seed); } int lh_char_equal(const void *k1, const void *k2) diff --git a/linkhash.h b/linkhash.h index 378de0b..950d09f 100644 --- a/linkhash.h +++ b/linkhash.h @@ -246,7 +246,7 @@ extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) * @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); +THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); /** * Lookup a record in the table diff --git a/random_seed.c b/random_seed.c new file mode 100644 index 0000000..3b520d4 --- /dev/null +++ b/random_seed.c @@ -0,0 +1,237 @@ +/* + * random_seed.c + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * 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 +#include "config.h" + +#define DEBUG_SEED(s) + + +#if defined ENABLE_RDRAND + +/* cpuid */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) +#define HAS_X86_CPUID 1 + +static void do_cpuid(int regs[], int h) +{ + __asm__ __volatile__( +#if defined __x86_64__ + "pushq %%rbx;\n" +#else + "pushl %%ebx;\n" +#endif + "cpuid;\n" +#if defined __x86_64__ + "popq %%rbx;\n" +#else + "popl %%ebx;\n" +#endif + : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(h)); +} + +#elif defined _MSC_VER + +#define HAS_X86_CPUID 1 +#define do_cpuid __cpuid + +#endif + +/* has_rdrand */ + +#if HAS_X86_CPUID + +static int has_rdrand() +{ + // CPUID.01H:ECX.RDRAND[bit 30] == 1 + int regs[4]; + do_cpuid(regs, 1); + return (regs[2] & (1 << 30)) != 0; +} + +#endif + +/* get_rdrand_seed - GCC x86 and X64 */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + +#define HAVE_RDRAND 1 + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; + // rdrand eax + __asm__ __volatile__("1: .byte 0x0F\n" + " .byte 0xC7\n" + " .byte 0xF0\n" + " jnc 1b;\n" + : "=a" (_eax)); + return _eax; +} + +#endif + +#if defined _MSC_VER + +#if _MSC_VER >= 1700 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2012 and above */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int r; + while (_rdrand32_step(&r) == 0); + return r; +} + +#elif defined _M_IX86 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; +retry: + // rdrand eax + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; +} + +#endif +#endif + +#endif /* defined ENABLE_RDRAND */ + + +/* has_dev_urandom */ + +#if defined (__APPLE__) || defined(__unix__) || defined(__linux__) + +#include +#include +#include +#include +#include +#include + +#define HAVE_DEV_RANDOM 1 + +static const char *dev_random_file = "/dev/urandom"; + +static int has_dev_urandom() +{ + struct stat buf; + if (stat(dev_random_file, &buf)) { + return 0; + } + return ((buf.st_mode & S_IFCHR) != 0); +} + + +/* get_dev_random_seed */ + +static int get_dev_random_seed() +{ + DEBUG_SEED("get_dev_random_seed"); + + int fd = open(dev_random_file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + + int r; + ssize_t nread = read(fd, &r, sizeof(r)); + if (nread != sizeof(r)) { + fprintf(stderr, "error read %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + else if (nread != sizeof(r)) { + fprintf(stderr, "error short read %s", dev_random_file); + exit(1); + } + close(fd); + return r; +} + +#endif + + +/* get_cryptgenrandom_seed */ + +#ifdef WIN32 + +#define HAVE_CRYPTGENRANDOM 1 + +#include +#pragma comment(lib, "advapi32.lib") + +static int get_cryptgenrandom_seed() +{ + DEBUG_SEED("get_cryptgenrandom_seed"); + + HCRYPTPROV hProvider = 0; + int r; + + if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + fprintf(stderr, "error CryptAcquireContextW"); + exit(1); + } + + if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) { + fprintf(stderr, "error CryptGenRandom"); + exit(1); + } + + CryptReleaseContext(hProvider, 0); + + return r; +} + +#endif + + +/* get_time_seed */ + +#include + +static int get_time_seed() +{ + DEBUG_SEED("get_time_seed"); + + return (int)time(NULL) * 433494437; +} + + +/* json_c_get_random_seed */ + +int json_c_get_random_seed() +{ +#if HAVE_RDRAND + if (has_rdrand()) return get_rdrand_seed(); +#endif +#if HAVE_DEV_RANDOM + if (has_dev_urandom()) return get_dev_random_seed(); +#endif +#if HAVE_CRYPTGENRANDOM + return get_cryptgenrandom_seed(); +#endif + return get_time_seed(); +} diff --git a/random_seed.h b/random_seed.h new file mode 100644 index 0000000..7362d67 --- /dev/null +++ b/random_seed.h @@ -0,0 +1,25 @@ +/* + * random_seed.h + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * 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 seed_h +#define seed_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern int json_c_get_random_seed(); + +#ifdef __cplusplus +} +#endif + +#endif From f84d9c55db449c46fa48ddc89953efa85ca0defb Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 10 Apr 2014 21:07:20 -0400 Subject: [PATCH 261/276] Update the ChangeLog with the changes for the 0.12 release. Bump the version in the release checklist. --- ChangeLog | 34 +++++++++++++++++++++++++++++++++- RELEASE_CHECKLIST.txt | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1f16787..451b8f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,43 @@ -NEXT.VERSION +0.12 + + * Address security issues: + * CVE-2013-6371: hash collision denial of service + * CVE-2013-6370: buffer overflow if size_t is larger than int + + * Avoid potential overflow in json_object_get_double + + * Eliminate the mc_abort() function and MC_ABORT macro. + + * Make the json_tokener_errors array local. It has been deprecated for + a while, and json_tokener_error_desc() should be used instead. + + * change the floating point output format to %.17g so values with + more than 6 digits show up in the output. + + * Remove the old libjson.so name compatibility support. The library is + only created as libjson-c.so now and headers are only installed + into the ${prefix}/json-c directory. + + * When supported by the linker, add the -Bsymbolic-functions flag. + + * Various changes to fix the build on MSVC. + + * Make strict mode more strict: + * number must not start with 0 + * no single-quote strings + * no comments + * trailing char not allowed + * only allow lowercase literals * Added a json_object_new_double_s() convenience function to allow an exact string representation of a double to be specified when creating the object and use it in json_tokener_parse_ex() so a re-serialized object more exactly matches the input. + * Add support NaN and Infinity + + 0.11 * IMPORTANT: the name of the library has changed to libjson-c.so and diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index a05b8a3..0bb2b77 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -1,7 +1,7 @@ Release checklist: -release=0.11 +release=0.12 git clone https://github.com/json-c/json-c json-c-${release} cd json-c-${release} From 515ba0dfb7d4def2f7f5f8c7ed78a729328666fe Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Thu, 10 Apr 2014 22:44:13 -0400 Subject: [PATCH 262/276] Bump versions up to 0.12.99 since a 0.12 release was just created. --- ChangeLog | 4 ++++ Doxyfile | 2 +- RELEASE_CHECKLIST.txt | 4 ++-- configure.ac | 2 +- json_c_version.h | 4 ++-- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 451b8f6..584ed1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ +NEXT.VERSION + + ...nothing yet... + 0.12 * Address security issues: diff --git a/Doxyfile b/Doxyfile index cf52c48..da39aca 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = json-c # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.11.99 +PROJECT_NUMBER = 0.12.99 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 0bb2b77..e8702e6 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -18,7 +18,7 @@ Make any fixes/changes *before* branching. Update the version in json_c_version.h Update the version in Doxyfile -Update the version in configure.in +Update the version in configure.ac Use ${release}. Update the libjson_la_LDFLAGS line in Makefile.am to the new version. @@ -85,7 +85,7 @@ git checkout master Add new section to ChangeLog Update the version in json_c_version.h Update the version in Doxyfile -Update the version in configure.in +Update the version in configure.ac Use ${release}.99 to indicate a version "newer" than anything on the branch. Leave the libjson_la_LDFLAGS line in Makefile.am alone. diff --git a/configure.ac b/configure.ac index 48c8e5f..c50f81b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ(2.52) # Process this file with autoconf to produce a configure script. -AC_INIT([json-c], 0.11.99, [json-c@googlegroups.com]) +AC_INIT([json-c], 0.12.99, [json-c@googlegroups.com]) AM_INIT_AUTOMAKE diff --git a/json_c_version.h b/json_c_version.h index 5d3db8f..d77f1a7 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -9,12 +9,12 @@ #define _json_c_version_h_ #define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 11 +#define JSON_C_MINOR_VERSION 12 #define JSON_C_MICRO_VERSION 99 #define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ (JSON_C_MINOR_VERSION << 8) | \ JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.11.99" +#define JSON_C_VERSION "0.12.99" const char *json_c_version(void); /* Returns JSON_C_VERSION */ int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ From 259c5c0b5fe87c2db41e7a989cc0ab5865170d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20Koreti=C4=87?= Date: Fri, 11 Apr 2014 10:03:40 +0200 Subject: [PATCH 263/276] Remove unused variable 'size' --- json_tokener.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 19de8ef..9a76293 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -352,12 +352,10 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, case json_tokener_state_inf: /* aka starts with 'i' */ { - int size; int size_inf; int is_negative = 0; printbuf_memappend_fast(tok->pb, &c, 1); - size = json_min(tok->st_pos+1, json_null_str_len); size_inf = json_min(tok->st_pos+1, json_inf_str_len); char *infbuf = tok->pb->buf; if (*infbuf == '-') From fa54bd542e8aaa7d8df8cf9fc3e152dff7bfd00e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 11 Apr 2014 20:06:27 -0400 Subject: [PATCH 264/276] Update the release checklist to include calculating the tarball checksums and updating the wiki. --- RELEASE_CHECKLIST.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index e8702e6..4713258 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -111,6 +111,21 @@ git commit vi index.html Add/change links to current release. +git commit index.html + +git push + +------------ + +Update checksums on wiki page. + +cd .. +openssl sha -sha256 json-c*gz +openssl md5 json-c*gz + +Copy and paste this output into the wiki page at: + https://github.com/json-c/json-c/wiki + ------------ Send an email to the mailing list. From 23620b827cf43f893fac6ddd67277d835c3fdc1d Mon Sep 17 00:00:00 2001 From: Haneef Mubarak Date: Sat, 12 Apr 2014 00:36:08 -0700 Subject: [PATCH 265/276] Update and rename README to README.md Markdownify + fix a few errors here and there --- README | 45 ---------------------------------------- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 45 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index 8c7301f..0000000 --- a/README +++ /dev/null @@ -1,45 +0,0 @@ -Building on Unix with git, gcc and autotools - -Home page for json-c: - https://github.com/json-c/json-c/wiki - - Caution: do NOT use sources from svn.metaparadigm.com, they are old. - -Prerequisites: - gcc (or another C compiler) - libtool - - If you're not using a release tarball, you'll also need: - autoconf (autoreconf) - automake - Make sure you have a complete libtool install, including libtoolize - -Github repo for json-c: - https://github.com/json-c/json-c - - $ git clone https://github.com/json-c/json-c.git - $ cd json-c - $ sh autogen.sh - -Then - - $ ./configure - $ make - $ make install - -To build and run the test programs run - - $ make check - -Linking to libjson-c - -If your system has pkgconfig then you can just add this to your makefile - -CFLAGS += $(shell pkg-config --cflags json-c) -LDFLAGS += $(shell pkg-config --libs json-c) - -Without pkgconfig, you would do something like this: - -JSON_C_DIR=/path/to/json_c/install -CFLAGS += -I$(JSON_C_DIR)/include/json-c -LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c diff --git a/README.md b/README.md new file mode 100644 index 0000000..89ed699 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +json-c +====== + +Building on Unix with git, gcc and autotools +-------------------------------------------- + +Home page for json-c: https://github.com/json-c/json-c/wiki + +Caution: do **NOT** use sources from svn.metaparadigm.com, they are old. + +Prerequisites: + + - `gcc`, `clang`, or another C compiler + - `libtool` + +If you're not using a release tarball, you'll also need: + + - `autoconf` (`autoreconf`) + - `automake` + +Make sure you have a complete libtool install, including libtoolize. + +Github repo for json-c: https://github.com/json-c/json-c + +```bash +$ git clone https://github.com/json-c/json-c.git +$ cd json-c +$ sh autogen.sh +``` + +followed by + +```bash +$ ./configure +$ make +$ make install +``` + +To build and run the test programs: + +```bash + $ make check +``` + +Linking to libjson-c +-------------------- + +If your system has pkgconfig, +then you can just add this to your makefile: + +```make +CFLAGS += $(shell pkg-config --cflags json-c) +LDFLAGS += $(shell pkg-config --libs json-c) +``` + +Without pkgconfig, you would do something like this: + +```make +JSON_C_DIR=/path/to/json_c/install +CFLAGS += -I$(JSON_C_DIR)/include/json-c +LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c +``` From 7870978c2e6da5fda7ffeb4e7ba8ee5aae9d8aab Mon Sep 17 00:00:00 2001 From: Haneef Mubarak Date: Sat, 12 Apr 2014 00:40:05 -0700 Subject: [PATCH 266/276] Update README.md - code blocks - slight text changes (rewording) - pretty printing --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 89ed699..e101114 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ -json-c -====== +`json-c` +======== -Building on Unix with git, gcc and autotools --------------------------------------------- +Building on *nix with `git`, `gcc` and `autotools` +-------------------------------------------------- Home page for json-c: https://github.com/json-c/json-c/wiki -Caution: do **NOT** use sources from svn.metaparadigm.com, they are old. +Caution: do **NOT** use sources from svn.metaparadigm.com, +they are old. Prerequisites: @@ -18,9 +19,9 @@ If you're not using a release tarball, you'll also need: - `autoconf` (`autoreconf`) - `automake` -Make sure you have a complete libtool install, including libtoolize. +Make sure you have a complete `libtool` install, including `libtoolize`. -Github repo for json-c: https://github.com/json-c/json-c +`json-c` GitHub repo: https://github.com/json-c/json-c ```bash $ git clone https://github.com/json-c/json-c.git @@ -39,21 +40,21 @@ $ make install To build and run the test programs: ```bash - $ make check +$ make check ``` -Linking to libjson-c --------------------- +Linking to `libjson-c` +---------------------- -If your system has pkgconfig, -then you can just add this to your makefile: +If your system has `pkgconfig`, +then you can just add this to your `makefile`: ```make CFLAGS += $(shell pkg-config --cflags json-c) LDFLAGS += $(shell pkg-config --libs json-c) ``` -Without pkgconfig, you would do something like this: +Without `pkgconfig`, you would do something like this: ```make JSON_C_DIR=/path/to/json_c/install From 4569e3e4304090a1f1e2ad7ea89b8f153be97168 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 19 Apr 2014 20:11:05 -0400 Subject: [PATCH 267/276] Fix minor typo in README file. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e101114..bf4d2e4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ `json-c` ======== -Building on *nix with `git`, `gcc` and `autotools` +Building on Unix with `git`, `gcc` and `autotools` -------------------------------------------------- Home page for json-c: https://github.com/json-c/json-c/wiki From 795e9151a178191db8a91193fd68931e442d2a40 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 19 Apr 2014 20:22:44 -0400 Subject: [PATCH 268/276] Add an empty README file to placate autoconf. --- README | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..e69de29 From 92a7740e901cfa520fd0cb21117b11b17a78b07c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 19 Apr 2014 20:23:54 -0400 Subject: [PATCH 269/276] Reformat some code in json_object.c --- json_object.c | 429 +++++++++++++++++++++++++++----------------------- 1 file changed, 231 insertions(+), 198 deletions(-) diff --git a/json_object.c b/json_object.c index 6cc73bc..c29a5f4 100644 --- a/json_object.c +++ b/json_object.c @@ -68,25 +68,29 @@ 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); + 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); +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 */ @@ -95,45 +99,51 @@ static void json_object_fini(void) { static int json_escape_str(struct printbuf *pb, char *str, int len) { - int pos = 0, start_offset = 0; - unsigned char c; - while (len--) { - c = str[pos]; - switch(c) { - case '\b': - case '\n': - case '\r': - case '\t': - case '\f': - case '"': - case '\\': - case '/': - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - if(c == '\b') printbuf_memappend(pb, "\\b", 2); - else if(c == '\n') printbuf_memappend(pb, "\\n", 2); - else if(c == '\r') printbuf_memappend(pb, "\\r", 2); - else if(c == '\t') printbuf_memappend(pb, "\\t", 2); - else if(c == '\f') printbuf_memappend(pb, "\\f", 2); - else if(c == '"') printbuf_memappend(pb, "\\\"", 2); - else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); - else if(c == '/') printbuf_memappend(pb, "\\/", 2); - start_offset = ++pos; - break; - default: - if(c < ' ') { - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - sprintbuf(pb, "\\u00%c%c", - json_hex_chars[c >> 4], - json_hex_chars[c & 0xf]); - start_offset = ++pos; - } else pos++; - } - } - if(pos - start_offset > 0) - printbuf_memappend(pb, str + start_offset, pos - start_offset); - return 0; + int pos = 0, start_offset = 0; + unsigned char c; + while (len--) + { + c = str[pos]; + switch(c) + { + case '\b': + case '\n': + case '\r': + case '\t': + case '\f': + case '"': + case '\\': + case '/': + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + + if(c == '\b') printbuf_memappend(pb, "\\b", 2); + else if(c == '\n') printbuf_memappend(pb, "\\n", 2); + else if(c == '\r') printbuf_memappend(pb, "\\r", 2); + else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '\f') printbuf_memappend(pb, "\\f", 2); + else if(c == '"') printbuf_memappend(pb, "\\\"", 2); + else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); + else if(c == '/') printbuf_memappend(pb, "\\/", 2); + + start_offset = ++pos; + break; + default: + if(c < ' ') + { + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + sprintbuf(pb, "\\u00%c%c", + json_hex_chars[c >> 4], + json_hex_chars[c & 0xf]); + start_offset = ++pos; + } else + pos++; + } + } + if (pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; } @@ -141,10 +151,9 @@ static int json_escape_str(struct printbuf *pb, char *str, int len) extern struct json_object* json_object_get(struct json_object *jso) { - if(jso) { - jso->_ref_count++; - } - return jso; + if (jso) + jso->_ref_count++; + return jso; } int json_object_put(struct json_object *jso) @@ -169,28 +178,29 @@ int json_object_put(struct json_object *jso) static void json_object_generic_delete(struct json_object* jso) { #ifdef REFCOUNT_DEBUG - MC_DEBUG("json_object_delete_%s: %p\n", + MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); - lh_table_delete(json_object_table, jso); + lh_table_delete(json_object_table, jso); #endif /* REFCOUNT_DEBUG */ - printbuf_free(jso->_pb); - free(jso); + printbuf_free(jso->_pb); + free(jso); } static struct json_object* json_object_new(enum json_type o_type) { - struct json_object *jso; + 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; + 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); + 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; + return jso; } @@ -198,16 +208,16 @@ static struct json_object* json_object_new(enum json_type o_type) 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); + 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; + if (!jso) + return json_type_null; + return jso->o_type; } /* set a custom conversion to string */ @@ -345,36 +355,39 @@ static int json_object_object_to_json_string(struct json_object* jso, static void json_object_lh_entry_free(struct lh_entry *ent) { - free(ent->k); - json_object_put((struct json_object*)ent->v); + 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); + 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, + 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; + 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; - } + 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, @@ -440,34 +453,39 @@ static int json_object_boolean_to_json_string(struct json_object* jso, int level, int flags) { - if(jso->o.c_boolean) return sprintbuf(pb, "true"); - else return sprintbuf(pb, "false"); + 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; + 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; - } + 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; + } } @@ -478,16 +496,17 @@ static int json_object_int_to_json_string(struct json_object* jso, int level, int flags) { - return sprintbuf(pb, "%"PRId64, jso->o.c_int64); + 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; + 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) @@ -531,30 +550,34 @@ int32_t json_object_get_int(struct json_object *jso) 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; + 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; + 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; - } + 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; + } } @@ -692,61 +715,68 @@ static int json_object_string_to_json_string(struct json_object* jso, int level, int flags) { - sprintbuf(pb, "\""); - json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); - sprintbuf(pb, "\""); - return 0; + 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); + 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 *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.str = strdup(s); + jso->o.c_string.len = strlen(s); + return jso; } struct json_object* json_object_new_string_len(const char *s, int len) { - struct json_object *jso = json_object_new(json_type_string); - if(!jso) return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.str = (char*)malloc(len + 1); - memcpy(jso->o.c_string.str, (void *)s, len); - jso->o.c_string.str[len] = '\0'; - jso->o.c_string.len = len; - return jso; + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.str = (char*)malloc(len + 1); + memcpy(jso->o.c_string.str, (void *)s, len); + jso->o.c_string.str[len] = '\0'; + jso->o.c_string.len = len; + return jso; } const char* json_object_get_string(struct json_object *jso) { - if(!jso) return NULL; - switch(jso->o_type) { - case json_type_string: - return jso->o.c_string.str; - default: - return json_object_to_json_string(jso); - } + 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; - } +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; + } } @@ -796,60 +826,63 @@ static int json_object_array_to_json_string(struct json_object* jso, static void json_object_array_entry_free(void *data) { - json_object_put((struct json_object*)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); + 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 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; - } + 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); + 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); + 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); + 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); + 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); + return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); } From 2149a04ca82dfa7568e010b875409c56cb7e6e55 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 19 Apr 2014 20:33:05 -0400 Subject: [PATCH 270/276] Check for failures when allocating memory; return NULL and set errno=ENOMEM in a few of those cases. Thanks to Susant Sahani for pointing out some of these. --- json_object.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index c29a5f4..8ed0239 100644 --- a/json_object.c +++ b/json_object.c @@ -374,6 +374,12 @@ struct json_object* json_object_new_object(void) 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); + if (!jso->o.c_object) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } return jso; } @@ -640,8 +646,15 @@ struct json_object* json_object_new_double_s(double d, const char *ds) if (!jso) return NULL; + char *new_ds = strdup(ds); + if (!new_ds) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } json_object_set_serializer(jso, json_object_userdata_to_json_string, - strdup(ds), json_object_free_userdata); + new_ds, json_object_free_userdata); return jso; } @@ -735,6 +748,12 @@ struct json_object* json_object_new_string(const char *s) jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; jso->o.c_string.str = strdup(s); + if (!jso->o.c_string.str) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } jso->o.c_string.len = strlen(s); return jso; } @@ -747,6 +766,12 @@ struct json_object* json_object_new_string_len(const char *s, int len) jso->_delete = &json_object_string_delete; jso->_to_json_string = &json_object_string_to_json_string; jso->o.c_string.str = (char*)malloc(len + 1); + if (!jso->o.c_string.str) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } memcpy(jso->o.c_string.str, (void *)s, len); jso->o.c_string.str[len] = '\0'; jso->o.c_string.len = len; From 1da0599e0ebd60a5038c0a43345fdb249a5a3ea3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 3 May 2014 22:26:26 -0400 Subject: [PATCH 271/276] Fix the definition of the error_description() macro in bits.h now that json_tokener_errors[] is not exported. --- bits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bits.h b/bits.h index c8cbbc8..6feee9e 100644 --- a/bits.h +++ b/bits.h @@ -22,7 +22,7 @@ #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 error_description(error) (json_tokener_get_error(error)) #define is_error(ptr) (ptr == NULL) #endif From d4e81f9ec8273914739808737fa0a27a3f0589fb Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 3 May 2014 22:29:10 -0400 Subject: [PATCH 272/276] Move the json_min() and json_max() macros to json_util.h and mark everything else in bits.h deprecated. Eliminate all uses of bits.h within the json-c code. --- arraylist.c | 5 +++-- bits.h | 25 ++++++++++++++++--------- json.h | 1 - json_tokener.c | 5 +++-- json_util.c | 1 - json_util.h | 9 +++++++++ printbuf.c | 5 +++-- 7 files changed, 34 insertions(+), 17 deletions(-) diff --git a/arraylist.c b/arraylist.c index 81b6fa2..1d899fa 100644 --- a/arraylist.c +++ b/arraylist.c @@ -20,7 +20,6 @@ # include #endif /* HAVE_STRINGS_H */ -#include "bits.h" #include "arraylist.h" struct array_list* @@ -63,7 +62,9 @@ static int array_list_expand_internal(struct array_list *arr, int max) int new_size; if(max < arr->size) return 0; - new_size = json_max(arr->size << 1, max); + new_size = arr->size << 1; + if (new_size < max) + new_size = 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*)); diff --git a/bits.h b/bits.h index 6feee9e..d14a1db 100644 --- a/bits.h +++ b/bits.h @@ -1,4 +1,7 @@ -/* +/** + * @file + * @deprecated Use json_util.h instead. + * * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. @@ -12,17 +15,21 @@ #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 - +/** + * @deprecated + */ #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +/** + * @deprecated + */ #define error_ptr(error) ((void*)error) +/** + * @deprecated + */ #define error_description(error) (json_tokener_get_error(error)) +/** + * @deprecated + */ #define is_error(ptr) (ptr == NULL) #endif diff --git a/json.h b/json.h index 4339b20..e198f5d 100644 --- a/json.h +++ b/json.h @@ -17,7 +17,6 @@ extern "C" { #endif -#include "bits.h" #include "debug.h" #include "linkhash.h" #include "arraylist.h" diff --git a/json_tokener.c b/json_tokener.c index 9a76293..60e81f2 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -23,7 +23,6 @@ #include #include -#include "bits.h" #include "debug.h" #include "printbuf.h" #include "arraylist.h" @@ -36,6 +35,8 @@ #include #endif /* HAVE_LOCALE_H */ +#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) + #if !HAVE_STRDUP && defined(_MSC_VER) /* MSC has the version as _strdup */ # define strdup _strdup @@ -536,7 +537,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, /* 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)); + tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4)); if(tok->st_pos == 4) { unsigned char unescaped_utf[4]; diff --git a/json_util.c b/json_util.c index 531f9af..2a5621b 100644 --- a/json_util.c +++ b/json_util.c @@ -53,7 +53,6 @@ # error You do not have snprintf on your system. #endif /* HAVE_SNPRINTF */ -#include "bits.h" #include "debug.h" #include "printbuf.h" #include "json_inttypes.h" diff --git a/json_util.h b/json_util.h index 1005e58..387dbc4 100644 --- a/json_util.h +++ b/json_util.h @@ -14,6 +14,15 @@ #include "json_object.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 + + #ifdef __cplusplus extern "C" { #endif diff --git a/printbuf.c b/printbuf.c index 9d56522..fe952b4 100644 --- a/printbuf.c +++ b/printbuf.c @@ -25,7 +25,6 @@ # error Not enough var arg support! #endif /* HAVE_STDARG_H */ -#include "bits.h" #include "debug.h" #include "printbuf.h" @@ -63,7 +62,9 @@ static int printbuf_extend(struct printbuf *p, int min_size) if (p->size >= min_size) return 0; - new_size = json_max(p->size * 2, min_size + 8); + new_size = p->size * 2; + if (new_size < min_size + 8) + new_size = min_size + 8; #ifdef PRINTBUF_DEBUG MC_DEBUG("printbuf_memappend: realloc " "bpos=%d min_size=%d old_size=%d new_size=%d\n", From 4841c48f81dbd4e557e647dd97ddade8711b8cee Mon Sep 17 00:00:00 2001 From: Alexandru Costache Date: Fri, 4 Jul 2014 11:58:14 +0300 Subject: [PATCH 273/276] Removed duplicate check in random_seed test - bug #140 --- random_seed.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/random_seed.c b/random_seed.c index 3b520d4..4f6dbb2 100644 --- a/random_seed.c +++ b/random_seed.c @@ -160,13 +160,10 @@ static int get_dev_random_seed() int r; ssize_t nread = read(fd, &r, sizeof(r)); if (nread != sizeof(r)) { - fprintf(stderr, "error read %s: %s", dev_random_file, strerror(errno)); - exit(1); - } - else if (nread != sizeof(r)) { - fprintf(stderr, "error short read %s", dev_random_file); + fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); exit(1); } + close(fd); return r; } From ca0ebe0f71b806f73a20d5d5e0da78aba5de42be Mon Sep 17 00:00:00 2001 From: Andrew Stubbs Date: Mon, 4 Aug 2014 11:44:25 +0100 Subject: [PATCH 274/276] Fix build using MinGW. MinGW requires wincrypt.h. GCC does not support #pragma comment, which trips Werror. --- random_seed.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/random_seed.c b/random_seed.c index 3b520d4..c47d271 100644 --- a/random_seed.c +++ b/random_seed.c @@ -181,7 +181,10 @@ static int get_dev_random_seed() #define HAVE_CRYPTGENRANDOM 1 #include +#include +#ifndef __GNUC__ #pragma comment(lib, "advapi32.lib") +#endif static int get_cryptgenrandom_seed() { From 048dcf288a8a154395e50c109a183d291dbdfa4d Mon Sep 17 00:00:00 2001 From: "Michael J. Chinn" Date: Sun, 10 Aug 2014 00:46:25 -0400 Subject: [PATCH 275/276] Remove json_type enum trailing comma --- json_object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_object.h b/json_object.h index 200ac40..0634758 100644 --- a/json_object.h +++ b/json_object.h @@ -105,7 +105,7 @@ typedef enum json_type { json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string } json_type; /* reference counting functions */ @@ -138,7 +138,7 @@ int json_object_put(struct json_object *obj); json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string */ extern int json_object_is_type(struct json_object *obj, enum json_type type); @@ -154,7 +154,7 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); json_type_int, json_type_object, json_type_array, - json_type_string, + json_type_string */ extern enum json_type json_object_get_type(struct json_object *obj); From 37f5d8696d2c60d106dbba9fe73a5ead40b8fd19 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Mon, 18 Aug 2014 10:28:38 +0200 Subject: [PATCH 276/276] improve doc for json_object_to_json_string() --- json_object.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_object.h b/json_object.h index 200ac40..9cdb6a8 100644 --- a/json_object.h +++ b/json_object.h @@ -161,12 +161,17 @@ extern enum json_type json_object_get_type(struct json_object *obj); /** Stringify object to json format. * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) + * The pointer you get is an internal of your json object. You don't + * have to free it, later use of json_object_put() should be sufficient. + * If you can not ensure there's no concurrent access to *obj use + * strdup(). * @param obj the json_object instance * @returns a string in JSON format */ extern const char* json_object_to_json_string(struct json_object *obj); /** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. * @param obj the json_object instance * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants * @returns a string in JSON format