Import Upstream version 0.99.8

This commit is contained in:
Lu zhiping 2022-07-12 13:56:38 +08:00
commit aa677ab317
119 changed files with 55783 additions and 0 deletions

8
AUTHORS Normal file
View File

@ -0,0 +1,8 @@
Rainer Gerhards <rgerhards@adiscon.com>
With special thanks for the original json-c library:
Michael Clark <michael@metaparadigm.com>
Jehiah Czebotar <jehiah@gmail.com>
Eric Haszlakiewicz <hawicz+json-c@gmail.com>
C. Watford (christopher.watford@gmail.com)

64
COPYING Normal file
View File

@ -0,0 +1,64 @@
Copyright (c) 2015 Rainer Gerhards
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) 2009-2012 Eric Haszlakiewicz
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----------------------------------------------------------------
Copyright (c) 2004, 2005 Metaparadigm Pte Ltd
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

343
ChangeLog Normal file
View File

@ -0,0 +1,343 @@
0.99.8 2017-12-18
- make build under gcc7 with strict settings (warning==error)
- bugfix: constant key names not properly handled
if fjson_object_object_add_ex() is used with option
FJSON_OBJECT_KEY_IS_CONSTANT, fjson_object_object_del() will still
try to delete the key name. Depending on use, this can lead to
double-free, use-after-free or no problem.
see also https://github.com/rsyslog/rsyslog/issues/1839
closes https://github.com/rsyslog/libfastjson/issues/148
- fix potentially invalid return value of fjson_object_iter_begin
this could lead to callers doing improper opreations and thus
could lead to a segfault in callers
detected by Coverity scan, CID 198891
- fix small potential memory leak in json_tokener (unlinkely to occur)
detected by Coverity Scan, CID 198890
0.99.7 2017-10-17
- added option for case-insensitive comparisons
This permits to search for json keys in a case-sensitive way.
The default is "off", as this is against the JSON spec. However,
rsyslog needs this capability to increase usability inside the
variable system.
We add a new API call to switch between case-sensitive and
case-insensitive comparison, with case-sensitive being the default.
closes https://github.com/rsyslog/libfastjson/issues/142
- Removed userdata and custom-serialization functions
Reasoning (from pull request):
The library uses the concept of "userdata" and "custom serialization
functions" that can be set from user space. However, to effectively
make use of this feature, a user must have a deep understanding of
the internal data representation of the library, which makes this
feature not very useful.
But what is worse: internally, the library itself also sometimes
assigns data to this userdata member (especially when working with
doubles), and it also sometimes assigns alternative serialization
functions. This makes the feature even more unusable, because as a
user you never can know when the userdata pointer is save to use
for your own settings, and when you must leave it alone because
it is used by the library.
Long story short. In this pull request I got rid of the userdata
pointer completely. The case where the library was using the
"userdata" (for storing the original string representation of a
parsed double) has been moved into the union that is already used
for storing values.
see also: https://github.com/rsyslog/libfastjson/pull/141
Thanks to Emiel Bruijntjes for the patch.
0.99.6 2017-06-19
- fix a build issue under Solaris
0.99.5 2017-05-03
- fix tautology comparison in tautology in `fjson_object_iter_equal`
- made build under Solaris again
- made to build under AIX
Thanks to github user purnimam1 for the patch
- fix floating point representation when fractional part is missing
see also https://github.com/rsyslog/libfastjson/issues/126
Thanks to Jan Gerhards for the patch.
- m4: fix detection of atomics
In cross-compilation, it is impossible to run code at configure time to
detect the target specifics.
As such, AC_TRY_RUN fails miserably to detect reliably that atomic
intrisics are present in a toolchain, and decides they are not just
because this is cross-compilation.
Instead of AC_TRY_RUN, use AC_LINK_IFELSE that does not need to actually
run code, since all we're interested in is whether the intrisics are
present (or not). Fix both the 32- and 64-bit variants, even if the
latter is not used currently.
Fixes build failures detected by the Buildroot autobuilders, like:
http://autobuild.buildroot.org/results/23a/23ac0e742ed3a70ae4d038f8c9eadc23e708f671/build-end.log
http://autobuild.buildroot.org/results/192/1923d0b570adba494f83747a9610ea6ec35f5223/build-end.log
and many other cases, espcially on architectures where such intrsics are
present, but where the toolchain does not have threads (and anyway, it
is much more efficient to use the intrisics rather than use mutexes).
Thanks to Yann E. MORIN for the patch.
- add fjson_object_dump() and fjson_object_write() functions
... that make it possible to dump the json tree without having to
dynamically allocate a string, and to write the tree to a FILE*.
NOTE: right now, most of the code is simply copied from the functions
that use the "printbuf" for writing the data. I have not touched the old
printbuf-implementation, because some other code may still rely on it.
However, in my opinion these printbuf-based functions (if it is desirable
to keep them in the first place) can now be re-implemented to use the more
flexible fjson_object_dump() function.
MAINTAINER NOTE: we need to performance-test any new implementation and will
do so. The results will ultimately decide which parts of the code remain in
the codebase.
Thanks to Emiel Bruijntjes for the patch.
0.99.4 2016-08-03
- fix tautology comparison in tautology in `fjson_object_iter_equal`
Thanks to Andres Stieger for the patch
- improve build system to handle slightly older autoconf versions
- fix build problems with gcc6
Thanks to Andres Stieger for the patch
0.99.3 2016-07-11
- new dependency: autoconf-archive
- exit() is no longer called in unexpected situations
The previous code called exit on some occasions and did not
give the caller a chance to do any cleanup or handling on
it's own. This has completely been removed. Note that it was
very unlikely that this problem affected a caller, as exit()
was only called under very rare circumstances (e.g. OOM).
- fjson_version now returns configure VERSION
This avoid inconsistency.
- removal of Windows and Android bits
Thanks to Michael Biebl for the patch.
- fixes of the build system
Thanks to Michael Biebl for the patch.
- dropped support for Windows and Android as we do not target
these platforms
- "make distcheck" now works
- fix invalid Unicode representation for some non US-ASCII
characters when printed as string. Note that this could
potentially also lead to a segfault
0.99.2 2016-03-07
- new API: json_object_get_member_count()
- make comaptible with autoconf < 2.64
0.99.1
was never released, but version number has accidently been used by
some Adiscon packages. In order to prevent confusion, we have
decided not to use this version number for any official version.
0.99.0 2015-12-22
- bugfix: reference counting was not thread-safe
NEXT.VERSION
...nothing yet...
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
the header files are now in include/json-c.
The pkgconfig name has also changed from json to json-c.
You should change your build to use appropriate -I and -l options.
A compatibility shim is in place so builds using the old name will
continue to work, but that will be removed in the next release.
* Maximum recursion depth is now a runtime option.
json_tokener_new() is provided for compatibility.
json_tokener_new_ex(depth)
* Include json_object_iterator.h in the installed headers.
* Add support for building on Android.
* Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid.
* Make it safe to delete keys while iterating with the json_object_object_foreach macro.
* Add a json_set_serializer() function to allow the string output of a json_object to be customized.
* Make float parsing locale independent.
* Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag.
* Enable -Werror when building.
* speed improvements to parsing 64-bit integers on systems with working sscanf
* Add a json_object_object_length function.
* Fix a bug (buffer overrun) when expanding arrays to more than 64 entries.
0.10
* Add a json_object_to_json_string_ext() function to allow output to be
formatted in a more human readable form.
* Add json_object_object_get_ex(), a NULL-safe get object method, to be able
to distinguish between a key not present and the value being NULL.
* Add an alternative iterator implementation, see json_object_iterator.h
* Make json_object_iter public to enable external use of the
json_object_object_foreachC macro.
* Add a printbuf_memset() function to provide an effecient way to set and
append things like whitespace indentation.
* Adjust json_object_is_type and json_object_get_type so they return
json_type_null for NULL objects and handle NULL passed to
json_objct_object_get().
* Rename boolean type to json_bool.
* Fix various compile issues for Visual Studio and MinGW.
* Allow json_tokener_parse_ex() to be re-used to parse multiple object.
Also, fix some parsing issues with capitalized hexadecimal numbers and
number in E notation.
* Add json_tokener_get_error() and json_tokener_error_desc() to better
encapsulate the process of retrieving errors while parsing.
* Various improvements to the documentation of many functions.
* Add new json_object_array_sort() function.
* Fix a bug in json_object_get_int(), which would incorrectly return 0
when called on a string type object.
Eric Haszlakiewicz
* Add a json_type_to_name() function.
Eric Haszlakiewicz
* Add a json_tokener_parse_verbose() function.
Jehiah Czebotar
* Improve support for null bytes within JSON strings.
Jehiah Czebotar
* Fix file descriptor leak if memory allocation fails in json_util
Zachary Blair, zack_blair at hotmail dot com
* Add int64 support. Two new functions json_object_net_int64 and
json_object_get_int64. Binary compatibility preserved.
Eric Haszlakiewicz, EHASZLA at transunion com
Rui Miguel Silva Seabra, rms at 1407 dot org
* Fix subtle bug in linkhash where lookup could hang after all slots
were filled then successively freed.
Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com
* Make json_object_from_file take const char *filename
Spotted by Vikram Raj V, vsagar at attinteractive dot com
* Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am)
Brent Miller, bdmiller at yahoo dash inc dot com
* Correction to comment describing printbuf_memappend in printbuf.h
Brent Miller, bdmiller at yahoo dash inc dot com
0.9
* Add README.html README-WIN32.html config.h.win32 to Makefile.am
Michael Clark, <michael@metaparadigm.com>
* Add const qualifier to the json_tokener_parse functions
Eric Haszlakiewicz, EHASZLA at transunion dot com
* Rename min and max so we can never clash with C or C++ std library
Ian Atha, thatha at yahoo dash inc dot com
* Fix any noticeable spelling or grammar errors.
* Make sure every va_start has a va_end.
* Check all pointers for validity.
Erik Hovland, erik at hovland dot org
* Fix json_object_get_boolean to return false for empty string
Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com
* optimizations to json_tokener_parse_ex(), printbuf_memappend()
Brent Miller, bdmiller at yahoo dash inc dot com
* Disable REFCOUNT_DEBUG by default in json_object.c
* Don't use this as a variable, so we can compile with a C++ compiler
* Add casts from void* to type of assignment when using malloc
* Add #ifdef __cplusplus guards to all of the headers
* Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table
Michael Clark, <michael@metaparadigm.com>
* Null pointer dereference fix. Fix json_object_get_boolean strlen test
to not return TRUE for zero length string. Remove redundant includes.
Erik Hovland, erik at hovland dot org
* Fixed warning reported by adding -Wstrict-prototypes
-Wold-style-definition to the compilatin flags.
Dotan Barak, dotanba at gmail dot com
* Add const correctness to public interfaces
Gerard Krol, g dot c dot krol at student dot tudelft dot nl
0.8
* Add va_end for every va_start
Dotan Barak, dotanba at gmail dot com
* Add macros to enable compiling out debug code
Geoffrey Young, geoff at modperlcookbook dot org
* Fix bug with use of capital E in numbers with exponents
Mateusz Loskot, mateusz at loskot dot net
* Add stddef.h include
* Patch allows for json-c compile with -Werror and not fail due to
-Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
Geoffrey Young, geoff at modperlcookbook dot org
0.7
* Add escaping of backslash to json output
* Add escaping of foward slash on tokenizing and output
* Changes to internal tokenizer from using recursion to
using a depth state structure to allow incremental parsing
0.6
* Fix bug in escaping of control characters
Johan Björklund, johbjo09 at kth dot se
* Remove include "config.h" from headers (should only
be included from .c files)
Michael Clark <michael@metaparadigm.com>
0.5
* Make headers C++ compatible by change *this to *obj
* Add ifdef C++ extern "C" to headers
* Use simpler definition of min and max in bits.h
Larry Lansing, llansing at fuzzynerd dot com
* Remove automake 1.6 requirement
* Move autogen commands into autogen.sh. Update README
* Remove error pointer special case for Windows
* Change license from LGPL to MIT
Michael Clark <michael@metaparadigm.com>
0.4
* Fix additional error case in object parsing
* Add back sign reversal in nested object parse as error pointer
value is negative, while error value is positive.
Michael Clark <michael@metaparadigm.com>
0.3
* fix pointer arithmetic bug for error pointer check in is_error() macro
* fix type passed to printbuf_memappend in json_tokener
* update autotools bootstrap instructions in README
Michael Clark <michael@metaparadigm.com>
0.2
* printbuf.c - C. Watford (christopher.watford@gmail.com)
Added a Win32/Win64 compliant implementation of vasprintf
* debug.c - C. Watford (christopher.watford@gmail.com)
Removed usage of vsyslog on Win32/Win64 systems, needs to be handled
by a configure script
* json_object.c - C. Watford (christopher.watford@gmail.com)
Added scope operator to wrap usage of json_object_object_foreach, this
needs to be rethought to be more ANSI C friendly
* json_object.h - C. Watford (christopher.watford@gmail.com)
Added Microsoft C friendly version of json_object_object_foreach
* json_tokener.c - C. Watford (christopher.watford@gmail.com)
Added a Win32/Win64 compliant implementation of strndup
* json_util.c - C. Watford (christopher.watford@gmail.com)
Added cast and mask to suffice size_t v. unsigned int conversion
correctness
* json_tokener.c - sign reversal issue on error info for nested object parse
spotted by Johan Björklund (johbjo09 at kth.se)
* json_object.c - escape " in json_escape_str
* Change to automake and libtool to build shared and static library
Michael Clark <michael@metaparadigm.com>
0.1
* initial release

370
INSTALL Normal file
View File

@ -0,0 +1,370 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
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 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.
Running `configure' might take a while. 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, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. 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.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
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=c99 CFLAGS=-g 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 can use 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 `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer 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.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' 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. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
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'.
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.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
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 option `--target=TYPE' 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
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--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.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

49
Makefile.am Normal file
View File

@ -0,0 +1,49 @@
EXTRA_DIST = README.html
SUBDIRS = . tests
lib_LTLIBRARIES = libfastjson.la
noinst_LTLIBRARIES = libfastjson-internal.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libfastjson.pc
libfastjsonincludedir = $(includedir)/libfastjson
libfastjsoninclude_HEADERS = \
atomic.h \
json.h \
json_object.h \
json_object_iterator.h \
json_object_private.h \
json_tokener.h \
json_util.h
libfastjson_la_CFLAGS = $(WARN_CFLAGS)
# info on version-info:
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
libfastjson_la_LDFLAGS = \
-version-info 6:0:2 \
-export-symbols-regex '^fjson_.*' \
-no-undefined \
@JSON_BSYMBOLIC_LDFLAGS@
libfastjson_la_LIBADD = libfastjson-internal.la
libfastjson_la_SOURCES = \
json_version.c \
json_object.c \
json_print.c \
json_object_iterator.c \
json_tokener.c \
json_util.c
libfastjson_internal_la_CFLAGS = $(WARN_CFLAGS)
libfastjson_internal_la_SOURCES = \
arraylist.h \
arraylist.c \
debug.h \
debug.c \
printbuf.h \
printbuf.c
ACLOCAL_AMFLAGS = -I m4

1163
Makefile.in Normal file

File diff suppressed because it is too large Load Diff

0
NEWS Normal file
View File

0
README Normal file
View File

31
README.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>JSON-C - A JSON implementation in C</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<h2>JSON-C - A JSON implementation in C</h2>
<h3>Overview</h3>
<p>JSON-C implements a reference counting object model that allows you to easily
construct JSON objects in C, output them as JSON formatted strings and parse
JSON formatted strings back into the C representation of JSON objects.</p>
<h3>Building</h3>
<p>To setup JSON-C to build on your system please run <tt>configure</tt> and <tt>make</tt>.</p>
<h3>Documentation</h3>
<P>Doxygen generated documentation exists <a href="doc/html/json__object_8h.html">here</a>.</P>
<h3><a href="https://github.com/json-c/json-c">GIT Reposository</a></h3>
<p><strong><code>git clone https://github.com/json-c/json-c.git</code></strong></p>
<h3><a href="http://groups.google.com/group/json-c">Mailing List</a></h3>
<pi>Send email to <strong><code>json-c <i>&lt;at&gt;</i> googlegroups <i>&lt;dot&gt;</i> com</code></strong></p>
<h3><a href="COPYING">License</a></h3>
<p>This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..</p>
<hr/>
</body>
</html>

1802
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

134
arraylist.c Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2016 Rainer Gerhards
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#endif /* STDC_HEADERS */
#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include "arraylist.h"
struct array_list*
array_list_new(array_list_free_fn *free_fn)
{
struct array_list *arr;
arr = (struct array_list*)calloc(1, sizeof(struct array_list));
if(!arr) return NULL;
arr->size = ARRAY_LIST_DEFAULT_SIZE;
arr->length = 0;
arr->free_fn = free_fn;
if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {
free(arr);
return NULL;
}
return arr;
}
extern void
array_list_free(struct array_list *arr)
{
int i;
for(i = 0; i < arr->length; i++)
if(arr->array[i]) arr->free_fn(arr->array[i]);
free(arr->array);
free(arr);
}
void*
array_list_get_idx(struct array_list *arr, int i)
{
if(i >= arr->length) return NULL;
return arr->array[i];
}
static int array_list_expand_internal(struct array_list *arr, int max)
{
void *t;
int new_size;
if(max < arr->size) return 0;
new_size = 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*));
arr->size = new_size;
return 0;
}
int
array_list_put_idx(struct array_list *arr, int idx, void *data)
{
if(array_list_expand_internal(arr, idx+1)) return -1;
if(arr->array[idx]) arr->free_fn(arr->array[idx]);
arr->array[idx] = data;
if(arr->length <= idx) arr->length = idx + 1;
return 0;
}
int
array_list_add(struct array_list *arr, void *data)
{
return array_list_put_idx(arr, arr->length, data);
}
/* work around wrong compiler message: GCC and clang do
* not handle sort_fn correctly if -Werror is given.
*/
#ifndef _AIX
#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#else
#if __GNUC__ < 6
#pragma GCC diagnostic ignored "-Werror"
#endif
#endif
#endif
void
array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
{
qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn);
}
#ifndef _AIX
#pragma GCC diagnostic pop
#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#else
#if __GNUC__ < 6
#pragma GCC diagnostic ignored "-Werror"
#endif
#endif
#endif
void* array_list_bsearch(const void **key, struct array_list *arr,
int (*sort_fn)(const void *, const void *))
{
return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]),
sort_fn);
}
#ifndef _AIX
#pragma GCC diagnostic pop
#endif
int
array_list_length(struct array_list *arr)
{
return arr->length;
}

59
arraylist.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _fj_arraylist_h_
#define _fj_arraylist_h_
#ifdef __cplusplus
extern "C" {
#endif
#define ARRAY_LIST_DEFAULT_SIZE 32
typedef void (array_list_free_fn) (void *data);
struct array_list
{
void **array;
int length;
int size;
array_list_free_fn *free_fn;
};
extern struct array_list*
array_list_new(array_list_free_fn *free_fn);
extern void
array_list_free(struct array_list *al);
extern void*
array_list_get_idx(struct array_list *al, int i);
extern int
array_list_put_idx(struct array_list *al, int i, void *data);
extern int
array_list_add(struct array_list *al, void *data);
extern int
array_list_length(struct array_list *al);
extern void
array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *));
extern void* array_list_bsearch(const void **key,
struct array_list *arr,
int (*sort_fn)(const void *, const void *));
#ifdef __cplusplus
}
#endif
#endif

227
atomic.h Normal file
View File

@ -0,0 +1,227 @@
/* This header supplies atomic operations. So far, we rely on GCC's
* atomic builtins. During configure, we check if atomic operatons are
* available. If they are not, I am making the necessary provisioning to live without them if
* they are not available. Please note that you should only use the macros
* here if you think you can actually live WITHOUT an explicit atomic operation,
* because in the non-presence of them, we simply do it without atomicitiy.
* Which, for word-aligned data types, usually (but only usually!) should work.
*
* We are using the functions described in
* http:/gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html
*
* THESE MACROS MUST ONLY BE USED WITH WORD-SIZED DATA TYPES!
*
* Note: this file was obtained at 2015-12-16 from the rsyslog project.
*
* Copyright 2008-2015 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* -or-
* see COPYING.ASL20 in the source distribution
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FJ_INCLUDED_ATOMIC_H
#define FJ_INCLUDED_ATOMIC_H
#ifdef HAVE_ATOMIC_BUILTINS
# define ATOMIC_SUB(data, val, phlpmut) __sync_fetch_and_sub(data, val)
# define ATOMIC_ADD(data, val) __sync_fetch_and_add(&(data), val)
# define ATOMIC_INC(data, phlpmut) ((void) __sync_fetch_and_add(data, 1))
# define ATOMIC_INC_AND_FETCH_int(data, phlpmut) __sync_fetch_and_add(data, 1)
# define ATOMIC_INC_AND_FETCH_unsigned(data, phlpmut) __sync_fetch_and_add(data, 1)
# define ATOMIC_DEC(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1))
# define ATOMIC_DEC_AND_FETCH(data, phlpmut) __sync_sub_and_fetch(data, 1)
# define ATOMIC_FETCH_32BIT(data, phlpmut) ((unsigned) __sync_fetch_and_and(data, 0xffffffff))
# define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1)
# define ATOMIC_STORE_0_TO_INT(data, phlpmut) __sync_fetch_and_and(data, 0)
# define ATOMIC_STORE_1_TO_INT(data, phlpmut) __sync_fetch_and_or(data, 1)
# define ATOMIC_STORE_INT_TO_INT(data, val) __sync_fetch_and_or(&(data), (val))
# define ATOMIC_CAS(data, oldVal, newVal, phlpmut) __sync_bool_compare_and_swap(data, (oldVal), (newVal))
# define ATOMIC_CAS_time_t(data, oldVal, newVal, phlpmut) __sync_bool_compare_and_swap(data, (oldVal), (newVal))
# define ATOMIC_CAS_VAL(data, oldVal, newVal, phlpmut) __sync_val_compare_and_swap(data, (oldVal), (newVal));
/* functions below are not needed if we have atomics */
# define DEF_ATOMIC_HELPER_MUT(x)
# define INIT_ATOMIC_HELPER_MUT(x)
# define DESTROY_ATOMIC_HELPER_MUT(x)
/* the following operations should preferrably be done atomic, but it is
* not fatal if not -- that means we can live with some missed updates. So be
* sure to use these macros only if that really does not matter!
*/
# define PREFER_ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
#else
/* note that we gained parctical proof that theoretical problems DO occur
* if we do not properly address them. See this blog post for details:
* http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html
* The bottom line is that if there are no atomics available, we should NOT
* simply go ahead and do without them - use mutexes or other things.
* rgerhards, 2009-01-30
*/
#include <pthread.h>
# define ATOMIC_INC(data, phlpmut) { \
pthread_mutex_lock(phlpmut); \
++(*(data)); \
pthread_mutex_unlock(phlpmut); \
}
# define ATOMIC_STORE_0_TO_INT(data, hlpmut) { \
pthread_mutex_lock(hlpmut); \
*(data) = 0; \
pthread_mutex_unlock(hlpmut); \
}
# define ATOMIC_STORE_1_TO_INT(data, hlpmut) { \
pthread_mutex_lock(hlpmut); \
*(data) = 1; \
pthread_mutex_unlock(hlpmut); \
}
static inline int
ATOMIC_CAS(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) {
int bSuccess;
pthread_mutex_lock(phlpmut);
if(*data == oldVal) {
*data = newVal;
bSuccess = 1;
} else {
bSuccess = 0;
}
pthread_mutex_unlock(phlpmut);
return(bSuccess);
}
static inline int
ATOMIC_CAS_time_t(time_t *data, time_t oldVal, time_t newVal, pthread_mutex_t *phlpmut) {
int bSuccess;
pthread_mutex_lock(phlpmut);
if(*data == oldVal) {
*data = newVal;
bSuccess = 1;
} else {
bSuccess = 0;
}
pthread_mutex_unlock(phlpmut);
return(bSuccess);
}
static inline int
ATOMIC_CAS_VAL(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) {
int val;
pthread_mutex_lock(phlpmut);
if(*data == oldVal) {
*data = newVal;
}
val = *data;
pthread_mutex_unlock(phlpmut);
return(val);
}
# define ATOMIC_DEC(data, phlpmut) { \
pthread_mutex_lock(phlpmut); \
--(*(data)); \
pthread_mutex_unlock(phlpmut); \
}
static inline int
ATOMIC_INC_AND_FETCH_int(int *data, pthread_mutex_t *phlpmut) {
int val;
pthread_mutex_lock(phlpmut);
val = ++(*data);
pthread_mutex_unlock(phlpmut);
return(val);
}
static inline unsigned
ATOMIC_INC_AND_FETCH_unsigned(unsigned *data, pthread_mutex_t *phlpmut) {
unsigned val;
pthread_mutex_lock(phlpmut);
val = ++(*data);
pthread_mutex_unlock(phlpmut);
return(val);
}
static inline int
ATOMIC_DEC_AND_FETCH(int *data, pthread_mutex_t *phlpmut) {
int val;
pthread_mutex_lock(phlpmut);
val = --(*data);
pthread_mutex_unlock(phlpmut);
return(val);
}
static inline int
ATOMIC_FETCH_32BIT(int *data, pthread_mutex_t *phlpmut) {
int val;
pthread_mutex_lock(phlpmut);
val = (*data);
pthread_mutex_unlock(phlpmut);
return(val);
}
static inline void
ATOMIC_SUB(int *data, int val, pthread_mutex_t *phlpmut) {
pthread_mutex_lock(phlpmut);
(*data) -= val;
pthread_mutex_unlock(phlpmut);
}
# define DEF_ATOMIC_HELPER_MUT(x) pthread_mutex_t x;
# define INIT_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL);
# define DESTROY_ATOMIC_HELPER_MUT(x) pthread_mutex_destroy(&(x));
# define PREFER_ATOMIC_INC(data) ((void) ++data)
#endif
/* we need to handle 64bit atomics seperately as some platforms have
* 32 bit atomics, but not 64 bit ones... -- rgerhards, 2010-12-01
*/
#if 0 /* currently disabled, we don't need it now and dont' have the data types present */
#ifdef HAVE_ATOMIC_BUILTINS64
# define ATOMIC_INC_uint64(data, phlpmut) ((void) __sync_fetch_and_add(data, 1))
# define ATOMIC_DEC_unit64(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1))
# define ATOMIC_INC_AND_FETCH_uint64(data, phlpmut) __sync_fetch_and_add(data, 1)
# define DEF_ATOMIC_HELPER_MUT64(x)
# define INIT_ATOMIC_HELPER_MUT64(x)
# define DESTROY_ATOMIC_HELPER_MUT64(x)
#else
# define ATOMIC_INC_uint64(data, phlpmut) { \
pthread_mutex_lock(phlpmut); \
++(*(data)); \
pthread_mutex_unlock(phlpmut); \
}
# define ATOMIC_DEC_uint64(data, phlpmut) { \
pthread_mutex_lock(phlpmut); \
--(*(data)); \
pthread_mutex_unlock(phlpmut); \
}
static inline unsigned
ATOMIC_INC_AND_FETCH_uint64(uint64 *data, pthread_mutex_t *phlpmut) {
uint64 val;
pthread_mutex_lock(phlpmut);
val = ++(*data);
pthread_mutex_unlock(phlpmut);
return(val);
}
# define DEF_ATOMIC_HELPER_MUT64(x) pthread_mutex_t x;
# define INIT_ATOMIC_HELPER_MUT64(x) pthread_mutex_init(&(x), NULL)
# define DESTROY_ATOMIC_HELPER_MUT64(x) pthread_mutex_destroy(&(x))
#endif /* #ifdef HAVE_ATOMIC_BUILTINS64 */
#endif
#endif /* #ifndef INCLUDED_ATOMIC_H */

347
compile Executable file
View File

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

1441
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

174
config.h.in Normal file
View File

@ -0,0 +1,174 @@
/* 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
/* Define if compiler provides atomic builtins */
#undef HAVE_ATOMIC_BUILTINS
/* Define if compiler provides 64 bit atomic builtins */
#undef HAVE_ATOMIC_BUILTINS64
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `open' function. */
#undef HAVE_OPEN
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strncasecmp' function. */
#undef HAVE_STRNCASECMP
/* Define to 1 if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#undef HAVE_SYS_CDEFS_H
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
/* Define to 1 if you have the `vprintf' function. */
#undef HAVE_VPRINTF
/* Define to 1 if you have the `vsnprintf' function. */
#undef HAVE_VSNPRINTF
/* Define to 1 if you have the `vsyslog' function. */
#undef HAVE_VSYSLOG
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* valgrind enabled */
#undef VALGRIND
/* Version number of package */
#undef VERSION
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t

1813
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

16316
configure vendored Executable file

File diff suppressed because it is too large Load Diff

166
configure.ac Normal file
View File

@ -0,0 +1,166 @@
AC_PREREQ(2.52)
# Process this file with autoconf to produce a configure script.
AC_INIT([libfastjson], [0.99.8], [rsyslog@lists.adiscon.com])
# AIXPORT START: Detect the underlying OS
unamestr=$(uname)
AM_CONDITIONAL([AIX], [test x$unamestr = xAIX])
# AIXPORT END
# AIXPORT : Set the required variables for AIX config script
if test "$unamestr" = "AIX"; then
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
LIBS="-lbsd -lm"
CPPFLAGS="-D_AIX -D_THREAD_SAFE -D_BSD=43"
LDFLAGS="-qcpluscmt -brtl -bexpall "
CC="xlc"
AC_PREFIX_DEFAULT(/usr)
fi
# AIXPORT END
AC_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE([subdir-objects])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC_C99
AC_PROG_MAKE_SET
m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], [AC_USE_SYSTEM_EXTENSIONS])
if test "$GCC" = "yes"
then
m4_ifdef([AX_IS_RELEASE], [
AX_IS_RELEASE([git-directory])
m4_ifdef([AX_COMPILER_FLAGS], [
AX_COMPILER_FLAGS()
], [
CFLAGS="$CFLAGS -W -Wall -Wformat-security -Wshadow -Wcast-align -Wpointer-arith -Wmissing-format-attribute -g"
AC_MSG_WARN([missing AX_COMPILER_FLAGS macro, not using it])
])
], [
CFLAGS="$CFLAGS -W -Wall -Wformat-security -Wshadow -Wcast-align -Wpointer-arith -Wmissing-format-attribute -g"
AC_MSG_WARN([missing AX_IS_RELEASE macro, not using AX_COMPILER_FLAGS macro because of this])
])
else
AC_MSG_WARN([compiler is not GCC or close compatible, not using ax_compiler_flags because of this (CC=$CC)])
fi
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
# enable silent build by default
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_ARG_ENABLE(valgrind,
[AS_HELP_STRING([--enable-valgrind],[enable running the testbench under valgrind memcheck tool @<:@default=no@:>@])],
[case "${enableval}" in
yes) enable_valgrind="yes" ;;
no) enable_valgrind="no" ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;;
esac],
[enable_valgrind="no"]
)
if test "$enable_valgrind" = "yes"; then
AC_CHECK_PROG(VALGRIND, [valgrind], [valgrind], [no])
if test "x$VALGRIND" = "xno"; then
AC_MSG_ERROR([--enable-valgrind given, but valgrind is not present on system])
fi
AC_SUBST(VALGRIND)
AC_DEFINE(VALGRIND, 1, [valgrind enabled])
fi
# Checks for programs.
# Checks for libraries.
# Checks for header files.
AM_PROG_CC_C_O
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 endian.h)
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
# check for availability of atomic operations
RS_ATOMIC_OPERATIONS
RS_ATOMIC_OPERATIONS_64BIT
# Checks for library functions.
AC_FUNC_VPRINTF
AC_FUNC_MEMCMP
AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
if test "$ac_cv_have_decl_isnan" = "yes" ; then
AC_TRY_LINK([#include <math.h>], [float f = 0.0; return isnan(f)], [], [LIBS="$LIBS -lm"])
fi
#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([AC_LANG_SOURCE([[
extern void json_object_get();
__asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libfastjson 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
# 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
libfastjson.pc
libfastjson-uninstalled.pc
tests/Makefile
])
AC_OUTPUT

83
debug.c Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#if HAVE_SYSLOG_H
# include <syslog.h>
#endif /* HAVE_SYSLOG_H */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif /* HAVE_SYS_PARAM_H */
#include "debug.h"
static int _syslog = 0;
static int _debug = 0;
void mc_set_debug(int debug) { _debug = debug; }
int mc_get_debug(void) { return _debug; }
extern void mc_set_syslog(int use_syslog)
{
_syslog = use_syslog;
}
void mc_debug(const char *msg, ...)
{
va_list ap;
if(_debug) {
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_DEBUG, msg, ap);
} else
#endif
vprintf(msg, ap);
va_end(ap);
}
}
void mc_error(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_ERR, msg, ap);
} else
#endif
vfprintf(stderr, msg, ap);
va_end(ap);
}
void mc_info(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
#if HAVE_VSYSLOG
if(_syslog) {
vsyslog(LOG_INFO, msg, ap);
} else
#endif
vfprintf(stderr, msg, ap);
va_end(ap);
}

71
debug.h Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _FJ_DEBUG_H_
#define _FJ_DEBUG_H_
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void mc_set_debug(int debug);
extern int mc_get_debug(void);
extern void mc_set_syslog(int syslog);
extern void mc_debug(const char *msg, ...) __attribute__((format(printf, 1, 2)));
extern void mc_error(const char *msg, ...) __attribute__((format(printf, 1, 2)));
extern void mc_info(const char *msg, ...) __attribute__((format(printf, 1, 2)));
#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_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
#ifdef MC_MAINTAINER_MODE
#define MC_SET_DEBUG(x) mc_set_debug(x)
#define MC_GET_DEBUG() mc_get_debug()
#define MC_SET_SYSLOG(x) mc_set_syslog(x)
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
#else
#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
#define MC_GET_DEBUG() (0)
#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
#endif
#ifdef __cplusplus
}
#endif
#endif

791
depcomp Executable file
View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

508
install-sh Executable file
View File

@ -0,0 +1,508 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2014-09-12.12; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# 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
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
# $RANDOM is not portable (e.g. dash); use it when possible to
# lower collision chance
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
# create the $tmpdir first (and fail if unsuccessful) to make sure
# that nobody tries to guess the $tmpdir name.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

83
json.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _fj_json_h_
#define _fj_json_h_
#ifdef __cplusplus
extern "C" {
#endif
#include "json_util.h"
#include "json_object.h"
#include "json_tokener.h"
#include "json_object_iterator.h"
/**
* Set initial size allocation for memory when creating strings,
* as is done for example in fjson_object_to_json_string(). The
* default size is 32, which is very conservative. If an app
* knows it typically deals with larger strings, performance
* can be improved by setting the initial size to a different
* number, e.g. 1k. Note that this also means that memory
* consumption can increase. How far entriely depens on the
* application and its use of json-c.
*
* Note: each time this function is called, the initial size is
* changed to the given value. Already existing elements are not
* affected. This function is usually meant to be called just once
* at start of an application, but there is no harm calling it more
* than once. Note that the function is NOT thread-safe and must not
* be called on different threads concurrently.
*
* @param size new initial size for printbuf (formatting buffer)
*/
extern void fjson_global_set_printbuf_initial_size(int size);
/**
* Set case sensitive/insensitive comparison mode. If set to 0,
* comparisons for JSON keys will be case-insensitive. Otherwise,
* they will be case-sensitive.
* NOTE: the JSON standard demands case sensitivity. By turning
* this off, the JSON standard is not obeyed. Most importantly,
* if keys exists which only differ in case, only partial data
* access is possible. So use with care and only if you know
* exactly what you are doing!
*/
extern void fjson_global_do_case_sensitive_comparison(const int newval);
/**
* report the current libfastjson version
*/
extern const char *fjson_version(void);
/**
* default string hash function
*/
#define FJSON_STR_HASH_DFLT 0
/**
* perl-like string hash function
*/
#define FJSON_STR_HASH_PERLLIKE 1
#ifndef FJSON_NATIVE_API_ONLY
#define JSON_C_STR_HASH_PERLLIKE FJSON_STR_HASH_PERLLIKE
#define json_global_set_string_hash(x) /**<< no longer exists nor is needed */
#define fjson_global_set_string_hash(x) /**<< no longer exists nor is needed */
#endif
#ifdef __cplusplus
}
#endif
#endif

1024
json_object.c Normal file

File diff suppressed because it is too large Load Diff

741
json_object.h Normal file
View File

@ -0,0 +1,741 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2015-2016 Rainer Gerhards
*
* 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 _fj_json_object_h_
#define _fj_json_object_h_
#ifdef __GNUC__
#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated))
#else
#define THIS_FUNCTION_IS_DEPRECATED(func) func
#endif
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define FJSON_OBJECT_DEF_HASH_ENTRIES 16
/* number of subjects within a children page. One page is allocated
* with each json object, and extensions are alwas done in page
* size increments. The size should be a compromise between not
* wasting too much space but also not doing too frequent mallocs.
* note: each page *entry* currently needs ~20 Bytes (x64). If this
* is important, check the actual number (sizeof(struct _fjson_child)).
*/
#define FJSON_OBJECT_CHLD_PG_SIZE 8
/**
* A flag for the fjson_object_to_json_string_ext() and
* fjson_object_to_file_ext() functions which causes the output
* to have no extra whitespace or formatting applied.
*/
#define FJSON_TO_STRING_PLAIN 0
/**
* A flag for the fjson_object_to_json_string_ext() and
* fjson_object_to_file_ext() functions which causes the output to have
* minimal whitespace inserted to make things slightly more readable.
*/
#define FJSON_TO_STRING_SPACED (1<<0)
/**
* A flag for the fjson_object_to_json_string_ext() and
* fjson_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 FJSON_TO_STRING_PRETTY (1<<1)
/**
* A flag for the fjson_object_to_json_string_ext() and
* fjson_object_to_file_ext() functions which causes
* the output to be formatted.
*
* Instead of a "Two Space Tab" this gives a single tab character.
*/
#define FJSON_TO_STRING_PRETTY_TAB (1<<3)
/**
* A flag to drop trailing zero for float values
*/
#define FJSON_TO_STRING_NOZERO (1<<2)
/**
* A flag for the fjson_object_object_add_ex function which
* causes the value to be added without a check if it already exists.
* Note: it is the responsibilty of the caller to ensure that no
* key is added multiple times. If this is done, results are
* unpredictable. While this option is somewhat dangerous, it
* permits potentially large performance savings in code that
* knows for sure the key values are unique (e.g. because the
* code adds a well-known set of constant key values).
*/
#define FJSON_OBJECT_ADD_KEY_IS_NEW (1<<1)
/**
* A flag for the fjson_object_object_add_ex function which
* flags the key as being constant memory. This means that
* the key will NOT be copied via strdup(), resulting in a
* potentially huge performance win (malloc, strdup and
* free are usually performance hogs). It is acceptable to
* use this flag for keys in non-constant memory blocks if
* the caller ensure that the memory holding the key lives
* longer than the corresponding json object. However, this
* is somewhat dangerous and should only be done if really
* justified.
* The general use-case for this flag is cases where the
* key is given as a real constant value in the function
* call, e.g. as in
* fjson_object_object_add_ex(obj, "ip", json,
* FJSON_OBJECT_KEY_IS_CONSTANT);
*/
#define FJSON_OBJECT_KEY_IS_CONSTANT (1<<2)
#undef FALSE
#define FALSE ((fjson_bool)0)
#undef TRUE
#define TRUE ((fjson_bool)1)
extern const char *fjson_number_chars;
extern const char *fjson_hex_chars;
/* CAW: added for ANSI C iteration correctness */
struct fjson_object_iter
{
char *key;
struct fjson_object *val;
struct lh_entry *entry;
};
/* forward structure definitions */
typedef int fjson_bool;
typedef struct printbuf printbuf;
typedef struct lh_table lh_table;
typedef struct array_list array_list;
typedef struct fjson_object fjson_object;
typedef struct fjson_object_iter fjson_object_iter;
typedef struct fjson_tokener fjson_tokener;
/**
* Type for a user-supplied write function
*/
typedef size_t (fjson_write_fn)(void *ptr, const char *buffer, size_t size);
/* supported object types */
typedef enum fjson_type {
/* If you change this, be sure to update fjson_type_to_name() too */
fjson_type_null,
fjson_type_boolean,
fjson_type_double,
fjson_type_int,
fjson_type_object,
fjson_type_array,
fjson_type_string
} fjson_type;
/* reference counting functions */
/**
* Increment the reference count of fjson_object, thereby grabbing shared
* ownership of obj.
*
* @param obj the fjson_object instance
*/
extern struct fjson_object* fjson_object_get(struct fjson_object *obj);
/**
* Decrement the reference count of fjson_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 fjson_object instance
* @returns 1 if the object was freed.
*/
int fjson_object_put(struct fjson_object *obj);
/**
* Check if the fjson_object is of a given type
* @param obj the fjson_object instance
* @param type one of:
fjson_type_null (i.e. obj == NULL),
fjson_type_boolean,
fjson_type_double,
fjson_type_int,
fjson_type_object,
fjson_type_array,
fjson_type_string
*/
extern int fjson_object_is_type(struct fjson_object *obj, enum fjson_type type);
/**
* Get the type of the fjson_object. See also fjson_type_to_name() to turn this
* into a string suitable, for instance, for logging.
*
* @param obj the fjson_object instance
* @returns type being one of:
fjson_type_null (i.e. obj == NULL),
fjson_type_boolean,
fjson_type_double,
fjson_type_int,
fjson_type_object,
fjson_type_array,
fjson_type_string
*/
extern enum fjson_type fjson_object_get_type(struct fjson_object *obj);
/**
* Get the size of the json string if it was dumped
* @param obj object to calculate the size of
* @returns the size of the json string
*/
extern size_t fjson_object_size(struct fjson_object *obj);
/**
* Extended version of the above function that accept a flags parameter identical
* to the fjson_object_dump_ext() function that you can use the specify how to
* format the string for which the size is calculated
* @param obj the object to calculate the size of
* @param flags extra flags
* @return size_t
*/
extern size_t fjson_object_size_ext(struct fjson_object *obj, int flags);
/**
* Dump object to a user-supplied function.
* Equivalent to fjson_object_write_ext(obj, FJSON_TO_STRING_SPACED, func, ptr)
* @param obj object to be written
* @param func your function that will be called to write the data
* @param ptr pointer that will be passed as first argument to your function
* @returns number of bytes written (the sum of all return values of calls to func)
*/
extern size_t fjson_object_dump(struct fjson_object *obj, fjson_write_fn *func, void *ptr);
/**
* Extended dump function that allows passing extra option. You can use all
* FJSON_TO_STRING_* constants for the flags
* @param obj object to be written
* @param flags extra flags
* @param func your function that will be called to write the data
* @param ptr pointer that will be passed as first argument to your function
* @returns number of bytes written (the sum of all return values of calls to func)
*/
extern size_t fjson_object_dump_ext(struct fjson_object *obj, int flags, fjson_write_fn *func, void *ptr);
/**
* Dump function that uses a user-supplied temporary buffer for dumping the
* json. Both the above declared fjson_object_dump() and fjson_object_dump_ext()
* functions uses an internal buffer of 128 bytes that is first filled before
* the user-supplied function is called. This buffer prevents that many calls
* to the callback function are done for single quotes, comma's and curly
* braces. All these calls are first buffered and grouped into a single call
* to the user space function. However, since the buffer limit is somewhat
* arbitrary, you can also use this fjson_object_dump_buffered() function to
* use your own temporary buffer. Note that the buffer might be completely
* overwritten during the call to this function, and that the contents of the
* buffer are undefined after the call.
* @param obj object to be written
* @param flags extra flags
* @param temp your temporary buffer that is used to group calls
* @param size size of your temporary buffer
* @param func your function that will be called to write the data
* @param ptr pointer that will be passed as first argument to your function
*/
extern size_t fjson_object_dump_buffered(struct fjson_object *obj, int flags, char *temp,
size_t size, fjson_write_fn *func, void *ptr);
/**
* Write the json tree to a file
* Equivalent to fjson_object_write_ext(obj, FJSON_TO_STRING_SPACED, fp)
* @param obj object to be written
* @param fp file-pointer to which output will be written
* @returns number of bytes written
*/
extern size_t fjson_object_write(struct fjson_object *obj, FILE *fp);
/**
* Extended write function that allows flags to be passed
* @param obj object to be written
* @param flags extra flags
* @param fp file-pointer to which output will be written
* @returns number of bytes written
*/
extern size_t fjson_object_write_ext(struct fjson_object *obj, int flags, FILE *fp);
/** Stringify object to json format.
* Equivalent to fjson_object_to_json_string_ext(obj, FJSON_TO_STRING_SPACED)
* The pointer you get is an internal of your json object. You don't
* have to free it, later use of fjson_object_put() should be sufficient.
* If you can not ensure there's no concurrent access to *obj use
* strdup().
* @param obj the fjson_object instance
* @returns a string in JSON format
*/
extern const char* fjson_object_to_json_string(struct fjson_object *obj);
/** Stringify object to json format
* @see fjson_object_to_json_string() for details on how to free string.
* @param obj the fjson_object instance
* @param flags formatting options, see FJSON_TO_STRING_PRETTY and other constants
* @returns a string in JSON format
*/
extern const char* fjson_object_to_json_string_ext(struct fjson_object *obj, int
flags);
/* object type methods */
/** Create a new empty object with a reference count of 1. The caller of
* this object initially has sole ownership. Remember, when using
* fjson_object_object_add or fjson_object_array_put_idx, ownership will
* transfer to the object/array. Call fjson_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 fjson_object_put.
*
* @returns a fjson_object of type fjson_type_object
*/
extern struct fjson_object* fjson_object_new_object(void);
/** Get the size of an object in terms of the number of fields it has.
* @param obj the fjson_object whose length to return
*/
extern int fjson_object_object_length(struct fjson_object* obj);
/** Add an object field to a fjson_object of type fjson_type_object
*
* The reference count will *not* be incremented. This is to make adding
* fields to objects in code more compact. If you want to retain a reference
* to an added object, independent of the lifetime of obj, you must wrap the
* passed object with fjson_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,
* fjson_object_new_object will give you ownership until you transfer it,
* whereas fjson_object_object_get does not.
*
* @param obj the fjson_object instance
* @param key the object field name (a private copy will be duplicated)
* @param val a fjson_object or NULL member to associate with the given field
*/
extern void fjson_object_object_add(struct fjson_object* obj, const char *key,
struct fjson_object *val);
/** Add an object field to a fjson_object of type fjson_type_object
*
* The semantics are identical to fjson_object_object_add, except that an
* additional flag fields gives you more control over some detail aspects
* of processing. See the description of FJSON_OBJECT_ADD_* flags for more
* details.
*
* @param obj the fjson_object instance
* @param key the object field name (a private copy will be duplicated)
* @param val a fjson_object or NULL member to associate with the given field
* @param opts process-modifying options. To specify multiple options, use
* arithmetic or (OPT1|OPT2)
*/
extern void fjson_object_object_add_ex(struct fjson_object* obj, const char *key,
struct fjson_object *val, const unsigned opts);
/** Get the fjson_object associate with a given object field
*
* *No* reference counts will be changed. There is no need to manually adjust
* reference counts through the fjson_object_put/fjson_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 fjson_object_put unless you have done a fjson_object_get).
* If you delete the value from obj (fjson_object_object_del) and wish to access
* the returned reference afterwards, make sure you have first gotten shared
* ownership through fjson_object_get (& don't forget to do a fjson_object_put
* or transfer ownership to prevent a memory leak).
*
* @param obj the fjson_object instance
* @param key the object field name
* @returns the fjson_object associated with the given field name
* @deprecated Please use fjson_object_object_get_ex
*/
THIS_FUNCTION_IS_DEPRECATED(extern struct fjson_object* fjson_object_object_get(struct fjson_object* obj,
const char *key));
/** Get the fjson_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 fjson_type_object).
*
* *No* reference counts will be changed. There is no need to manually adjust
* reference counts through the fjson_object_put/fjson_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 fjson_object instance
* @param key the object field name
* @param value a pointer where to store a reference to the fjson_object
* associated with the given field name.
*
* It is safe to pass a NULL value.
* @returns whether or not the key exists
*/
extern fjson_bool fjson_object_object_get_ex(struct fjson_object* obj,
const char *key,
struct fjson_object **value);
/** Delete the given fjson_object field
*
* The reference count will be decremented for the deleted object. If there
* are no more owners of the value represented by this key, then the value is
* freed. Otherwise, the reference to the value will remain in memory.
*
* @param obj the fjson_object instance
* @param key the object field name
*/
extern void fjson_object_object_del(struct fjson_object* obj, const char *key);
/* Array type methods */
/** Create a new empty fjson_object of type fjson_type_array
* @returns a fjson_object of type fjson_type_array
*/
extern struct fjson_object* fjson_object_new_array(void);
/** Get the arraylist of a fjson_object of type fjson_type_array
* @param obj the fjson_object instance
* @returns an arraylist
*/
extern struct array_list* fjson_object_get_array(struct fjson_object *obj);
/** Get the length of a fjson_object of type fjson_type_array
* @param obj the fjson_object instance
* @returns an int
*/
extern int fjson_object_array_length(struct fjson_object *obj);
/** Sorts the elements of jso of type fjson_type_array
*
* Pointers to the fjson_object pointers will be passed as the two arguments
* to @sort_fn
*
* @param obj the fjson_object instance
* @param sort_fn a sorting function
*/
extern void fjson_object_array_sort(struct fjson_object *jso, int(*sort_fn)(const void *, const void *));
/** Binary search a sorted array for a specified key object.
*
* It depends on your compare function what's sufficient as a key.
* Usually you create some dummy object with the parameter compared in
* it, to identify the right item you're actually looking for.
*
* @see fjson_object_array_sort() for hints on the compare function.
*
* @param key a dummy fjson_object with the right key
* @param jso the array object we're searching
* @param sort_fn the sort/compare function
*
* @return the wanted fjson_object instance
*/
extern struct fjson_object* fjson_object_array_bsearch(
const struct fjson_object *key,
const struct fjson_object *jso,
int (*sort_fn)(const void *, const void *));
/** Add an element to the end of a fjson_object of type fjson_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 fjson_object_get
*
* @param obj the fjson_object instance
* @param val the fjson_object to be added
*/
extern int fjson_object_array_add(struct fjson_object *obj,
struct fjson_object *val);
/** Insert or replace an element at a specified index in an array (a fjson_object of type fjson_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 fjson_object_get
*
* The reference count of a replaced object will be decremented.
*
* The array size will be automatically be expanded to the size of the
* index if the index is larger than the current size.
*
* @param obj the fjson_object instance
* @param idx the index to insert the element at
* @param val the fjson_object to be added
*/
extern int fjson_object_array_put_idx(struct fjson_object *obj, int idx,
struct fjson_object *val);
/** Get the element at specificed index of the array (a fjson_object of type fjson_type_array)
* @param obj the fjson_object instance
* @param idx the index to get the element at
* @returns the fjson_object at the specified index (or NULL)
*/
extern struct fjson_object* fjson_object_array_get_idx(struct fjson_object *obj,
int idx);
/* fjson_bool type methods */
/** Create a new empty fjson_object of type fjson_type_boolean
* @param b a fjson_bool TRUE or FALSE (1 or 0)
* @returns a fjson_object of type fjson_type_boolean
*/
extern struct fjson_object* fjson_object_new_boolean(fjson_bool b);
/** Get the fjson_bool value of a fjson_object
*
* The type is coerced to a fjson_bool if the passed object is not a fjson_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 fjson_object instance
* @returns a fjson_bool
*/
extern fjson_bool fjson_object_get_boolean(struct fjson_object *obj);
/* int type methods */
/** Create a new empty fjson_object of type fjson_type_int
* Note that values are stored as 64-bit values internally.
* To ensure the full range is maintained, use fjson_object_new_int64 instead.
* @param i the integer
* @returns a fjson_object of type fjson_type_int
*/
extern struct fjson_object* fjson_object_new_int(int32_t i);
/** Create a new empty fjson_object of type fjson_type_int
* @param i the integer
* @returns a fjson_object of type fjson_type_int
*/
extern struct fjson_object* fjson_object_new_int64(int64_t i);
/** Get the int value of a fjson_object
*
* The type is coerced to a int if the passed object is not a int.
* double objects will return their integer conversion. Strings will be
* parsed as an integer. If no conversion exists then 0 is returned
* and errno is set to EINVAL. null is equivalent to 0 (no error values set)
*
* Note that integers are stored internally as 64-bit values.
* If the value of too big or too small to fit into 32-bit, INT32_MAX or
* INT32_MIN are returned, respectively.
*
* @param obj the fjson_object instance
* @returns an int
*/
extern int32_t fjson_object_get_int(struct fjson_object *obj);
/** Get the int value of a fjson_object
*
* The type is coerced to a int64 if the passed object is not a int64.
* double objects will return their int64 conversion. Strings will be
* parsed as an int64. If no conversion exists then 0 is returned.
*
* NOTE: Set errno to 0 directly before a call to this function to determine
* whether or not conversion was successful (it does not clear the value for
* you).
*
* @param obj the fjson_object instance
* @returns an int64
*/
extern int64_t fjson_object_get_int64(struct fjson_object *obj);
/* double type methods */
/** Create a new empty fjson_object of type fjson_type_double
* @param d the double
* @returns a fjson_object of type fjson_type_double
*/
extern struct fjson_object* fjson_object_new_double(double d);
/**
* Create a new fjson_object of type fjson_type_double, using
* the exact 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 fjson_tokener_parse_ex() to allow for
* an exact re-serialization of a parsed object.
*
* @param d the numeric value of the double.
* @param ds the string representation of the double. This will be copied.
*/
extern struct fjson_object* fjson_object_new_double_s(double d, const char *ds);
/** Get the double floating point value of a fjson_object
*
* The type is coerced to a double if the passed object is not a double.
* integer objects will return their double conversion. Strings will be
* parsed as a double. If no conversion exists then 0.0 is returned and
* errno is set to EINVAL. null is equivalent to 0 (no error values set)
*
* If the value is too big to fit in a double, then the value is set to
* the closest infinity with errno set to ERANGE. If strings cannot be
* converted to their double value, then EINVAL is set & NaN is returned.
*
* Arrays of length 0 are interpreted as 0 (with no error flags set).
* Arrays of length 1 are effectively cast to the equivalent object and
* converted using the above rules. All other arrays set the error to
* EINVAL & return NaN.
*
* NOTE: Set errno to 0 directly before a call to this function to
* determine whether or not conversion was successful (it does not clear
* the value for you).
*
* @param obj the fjson_object instance
* @returns a double floating point number
*/
extern double fjson_object_get_double(struct fjson_object *obj);
/* string type methods */
/** Create a new empty fjson_object of type fjson_type_string
*
* A copy of the string is made and the memory is managed by the fjson_object
*
* @param s the string
* @returns a fjson_object of type fjson_type_string
*/
extern struct fjson_object* fjson_object_new_string(const char *s);
extern struct fjson_object* fjson_object_new_string_len(const char *s, int len);
/** Get the string value of a fjson_object
*
* If the passed object is not of type fjson_type_string then the JSON
* representation of the object is returned.
*
* The returned string memory is managed by the fjson_object and will
* be freed when the reference count of the fjson_object drops to zero.
*
* @param obj the fjson_object instance
* @returns a string
*/
extern const char* fjson_object_get_string(struct fjson_object *obj);
/** Get the string length of a fjson_object
*
* If the passed object is not of type fjson_type_string then zero
* will be returned.
*
* @param obj the fjson_object instance
* @returns int
*/
extern int fjson_object_get_string_len(struct fjson_object *obj);
/** Get the number of direct members inside a json object.
*
* @param obj the fjson_object instance
* @returns int
*/
int fjson_object_get_member_count(struct fjson_object *jso);
/* The following is a source code compatibility layer
* in regard to json-c.
* It currently is aimed at the rsyslog family of projects,
* we may extend or drop it later.
*/
#ifndef FJSON_NATIVE_API_ONLY
#define JSON_C_TO_STRING_PLAIN FJSON_TO_STRING_PLAIN
#define JSON_C_TO_STRING_SPACED FJSON_TO_STRING_SPACED
#define JSON_C_TO_STRING_PRETTY FJSON_TO_STRING_PRETTY
#define JSON_C_TO_STRING_PRETTY_TAB FJSON_TO_STRING_PRETTY_TAB
#define JSON_C_TO_STRING_NOZERO FJSON_TO_STRING_NOZERO
#define JSON_C_OBJECT_ADD_KEY_IS_NEW FJSON_OBJECT_ADD_KEY_IS_NEW
#define JSON_C_OBJECT_KEY_IS_CONSTANT FJSON_OBJECT_KEY_IS_CONSTANT
/* forward structure definitions */
#if 0
typedef int fjson_bool;
typedef struct printbuf printbuf;
typedef struct lh_table lh_table;
typedef struct array_list array_list;
typedef struct fjson_object fjson_object;
typedef struct fjson_tokener fjson_tokener;
#endif
#define json_bool fjson_bool
#define json_type fjson_type
#define json_type_null fjson_type_null
#define json_type_boolean fjson_type_boolean
#define json_type_double fjson_type_double
#define json_type_int fjson_type_int
#define json_type_object fjson_type_object
#define json_type_array fjson_type_array
#define json_type_string fjson_type_string
#define json_object_iter fjson_object_iter
#define json_object fjson_object
#define json_object_get fjson_object_get
#define json_object_put fjson_object_put
#define json_object_is_type fjson_object_is_type
#define json_object_get_type(x) fjson_object_get_type((x))
#define json_object_to_json_string(x) fjson_object_to_json_string((x))
#define json_object_to_json_string_ext(a, b) fjson_object_to_json_string_ext((a), (b))
#define json_object_new_object() fjson_object_new_object()
#define json_object_object_length(a) fjson_object_object_length((a))
#define json_object_object_add(a, b, c) fjson_object_object_add((a), (b), (c))
#define json_object_object_add_ex fjson_object_object_add_ex
#define json_object_object_get_ex fjson_object_object_get_ex
#define json_object_object_get fjson_object_object_get
#define json_object_object_del fjson_object_object_del
#define json_object_new_array fjson_object_new_array
#define json_object_get_array fjson_object_get_array
#define json_object_array_length fjson_object_array_length
#define json_object_array_sort fjson_object_array_sort
#define json_object_array_bsearch fjson_object_array_bsearch
#define json_object_array_add fjson_object_array_add
#define json_object_array_put_idx fjson_object_array_put_idx
#define json_object_array_get_idx fjson_object_array_get_idx
#define json_object_new_boolean fjson_object_new_boolean
#define json_object_get_boolean fjson_object_get_boolean
#define json_object_new_int fjson_object_new_int
#define json_object_new_int64 fjson_object_new_int64
#define json_object_new_double fjson_object_new_double
#define json_object_new_double_s fjson_object_new_double_s
#define json_object_get_double fjson_object_get_double
#define json_object_new_string fjson_object_new_string
#define json_object_new_string_len fjson_object_new_string_len
#define json_object_get_string fjson_object_get_string
#define json_object_get_int fjson_object_get_int
#define json_object_get_int64 fjson_object_get_int64
#define json_object_get_string_len fjson_object_get_string_len
#define json_object_get_member_count fjson_object_get_member_count
#endif
#ifdef __cplusplus
}
#endif
#endif

208
json_object_iterator.c Normal file
View File

@ -0,0 +1,208 @@
/**
*******************************************************************************
* @file fjson_object_iterator.c
*
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
* @brief json-c forces clients to use its private data
* structures for JSON Object iteration. This API
* implementation corrects that by abstracting the
* private json-c details.
*
*******************************************************************************
*/
#include "config.h"
#include <stddef.h>
#include "json.h"
#include "json_object_private.h"
#include "json_object_iterator.h"
#include "debug.h"
/**
* How It Works
*
* For each JSON Object, json-c maintains a linked list of zero
* or more lh_entry (link-hash entry) structures inside the
* Object's link-hash table (lh_table).
*
* Each lh_entry structure on the JSON Object's linked list
* represents a single name/value pair. The "next" field of the
* last lh_entry in the list is set to NULL, which terminates
* the list.
*
* We represent a valid iterator that refers to an actual
* name/value pair via a pointer to the pair's lh_entry
* structure set as the iterator's opaque_ field.
*
* We follow json-c's current pair list representation by
* representing a valid "end" iterator (one that refers past the
* last pair) with a NULL value in the iterator's opaque_ field.
*
* A JSON Object without any pairs in it will have the "head"
* field of its lh_table structure set to NULL. For such an
* object, fjson_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.
*/
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_begin(struct fjson_object *const __restrict__ obj)
{
struct fjson_object_iterator iter = {
.objs_remain = 0,
.curr_idx = 0,
.pg = NULL
};
if(obj->o_type == fjson_type_object) {
iter.objs_remain = obj->o.c_obj.nelem;
if(iter.objs_remain > 0) {
iter.curr_idx = 0;
iter.pg = &obj->o.c_obj.pg;
/* check if first slot is empty, if so, advance */
if(iter.pg->children[0].k == NULL) {
++iter.objs_remain; /* correct _iter_next decrement */
fjson_object_iter_next(&iter);
}
}
}
return iter;
}
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_end(const struct fjson_object __attribute__((unused)) *obj)
{
struct fjson_object_iterator iter = {
.objs_remain = 0,
.curr_idx = 0,
.pg = NULL
};
return iter;
}
/**
* ****************************************************************************
*/
void
fjson_object_iter_next(struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
if(iter->objs_remain > 0) {
--iter->objs_remain;
if(iter->objs_remain > 0) {
++iter->curr_idx;
if(iter->curr_idx == FJSON_OBJECT_CHLD_PG_SIZE) {
iter->pg = iter->pg->next;
iter->curr_idx = 0;
}
/* check empty slots; TODO: recurse or iterate? */
if(iter->pg->children[iter->curr_idx].k == NULL) {
++iter->objs_remain; /* correct */
fjson_object_iter_next(iter);
}
}
}
}
/**
* ****************************************************************************
*/
const char*
fjson_object_iter_peek_name(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return iter->pg->children[iter->curr_idx].k;
}
/**
* ****************************************************************************
*/
struct fjson_object*
fjson_object_iter_peek_value(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return iter->pg->children[iter->curr_idx].v;
}
/**
* ****************************************************************************
*/
struct _fjson_child*
_fjson_object_iter_peek_child(const struct fjson_object_iterator *const __restrict__ iter)
{
JASSERT(NULL != iter);
return (struct _fjson_child*) &(iter->pg->children[iter->curr_idx]);
}
/**
* ****************************************************************************
*/
fjson_bool
fjson_object_iter_equal(const struct fjson_object_iterator* iter1,
const struct fjson_object_iterator* iter2)
{
int is_eq;
JASSERT(NULL != iter1);
JASSERT(NULL != iter2);
if (iter1->objs_remain == iter2->objs_remain) {
if (iter1->objs_remain == 0) {
is_eq = 1;
} else {
if ( (iter1->curr_idx == iter2->curr_idx) &&
(iter1->pg == iter2->pg) ) {
is_eq = 1;
} else {
is_eq = 0;
}
}
} else {
is_eq= 0;
}
return is_eq;
}
/**
* ****************************************************************************
*/
struct fjson_object_iterator
fjson_object_iter_init_default(void)
{
struct fjson_object_iterator iter;
/**
* @note Make this an invalid value, such that
* accidental access to it would likely be trapped by the
* hardware as an invalid address.
*/
iter.pg = NULL;
iter.curr_idx = 0;
iter.objs_remain = 1;
return iter;
}

257
json_object_iterator.h Normal file
View File

@ -0,0 +1,257 @@
/**
*******************************************************************************
* @file fjson_object_iterator.h
*
* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
* @brief json-c forces clients to use its private data
* structures for JSON Object iteration. This API
* corrects that by abstracting the private json-c
* details.
*
* API attributes: <br>
* * Thread-safe: NO<br>
* * Reentrant: NO
*
*******************************************************************************
*/
#ifndef FJ_JSON_OBJECT_ITERATOR_H
#define FJ_JSON_OBJECT_ITERATOR_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Forward declaration for the opaque iterator information.
*/
struct fjson_object_iter_info_;
/**
* The opaque iterator that references a name/value pair within
* a JSON Object instance or the "end" iterator value.
*/
struct fjson_object_iterator {
int objs_remain;
int curr_idx;
const struct _fjson_child_pg *pg;
};
/**
* forward declaration of json-c's JSON value instance structure
*/
struct fjson_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 fjson_object_iterator iter = fjson_object_iter_init_default();
* MyClass() : iter_(fjson_object_iter_init_default())
* @endcode
*
* @note The initialized value doesn't reference any specific
* pair, is considered an invalid iterator, and MUST NOT
* be passed to any json-c API that expects a valid
* iterator.
*
* @note User and internal code MUST NOT make any assumptions
* about and dependencies on the value of the "default"
* iterator value.
*
* @return fjson_object_iterator
*/
struct fjson_object_iterator
fjson_object_iter_init_default(void);
/** Retrieves an iterator to the first pair of the JSON Object.
*
* @warning Any modification of the underlying pair invalidates all
* iterators to that pair.
*
* @param obj JSON Object instance (MUST be of type fjson_object)
*
* @return fjson_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 fjson_object_iterator it;
* struct fjson_object_iterator itEnd;
* struct fjson_object* obj;
*
* obj = fjson_tokener_parse("{'first':'george', 'age':100}");
* it = fjson_object_iter_begin(obj);
* itEnd = fjson_object_iter_end(obj);
*
* while (!fjson_object_iter_equal(&it, &itEnd)) {
* printf("%s\n",
* fjson_object_iter_peek_name(&it));
* fjson_object_iter_next(&it);
* }
*
* @endcode
*/
struct fjson_object_iterator
fjson_object_iter_begin(struct fjson_object* obj);
/** Retrieves the iterator that represents the position beyond the
* last pair of the given JSON Object instance.
*
* @warning Do NOT write code that assumes that the "end"
* iterator value is NULL, even if it is so in a
* particular instance of the implementation.
*
* @note The reason we do not (and MUST NOT) provide
* "fjson_object_iter_is_end(fjson_object_iterator* iter)"
* type of API is because it would limit the underlying
* representation of name/value containment (or force us
* to add additional, otherwise unnecessary, fields to
* the iterator structure). The "end" iterator and the
* equality test method, on the other hand, permit us to
* cleanly abstract pretty much any reasonable underlying
* representation without burdening the iterator
* structure with unnecessary data.
*
* @note For performance reasons, memorize the "end" iterator prior
* to any loop.
*
* @param obj JSON Object instance (MUST be of type fjson_object)
*
* @return fjson_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 fjson_object_iterator
fjson_object_iter_end(const struct fjson_object* obj);
/** Returns an iterator to the next pair, if any
*
* @warning Any modification of the underlying pair
* invalidates all iterators to that pair.
*
* @param iter [IN/OUT] Pointer to iterator that references a
* name/value pair; MUST be a valid, non-end iterator.
* WARNING: bad things will happen if invalid or "end"
* iterator is passed. Upon return will contain the
* reference to the next pair if there is one; if there
* are no more pairs, will contain the "end" iterator
* value, which may be compared against the return value
* of fjson_object_iter_end() for the same JSON Object
* instance.
*/
void
fjson_object_iter_next(struct fjson_object_iterator* iter);
/** Returns a const pointer to the name of the pair referenced
* by the given iterator.
*
* @param iter pointer to iterator that references a name/value
* pair; MUST be a valid, non-end iterator.
*
* @warning bad things will happen if an invalid or
* "end" iterator is passed.
*
* @return const char* Pointer to the name of the referenced
* name/value pair. The name memory belongs to the
* name/value pair, will be freed when the pair is
* deleted or modified, and MUST NOT be modified or
* freed by the user.
*/
const char*
fjson_object_iter_peek_name(const struct fjson_object_iterator* iter);
/** Returns a pointer to the json-c instance representing the
* value of the referenced name/value pair, without altering
* the instance's reference count.
*
* @param iter pointer to iterator that references a name/value
* pair; MUST be a valid, non-end iterator.
*
* @warning bad things will happen if invalid or
* "end" iterator is passed.
*
* @return struct fjson_object* Pointer to the json-c value
* instance of the referenced name/value pair; the
* value's reference count is not changed by this
* function: if you plan to hold on to this json-c node,
* take a look at fjson_object_get() and
* fjson_object_put(). IMPORTANT: json-c API represents
* the JSON Null value as a NULL fjson_object instance
* pointer.
*/
struct fjson_object*
fjson_object_iter_peek_value(const struct fjson_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
* "fjson_object_iter_is_end(fjson_object_iterator* iter)"
* type of API is because it would limit the underlying
* representation of name/value containment (or force us
* to add additional, otherwise unnecessary, fields to
* the iterator structure). The equality test method, on
* the other hand, permits us to cleanly abstract pretty
* much any reasonable underlying representation.
*
* @param iter1 Pointer to first valid, non-NULL iterator
* @param iter2 POinter to second valid, non-NULL iterator
*
* @warning if a NULL iterator pointer or an uninitialized
* or invalid iterator, or iterators derived from
* different JSON Object instances are passed, bad things
* will happen!
*
* @return fjson_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.
*/
fjson_bool
fjson_object_iter_equal(const struct fjson_object_iterator* iter1,
const struct fjson_object_iterator* iter2);
/* some private functions -- TODO: move to their own header */
struct _fjson_child*
_fjson_object_iter_peek_child(const struct fjson_object_iterator *const __restrict__ iter);
#ifndef FJSON_NATIVE_API_ONLY
#define json_object_iter_info_ fjson_object_iter_info_
#define json_object_iterator fjson_object_iterator
#define json_object_iter_init_default fjson_object_iter_init_default
#define json_object_iter_begin fjson_object_iter_begin
#define json_object_iter_end fjson_object_iter_end
#define json_object_iter_next fjson_object_iter_next
#define json_object_iter_peek_name fjson_object_iter_peek_name
#define json_object_iter_peek_value fjson_object_iter_peek_value
#define json_object_iter_equal fjson_object_iter_equal
#endif
#ifdef __cplusplus
}
#endif
#endif /* FJSON_OBJECT_ITERATOR_H */

97
json_object_private.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2015 Rainer Gerhards
*
* 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 _fj_json_object_private_h_
#define _fj_json_object_private_h_
#include "atomic.h"
#ifdef __cplusplus
extern "C" {
#endif
/* define a couple of attributes to improve cross-platform builds */
#if __GNUC__ > 6
#define ATTR_FALLTHROUGH __attribute__((fallthrough));
#else
#define ATTR_FALLTHROUGH
#endif
#define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in fjson_object for strings? */
/**
* Type of the delete and serialization functions.
*/
typedef void (fjson_object_private_delete_fn)(struct fjson_object *o);
typedef int (fjson_object_to_json_string_fn)(struct fjson_object *jso,
struct printbuf *pb,
int level,
int flags);
struct _fjson_child {
/**
* The key.
*/
const char *k;
int k_is_constant;
struct {
unsigned k_is_constant : 1;
} flags;
/**
* The value.
*/
struct fjson_object *v;
};
struct _fjson_child_pg {
struct _fjson_child children[FJSON_OBJECT_CHLD_PG_SIZE];
struct _fjson_child_pg *next;
};
struct fjson_object
{
enum fjson_type o_type;
fjson_object_private_delete_fn *_delete;
fjson_object_to_json_string_fn *_to_json_string;
int _ref_count;
struct printbuf *_pb;
union data {
fjson_bool c_boolean;
struct {
double value;
char *source;
} c_double;
int64_t c_int64;
struct {
int nelem;
int ndeleted;
struct _fjson_child_pg pg;
struct _fjson_child_pg *lastpg;
} c_obj;
struct array_list *c_array;
struct {
union {
/* optimize: if we have small strings, we can store them
* directly. This saves considerable CPU cycles AND memory.
*/
char *ptr;
char data[LEN_DIRECT_STRING_DATA];
} str;
int len;
} c_string;
} o;
DEF_ATOMIC_HELPER_MUT(_mut_ref_count)
};
#ifdef __cplusplus
}
#endif
#endif

580
json_print.c Normal file
View File

@ -0,0 +1,580 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (c) 2015 Rainer Gerhards
* Copyright (c) 2016 Copernica BV
*
* 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"
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#else /* !HAVE_STDARG_H */
# error Not enough var arg support!
#endif /* HAVE_STDARG_H */
#include "json_object.h"
#include "json_object_private.h"
#include "json_object_iterator.h"
#if !defined(HAVE_SNPRINTF)
# error You do not have snprintf on your system.
#endif /* HAVE_SNPRINTF */
#if !defined(HAVE_VASPRINTF)
/* CAW: compliant version of vasprintf */
/* Note: on OpenCSW, we have vasprintf() inside the headers, but not inside the lib.
* So we need to use a different name, else we get issues with redefinitions. We
* we solve this by using the macro below, which just renames the function BUT
* does not affect the (variadic) arguments.
* rgerhards, 2017-04-11
*/
#define vasprintf rs_vasprintf
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
static int rs_vasprintf(char **buf, const char *fmt, va_list ap)
{
int chars;
char *b;
static char _T_emptybuffer = '\0';
if(!buf) { return -1; }
/* 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 */
b = (char*)malloc(sizeof(char)*chars);
if(!b) { return -1; }
if((chars = vsprintf(b, fmt, ap)) < 0) {
free(b);
} else {
*buf = b;
}
return chars;
}
#pragma GCC diagnostic pop
#endif /* !HAVE_VASPRINTF */
/**
* Internal structure that we use for buffering the print output
*/
struct buffer {
char *buffer;
size_t size;
size_t filled;
fjson_write_fn *overflow;
void *ptr;
};
/**
* Internal method to flush the buffer
* @param buffer
* @return size_t
*/
static size_t buffer_flush(struct buffer *buffer)
{
// call the user-supplied overflow function
size_t result = buffer->overflow(buffer->ptr, buffer->buffer, buffer->filled);
// buffer is empty now
buffer->filled = 0;
// done
return result;
}
/**
* Internal method to append data to the buffer
* @param buffer
* @param data
* @param size
* @return size_t
*/
static size_t buffer_append(struct buffer *buffer, const char *data, size_t size)
{
// return value
size_t result = 0;
// is the data to big to fit in the buffer?
if (buffer->filled + size > buffer->size)
{
// flush current buffer
if (buffer->filled > 0) result += buffer_flush(buffer);
// does it still not fit? then we pass it to the callback immediately
if (size > buffer->size) return result + buffer->overflow(buffer->ptr, data, size);
}
// append to the buffer
memcpy(buffer->buffer + buffer->filled, data, size);
// update buffer size
buffer->filled += size;
// done
return result;
}
/**
* Internal method to printf() into the buffer
* @param buffer
* @param format
* @param ...
* @return size_t
*/
__attribute__((__format__(__printf__, 2, 3)))
static size_t buffer_printf(struct buffer *buffer, const char *format, ...)
{
// return value
size_t result = 0;
// variables used in this function
va_list arguments;
char *tmp;
int size;
// make sure we have sufficient room in our buffer
if (buffer->size - buffer->filled < 32) result += buffer_flush(buffer);
// initialize varargs
va_start(arguments, format);
// write to the buffer (note the extra char for the extra null that is written by vsnprintf())
size = vsnprintf(buffer->buffer + buffer->filled, buffer->size - buffer->filled - 1, format, arguments);
// clean up varargs (it is not possible to reuse the vararg arguments later on,
// the have to be reset and possible reinitialized later on)
va_end(arguments);
// was this all successful?
if (size >= 0 && size < (int)(buffer->size - buffer->filled))
{
// this was a major success
buffer->filled += size;
}
else if (size > 0 && size < (int)buffer->size)
{
// there was not enough room in the buffer, but it would have been enough if
// we would have been able to use the entire buffer, so we reset the buffer,
// and retry the whole procedure
result += buffer_flush(buffer);
// buffer is empty now, we can retry, start with the vararg initialization
va_start(arguments, format);
// format into the buffer, again
buffer->size += vsnprintf(buffer->buffer + buffer->filled,
buffer->size - buffer->filled - 1, format, arguments);
// clean up varargs
va_end(arguments);
}
else
{
// initialize varargs
va_start(arguments, format);
// our own buffer is not big enough to fit the text, we are going to use
// a dynamically allocated buffer using vasprintf(), init varargs first
va_start(arguments, format);
// use dynamically allocated vasprintf() call
size = vasprintf(&tmp, format, arguments);
// clean up varargs
va_end(arguments);
// was this a success?
if (size > 0) result += buffer_append(buffer, tmp, size);
// deallocate the memory
if (size >= 0) free(tmp);
}
// done
return result;
}
/* Forward declaration of the write function */
static size_t write(struct fjson_object *jso, int level, int flags, struct buffer *buffer);
/**
* helper for accessing the optimized string data component in fjson_object
* @param jso
* @return
*/
static const char *get_string_component(struct fjson_object *jso)
{
return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ?
jso->o.c_string.str.data : jso->o.c_string.str.ptr;
}
/**
* string escaping
*
* String escaping is a surprisingly performance intense operation.
* I spent many hours in the profiler, and the root problem seems
* to be that there is no easy way to detect the character classes
* that need to be escaped, where the root cause is that these
* characters are spread all over the ascii table. I tried
* several approaches, including call tables, re-structuring
* the case condition, different types of if conditions and
* reordering the if conditions. What worked out best is this:
* The regular case is that a character must not be escaped. So
* we want to process that as fast as possible. In order to
* detect this as quickly as possible, we have a lookup table
* that tells us if a char needs escaping ("needsEscape", below).
* This table has a spot for each ascii code. Note that it uses
* chars, because anything larger causes worse cache operation
* and anything smaller requires bit indexing and masking
* operations, which are also comparatively costly. So plain
* chars work best. What we then do is a single lookup into the
* table to detect if we need to escape a character. If we need,
* we go into the depth of actual escape detection. But if we
* do NOT need to escape, we just quickly advance the index
* and are done with that char. Note that it may look like the
* extra table lookup costs performance, but right the contrary
* is the case. We get amore than 30% performance increase due
* to it (compared to the latest version of the code that did not
* do the lookups).
* rgerhards@adiscon.com, 2015-11-18
* using now external char_needsEscape array. -- rgerhards, 2016-11-30
*/
extern const char char_needsEscape[256];
/**
* Function to escape a string
* @param str the string to be escaped
* @param buffer the internal buffer to write to
* @return size_t number of bytes written
*/
static size_t escape(const char *str, struct buffer *buffer)
{
size_t result = 0;
const char *start_offset = str;
while(1) { /* broken below on 0-byte */
if(char_needsEscape[*((unsigned char*)str)]) {
if(*str == '\0') break;
if(str != start_offset) result += buffer_append(buffer, start_offset, str - start_offset);
switch(*str) {
case '\b': result += buffer_append(buffer, "\\b", 2); break;
case '\n': result += buffer_append(buffer, "\\n", 2); break;
case '\r': result += buffer_append(buffer, "\\r", 2); break;
case '\t': result += buffer_append(buffer, "\\t", 2); break;
case '\f': result += buffer_append(buffer, "\\f", 2); break;
case '"': result += buffer_append(buffer, "\\\"", 2); break;
case '\\': result += buffer_append(buffer, "\\\\", 2); break;
case '/': result += buffer_append(buffer, "\\/", 2); break;
default:
result += buffer_printf(buffer, "\\u00%c%c",
fjson_hex_chars[*str >> 4], fjson_hex_chars[*str & 0xf]);
break;
}
start_offset = ++str;
} else
++str;
}
if(str != start_offset) result += buffer_append(buffer, start_offset, str - start_offset);
return result;
}
/* add indentation */
static size_t indent(int level, int flags, struct buffer *buffer)
{
// result variable, and loop counter
size_t result = 0;
int i;
// skip if pretty-printing is not needed
if (!(flags & FJSON_TO_STRING_PRETTY)) return 0;
// iterate to add the spaces
for (i = 0; i < level; ++i)
{
// write a tab or two spaces
if (flags & FJSON_TO_STRING_PRETTY_TAB) result += buffer_append(buffer, "\t", 1);
else result += buffer_append(buffer, " ", 2);
}
// done
return result;
}
/* write a json object */
static size_t write_object(struct fjson_object* jso, int level, int flags, struct buffer *buffer)
{
int had_children = 0;
size_t result = 0;
result += buffer_append(buffer, "{" /*}*/, 1);
if (flags & FJSON_TO_STRING_PRETTY) result += buffer_append(buffer, "\n", 1);
struct fjson_object_iterator it = fjson_object_iter_begin(jso);
struct fjson_object_iterator itEnd = fjson_object_iter_end(jso);
while (!fjson_object_iter_equal(&it, &itEnd)) {
if (had_children)
{
result += buffer_append(buffer, ",", 1);
if (flags & FJSON_TO_STRING_PRETTY) result += buffer_append(buffer, "\n", 1);
}
had_children = 1;
if (flags & FJSON_TO_STRING_SPACED) result += buffer_append(buffer, " ", 1);
result += indent(level+1, flags, buffer);
result += buffer_append(buffer, "\"", 1);
result += escape(fjson_object_iter_peek_name(&it), buffer);
if (flags & FJSON_TO_STRING_SPACED) result += buffer_append(buffer, "\": ", 3);
else result += buffer_append(buffer, "\":", 2);
result += write(fjson_object_iter_peek_value(&it), level+1, flags, buffer);
fjson_object_iter_next(&it);
}
if (flags & FJSON_TO_STRING_PRETTY)
{
if (had_children) result += buffer_append(buffer, "\n", 1);
result += indent(level, flags, buffer);
}
if (flags & FJSON_TO_STRING_SPACED) result += buffer_append(buffer, /*{*/ " }", 2);
else result += buffer_append(buffer, /*{*/ "}", 1);
return result;
}
/* write a json boolean */
static size_t write_boolean(struct fjson_object* jso, struct buffer *buffer)
{
if (jso->o.c_boolean) return buffer_append(buffer, "true", 4);
else return buffer_append(buffer, "false", 5);
}
/* write a json int */
static size_t write_int(struct fjson_object* jso, struct buffer *buffer)
{
// printf into the buffer
return buffer_printf(buffer, "%" PRId64, jso->o.c_int64);
}
/* write a json floating point */
static size_t write_double(struct fjson_object* jso, int flags, struct buffer *buffer)
{
// return value for the function
size_t result = 0;
// helper functions to fix the output
char *buf, *p, *q;
// needed for modf()
double dummy;
// if the original value is set, we reuse that
if (jso->o.c_double.source) return buffer_append(buffer, jso->o.c_double.source, strlen(jso->o.c_double.source));
/* 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.value)) return buffer_append(buffer, "NaN", 3);
if(isinf(jso->o.c_double.value)) return buffer_printf(buffer, jso->o.c_double.value > 0 ? "Infinity" : "-Infinity");
// store the beginning of the buffer (this is where buffer_printf() will most likely write)
buf = buffer->buffer + buffer->filled;
// write to the buffer
result = buffer_printf(buffer, (modf(jso->o.c_double.value, &dummy)==0)?"%.17g.0":"%.17g", jso->o.c_double.value);
// if the buffer got flushed
if (buffer->buffer + buffer->filled < buf) buf = buffer->buffer;
// if localization stuff caused "," to be generated instead of "."
// @todo is there not a nicer way to work around that???
p = strchr(buf, ',');
if (p) {
*p = '.';
} else {
p = strchr(buf, '.');
}
// remove trailing zero's
if (p && (flags & FJSON_TO_STRING_NOZERO)) {
/* last useful digit, always keep 1 zero */
p++;
for (q=p ; *q ; q++) {
if (*q!='0') p=q;
}
/* drop trailing zeroes */
buffer->filled = p - buffer->buffer;
}
// done
return result;
}
/* write a json string */
static size_t write_string(struct fjson_object* jso, struct buffer *buffer)
{
return buffer_append(buffer, "\"", 1) + escape(get_string_component(jso), buffer) + buffer_append(buffer, "\"", 1);
}
/* write a json array */
static size_t write_array(struct fjson_object* jso, int level, int flags, struct buffer *buffer)
{
int had_children = 0;
int ii;
size_t result = 0;
result += buffer_append(buffer, "[", 1);
if (flags & FJSON_TO_STRING_PRETTY) result += buffer_append(buffer, "\n", 1);
for(ii=0; ii < fjson_object_array_length(jso); ii++)
{
if (had_children)
{
result += buffer_append(buffer, ",", 1);
if (flags & FJSON_TO_STRING_PRETTY) result += buffer_append(buffer, "\n", 1);
}
had_children = 1;
if (flags & FJSON_TO_STRING_SPACED) result += buffer_append(buffer, " ", 1);
result += indent(level + 1, flags, buffer);
result += write(fjson_object_array_get_idx(jso, ii), level+1, flags, buffer);
}
if (flags & FJSON_TO_STRING_PRETTY)
{
if (had_children) result += buffer_append(buffer, "\n", 1);
result += indent(level, flags, buffer);
}
if (flags & FJSON_TO_STRING_SPACED) result += buffer_append(buffer, " ]", 2);
else result += buffer_append(buffer, "]", 1);
return result;
}
/* write a json value */
static size_t write(struct fjson_object *jso, int level, int flags, struct buffer *buffer)
{
// if object is not set
if (!jso) return buffer_append(buffer, "null", 4);
// check type
switch(jso->o_type) {
case fjson_type_null: return buffer_append(buffer, "null", 4);
case fjson_type_boolean: return write_boolean(jso, buffer);
case fjson_type_double: return write_double(jso, flags, buffer);
case fjson_type_int: return write_int(jso, buffer);
case fjson_type_object: return write_object(jso, level, flags, buffer);
case fjson_type_array: return write_array(jso, level, flags, buffer);
case fjson_type_string: return write_string(jso, buffer);
default: return 0;
}
}
/* wrapper around fwrite() that has the same signature as fjson_write_fn */
static size_t fwrite_wrapper(void *ptr, const char *buffer, size_t size)
{
return fwrite(buffer, 1, size, ptr);
}
/* dummy output function that does not output, but is used to calculate the size */
static size_t calculate(void __attribute__((unused)) *ptr, const char __attribute__((unused)) *buffer, size_t size)
{
return size;
}
/* extended dump to which the helper buffer can be passed */
size_t fjson_object_dump_buffered(struct fjson_object *jso, int flags, char *temp,
size_t size, fjson_write_fn *func, void *ptr)
{
// construct a buffer
struct buffer object;
// initialize the properties
object.buffer = temp;
object.size = size;
object.filled = 0;
object.overflow = func;
object.ptr = ptr;
// write the value
size_t result = write(jso, 0, flags, &object);
// ready if buffer is now empty
if (object.size == 0) return result;
// flush the buffer
return result + buffer_flush(&object);
}
/* extended dump function to string */
size_t fjson_object_dump_ext(struct fjson_object *jso, int flags, fjson_write_fn *func, void *ptr)
{
// create a local 1k buffer on the stack
char buffer[1024];
// pass on to the other function
return fjson_object_dump_buffered(jso, flags, buffer, 1024, func, ptr);
}
/* more simple write function */
size_t fjson_object_dump(struct fjson_object *jso, fjson_write_fn *func, void *ptr)
{
// write the value
return fjson_object_dump_ext(jso, FJSON_TO_STRING_SPACED, func, ptr);
}
/* extended function to calculate the size */
size_t fjson_object_size_ext(struct fjson_object *jso, int flags)
{
// write the value with a dummy function (this is a simple implementation that
// can later be optimized in a pure size-calculating function)
return fjson_object_dump_ext(jso, flags, &calculate, NULL);
}
/* function to calculate the size */
size_t fjson_object_size(struct fjson_object *jso)
{
// write the value with a dummy function (this is a simple implementation that
// can later be optimized in a pure size-calculating function)
return fjson_object_dump(jso, &calculate, NULL);
}
/* write to a file* */
size_t fjson_object_write(struct fjson_object *obj, FILE *fp)
{
return fjson_object_dump_ext(obj, FJSON_TO_STRING_SPACED, fwrite_wrapper, fp);
}
/* write to a file with custom output flags */
size_t fjson_object_write_ext(struct fjson_object *obj, int flags, FILE *fp)
{
return fjson_object_dump_ext(obj, flags, fwrite_wrapper, fp);
}

958
json_tokener.c Normal file
View File

@ -0,0 +1,958 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2016 Rainer Gerhards
*
* 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"
/* this is a work-around until we manage to fix configure.ac */
#ifndef _AIX
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <inttypes.h>
#include "debug.h"
#include "printbuf.h"
#include "arraylist.h"
#include "json_object.h"
#include "json_object_private.h"
#include "json_tokener.h"
#include "json_util.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif /* HAVE_LOCALE_H */
#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
#if !HAVE_STRDUP
#error You do not have strdup on your system.
#endif /* HAVE_STRDUP */
#if !HAVE_STRNCASECMP
#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 fjson_null_str[] = "null";
static const int fjson_null_str_len = sizeof(fjson_null_str) - 1;
static const char fjson_inf_str[] = "Infinity";
static const int fjson_inf_str_len = sizeof(fjson_inf_str) - 1;
static const char fjson_nan_str[] = "NaN";
static const int fjson_nan_str_len = sizeof(fjson_nan_str) - 1;
static const char fjson_true_str[] = "true";
static const int fjson_true_str_len = sizeof(fjson_true_str) - 1;
static const char fjson_false_str[] = "false";
static const int fjson_false_str_len = sizeof(fjson_false_str) - 1;
const char *fjson_tokener_errors[15] = {
"success",
"continue",
"nesting too deep",
"unexpected end of data",
"unexpected character",
"null expected",
"boolean expected",
"number expected",
"array value separator ',' expected",
"quoted object property name expected",
"object property name separator ':' expected",
"object value separator ',' expected",
"invalid string sequence",
"expected comment",
"buffer size overflow"
};
const char *fjson_tokener_error_desc(enum fjson_tokener_error jerr)
{
int jerr_int = (int)jerr;
if (jerr_int < 0 || jerr_int >= (int)(sizeof(fjson_tokener_errors) / sizeof(fjson_tokener_errors[0])))
return "Unknown error, invalid fjson_tokener_error value passed to fjson_tokener_error_desc()";
return fjson_tokener_errors[jerr];
}
enum fjson_tokener_error fjson_tokener_get_error(fjson_tokener * tok)
{
return tok->err;
}
/* Stuff for decoding unicode sequences */
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00)
#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD };
struct fjson_tokener *fjson_tokener_new_ex(int depth)
{
struct fjson_tokener *tok;
tok = (struct fjson_tokener *)calloc(1, sizeof(struct fjson_tokener));
if (!tok)
return NULL;
tok->stack = (struct fjson_tokener_srec *)calloc(depth, sizeof(struct fjson_tokener_srec));
if (!tok->stack) {
free(tok);
return NULL;
}
tok->pb = printbuf_new();
tok->max_depth = depth;
fjson_tokener_reset(tok);
return tok;
}
struct fjson_tokener *fjson_tokener_new(void)
{
return fjson_tokener_new_ex(FJSON_TOKENER_DEFAULT_DEPTH);
}
void fjson_tokener_free(struct fjson_tokener *tok)
{
fjson_tokener_reset(tok);
if (tok->pb)
printbuf_free(tok->pb);
if (tok->stack)
free(tok->stack);
free(tok);
}
static void __attribute__((nonnull(1)))
fjson_tokener_reset_level(struct fjson_tokener *const tok, const int depth)
{
tok->stack[depth].state = fjson_tokener_state_eatws;
tok->stack[depth].saved_state = fjson_tokener_state_start;
fjson_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 fjson_tokener_reset(struct fjson_tokener *const tok)
{
int i;
if (!tok)
return;
for (i = tok->depth; i >= 0; i--)
fjson_tokener_reset_level(tok, i);
tok->depth = 0;
tok->err = fjson_tokener_success;
}
struct fjson_object * __attribute__((nonnull(1)))
fjson_tokener_parse(const char *const str)
{
enum fjson_tokener_error jerr_ignored;
struct fjson_object *obj;
obj = fjson_tokener_parse_verbose(str, &jerr_ignored);
return obj;
}
struct fjson_object * __attribute__((nonnull(1, 2)))
fjson_tokener_parse_verbose(const char *const str,
enum fjson_tokener_error *const error)
{
struct fjson_tokener *tok;
struct fjson_object *obj;
tok = fjson_tokener_new();
if (!tok)
return NULL;
obj = fjson_tokener_parse_ex(tok, str, -1);
*error = tok->err;
if (tok->err != fjson_tokener_success) {
if (obj != NULL)
fjson_object_put(obj);
obj = NULL;
}
fjson_tokener_free(tok);
return obj;
}
#define state tok->stack[tok->depth].state
#define saved_state tok->stack[tok->depth].saved_state
#define current tok->stack[tok->depth].current
#define obj_field_name tok->stack[tok->depth].obj_field_name
/* Optimization:
* fjson_tokener_parse_ex() consumed a lot of CPU in its main loop,
* iterating character-by character. A large performance boost is
* achieved by using tighter loops to locally handle units such as
* comments and strings. Loops that handle an entire token within
* their scope also gather entire strings and pass them to
* printbuf_memappend() in a single call, rather than calling
* printbuf_memappend() one char at a time.
*
* PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is
* common to both the main loop and the tighter loops.
*/
/* PEEK_CHAR(dest, tok) macro:
* Peeks at the current char and stores it in dest.
* Returns 1 on success, sets tok->err and returns 0 if no more chars.
* Implicit inputs: str, len vars
*/
#define PEEK_CHAR(dest, tok) \
(((tok)->char_offset == len) ? \
(((tok)->depth == 0 && state == fjson_tokener_state_eatws && saved_state == fjson_tokener_state_finish) ? \
(((tok)->err = fjson_tokener_success), 0) \
: \
(((tok)->err = fjson_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 fjson_object *fjson_tokener_parse_ex(struct fjson_tokener *tok, const char *str, int len)
{
struct fjson_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 = fjson_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 = fjson_tokener_error_size;
# ifdef HAVE_SETLOCALE
free(oldlocale);
# endif
return NULL;
}
while (PEEK_CHAR(c, tok)) {
redo_char:
switch (state) {
case fjson_tokener_state_eatws:
/* Advance until we change state */
while (isspace((int)c)) {
if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok)))
goto out;
}
if (c == '/' && !(tok->flags & FJSON_TOKENER_STRICT)) {
printbuf_reset(tok->pb);
printbuf_memappend_fast(tok->pb, &c, 1);
state = fjson_tokener_state_comment_start;
} else {
state = saved_state;
goto redo_char;
}
break;
case fjson_tokener_state_start:
switch (c) {
case '{':
state = fjson_tokener_state_eatws;
saved_state = fjson_tokener_state_object_field_start;
current = fjson_object_new_object();
break;
case '[':
state = fjson_tokener_state_eatws;
saved_state = fjson_tokener_state_array;
current = fjson_object_new_array();
break;
case 'I':
case 'i':
state = fjson_tokener_state_inf;
printbuf_reset(tok->pb);
tok->st_pos = 0;
goto redo_char;
case 'N':
case 'n':
state = fjson_tokener_state_null; // or NaN
printbuf_reset(tok->pb);
tok->st_pos = 0;
goto redo_char;
case '\'':
if (tok->flags & FJSON_TOKENER_STRICT) {
/* in STRICT mode only double-quote are allowed */
tok->err = fjson_tokener_error_parse_unexpected;
goto out;
}
/* TODO: verify if FALLTHROUGH is actually right! */
ATTR_FALLTHROUGH
case '"':
state = fjson_tokener_state_string;
printbuf_reset(tok->pb);
tok->quote_char = c;
break;
case 'T':
case 't':
case 'F':
case 'f':
state = fjson_tokener_state_boolean;
printbuf_reset(tok->pb);
tok->st_pos = 0;
goto redo_char;
#if defined(__GNUC__)
case '0' ... '9':
#else
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
#endif
case '-':
state = fjson_tokener_state_number;
printbuf_reset(tok->pb);
tok->is_double = 0;
goto redo_char;
default:
tok->err = fjson_tokener_error_parse_unexpected;
goto out;
}
break;
case fjson_tokener_state_finish:
if (tok->depth == 0)
goto out;
obj = fjson_object_get(current);
fjson_tokener_reset_level(tok, tok->depth);
tok->depth--;
goto redo_char;
case fjson_tokener_state_inf: /* aka starts with 'i' */
{
size_t size_inf;
int is_negative = 0;
printbuf_memappend_fast(tok->pb, &c, 1);
size_inf = fjson_min(tok->st_pos + 1, fjson_inf_str_len);
char *infbuf = tok->pb->buf;
if (*infbuf == '-') {
infbuf++;
is_negative = 1;
}
if ((!(tok->flags & FJSON_TOKENER_STRICT) &&
strncasecmp(fjson_inf_str, infbuf, size_inf) == 0) ||
(strncmp(fjson_inf_str, infbuf, size_inf) == 0)
) {
if (tok->st_pos == fjson_inf_str_len) {
current = fjson_object_new_double(is_negative ? -INFINITY : INFINITY);
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
} else {
tok->err = fjson_tokener_error_parse_unexpected;
goto out;
}
tok->st_pos++;
}
break;
case fjson_tokener_state_null: /* aka starts with 'n' */
{
int size;
int size_nan;
printbuf_memappend_fast(tok->pb, &c, 1);
size = fjson_min(tok->st_pos + 1, fjson_null_str_len);
size_nan = fjson_min(tok->st_pos + 1, fjson_nan_str_len);
if ((!(tok->flags & FJSON_TOKENER_STRICT) &&
strncasecmp(fjson_null_str, tok->pb->buf, size) == 0)
|| (strncmp(fjson_null_str, tok->pb->buf, size) == 0)
) {
if (tok->st_pos == fjson_null_str_len) {
current = NULL;
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
} else if ((!(tok->flags & FJSON_TOKENER_STRICT) &&
strncasecmp(fjson_nan_str, tok->pb->buf, size_nan) == 0) ||
(strncmp(fjson_nan_str, tok->pb->buf, size_nan) == 0)
) {
if (tok->st_pos == fjson_nan_str_len) {
current = fjson_object_new_double(NAN);
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
} else {
tok->err = fjson_tokener_error_parse_null;
goto out;
}
tok->st_pos++;
}
break;
case fjson_tokener_state_comment_start:
if (c == '*') {
state = fjson_tokener_state_comment;
} else if (c == '/') {
state = fjson_tokener_state_comment_eol;
} else {
tok->err = fjson_tokener_error_parse_comment;
goto out;
}
printbuf_memappend_fast(tok->pb, &c, 1);
break;
case fjson_tokener_state_comment:
{
/* Advance until we change state */
const char *case_start = str;
while (c != '*') {
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
goto out;
}
}
printbuf_memappend_fast(tok->pb, case_start, 1 + str - case_start);
state = fjson_tokener_state_comment_end;
}
break;
case fjson_tokener_state_comment_eol:
{
/* Advance until we change state */
const char *case_start = str;
while (c != '\n') {
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
goto out;
}
}
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
MC_DEBUG("fjson_tokener_comment: %s\n", tok->pb->buf);
state = fjson_tokener_state_eatws;
}
break;
case fjson_tokener_state_comment_end:
printbuf_memappend_fast(tok->pb, &c, 1);
if (c == '/') {
MC_DEBUG("fjson_tokener_comment: %s\n", tok->pb->buf);
state = fjson_tokener_state_eatws;
} else {
state = fjson_tokener_state_comment;
}
break;
case fjson_tokener_state_string:
{
/* Advance until we change state */
const char *case_start = str;
while (1) {
if (c == tok->quote_char) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
current = fjson_object_new_string_len(tok->pb->buf, tok->pb->bpos);
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
break;
} else if (c == '\\') {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
saved_state = fjson_tokener_state_string;
state = fjson_tokener_state_string_escape;
break;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
goto out;
}
}
}
break;
case fjson_tokener_state_string_escape:
switch (c) {
case '"':
case '\\':
case '/':
printbuf_memappend_fast(tok->pb, &c, 1);
state = saved_state;
break;
case 'b':
case 'n':
case 'r':
case 't':
case 'f':
if (c == 'b')
printbuf_memappend_fast(tok->pb, "\b", 1);
else if (c == 'n')
printbuf_memappend_fast(tok->pb, "\n", 1);
else if (c == 'r')
printbuf_memappend_fast(tok->pb, "\r", 1);
else if (c == 't')
printbuf_memappend_fast(tok->pb, "\t", 1);
else if (c == 'f')
printbuf_memappend_fast(tok->pb, "\f", 1);
state = saved_state;
break;
case 'u':
tok->ucs_char = 0;
tok->st_pos = 0;
state = fjson_tokener_state_escape_unicode;
break;
default:
tok->err = fjson_tokener_error_parse_string;
goto out;
}
break;
case fjson_tokener_state_escape_unicode:
{
unsigned int got_hi_surrogate = 0;
/* Handle a 4-byte sequence, or two sequences if a surrogate pair */
while (1) {
if (strchr(fjson_hex_chars, c)) {
tok->ucs_char +=
((unsigned int)jt_hexdigit(c) << ((3 - tok->st_pos++) * 4));
if (tok->st_pos == 4) {
unsigned char unescaped_utf[4];
if (got_hi_surrogate) {
if (IS_LOW_SURROGATE(tok->ucs_char)) {
/* Recalculate the ucs_char, then fall thru to process
normally */
tok->ucs_char =
DECODE_SURROGATE_PAIR(got_hi_surrogate,
tok->ucs_char);
} else {
/* Hi surrogate was not followed by a low
* surrogate */
/* Replace the hi and process the rest normally */
printbuf_memappend_fast(tok->pb,
(char *)
utf8_replacement_char,
3);
}
got_hi_surrogate = 0;
/* clang static analyzer thins that got_hi_surrogate
* is never read, * however, it is read on each
* iteration. So I assume clang has a false positive.
* We use the otherwise nonsense statement below to
* make it happy.
*/
if (got_hi_surrogate) {
};
}
if (tok->ucs_char < 0x80) {
unescaped_utf[0] = tok->ucs_char;
printbuf_memappend_fast(tok->pb, (char *)unescaped_utf,
1);
} else if (tok->ucs_char < 0x800) {
unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
printbuf_memappend_fast(tok->pb, (char *)unescaped_utf,
2);
} else if (IS_HIGH_SURROGATE(tok->ucs_char)) {
/* Got a high surrogate. Remember it and look for the
* the beginning of another sequence, which should be the
* low surrogate.
*/
got_hi_surrogate = tok->ucs_char;
/* Not at end, and the next two chars should be "\u" */
if ((tok->char_offset + 1 != len) &&
(tok->char_offset + 2 != len) &&
(str[1] == '\\') && (str[2] == 'u')) {
/* Advance through the 16 bit surrogate, and
* move on to the next sequence. The next
* step is to process the following
* characters.
*/
if (!ADVANCE_CHAR(str, tok)
|| !ADVANCE_CHAR(str, tok)) {
printbuf_memappend_fast(tok->pb,
(char *)
utf8_replacement_char,
3);
}
/* Advance to the first char of the next sequence and
* continue processing with the next sequence.
*/
if (!ADVANCE_CHAR(str, tok)
|| !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb,
(char *)
utf8_replacement_char,
3);
goto out;
}
tok->ucs_char = 0;
tok->st_pos = 0;
continue;/* other fjson_tokener_state_escape_unicode */
} else {
/* Got a high surrogate without another sequence
* following it. Put a replacement char in for
* the hi surrogate and pretend we finished.
*/
printbuf_memappend_fast(tok->pb,
(char *)
utf8_replacement_char,
3);
}
} else if (IS_LOW_SURROGATE(tok->ucs_char)) {
/* Got a low surrogate not preceded by a high */
printbuf_memappend_fast(tok->pb,
(char *)utf8_replacement_char,
3);
} else if (tok->ucs_char < 0x10000) {
unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
printbuf_memappend_fast(tok->pb, (char *)unescaped_utf,
3);
} else if (tok->ucs_char < 0x110000) {
unescaped_utf[0] =
0xf0 | ((tok->ucs_char >> 18) & 0x07);
unescaped_utf[1] =
0x80 | ((tok->ucs_char >> 12) & 0x3f);
unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
printbuf_memappend_fast(tok->pb, (char *)unescaped_utf,
4);
} else {
/* Don't know what we got--insert the replacement char */
printbuf_memappend_fast(tok->pb,
(char *)utf8_replacement_char,
3);
}
state = saved_state;
break;
}
} else {
tok->err = fjson_tokener_error_parse_string;
goto out;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
if (got_hi_surrogate) /* Clean up any pending chars */
printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char,
3);
goto out;
}
}
}
break;
case fjson_tokener_state_boolean:
{
int size1, size2;
printbuf_memappend_fast(tok->pb, &c, 1);
size1 = fjson_min(tok->st_pos + 1, fjson_true_str_len);
size2 = fjson_min(tok->st_pos + 1, fjson_false_str_len);
if ((!(tok->flags & FJSON_TOKENER_STRICT) &&
strncasecmp(fjson_true_str, tok->pb->buf, size1) == 0)
|| (strncmp(fjson_true_str, tok->pb->buf, size1) == 0)
) {
if (tok->st_pos == fjson_true_str_len) {
current = fjson_object_new_boolean(1);
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
} else if ((!(tok->flags & FJSON_TOKENER_STRICT) &&
strncasecmp(fjson_false_str, tok->pb->buf, size2) == 0)
|| (strncmp(fjson_false_str, tok->pb->buf, size2) == 0)) {
if (tok->st_pos == fjson_false_str_len) {
current = fjson_object_new_boolean(0);
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
} else {
tok->err = fjson_tokener_error_parse_boolean;
goto out;
}
tok->st_pos++;
}
break;
case fjson_tokener_state_number:
{
/* Advance until we change state */
const char *case_start = str;
int case_len = 0;
int is_exponent = 0;
int negativesign_next_possible_location = 1;
while (c && strchr(fjson_number_chars, c)) {
++case_len;
/* non-digit characters checks */
/* note: since the main loop condition to get here was
an input starting with 0-9 or '-', we are
protected from input starting with '.' or
e/E. */
if (c == '.') {
if (tok->is_double != 0) {
/* '.' can only be found once, and out of the exponent part.
Thus, if the input is already flagged as double, it
is invalid. */
tok->err = fjson_tokener_error_parse_number;
goto out;
}
tok->is_double = 1;
}
if (c == 'e' || c == 'E') {
if (is_exponent != 0) {
/* only one exponent possible */
tok->err = fjson_tokener_error_parse_number;
goto out;
}
is_exponent = 1;
tok->is_double = 1;
/* the exponent part can begin with a negative sign */
negativesign_next_possible_location = case_len + 1;
}
if (c == '-' && case_len != negativesign_next_possible_location) {
/* If the negative sign is not where expected (ie
start of input or start of exponent part), the
input is invalid. */
tok->err = fjson_tokener_error_parse_number;
goto out;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb, case_start, case_len);
goto out;
}
}
if (case_len > 0)
printbuf_memappend_fast(tok->pb, case_start, case_len);
// Check for -Infinity
if (tok->pb->buf[0] == '-' && case_len == 1 && (c == 'i' || c == 'I')) {
state = fjson_tokener_state_inf;
goto redo_char;
}
}
{
int64_t num64;
double numd;
if (!tok->is_double && fjson_parse_int64(tok->pb->buf, &num64) == 0) {
if (num64 && tok->pb->buf[0] == '0' && (tok->flags & FJSON_TOKENER_STRICT)) {
/* in strict mode, number must not start with 0 */
tok->err = fjson_tokener_error_parse_number;
goto out;
}
current = fjson_object_new_int64(num64);
} else if (tok->is_double && fjson_parse_double(tok->pb->buf, &numd) == 0) {
current = fjson_object_new_double_s(numd, tok->pb->buf);
} else {
tok->err = fjson_tokener_error_parse_number;
goto out;
}
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
goto redo_char;
}
break;
case fjson_tokener_state_array_after_sep:
case fjson_tokener_state_array:
if (c == ']') {
if (state == fjson_tokener_state_array_after_sep && (tok->flags & FJSON_TOKENER_STRICT)) {
tok->err = fjson_tokener_error_parse_unexpected;
goto out;
}
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
} else {
if (tok->depth >= tok->max_depth - 1) {
tok->err = fjson_tokener_error_depth;
goto out;
}
state = fjson_tokener_state_array_add;
tok->depth++;
fjson_tokener_reset_level(tok, tok->depth);
goto redo_char;
}
break;
case fjson_tokener_state_array_add:
fjson_object_array_add(current, obj);
saved_state = fjson_tokener_state_array_sep;
state = fjson_tokener_state_eatws;
goto redo_char;
case fjson_tokener_state_array_sep:
if (c == ']') {
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
} else if (c == ',') {
saved_state = fjson_tokener_state_array_after_sep;
state = fjson_tokener_state_eatws;
} else {
tok->err = fjson_tokener_error_parse_array;
goto out;
}
break;
case fjson_tokener_state_object_field_start:
case fjson_tokener_state_object_field_start_after_sep:
if (c == '}') {
if (state == fjson_tokener_state_object_field_start_after_sep &&
(tok->flags & FJSON_TOKENER_STRICT)) {
tok->err = fjson_tokener_error_parse_unexpected;
goto out;
}
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
} else if (c == '"' || c == '\'') {
tok->quote_char = c;
printbuf_reset(tok->pb);
state = fjson_tokener_state_object_field;
} else {
tok->err = fjson_tokener_error_parse_object_key_name;
goto out;
}
break;
case fjson_tokener_state_object_field:
{
/* Advance until we change state */
const char *case_start = str;
while (1) {
if (c == tok->quote_char) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
obj_field_name = strdup(tok->pb->buf);
saved_state = fjson_tokener_state_object_field_end;
state = fjson_tokener_state_eatws;
break;
} else if (c == '\\') {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
saved_state = fjson_tokener_state_object_field;
state = fjson_tokener_state_string_escape;
break;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
printbuf_memappend_fast(tok->pb, case_start, str - case_start);
goto out;
}
}
}
break;
case fjson_tokener_state_object_field_end:
if (c == ':') {
saved_state = fjson_tokener_state_object_value;
state = fjson_tokener_state_eatws;
} else {
tok->err = fjson_tokener_error_parse_object_key_sep;
goto out;
}
break;
case fjson_tokener_state_object_value:
if (tok->depth >= tok->max_depth - 1) {
tok->err = fjson_tokener_error_depth;
goto out;
}
state = fjson_tokener_state_object_value_add;
tok->depth++;
fjson_tokener_reset_level(tok, tok->depth);
goto redo_char;
case fjson_tokener_state_object_value_add:
fjson_object_object_add(current, obj_field_name, obj);
free(obj_field_name);
obj_field_name = NULL;
saved_state = fjson_tokener_state_object_sep;
state = fjson_tokener_state_eatws;
goto redo_char;
case fjson_tokener_state_object_sep:
if (c == '}') {
saved_state = fjson_tokener_state_finish;
state = fjson_tokener_state_eatws;
} else if (c == ',') {
saved_state = fjson_tokener_state_object_field_start_after_sep;
state = fjson_tokener_state_eatws;
} else {
tok->err = fjson_tokener_error_parse_object_value_sep;
goto out;
}
break;
default:
/* TODO: this should not happen, emit error msg? */
break;
}
if (!ADVANCE_CHAR(str, tok))
goto out;
} /* while(POP_CHAR) */
out:
if (c && (state == fjson_tokener_state_finish) && (tok->depth == 0) && (tok->flags & FJSON_TOKENER_STRICT)) {
/* unexpected char after JSON data */
tok->err = fjson_tokener_error_parse_unexpected;
}
if (!c) { /* We hit an eof char (0) */
if (state != fjson_tokener_state_finish && saved_state != fjson_tokener_state_finish)
tok->err = fjson_tokener_error_parse_eof;
}
#ifdef HAVE_SETLOCALE
setlocale(LC_NUMERIC, oldlocale);
if (oldlocale)
free(oldlocale);
#endif
if (tok->err == fjson_tokener_success) {
fjson_object *ret = fjson_object_get(current);
int ii;
/* Partially reset, so we parse additional objects on subsequent calls. */
for (ii = tok->depth; ii >= 0; ii--)
fjson_tokener_reset_level(tok, ii);
return ret;
}
MC_DEBUG("fjson_tokener_parse_ex: error %s at offset %d\n", fjson_tokener_errors[tok->err], tok->char_offset);
return NULL;
}
void fjson_tokener_set_flags(struct fjson_tokener *tok, int flags)
{
tok->flags = flags;
}

221
json_tokener.h Normal file
View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _fj_json_tokener_h_
#define _fj_json_tokener_h_
#include <stddef.h>
#include "json_object.h"
#ifdef __cplusplus
extern "C" {
#endif
enum fjson_tokener_error {
fjson_tokener_success,
fjson_tokener_continue,
fjson_tokener_error_depth,
fjson_tokener_error_parse_eof,
fjson_tokener_error_parse_unexpected,
fjson_tokener_error_parse_null,
fjson_tokener_error_parse_boolean,
fjson_tokener_error_parse_number,
fjson_tokener_error_parse_array,
fjson_tokener_error_parse_object_key_name,
fjson_tokener_error_parse_object_key_sep,
fjson_tokener_error_parse_object_value_sep,
fjson_tokener_error_parse_string,
fjson_tokener_error_parse_comment,
fjson_tokener_error_size
};
enum fjson_tokener_state {
fjson_tokener_state_eatws,
fjson_tokener_state_start,
fjson_tokener_state_finish,
fjson_tokener_state_null,
fjson_tokener_state_comment_start,
fjson_tokener_state_comment,
fjson_tokener_state_comment_eol,
fjson_tokener_state_comment_end,
fjson_tokener_state_string,
fjson_tokener_state_string_escape,
fjson_tokener_state_escape_unicode,
fjson_tokener_state_boolean,
fjson_tokener_state_number,
fjson_tokener_state_array,
fjson_tokener_state_array_add,
fjson_tokener_state_array_sep,
fjson_tokener_state_object_field_start,
fjson_tokener_state_object_field,
fjson_tokener_state_object_field_end,
fjson_tokener_state_object_value,
fjson_tokener_state_object_value_add,
fjson_tokener_state_object_sep,
fjson_tokener_state_array_after_sep,
fjson_tokener_state_object_field_start_after_sep,
fjson_tokener_state_inf
};
struct fjson_tokener_srec
{
enum fjson_tokener_state state, saved_state;
struct fjson_object *obj;
struct fjson_object *current;
char *obj_field_name;
};
#define FJSON_TOKENER_DEFAULT_DEPTH 32
struct fjson_tokener
{
char *str;
struct printbuf *pb;
int max_depth, depth, is_double, st_pos, char_offset;
enum fjson_tokener_error err;
unsigned int ucs_char;
char quote_char;
struct fjson_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 fjson_tokener_set_flags()
*/
#define FJSON_TOKENER_STRICT 0x01
/**
* Given an error previously returned by fjson_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 *fjson_tokener_error_desc(enum fjson_tokener_error jerr);
/**
* Retrieve the error caused by the last call to fjson_tokener_parse_ex(),
* or fjson_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 fjson_tokener_continue.
*
* See also fjson_tokener_error_desc().
*/
enum fjson_tokener_error fjson_tokener_get_error(struct fjson_tokener *tok);
extern struct fjson_tokener* fjson_tokener_new(void);
extern struct fjson_tokener* fjson_tokener_new_ex(int depth);
extern void fjson_tokener_free(struct fjson_tokener *tok);
extern void fjson_tokener_reset(struct fjson_tokener *tok);
extern struct fjson_object* fjson_tokener_parse(const char *str);
extern struct fjson_object* fjson_tokener_parse_verbose(const char *str, enum fjson_tokener_error *error);
/**
* Set flags that control how parsing will be done.
*/
extern void fjson_tokener_set_flags(struct fjson_tokener *tok, int flags);
/**
* Parse a string and return a non-NULL fjson_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 fjson_tokener_get_error() will be return
* fjson_tokener_continue.
* fjson_tokener_parse_ex() can then be called with additional bytes in str
* to continue the parsing.
*
* If fjson_tokener_parse_ex() returns NULL and the error anything other than
* fjson_tokener_continue, a fatal error has occurred and parsing must be
* halted. Then tok object must not be re-used until fjson_tokener_reset() is
* called.
*
* When a valid JSON value is parsed, a non-NULL fjson_object will be
* returned. Also, fjson_tokener_get_error() will return fjson_tokener_success.
* Be sure to check the type with fjson_object_is_type() or
* fjson_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 fjson_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
fjson_object *jobj = NULL;
const char *mystring = NULL;
int stringlen = 0;
enum fjson_tokener_error jerr;
do {
mystring = ... // get JSON string, e.g. read from file, etc...
stringlen = strlen(mystring);
jobj = fjson_tokener_parse_ex(tok, mystring, stringlen);
} while ((jerr = fjson_tokener_get_error(tok)) == fjson_tokener_continue);
if (jerr != fjson_tokener_success)
{
fprintf(stderr, "Error: %s\n", fjson_tokener_error_desc(jerr));
// Handle errors, as appropriate for your application.
}
if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
{
// Handle extra characters after parsed object as desired.
// e.g. issue an error, parse another object from that point, etc...
}
// Success, use jobj here.
@endcode
*
* @param tok a fjson_tokener previously allocated with fjson_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 fjson_object* fjson_tokener_parse_ex(struct fjson_tokener *tok,
const char *str, int len);
#ifndef FJSON_NATIVE_API_ONLY
#define json_tokener fjson_tokener
#define json_tokener_error fjson_tokener_error
extern const char* fjson_tokener_errors[15];
#define json_tokener_errors fjson_tokener_errors
#define json_tokener_continue fjson_tokener_continue
#define json_tokener_reset fjson_tokener_reset
#define json_tokener_new() fjson_tokener_new()
#define json_tokener_parse fjson_tokener_parse
#define json_tokener_parse_ex(a, b, c) fjson_tokener_parse_ex((a), (b), (c))
#define json_tokener_free(a) fjson_tokener_free((a))
#define json_tokener_error_desc(a) fjson_tokener_error_desc((a))
#endif
#ifdef __cplusplus
}
#endif
#endif

290
json_util.c Normal file
View File

@ -0,0 +1,290 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#undef realloc
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdint.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if !defined(HAVE_SNPRINTF)
# error You do not have snprintf on your system.
#endif /* HAVE_SNPRINTF */
#include "debug.h"
#include "printbuf.h"
#include "json_object.h"
#include "json_tokener.h"
#include "json_util.h"
static int sscanf_is_broken = 0;
static int sscanf_is_broken_testdone = 0;
static void sscanf_is_broken_test(void);
/*
* Create a JSON object from already opened file descriptor.
*
* This function can be helpful, when you opened the file already,
* e.g. when you have a temp file.
* Note, that the fd must be readable at the actual position, i.e.
* use lseek(fd, 0, SEEK_SET) before.
*/
struct fjson_object* fjson_object_from_fd(int fd)
{
struct printbuf *pb;
struct fjson_object *obj;
char buf[FJSON_FILE_BUF_SIZE];
int ret;
if(!(pb = printbuf_new())) {
MC_ERROR("fjson_object_from_file: printbuf_new failed\n");
return NULL;
}
while((ret = read(fd, buf, FJSON_FILE_BUF_SIZE)) > 0) {
printbuf_memappend(pb, buf, ret);
}
if(ret < 0) {
MC_ERROR("fjson_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno));
printbuf_free(pb);
return NULL;
}
obj = fjson_tokener_parse(pb->buf);
printbuf_free(pb);
return obj;
}
struct fjson_object* fjson_object_from_file(const char *filename)
{
struct fjson_object *obj;
int fd;
if((fd = open(filename, O_RDONLY)) < 0) {
MC_ERROR("fjson_object_from_file: error opening file %s: %s\n",
filename, strerror(errno));
return NULL;
}
obj = fjson_object_from_fd(fd);
close(fd);
return obj;
}
/* extended "format and write to file" function */
int fjson_object_to_file_ext(const char *filename, struct fjson_object *obj, int flags)
{
const char *fjson_str;
int fd, ret;
unsigned int wpos, wsize;
if(!obj) {
MC_ERROR("fjson_object_to_file: object is null\n");
return -1;
}
if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
MC_ERROR("fjson_object_to_file: error opening file %s: %s\n",
filename, strerror(errno));
return -1;
}
if(!(fjson_str = fjson_object_to_json_string_ext(obj,flags))) {
close(fd);
return -1;
}
wsize = (unsigned int)(strlen(fjson_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
wpos = 0;
while(wpos < wsize) {
if((ret = write(fd, fjson_str + wpos, wsize-wpos)) < 0) {
close(fd);
MC_ERROR("fjson_object_to_file: error writing file %s: %s\n",
filename, strerror(errno));
return -1;
}
/* because of the above check for ret < 0, we can safely cast and add */
wpos += (unsigned int)ret;
}
close(fd);
return 0;
}
// backwards compatible "format and write to file" function
int fjson_object_to_file(const char *filename, struct fjson_object *obj)
{
return fjson_object_to_file_ext(filename, obj, FJSON_TO_STRING_PLAIN);
}
int fjson_parse_double(const char *buf, double *retval)
{
return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
}
/*
* Not all implementations of sscanf actually work properly.
* Check whether the one we're currently using does, and if
* it's broken, enable the workaround code.
*/
static void sscanf_is_broken_test(void)
{
int64_t num64;
int ret_errno, is_int64_min, ret_errno2, is_int64_max;
(void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64);
ret_errno = errno;
is_int64_min = (num64 == INT64_MIN);
(void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64);
ret_errno2 = errno;
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 fjson_parse_int64(const char *buf, int64_t *retval)
{
int64_t num64;
const char *buf_sig_digits;
int orig_has_neg;
int saved_errno;
if (!sscanf_is_broken_testdone)
{
sscanf_is_broken_test();
sscanf_is_broken_testdone = 1;
}
// Skip leading spaces
while (isspace((int)*buf) && *buf)
buf++;
errno = 0; // sscanf won't always set errno, so initialize
if (sscanf(buf, "%" SCNd64, &num64) != 1)
{
MC_DEBUG("Failed to parse, sscanf != 1\n");
return 1;
}
saved_errno = errno;
buf_sig_digits = buf;
orig_has_neg = 0;
if (*buf_sig_digits == '-')
{
buf_sig_digits++;
orig_has_neg = 1;
}
// Not all sscanf implementations actually work
if (sscanf_is_broken && saved_errno != ERANGE)
{
char buf_cmp[100];
char *buf_cmp_start = buf_cmp;
int recheck_has_neg = 0;
int buf_cmp_len;
// Skip leading zeros, but keep at least one digit
while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0')
buf_sig_digits++;
if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
orig_has_neg = 0; // "-0" is the same as just plain "0"
snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
if (*buf_cmp_start == '-')
{
recheck_has_neg = 1;
buf_cmp_start++;
}
// No need to skip leading spaces or zeros here.
buf_cmp_len = strlen(buf_cmp_start);
/**
* If the sign is different, or
* some of the digits are different, or
* there is another digit present in the original string
* then we have NOT successfully parsed the value.
*/
if (orig_has_neg != recheck_has_neg ||
strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
((int)strlen(buf_sig_digits) != buf_cmp_len &&
isdigit((int)buf_sig_digits[buf_cmp_len])
)
)
{
saved_errno = ERANGE;
}
}
// Not all sscanf impl's set the value properly when out of range.
// Always do this, even for properly functioning implementations,
// since it shouldn't slow things down much.
if (saved_errno == ERANGE)
{
if (orig_has_neg)
num64 = INT64_MIN;
else
num64 = INT64_MAX;
}
*retval = num64;
return 0;
}
#define NELEM(a) (sizeof(a) / sizeof(a[0]))
static const char* fjson_type_name[] = {
/* If you change this, be sure to update the enum fjson_type definition too */
"null",
"boolean",
"double",
"int",
"object",
"array",
"string",
};
const char *fjson_type_to_name(enum fjson_type o_type)
{
int o_type_int = (int)o_type;
if (o_type_int < 0 || o_type_int >= (int)NELEM(fjson_type_name))
{
MC_ERROR("fjson_type_to_name: type %d is out of range [0,%zu]\n", o_type, NELEM(fjson_type_name));
return NULL;
}
return fjson_type_name[o_type];
}

52
json_util.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#ifndef _fj_json_util_h_
#define _fj_json_util_h_
#include "json_object.h"
#ifndef fjson_min
#define fjson_min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef fjson_max
#define fjson_max(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define FJSON_FILE_BUF_SIZE 4096
/* utility functions */
extern struct fjson_object* fjson_object_from_file(const char *filename);
extern struct fjson_object* fjson_object_from_fd(int fd);
extern int fjson_object_to_file(const char *filename, struct fjson_object *obj);
extern int fjson_object_to_file_ext(const char *filename, struct fjson_object *obj, int flags);
extern int fjson_parse_int64(const char *buf, int64_t *retval);
extern int fjson_parse_double(const char *buf, double *retval);
/**
* Return a string describing the type of the object.
* e.g. "int", or "object", etc...
*/
extern const char *fjson_type_to_name(enum fjson_type o_type);
#ifndef FJSON_NATIVE_API_ONLY
#define json_type_to_name fjson_type_to_name
#endif
#ifdef __cplusplus
}
#endif
#endif

15
json_version.c Normal file
View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2012 Eric Haszlakiewicz
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*/
#include "config.h"
#include "json.h"
const char *fjson_version(void)
{
return VERSION;
}

View File

@ -0,0 +1,11 @@
prefix=
exec_prefix=
libdir=@abs_top_builddir@
includedir=@abs_top_srcdir@
Name: json
Description: JSON implementation in C
Version: @VERSION@
Requires:
Libs: -L@abs_top_builddir@ -ljson-c
Cflags: -I@abs_top_srcdir@

12
libfastjson.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libfastjson
Description: a fast JSON implementation in C
Version: @VERSION@
Requires:
Libs.private: @LIBS@
Libs: -L${libdir} -lfastjson
Cflags: -I${includedir}/libfastjson

11156
ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

51
m4/atomic_operations.m4 Normal file
View File

@ -0,0 +1,51 @@
# rsyslog
#
# atomic_operations.m4 - autoconf macro to check if compiler supports atomic
# operations
#
# rgerhards, 2008-09-18, added based on
# http://svn.apache.org/repos/asf/apr/apr/trunk/configure.in
#
#
AC_DEFUN([RS_ATOMIC_OPERATIONS],
[AC_CACHE_CHECK([whether the compiler provides atomic builtins], [ap_cv_atomic_builtins],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
unsigned long val = 1010, tmp, *mem = &val;
if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020)
return 1;
tmp = val;
if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010)
return 1;
if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0)
return 1;
tmp = 3030;
if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp)
return 1;
if (__sync_lock_test_and_set(&val, 4040) != 3030)
return 1;
mem = &tmp;
if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp)
return 1;
__sync_synchronize();
if (mem != &val)
return 1;
return 0;
]])], [ap_cv_atomic_builtins=yes], [ap_cv_atomic_builtins=no])])
if test "$ap_cv_atomic_builtins" = "yes"; then
AC_DEFINE(HAVE_ATOMIC_BUILTINS, 1, [Define if compiler provides atomic builtins])
fi
])

View File

@ -0,0 +1,51 @@
# rsyslog
#
# atomic_operations.m4 - autoconf macro to check if compiler supports atomic
# operations
#
# rgerhards, 2008-09-18, added based on
# http://svn.apache.org/repos/asf/apr/apr/trunk/configure.in
#
#
AC_DEFUN([RS_ATOMIC_OPERATIONS_64BIT],
[AC_CACHE_CHECK([whether the compiler provides atomic builtins for 64 bit data types], [ap_cv_atomic_builtins_64],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
unsigned long long val = 1010, tmp, *mem = &val;
if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020)
return 1;
tmp = val;
if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010)
return 1;
if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0)
return 1;
tmp = 3030;
if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp)
return 1;
if (__sync_lock_test_and_set(&val, 4040) != 3030)
return 1;
mem = &tmp;
if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp)
return 1;
__sync_synchronize();
if (mem != &val)
return 1;
return 0;
]])], [ap_cv_atomic_builtins_64=yes], [ap_cv_atomic_builtins_64=no])])
if test "$ap_cv_atomic_builtins_64" = "yes"; then
AC_DEFINE(HAVE_ATOMIC_BUILTINS64, 1, [Define if compiler provides 64 bit atomic builtins])
fi
])

View File

@ -0,0 +1,65 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
done
])dnl AX_APPEND_COMPILE_FLAGS

71
m4/ax_append_flag.m4 Normal file
View File

@ -0,0 +1,71 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
#
# DESCRIPTION
#
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
# added in between.
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
# FLAG.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AC_DEFUN([AX_APPEND_FLAG],
[dnl
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
AS_VAR_SET_IF(FLAGS,[
AS_CASE([" AS_VAR_GET(FLAGS) "],
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
[
AS_VAR_APPEND(FLAGS,[" $1"])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
],
[
AS_VAR_SET(FLAGS,[$1])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG

View File

@ -0,0 +1,74 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

37
m4/ax_require_defined.m4 Normal file
View File

@ -0,0 +1,37 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED

8388
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

437
m4/ltoptions.m4 vendored Normal file
View File

@ -0,0 +1,437 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option '$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
[_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the 'shared' and
# 'disable-shared' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the 'static' and
# 'disable-static' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the 'fast-install'
# and 'disable-fast-install' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_AIX_SONAME([DEFAULT])
# ----------------------------------
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
m4_define([_LT_WITH_AIX_SONAME],
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[[5-9]]*,yes)
AC_MSG_CHECKING([which variant of shared library versioning to provide])
AC_ARG_WITH([aix-soname],
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
[case $withval in
aix|svr4|both)
;;
*)
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
;;
esac
lt_cv_with_aix_soname=$with_aix_soname],
[AC_CACHE_VAL([lt_cv_with_aix_soname],
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
with_aix_soname=$lt_cv_with_aix_soname])
AC_MSG_RESULT([$with_aix_soname])
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
# the AIX toolchain works better with OBJECT_MODE set (default 32).
if test 64 = "${OBJECT_MODE-32}"; then
shared_archive_member_spec=shr_64
else
shared_archive_member_spec=shr
fi
fi
;;
*)
with_aix_soname=aix
;;
esac
_LT_DECL([], [shared_archive_member_spec], [0],
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
])# _LT_WITH_AIX_SONAME
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

124
m4/ltsugar.m4 vendored Normal file
View File

@ -0,0 +1,124 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59, which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 4179 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.6])
m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.6'
macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

99
m4/lt~obsolete.m4 vendored Normal file
View File

@ -0,0 +1,99 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

215
missing Executable file
View File

@ -0,0 +1,215 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

235
printbuf.c Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
* The copyrights to the contents of this file are licensed under the MIT License
* (http://www.opensource.org/licenses/mit-license.php)
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#else /* !HAVE_STDARG_H */
# error Not enough var arg support!
#endif /* HAVE_STDARG_H */
#include "json.h"
#include "debug.h"
#include "printbuf.h"
static int printbuf_initial_size = 32;
static int printbuf_extend(struct printbuf *p, int min_size);
void fjson_global_set_printbuf_initial_size(int size)
{
printbuf_initial_size = size;
}
struct printbuf* printbuf_new(void)
{
struct printbuf *p;
p = (struct printbuf*)malloc(sizeof(struct printbuf));
if(!p) return NULL;
/* note: *ALL* data items must be initialized! */
p->size = printbuf_initial_size;
p->bpos = 0;
if(!(p->buf = (char*)malloc(p->size))) {
free(p);
return NULL;
}
return p;
}
/**
* Extend the buffer p so it has a size of at least min_size.
*
* If the current size is large enough, nothing is changed.
*
* Note: this does not check the available space! The caller
* is responsible for performing those calculations.
*/
static int printbuf_extend(struct printbuf *p, int min_size)
{
char *t;
int new_size;
if (p->size >= min_size)
return 0;
new_size = 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",
p->bpos, min_size, p->size, new_size);
#endif /* PRINTBUF_DEBUG */
if(!(t = (char*)realloc(p->buf, new_size)))
return -1;
p->size = new_size;
p->buf = t;
return 0;
}
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
{
if (p->size <= p->bpos + size + 1) {
if (printbuf_extend(p, p->bpos + size + 1) < 0)
return -1;
}
if(size > 1)
memcpy(p->buf + p->bpos, buf, size);
else
p->buf[p->bpos]= *buf;
p->bpos += size;
p->buf[p->bpos]= '\0';
return size;
}
/* same as printbuf_memappend(), but contains some performance enhancements */
void printbuf_memappend_no_nul(struct printbuf *p, const char *buf, const int size)
{
if (p->size <= p->bpos + size) {
if (printbuf_extend(p, p->bpos + size) < 0)
/* ignore new data, best we can do */
return;
}
memcpy(p->buf + p->bpos, buf, size);
p->bpos += size;
}
/* add a single character to printbuf */
void printbuf_memappend_char(struct printbuf *p, const char c)
{
if (p->size <= p->bpos + 1) {
if (printbuf_extend(p, p->bpos + 1) < 0)
/* ignore new data, best we can do */
return;
}
p->buf[p->bpos++]= c;
}
void printbuf_terminate_string(struct printbuf *const p)
{
if (p->size <= p->bpos + 1) {
if (printbuf_extend(p, p->bpos + 1) < 0)
--p->bpos; /* overwrite last byte, best we can do */
}
p->buf[p->bpos]= '\0';
}
int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
{
int size_needed;
if (offset == -1)
offset = pb->bpos;
size_needed = offset + len;
if (pb->size < size_needed)
{
if (printbuf_extend(pb, size_needed) < 0)
return -1;
}
memset(pb->buf + offset, charvalue, len);
if (pb->bpos < size_needed)
pb->bpos = size_needed;
return 0;
}
#if !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */
# error Need vsnprintf!
#endif /* !HAVE_VSNPRINTF */
#if !defined(HAVE_VASPRINTF)
/* CAW: compliant version of vasprintf */
/* Note: on OpenCSW, we have vasprintf() inside the headers, but not inside the lib.
* So we need to use a different name, else we get issues with redefinitions. We
* we solve this by using the macro below, which just renames the function BUT
* does not affect the (variadic) arguments.
* rgerhards, 2017-04-11
*/
#define vasprintf rs_vasprintf
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
static int rs_vasprintf(char **buf, const char *fmt, va_list ap)
{
int chars;
char *b;
static char _T_emptybuffer = '\0';
if(!buf) { return -1; }
/* 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 */
b = (char*)malloc(sizeof(char)*chars);
if(!b) { return -1; }
if((chars = vsprintf(b, fmt, ap)) < 0) {
free(b);
} else {
*buf = b;
}
return chars;
}
#pragma GCC diagnostic pop
#endif /* !HAVE_VASPRINTF */
int sprintbuf(struct printbuf *p, const char *msg, ...)
{
va_list ap;
char *t;
int size;
char buf[128];
/* user stack buffer first */
va_start(ap, msg);
size = vsnprintf(buf, 128, msg, ap);
va_end(ap);
/* if string is greater than stack buffer, then use dynamic string
with vasprintf. Note: some implementation of vsnprintf return -1
if output is truncated whereas some return the number of bytes that
would have been written - this code handles both cases. */
if(size == -1 || size > 127) {
va_start(ap, msg);
if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
va_end(ap);
printbuf_memappend(p, t, size);
free(t);
return size;
} else {
printbuf_memappend(p, buf, size);
return size;
}
}
void printbuf_reset(struct printbuf *p)
{
p->buf[0] = '\0';
p->bpos = 0;
}
void printbuf_free(struct printbuf *p)
{
if(p) {
free(p->buf);
free(p);
}
}

84
printbuf.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*
* Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
* The copyrights to the contents of this file are licensed under the MIT License
* (http://www.opensource.org/licenses/mit-license.php)
*/
#ifndef _fj_printbuf_h_
#define _fj_printbuf_h_
#ifdef __cplusplus
extern "C" {
#endif
struct printbuf {
char *buf;
int bpos;
int size;
};
extern struct printbuf*
printbuf_new(void);
/* As an optimization, printbuf_memappend_fast is defined as a macro
* that handles copying data if the buffer is large enough; otherwise
* it invokes printbuf_memappend_real() which performs the heavy
* lifting of realloc()ing the buffer and copying data.
* Your code should not use printbuf_memappend directly--use
* printbuf_memappend_fast instead.
*/
extern int
printbuf_memappend(struct printbuf *p, const char *buf, int size);
#define printbuf_memappend_fast(p, bufptr, bufsize) \
do { \
if ((p->size - p->bpos) > bufsize) { \
memcpy(p->buf + p->bpos, (bufptr), bufsize); \
p->bpos += bufsize; \
p->buf[p->bpos]= '\0'; \
} else { printbuf_memappend(p, (bufptr), bufsize); }\
} while (0)
/* The following functions provide a printbuf interface where the
* string terminator '\0' is not always written. This is faster, but
* the string cannot be used with standard functions while being
* constructed. To do so, printbuf_terminate_string() must be
* called first.
*/
void printbuf_memappend_no_nul(struct printbuf *p, const char *buf, int size);
void printbuf_memappend_char(struct printbuf *p, const char c);
void printbuf_terminate_string(struct printbuf *const p);
#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, ...) __attribute__((__format__(__printf__, 2, 3)));
extern void
printbuf_reset(struct printbuf *p);
extern void
printbuf_free(struct printbuf *p);
#ifdef __cplusplus
}
#endif
#endif

148
test-driver Executable file
View File

@ -0,0 +1,148 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--]
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
*) break;;
esac
shift
done
missing_opts=
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
if test x"$missing_opts" != x; then
usage_error "the following mandatory options are missing:$missing_opts"
fi
if test $# -eq 0; then
usage_error "missing argument"
fi
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
"$@" >$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $tweaked_estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report the test outcome and exit status in the logs, so that one can
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
echo "$res $test_name (exit status: $estatus)" >>$log_file
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

92
tests/Makefile.am Normal file
View File

@ -0,0 +1,92 @@
export VALGRIND=@VALGRIND@
LDADD = $(top_builddir)/libfastjson.la \
$(top_builddir)/libfastjson-internal.la
AM_CFLAGS = $(WARN_CFLAGS)
TESTS=
TESTS+= ucs_copyright_char.test
TESTS+= test_float.test
TESTS+= test1.test
TESTS+= test2.test
TESTS+= test4.test
TESTS+= testReplaceExisting.test
TESTS+= test_parse_int64.test
TESTS+= test_cast.test
TESTS+= test_parse.test
TESTS+= test_locale.test
TESTS+= test_charcase.test
TESTS+= test_printbuf.test
TESTS+= test_obj_iter-del.test
TESTS+= test_object_object_add_ex.test
TESTS+= test_many_subobj.test
TESTS+= test_obj_obj_get_ex-null.test
# we officially do NOT support NUL bytes (however, we may
# later add a workaround to at least transparently pass them
# through, thus I keep this as reference).
#TESTS+= test_null.test
check_PROGRAMS=
check_PROGRAMS += $(TESTS:.test=)
# some programs that do internal checking
check_PROGRAMS += chk_version \
cr_obj_multi
TESTS += chk_version
check_PROGRAMS += chk_version \
cr_obj_multi
cr_obj_multi_SOURCES = cr_obj_multi.c
chk_version_SOURCES = chk_version.c
test_printbuf_SOURCES = test_printbuf.c
# Note: handled by test1.test
check_PROGRAMS += test1Formatted
test1Formatted_SOURCES = test1.c parse_flags.c parse_flags.h
test1Formatted_CPPFLAGS = -DTEST_FORMATTED
# Note: handled by test2.test
check_PROGRAMS += test2Formatted
test2Formatted_SOURCES = test2.c parse_flags.c parse_flags.h
test2Formatted_CPPFLAGS = -DTEST_FORMATTED
# Note: handled by object_object_add_ex.test
check_PROGRAMS += test_object_object_add_exFormatted
test_object_object_add_exFormatted_SOURCES = test_object_object_add_ex.c parse_flags.c parse_flags.h
test_object_object_add_exFormatted_CPPFLAGS = -DTEST_FORMATTED
EXTRA_DIST=
EXTRA_DIST += $(TESTS)
EXTRA_DIST += test-defs.sh
EXTRA_DIST += test1.expected
EXTRA_DIST += test1Formatted_plain.expected
EXTRA_DIST += test1Formatted_pretty.expected
EXTRA_DIST += test1Formatted_spaced.expected
EXTRA_DIST += test2.expected
EXTRA_DIST += test2Formatted_plain.expected
EXTRA_DIST += test2Formatted_pretty.expected
EXTRA_DIST += test2Formatted_spaced.expected
EXTRA_DIST += test4.expected
EXTRA_DIST += ucs_copyright_char.expected
EXTRA_DIST += test_float.expected
EXTRA_DIST += test_cast.expected
EXTRA_DIST += test_charcase.expected
EXTRA_DIST += test_locale.expected
EXTRA_DIST += test_null.expected
EXTRA_DIST += test_parse.expected
EXTRA_DIST += test_parse_int64.expected
EXTRA_DIST += test_printbuf.expected
EXTRA_DIST += testReplaceExisting.expected
EXTRA_DIST += test_obj_iter-del.expected
EXTRA_DIST += test_object_object_add_ex.expected
EXTRA_DIST += test_object_object_add_exFormatted_plain.expected
EXTRA_DIST += test_object_object_add_exFormatted_pretty.expected
EXTRA_DIST += test_object_object_add_exFormatted_spaced.expected
EXTRA_DIST += test_many_subobj.expected
EXTRA_DIST += test_obj_obj_get_ex-null.expected
testsubdir=testSubDir
TESTS_ENVIRONMENT = top_builddir=$(top_builddir)

1327
tests/Makefile.in Normal file

File diff suppressed because it is too large Load Diff

228
tests/chk_version Executable file
View File

@ -0,0 +1,228 @@
#! /bin/bash
# chk_version - temporary wrapper script for .libs/chk_version
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-0.1
#
# The chk_version program cannot be directly executed until all the libtool
# libraries that it depends on are installed.
#
# This wrapper script should never be moved out of the build directory.
# If it is, it will not operate correctly.
# Sed substitution that helps us do robust quoting. It backslashifies
# metacharacters that are still active within double-quoted strings.
sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
# Be Bourne compatible
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
else
case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
fi
BIN_SH=xpg4; export BIN_SH # for Tru64
DUALCASE=1; export DUALCASE # for MKS sh
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
relink_command="(cd /home/rger/proj/libfastjson/tests; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/home/rger/proj/phd/software/cplex/opl/bin/x86-64_linux/; export LD_LIBRARY_PATH; PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/rger/proj/phd/software/cplex/cplex/bin/x86-64_linux/:/home/rger/proj/phd/software/cplex/opl/bin/x86-64_linux/:/home/rger/proj/phd/software/cplex/opl/oplide:/home/rger/proj/coverty/cov-analysis-linux64-2017.07/bin; export PATH; gcc -fno-strict-aliasing -Wall -Wextra -Wundef -Wnested-externs -Wwrite-strings -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wno-unused-parameter -Wno-missing-field-initializers -Wdeclaration-after-statement -Wformat=2 -Wold-style-definition -Wcast-align -Wformat-nonliteral -Wformat-security -Wsign-compare -Wstrict-aliasing -Wshadow -Winline -Wpacked -Wmissing-format-attribute -Wmissing-noreturn -Winit-self -Wmissing-include-dirs -Wunused-but-set-variable -Warray-bounds -Wimplicit-function-declaration -Wreturn-type -Wswitch-enum -Wswitch-default -Werror -Wno-suggest-attribute=format -Wno-error=unused-parameter -Wno-error=missing-field-initializers -g -o \$progdir/\$file chk_version.o ../.libs/libfastjson.so ../.libs/libfastjson-internal.a -Wl,-rpath -Wl,/home/rger/proj/libfastjson/.libs)"
# This environment variable determines our operation mode.
if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
# install mode needs the following variables:
generated_by_libtool_version='2.4.6'
notinst_deplibs=' ../libfastjson.la'
else
# When we are sourced in execute mode, $file and $ECHO are already set.
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
file="$0"
# A function that is used when there is no print builtin or printf.
func_fallback_echo ()
{
eval 'cat <<_LTECHO_EOF
$1
_LTECHO_EOF'
}
ECHO="printf %s\\n"
fi
# Very basic option parsing. These options are (a) specific to
# the libtool wrapper, (b) are identical between the wrapper
# /script/ and the wrapper /executable/ that is used only on
# windows platforms, and (c) all begin with the string --lt-
# (application programs are unlikely to have options that match
# this pattern).
#
# There are only two supported options: --lt-debug and
# --lt-dump-script. There is, deliberately, no --lt-help.
#
# The first argument to this parsing function should be the
# script's ../libtool value, followed by no.
lt_option_debug=
func_parse_lt_options ()
{
lt_script_arg0=$0
shift
for lt_opt
do
case "$lt_opt" in
--lt-debug) lt_option_debug=1 ;;
--lt-dump-script)
lt_dump_D=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
lt_dump_F=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%^.*/%%'`
cat "$lt_dump_D/$lt_dump_F"
exit 0
;;
--lt-*)
$ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
exit 1
;;
esac
done
# Print the debug banner immediately:
if test -n "$lt_option_debug"; then
echo "chk_version:chk_version:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-0.1" 1>&2
fi
}
# Used when --lt-debug. Prints its arguments to stdout
# (redirection is the responsibility of the caller)
func_lt_dump_args ()
{
lt_dump_args_N=1;
for lt_arg
do
$ECHO "chk_version:chk_version:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
lt_dump_args_N=`expr $lt_dump_args_N + 1`
done
}
# Core function for launching the target application
func_exec_program_core ()
{
if test -n "$lt_option_debug"; then
$ECHO "chk_version:chk_version:$LINENO: newargv[0]: $progdir/$program" 1>&2
func_lt_dump_args ${1+"$@"} 1>&2
fi
exec "$progdir/$program" ${1+"$@"}
$ECHO "$0: cannot exec $program $*" 1>&2
exit 1
}
# A function to encapsulate launching the target application
# Strips options in the --lt-* namespace from $@ and
# launches target application with the remaining arguments.
func_exec_program ()
{
case " $* " in
*\ --lt-*)
for lt_wr_arg
do
case $lt_wr_arg in
--lt-*) ;;
*) set x "$@" "$lt_wr_arg"; shift;;
esac
shift
done ;;
esac
func_exec_program_core ${1+"$@"}
}
# Parse options
func_parse_lt_options "$0" ${1+"$@"}
# Find the directory that this script lives in.
thisdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
test "x$thisdir" = "x$file" && thisdir=.
# Follow symbolic links until we get to the real thisdir.
file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
while test -n "$file"; do
destdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
# If there was a directory component, then change thisdir.
if test "x$destdir" != "x$file"; then
case "$destdir" in
[\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
*) thisdir="$thisdir/$destdir" ;;
esac
fi
file=`$ECHO "$file" | /bin/sed 's%^.*/%%'`
file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
done
# Usually 'no', except on cygwin/mingw when embedded into
# the cwrapper.
WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
# special case for '.'
if test "$thisdir" = "."; then
thisdir=`pwd`
fi
# remove .libs from thisdir
case "$thisdir" in
*[\\/].libs ) thisdir=`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*$%%'` ;;
.libs ) thisdir=. ;;
esac
fi
# Try to get the absolute directory name.
absdir=`cd "$thisdir" && pwd`
test -n "$absdir" && thisdir="$absdir"
program=lt-'chk_version'
progdir="$thisdir/.libs"
if test ! -f "$progdir/$program" ||
{ file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \
test "X$file" != "X$progdir/$program"; }; then
file="$$-$program"
if test ! -d "$progdir"; then
mkdir "$progdir"
else
rm -f "$progdir/$file"
fi
# relink executable if necessary
if test -n "$relink_command"; then
if relink_command_output=`eval $relink_command 2>&1`; then :
else
$ECHO "$relink_command_output" >&2
rm -f "$progdir/$file"
exit 1
fi
fi
mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
{ rm -f "$progdir/$program";
mv -f "$progdir/$file" "$progdir/$program"; }
rm -f "$progdir/$file"
fi
if test -f "$progdir/$program"; then
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
# Run the actual program with our arguments.
func_exec_program ${1+"$@"}
fi
else
# The program doesn't exist.
$ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
$ECHO "This script is just a wrapper for $program." 1>&2
$ECHO "See the libtool documentation for more information." 1>&2
exit 1
fi
fi

26
tests/chk_version.c Normal file
View File

@ -0,0 +1,26 @@
/* libfastjson testbench tool
*
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include "../json.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
if(strcmp(fjson_version(), VERSION)) {
fprintf(stderr, "ERROR: fjson_version reports '%s', VERSION is '%s'.\n",
fjson_version(), VERSION);
exit(1);
}
return 0;
}

46
tests/cr_obj_multi.c Normal file
View File

@ -0,0 +1,46 @@
/* libfastjson testbench tool
*
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include "../json.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_CREATIONS 1000000
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
int i;
char pb[64];
struct fjson_object **json = calloc(NUM_CREATIONS, sizeof(struct fjson_object *));
if(json == NULL) {
perror("malloc ptr table failed:");
exit(1);
}
for(i = 0 ; i < NUM_CREATIONS ; ++i) {
json[i] = fjson_object_new_object();
//fprintf(stderr, "main: json[%d] %p\n", i, json[i]);
snprintf(pb, sizeof(pb), "%d", i);
fjson_object_object_add(json[i], pb, fjson_object_new_string(pb));
}
/* free all objects again */
for(i = 0 ; i < NUM_CREATIONS ; ++i) {
fjson_object_put(json[i]);
}
free(json);
return 0;
}

49
tests/parse_flags.c Normal file
View File

@ -0,0 +1,49 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../json.h"
#include "parse_flags.h"
#if !defined(HAVE_STRCASECMP)
# error You do not have strcasecmp on your system.
#endif /* HAVE_STRNCASECMP */
static struct {
const char *arg;
int flag;
} format_args[] = {
{ "plain", FJSON_TO_STRING_PLAIN },
{ "spaced", FJSON_TO_STRING_SPACED },
{ "pretty", FJSON_TO_STRING_PRETTY },
};
#ifndef NELEM
#define NELEM(x) (sizeof(x) / sizeof(&x[0]))
#endif
int parse_flags(int argc, char **argv)
{
int arg_idx;
int sflags = 0;
for (arg_idx = 1; arg_idx < argc ; arg_idx++)
{
int jj;
for (jj = 0; jj < (int)NELEM(format_args); jj++)
{
if (strcasecmp(argv[arg_idx], format_args[jj].arg) == 0)
{
sflags |= format_args[jj].flag;
break;
}
}
if (jj == NELEM(format_args))
{
printf("Unknown arg: %s\n", argv[arg_idx]);
exit(1);
}
}
return sflags;
}

4
tests/parse_flags.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef __parse_flags_h
#define __parse_flags_h
int parse_flags(int argc, char **argv);
#endif

128
tests/test-defs.sh Executable file
View File

@ -0,0 +1,128 @@
#!/bin/sh
# Make sure srcdir is an absolute path. Supply the variable
# if it does not exist. We want to be able to run the tests
# stand-alone!!
#
srcdir=${srcdir-.}
if test ! -d $srcdir ; then
echo "test-defs.sh: installation error" 1>&2
exit 1
fi
# Use absolute paths
case "$srcdir" in
/* | [A-Za-z]:\\*) ;;
*) srcdir=`\cd $srcdir && pwd` ;;
esac
case "$top_builddir" in
/* | [A-Za-z]:\\*) ;;
*) top_builddir=`\cd ${top_builddir-..} && pwd` ;;
esac
top_builddir=${top_builddir}/tests
progname=`echo "$0" | sed 's,^.*/,,'`
testname=`echo "$progname" | sed 's,-.*$,,'`
testsubdir=${testsubdir-testSubDir}
testsubdir=${testsubdir}/${progname}
# User can set VERBOSE to cause output redirection
case "$VERBOSE" in
[Nn]|[Nn][Oo]|0|"")
VERBOSE=0
exec > /dev/null
;;
[Yy]|[Yy][Ee][Ss])
VERBOSE=1
;;
esac
rm -rf "$testsubdir" > /dev/null 2>&1
mkdir -p "$testsubdir"
CURDIR=`pwd`
cd "$testsubdir" \
|| { echo "Cannot make or change into $testsubdir"; exit 1; }
echo "=== Running test $progname"
CMP="${CMP-cmp}"
#
# This is a common function to check the results of a test program
# that is intended to generate consistent output across runs.
#
# ${top_builddir} must be set to the top level build directory.
#
# Output will be written to the current directory.
#
# It must be passed the name of the test command to run, which must be present
# in the ${top_builddir} directory.
#
# It will compare the output of running that against <name of command>.expected
#
run_output_test()
{
if [ "$1" = "-o" ] ; then
TEST_OUTPUT="$2"
shift
shift
fi
TEST_COMMAND="$1"
shift
if [ -z "${TEST_OUTPUT}" ] ; then
TEST_OUTPUT=${TEST_COMMAND}
fi
REDIR_OUTPUT="> \"${TEST_OUTPUT}.out\""
if [ $VERBOSE -gt 1 ] ; then
REDIR_OUTPUT="| tee \"${TEST_OUTPUT}.out\""
fi
if [ "$VALGRIND" = "valgrind" ] ; then
eval valgrind --tool=memcheck \
--trace-children=yes \
--demangle=yes \
--log-file="${TEST_OUTPUT}.vg.out" \
--leak-check=full \
--show-reachable=yes \
--run-libc-freeres=yes \
"\"${top_builddir}/${TEST_COMMAND}\"" \"\$@\" ${REDIR_OUTPUT}
err=$?
else
eval "\"${top_builddir}/${TEST_COMMAND}"\" \"\$@\" ${REDIR_OUTPUT}
err=$?
fi
if [ $err -ne 0 ] ; then
echo "ERROR: \"${TEST_COMMAND} $@\" exited with non-zero exit status: $err" 1>&2
fi
if [ "$VALGRIND" = "valgrind" ] ; then
if ! tail -1 "${TEST_OUTPUT}.vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then
echo "ERROR: valgrind found errors during execution:" 1>&2
cat "${TEST_OUTPUT}.vg.out"
err=1
fi
fi
if ! "$CMP" -s "${srcdir}/${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 "${srcdir}/${TEST_OUTPUT}.expected" "$testsubdir/${TEST_OUTPUT}.out")
echo "cp \"$testsubdir/${TEST_OUTPUT}.out\" \"${srcdir}/${TEST_OUTPUT}.expected\"" 1>&2
err=1
fi
# remove temp files for successful builds
# this clanup is required for "make distcheck"
if [ $err -eq 0 ] ; then
rm -rf ${CURDIR}/${testsubdir}/*
fi
return $err
}

145
tests/test1.c Normal file
View File

@ -0,0 +1,145 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../debug.h"
#include "parse_flags.h"
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#define DEBUG_SEED(s)
static int sort_fn (const void *j1, const void *j2)
{
fjson_object * const *jso1, * const *jso2;
int i1, i2;
jso1 = (fjson_object* const*)j1;
jso2 = (fjson_object* const*)j2;
if (!*jso1 && !*jso2)
return 0;
if (!*jso1)
return -1;
if (!*jso2)
return 1;
i1 = fjson_object_get_int(*jso1);
i2 = fjson_object_get_int(*jso2);
return i1 - i2;
}
#ifdef TEST_FORMATTED
#define fjson_object_to_json_string(obj) fjson_object_to_json_string_ext(obj,sflags)
#else
/* no special define */
#endif
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
fjson_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 = fjson_object_new_string("\t");
printf("my_string=%s\n", fjson_object_get_string(my_string));
printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
fjson_object_put(my_string);
my_string = fjson_object_new_string("\\");
printf("my_string=%s\n", fjson_object_get_string(my_string));
printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
fjson_object_put(my_string);
my_string = fjson_object_new_string("foo");
printf("my_string=%s\n", fjson_object_get_string(my_string));
printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
my_int = fjson_object_new_int(9);
printf("my_int=%d\n", fjson_object_get_int(my_int));
printf("my_int.to_string()=%s\n", fjson_object_to_json_string(my_int));
my_array = fjson_object_new_array();
fjson_object_array_add(my_array, fjson_object_new_int(1));
fjson_object_array_add(my_array, fjson_object_new_int(2));
fjson_object_array_add(my_array, fjson_object_new_int(3));
fjson_object_array_put_idx(my_array, 4, fjson_object_new_int(5));
printf("my_array=\n");
for(i=0; i < fjson_object_array_length(my_array); i++)
{
fjson_object *obj = fjson_object_array_get_idx(my_array, i);
printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
}
printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
fjson_object_put(my_array);
my_array = fjson_object_new_array();
fjson_object_array_add(my_array, fjson_object_new_int(3));
fjson_object_array_add(my_array, fjson_object_new_int(1));
fjson_object_array_add(my_array, fjson_object_new_int(2));
fjson_object_array_put_idx(my_array, 4, fjson_object_new_int(0));
printf("my_array=\n");
for(i=0; i < fjson_object_array_length(my_array); i++)
{
fjson_object *obj = fjson_object_array_get_idx(my_array, i);
printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
}
printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
fjson_object_array_sort(my_array, sort_fn);
printf("my_array=\n");
for(i=0; i < fjson_object_array_length(my_array); i++)
{
fjson_object *obj = fjson_object_array_get_idx(my_array, i);
printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
}
printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
my_object = fjson_object_new_object();
fjson_object_object_add(my_object, "abc", fjson_object_new_int(12));
fjson_object_object_add(my_object, "foo", fjson_object_new_string("bar"));
fjson_object_object_add(my_object, "bool0", fjson_object_new_boolean(0));
fjson_object_object_add(my_object, "bool1", fjson_object_new_boolean(1));
fjson_object_object_add(my_object, "baz", fjson_object_new_string("bang"));
fjson_object *baz_obj = fjson_object_new_string("fark");
fjson_object_get(baz_obj);
fjson_object_object_add(my_object, "baz", baz_obj);
fjson_object_object_del(my_object, "baz");
/* baz_obj should still be valid */
printf("baz_obj.to_string()=%s\n", fjson_object_to_json_string(baz_obj));
fjson_object_put(baz_obj);
/*fjson_object_object_add(my_object, "arr", my_array);*/
printf("my_object=\n");
struct fjson_object_iterator it = fjson_object_iter_begin(my_object);
struct fjson_object_iterator itEnd = fjson_object_iter_end(my_object);
while (!fjson_object_iter_equal(&it, &itEnd)) {
printf("\t%s: %s\n",
fjson_object_iter_peek_name(&it),
fjson_object_to_json_string(fjson_object_iter_peek_value(&it)));
fjson_object_iter_next(&it);
}
printf("my_object.to_string()=%s\n", fjson_object_to_json_string(my_object));
fjson_object_put(my_string);
fjson_object_put(my_int);
fjson_object_put(my_object);
fjson_object_put(my_array);
return 0;
}

36
tests/test1.expected Normal file
View File

@ -0,0 +1,36 @@
my_string=
my_string.to_string()="\t"
my_string=\
my_string.to_string()="\\"
my_string=foo
my_string.to_string()="foo"
my_int=9
my_int.to_string()=9
my_array=
[0]=1
[1]=2
[2]=3
[3]=null
[4]=5
my_array.to_string()=[ 1, 2, 3, null, 5 ]
my_array=
[0]=3
[1]=1
[2]=2
[3]=null
[4]=0
my_array.to_string()=[ 3, 1, 2, null, 0 ]
my_array=
[0]=null
[1]=0
[2]=1
[3]=2
[4]=3
my_array.to_string()=[ null, 0, 1, 2, 3 ]
baz_obj.to_string()="fark"
my_object=
abc: 12
foo: "bar"
bool0: false
bool1: true
my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }

22
tests/test1.test Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test1
_err=$?
for flag in plain spaced pretty ; do
run_output_test -o test1Formatted_${flag} test1Formatted ${flag}
_err2=$?
if [ $_err -eq 0 ] ; then
_err=$_err2
fi
done
exit $_err

View File

@ -0,0 +1,36 @@
my_string=
my_string.to_string()="\t"
my_string=\
my_string.to_string()="\\"
my_string=foo
my_string.to_string()="foo"
my_int=9
my_int.to_string()=9
my_array=
[0]=1
[1]=2
[2]=3
[3]=null
[4]=5
my_array.to_string()=[1,2,3,null,5]
my_array=
[0]=3
[1]=1
[2]=2
[3]=null
[4]=0
my_array.to_string()=[3,1,2,null,0]
my_array=
[0]=null
[1]=0
[2]=1
[3]=2
[4]=3
my_array.to_string()=[null,0,1,2,3]
baz_obj.to_string()="fark"
my_object=
abc: 12
foo: "bar"
bool0: false
bool1: true
my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true}

View File

@ -0,0 +1,59 @@
my_string=
my_string.to_string()="\t"
my_string=\
my_string.to_string()="\\"
my_string=foo
my_string.to_string()="foo"
my_int=9
my_int.to_string()=9
my_array=
[0]=1
[1]=2
[2]=3
[3]=null
[4]=5
my_array.to_string()=[
1,
2,
3,
null,
5
]
my_array=
[0]=3
[1]=1
[2]=2
[3]=null
[4]=0
my_array.to_string()=[
3,
1,
2,
null,
0
]
my_array=
[0]=null
[1]=0
[2]=1
[3]=2
[4]=3
my_array.to_string()=[
null,
0,
1,
2,
3
]
baz_obj.to_string()="fark"
my_object=
abc: 12
foo: "bar"
bool0: false
bool1: true
my_object.to_string()={
"abc":12,
"foo":"bar",
"bool0":false,
"bool1":true
}

View File

@ -0,0 +1,36 @@
my_string=
my_string.to_string()="\t"
my_string=\
my_string.to_string()="\\"
my_string=foo
my_string.to_string()="foo"
my_int=9
my_int.to_string()=9
my_array=
[0]=1
[1]=2
[2]=3
[3]=null
[4]=5
my_array.to_string()=[ 1, 2, 3, null, 5 ]
my_array=
[0]=3
[1]=1
[2]=2
[3]=null
[4]=0
my_array.to_string()=[ 3, 1, 2, null, 0 ]
my_array=
[0]=null
[1]=0
[2]=1
[3]=2
[4]=3
my_array.to_string()=[ null, 0, 1, 2, 3 ]
baz_obj.to_string()="fark"
my_object=
abc: 12
foo: "bar"
bool0: false
bool1: true
my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }

36
tests/test2.c Normal file
View File

@ -0,0 +1,36 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../debug.h"
#include "parse_flags.h"
#ifdef TEST_FORMATTED
#define fjson_object_to_json_string(obj) fjson_object_to_json_string_ext(obj,sflags)
#else
/* no special define */
#endif
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
fjson_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 = fjson_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", fjson_object_to_json_string(new_obj));
fjson_object_put(new_obj);
return 0;
}

1
tests/test2.expected Normal file
View File

@ -0,0 +1 @@
new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }

22
tests/test2.test Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test2
_err=$?
for flag in plain spaced pretty ; do
run_output_test -o test2Formatted_${flag} test2Formatted ${flag}
_err2=$?
if [ $_err -eq 0 ] ; then
_err=$_err2
fi
done
exit $_err

View File

@ -0,0 +1 @@
new_obj.to_string()={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":[{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML","markup"]}]}}}

View File

@ -0,0 +1,23 @@
new_obj.to_string()={
"glossary":{
"title":"example glossary",
"GlossDiv":{
"title":"S",
"GlossList":[
{
"ID":"SGML",
"SortAs":"SGML",
"GlossTerm":"Standard Generalized Markup Language",
"Acronym":"SGML",
"Abbrev":"ISO 8879:1986",
"GlossDef":"A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso":[
"GML",
"XML",
"markup"
]
}
]
}
}
}

View File

@ -0,0 +1 @@
new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }

57
tests/test4.c Normal file
View File

@ -0,0 +1,57 @@
/*
* gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#define DEBUG_SEED(s)
#include "../json_object.h"
#include "../json_tokener.h"
static 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(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
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 fjson_object *parse_result = fjson_tokener_parse((char*)input);
const char *unjson = fjson_object_get_string(parse_result);
printf("input: %s\n", input);
int strings_match = !strcmp( expected, unjson);
int retval = 0;
if (strings_match)
{
printf("JSON parse result is correct: %s\n", unjson);
printf("PASS\n");
} else {
printf("JSON parse result doesn't match expected string\n");
printf("expected string bytes: ");
print_hex( expected);
printf("parsed string bytes: ");
print_hex( unjson);
printf("FAIL\n");
retval = 1;
}
fjson_object_put(parse_result);
return retval;
}

3
tests/test4.expected Normal file
View File

@ -0,0 +1,3 @@
input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27"
JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧
PASS

12
tests/test4.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test4
exit $?

View File

@ -0,0 +1,97 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../debug.h"
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
struct fjson_object_iterator it;
struct fjson_object_iterator itEnd;
const char *key;
MC_SET_DEBUG(1);
/*
* Check that replacing an existing object keeps the key valid,
* and that it keeps the order the same.
*/
fjson_object *my_object = fjson_object_new_object();
fjson_object_object_add(my_object, "foo1", fjson_object_new_string("bar1"));
fjson_object_object_add(my_object, "foo2", fjson_object_new_string("bar2"));
fjson_object_object_add(my_object, "deleteme", fjson_object_new_string("bar2"));
fjson_object_object_add(my_object, "foo3", fjson_object_new_string("bar3"));
printf("==== delete-in-loop test starting ====\n");
int orig_count = 0;
itEnd = fjson_object_iter_end(my_object);
it = fjson_object_iter_begin(my_object);
while (!fjson_object_iter_equal(&it, &itEnd)) {
key = fjson_object_iter_peek_name(&it);
printf("Key at index %d is [%s]", orig_count, key);
/* need to advance now, as del invalidates "it" */
fjson_object_iter_next(&it);
if (strcmp(key, "deleteme") == 0) {
fjson_object_object_del(my_object, key);
printf(" (deleted)\n");
} else {
printf(" (kept)\n");
}
orig_count++;
}
printf("==== replace-value first loop starting ====\n");
const char *original_key = NULL;
orig_count = 0;
itEnd = fjson_object_iter_end(my_object);
it = fjson_object_iter_begin(my_object);
while (!fjson_object_iter_equal(&it, &itEnd)) {
key = fjson_object_iter_peek_name(&it);
/* need to advance now, as modify invalidates "it" */
fjson_object_iter_next(&it);
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;
fjson_object_object_add(my_object, key, fjson_object_new_string("zzz"));
}
printf("==== second loop starting ====\n");
int new_count = 0;
int retval = 0;
itEnd = fjson_object_iter_end(my_object);
it = fjson_object_iter_begin(my_object);
while (!fjson_object_iter_equal(&it, &itEnd)) {
key = fjson_object_iter_peek_name(&it);
/* need to advance now, as modify invalidates "it" */
fjson_object_iter_next(&it);
printf("Key at index %d is [%s]\n", new_count, key);
new_count++;
if (strcmp(key, "foo2") != 0)
continue;
printf("pointer for key [%s] does %smatch\n", key,
(key == original_key) ? "" : "NOT ");
if (key != 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;
}
fjson_object_put( my_object );
return retval;
}

View File

@ -0,0 +1,15 @@
==== delete-in-loop test starting ====
Key at index 0 is [foo1] (kept)
Key at index 1 is [foo2] (kept)
Key at index 2 is [deleteme] (deleted)
Key at index 3 is [foo3] (kept)
==== replace-value first loop starting ====
Key at index 0 is [foo1]
Key at index 1 is [foo2]
replacing value for key [foo2]
Key at index 2 is [foo3]
==== second loop starting ====
Key at index 0 is [foo1]
Key at index 1 is [foo2]
pointer for key [foo2] does match
Key at index 2 is [foo3]

12
tests/testReplaceExisting.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test testReplaceExisting
exit $?

114
tests/test_cast.c Normal file
View File

@ -0,0 +1,114 @@
/*
* Tests if casting within the fjson_object_get_* functions work correctly.
* Also checks the fjson_object_get_type and fjson_object_is_type functions.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "../json_object.h"
#include "../json_tokener.h"
#include "../json_util.h"
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
static void getit(struct fjson_object *new_obj, const char *field);
static void checktype_header(void);
static void checktype(struct fjson_object *new_obj, const char *field);
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
const char *input = "{\n\
\"string_of_digits\": \"123\",\n\
\"regular_number\": 222,\n\
\"decimal_number\": 99.55,\n\
\"boolean_true\": true,\n\
\"boolean_false\": false,\n\
\"big_number\": 2147483649,\n\
\"a_null\": null,\n\
}";
/* Note: 2147483649 = INT_MAX + 2 */
struct fjson_object *new_obj;
new_obj = fjson_tokener_parse(input);
printf("Parsed input: %s\n", input);
printf("Result is %s\n", (new_obj == NULL) ? "NULL (error!)" : "not NULL");
if (!new_obj)
return 1; // oops, we failed.
getit(new_obj, "string_of_digits");
getit(new_obj, "regular_number");
getit(new_obj, "decimal_number");
getit(new_obj, "boolean_true");
getit(new_obj, "boolean_false");
getit(new_obj, "big_number");
getit(new_obj, "a_null");
// Now check the behaviour of the fjson_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");
fjson_object_put(new_obj);
return 0;
}
static void getit(struct fjson_object *new_obj, const char *field)
{
struct fjson_object *o = NULL;
if (!fjson_object_object_get_ex(new_obj, field, &o))
printf("Field %s does not exist\n", field);
enum fjson_type o_type = fjson_object_get_type(o);
printf("new_obj.%s fjson_object_get_type()=%s\n", field,
fjson_type_to_name(o_type));
printf("new_obj.%s fjson_object_get_int()=%d\n", field,
fjson_object_get_int(o));
printf("new_obj.%s fjson_object_get_int64()=%" PRId64 "\n", field,
fjson_object_get_int64(o));
printf("new_obj.%s fjson_object_get_boolean()=%d\n", field,
fjson_object_get_boolean(o));
printf("new_obj.%s fjson_object_get_double()=%f\n", field,
fjson_object_get_double(o));
}
static void checktype_header(void)
{
printf("fjson_object_is_type: %s,%s,%s,%s,%s,%s,%s\n",
fjson_type_to_name(fjson_type_null),
fjson_type_to_name(fjson_type_boolean),
fjson_type_to_name(fjson_type_double),
fjson_type_to_name(fjson_type_int),
fjson_type_to_name(fjson_type_object),
fjson_type_to_name(fjson_type_array),
fjson_type_to_name(fjson_type_string));
}
static void checktype(struct fjson_object *new_obj, const char *field)
{
struct fjson_object *o = new_obj;
if (field && !fjson_object_object_get_ex(new_obj, field, &o))
printf("Field %s does not exist\n", field);
printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n",
field ? "." : " ", field ? field : "",
fjson_object_is_type(o, fjson_type_null),
fjson_object_is_type(o, fjson_type_boolean),
fjson_object_is_type(o, fjson_type_double),
fjson_object_is_type(o, fjson_type_int),
fjson_object_is_type(o, fjson_type_object),
fjson_object_is_type(o, fjson_type_array),
fjson_object_is_type(o, fjson_type_string));
}

56
tests/test_cast.expected Normal file
View File

@ -0,0 +1,56 @@
Parsed input: {
"string_of_digits": "123",
"regular_number": 222,
"decimal_number": 99.55,
"boolean_true": true,
"boolean_false": false,
"big_number": 2147483649,
"a_null": null,
}
Result is not NULL
new_obj.string_of_digits fjson_object_get_type()=string
new_obj.string_of_digits fjson_object_get_int()=123
new_obj.string_of_digits fjson_object_get_int64()=123
new_obj.string_of_digits fjson_object_get_boolean()=1
new_obj.string_of_digits fjson_object_get_double()=123.000000
new_obj.regular_number fjson_object_get_type()=int
new_obj.regular_number fjson_object_get_int()=222
new_obj.regular_number fjson_object_get_int64()=222
new_obj.regular_number fjson_object_get_boolean()=1
new_obj.regular_number fjson_object_get_double()=222.000000
new_obj.decimal_number fjson_object_get_type()=double
new_obj.decimal_number fjson_object_get_int()=99
new_obj.decimal_number fjson_object_get_int64()=99
new_obj.decimal_number fjson_object_get_boolean()=1
new_obj.decimal_number fjson_object_get_double()=99.550000
new_obj.boolean_true fjson_object_get_type()=boolean
new_obj.boolean_true fjson_object_get_int()=1
new_obj.boolean_true fjson_object_get_int64()=1
new_obj.boolean_true fjson_object_get_boolean()=1
new_obj.boolean_true fjson_object_get_double()=1.000000
new_obj.boolean_false fjson_object_get_type()=boolean
new_obj.boolean_false fjson_object_get_int()=0
new_obj.boolean_false fjson_object_get_int64()=0
new_obj.boolean_false fjson_object_get_boolean()=0
new_obj.boolean_false fjson_object_get_double()=0.000000
new_obj.big_number fjson_object_get_type()=int
new_obj.big_number fjson_object_get_int()=2147483647
new_obj.big_number fjson_object_get_int64()=2147483649
new_obj.big_number fjson_object_get_boolean()=1
new_obj.big_number fjson_object_get_double()=2147483649.000000
new_obj.a_null fjson_object_get_type()=null
new_obj.a_null fjson_object_get_int()=0
new_obj.a_null fjson_object_get_int64()=0
new_obj.a_null fjson_object_get_boolean()=0
new_obj.a_null fjson_object_get_double()=0.000000
================================
fjson_object_is_type: null,boolean,double,int,object,array,string
new_obj : 0,0,0,0,1,0,0
new_obj.string_of_digits : 0,0,0,0,0,0,1
new_obj.regular_number : 0,0,0,1,0,0,0
new_obj.decimal_number : 0,0,1,0,0,0,0
new_obj.boolean_true : 0,1,0,0,0,0,0
new_obj.boolean_false : 0,1,0,0,0,0,0
new_obj.big_number : 0,0,0,1,0,0,0
new_obj.a_null : 1,0,0,0,0,0,0

12
tests/test_cast.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test_cast
exit $?

48
tests/test_charcase.c Normal file
View File

@ -0,0 +1,48 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../json_tokener.h"
#include "../debug.h"
#define CHK(x) if (!(x)) { \
printf("%s:%d: unexpected result with '%s'\n", \
__FILE__, __LINE__, #x); \
exit(1); \
}
static void test_case_parse(void);
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
MC_SET_DEBUG(1);
test_case_parse();
return 0;
}
/* make sure only lowercase forms are parsed in strict mode */
static void test_case_parse(void)
{
struct fjson_tokener *tok;
fjson_object *new_obj;
tok = fjson_tokener_new();
fjson_tokener_set_flags(tok, FJSON_TOKENER_STRICT);
new_obj = fjson_tokener_parse_ex(tok, "True", 4);
CHK(new_obj == NULL);
new_obj = fjson_tokener_parse_ex(tok, "False", 5);
CHK(new_obj == NULL);
new_obj = fjson_tokener_parse_ex(tok, "Null", 4);
CHK(new_obj == NULL);
printf("OK\n");
fjson_tokener_free(tok);
}

View File

@ -0,0 +1 @@
OK

12
tests/test_charcase.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test_charcase
exit $?

24
tests/test_float.c Normal file
View File

@ -0,0 +1,24 @@
/* Copyright (C) 2016 by Rainer Gerhards
* Released under ASL 2.0 */
#include "config.h"
#include <stdio.h>
#include "../json_object.h"
#include "../json_tokener.h"
int main(void)
{
fjson_object *json;
json = fjson_object_new_double(1.0);
printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
json_object_put(json);
json = fjson_object_new_double(1.23);
printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
json_object_put(json);
json = fjson_object_new_double(123456789.0);
printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
json_object_put(json);
json = fjson_object_new_double(123456789.123);
printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
json_object_put(json);
return 0;
}

View File

@ -0,0 +1,4 @@
json = 1.0
json = 1.23
json = 123456789.0
json = 123456789.123

12
tests/test_float.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test_float
exit $?

32
tests/test_locale.c Normal file
View File

@ -0,0 +1,32 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../json_tokener.h"
#include "../debug.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif /* HAVE_LOCALE_H */
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
fjson_object *new_obj;
#ifdef HAVE_SETLOCALE
setlocale(LC_NUMERIC, "de_DE");
#else
printf("No locale\n");
#endif
MC_SET_DEBUG(1);
new_obj = fjson_tokener_parse("[1.2,3.4,123456.78,5.0,2.3e10]");
printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
printf("new_obj.to_string()=%s\n", fjson_object_to_json_string_ext(new_obj,FJSON_TO_STRING_NOZERO));
fjson_object_put(new_obj);
return 0;
}

View File

@ -0,0 +1,2 @@
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]

12
tests/test_locale.test Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
run_output_test test_locale
exit $?

79
tests/test_many_subobj.c Normal file
View File

@ -0,0 +1,79 @@
/* libfastjson testbench tool
*
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include "../json.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_SUBOBJ 200
#define NUM_SUBOBJ_HALF (NUM_SUBOBJ/2)
#define NUM_SUBOBJ_QUARTER (NUM_SUBOBJ/4)
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
int i;
char pb[64];
struct fjson_object *json = fjson_object_new_object();
if (json == NULL) {
perror("malloc ptr table failed:");
exit(1);
}
/* add some keys */
for (i = 0 ; i < NUM_SUBOBJ ; ++i) {
snprintf(pb, sizeof(pb), "key-%d", i);
fjson_object_object_add_ex(json, pb, fjson_object_new_int(i), 0);
}
printf("STEP1: %s\n", fjson_object_to_json_string(json));
/* delete some keys */
for (i = NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
i < NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER ;
++i) {
snprintf(pb, sizeof(pb), "key-%d", i);
fjson_object_object_del(json, pb);
}
printf("STEP2: %s\n", fjson_object_to_json_string(json));
/* add new keys */
for (i = NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER - 1;
i >= NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
--i) {
snprintf(pb, sizeof(pb), "KEY-%d", i);
fjson_object_object_add_ex(json, pb, fjson_object_new_int(i), 0);
}
printf("STEP3: %s\n", fjson_object_to_json_string(json));
/* delete the new keys again, and also update key values */
for (i = NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
i < NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER ;
++i) {
snprintf(pb, sizeof(pb), "KEY-%d", i);
fjson_object_object_del(json, pb);
}
for (i = 0 ; i < NUM_SUBOBJ ; ++i) {
snprintf(pb, sizeof(pb), "key-%d", i);
fjson_object_object_add_ex(json, pb, fjson_object_new_int(i*10), 0);
}
printf("STEP4: %s\n", fjson_object_to_json_string(json));
/* add one more key to see that adding works when extending the array */
snprintf(pb, sizeof(pb), "key-%d", NUM_SUBOBJ);
fjson_object_object_add(json, pb, fjson_object_new_int(NUM_SUBOBJ));
printf("STEP5:%s\n", fjson_object_to_json_string(json));
fjson_object_put(json);
return 0;
}

View File

@ -0,0 +1,5 @@
STEP1: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "key-50": 50, "key-51": 51, "key-52": 52, "key-53": 53, "key-54": 54, "key-55": 55, "key-56": 56, "key-57": 57, "key-58": 58, "key-59": 59, "key-60": 60, "key-61": 61, "key-62": 62, "key-63": 63, "key-64": 64, "key-65": 65, "key-66": 66, "key-67": 67, "key-68": 68, "key-69": 69, "key-70": 70, "key-71": 71, "key-72": 72, "key-73": 73, "key-74": 74, "key-75": 75, "key-76": 76, "key-77": 77, "key-78": 78, "key-79": 79, "key-80": 80, "key-81": 81, "key-82": 82, "key-83": 83, "key-84": 84, "key-85": 85, "key-86": 86, "key-87": 87, "key-88": 88, "key-89": 89, "key-90": 90, "key-91": 91, "key-92": 92, "key-93": 93, "key-94": 94, "key-95": 95, "key-96": 96, "key-97": 97, "key-98": 98, "key-99": 99, "key-100": 100, "key-101": 101, "key-102": 102, "key-103": 103, "key-104": 104, "key-105": 105, "key-106": 106, "key-107": 107, "key-108": 108, "key-109": 109, "key-110": 110, "key-111": 111, "key-112": 112, "key-113": 113, "key-114": 114, "key-115": 115, "key-116": 116, "key-117": 117, "key-118": 118, "key-119": 119, "key-120": 120, "key-121": 121, "key-122": 122, "key-123": 123, "key-124": 124, "key-125": 125, "key-126": 126, "key-127": 127, "key-128": 128, "key-129": 129, "key-130": 130, "key-131": 131, "key-132": 132, "key-133": 133, "key-134": 134, "key-135": 135, "key-136": 136, "key-137": 137, "key-138": 138, "key-139": 139, "key-140": 140, "key-141": 141, "key-142": 142, "key-143": 143, "key-144": 144, "key-145": 145, "key-146": 146, "key-147": 147, "key-148": 148, "key-149": 149, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
STEP2: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
STEP3: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "KEY-149": 149, "KEY-148": 148, "KEY-147": 147, "KEY-146": 146, "KEY-145": 145, "KEY-144": 144, "KEY-143": 143, "KEY-142": 142, "KEY-141": 141, "KEY-140": 140, "KEY-139": 139, "KEY-138": 138, "KEY-137": 137, "KEY-136": 136, "KEY-135": 135, "KEY-134": 134, "KEY-133": 133, "KEY-132": 132, "KEY-131": 131, "KEY-130": 130, "KEY-129": 129, "KEY-128": 128, "KEY-127": 127, "KEY-126": 126, "KEY-125": 125, "KEY-124": 124, "KEY-123": 123, "KEY-122": 122, "KEY-121": 121, "KEY-120": 120, "KEY-119": 119, "KEY-118": 118, "KEY-117": 117, "KEY-116": 116, "KEY-115": 115, "KEY-114": 114, "KEY-113": 113, "KEY-112": 112, "KEY-111": 111, "KEY-110": 110, "KEY-109": 109, "KEY-108": 108, "KEY-107": 107, "KEY-106": 106, "KEY-105": 105, "KEY-104": 104, "KEY-103": 103, "KEY-102": 102, "KEY-101": 101, "KEY-100": 100, "KEY-99": 99, "KEY-98": 98, "KEY-97": 97, "KEY-96": 96, "KEY-95": 95, "KEY-94": 94, "KEY-93": 93, "KEY-92": 92, "KEY-91": 91, "KEY-90": 90, "KEY-89": 89, "KEY-88": 88, "KEY-87": 87, "KEY-86": 86, "KEY-85": 85, "KEY-84": 84, "KEY-83": 83, "KEY-82": 82, "KEY-81": 81, "KEY-80": 80, "KEY-79": 79, "KEY-78": 78, "KEY-77": 77, "KEY-76": 76, "KEY-75": 75, "KEY-74": 74, "KEY-73": 73, "KEY-72": 72, "KEY-71": 71, "KEY-70": 70, "KEY-69": 69, "KEY-68": 68, "KEY-67": 67, "KEY-66": 66, "KEY-65": 65, "KEY-64": 64, "KEY-63": 63, "KEY-62": 62, "KEY-61": 61, "KEY-60": 60, "KEY-59": 59, "KEY-58": 58, "KEY-57": 57, "KEY-56": 56, "KEY-55": 55, "KEY-54": 54, "KEY-53": 53, "KEY-52": 52, "KEY-51": 51, "KEY-50": 50, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
STEP4: { "key-0": 0, "key-1": 10, "key-2": 20, "key-3": 30, "key-4": 40, "key-5": 50, "key-6": 60, "key-7": 70, "key-8": 80, "key-9": 90, "key-10": 100, "key-11": 110, "key-12": 120, "key-13": 130, "key-14": 140, "key-15": 150, "key-16": 160, "key-17": 170, "key-18": 180, "key-19": 190, "key-20": 200, "key-21": 210, "key-22": 220, "key-23": 230, "key-24": 240, "key-25": 250, "key-26": 260, "key-27": 270, "key-28": 280, "key-29": 290, "key-30": 300, "key-31": 310, "key-32": 320, "key-33": 330, "key-34": 340, "key-35": 350, "key-36": 360, "key-37": 370, "key-38": 380, "key-39": 390, "key-40": 400, "key-41": 410, "key-42": 420, "key-43": 430, "key-44": 440, "key-45": 450, "key-46": 460, "key-47": 470, "key-48": 480, "key-49": 490, "key-50": 500, "key-51": 510, "key-52": 520, "key-53": 530, "key-54": 540, "key-55": 550, "key-56": 560, "key-57": 570, "key-58": 580, "key-59": 590, "key-60": 600, "key-61": 610, "key-62": 620, "key-63": 630, "key-64": 640, "key-65": 650, "key-66": 660, "key-67": 670, "key-68": 680, "key-69": 690, "key-70": 700, "key-71": 710, "key-72": 720, "key-73": 730, "key-74": 740, "key-75": 750, "key-76": 760, "key-77": 770, "key-78": 780, "key-79": 790, "key-80": 800, "key-81": 810, "key-82": 820, "key-83": 830, "key-84": 840, "key-85": 850, "key-86": 860, "key-87": 870, "key-88": 880, "key-89": 890, "key-90": 900, "key-91": 910, "key-92": 920, "key-93": 930, "key-94": 940, "key-95": 950, "key-96": 960, "key-97": 970, "key-98": 980, "key-99": 990, "key-100": 1000, "key-101": 1010, "key-102": 1020, "key-103": 1030, "key-104": 1040, "key-105": 1050, "key-106": 1060, "key-107": 1070, "key-108": 1080, "key-109": 1090, "key-110": 1100, "key-111": 1110, "key-112": 1120, "key-113": 1130, "key-114": 1140, "key-115": 1150, "key-116": 1160, "key-117": 1170, "key-118": 1180, "key-119": 1190, "key-120": 1200, "key-121": 1210, "key-122": 1220, "key-123": 1230, "key-124": 1240, "key-125": 1250, "key-126": 1260, "key-127": 1270, "key-128": 1280, "key-129": 1290, "key-130": 1300, "key-131": 1310, "key-132": 1320, "key-133": 1330, "key-134": 1340, "key-135": 1350, "key-136": 1360, "key-137": 1370, "key-138": 1380, "key-139": 1390, "key-140": 1400, "key-141": 1410, "key-142": 1420, "key-143": 1430, "key-144": 1440, "key-145": 1450, "key-146": 1460, "key-147": 1470, "key-148": 1480, "key-149": 1490, "key-150": 1500, "key-151": 1510, "key-152": 1520, "key-153": 1530, "key-154": 1540, "key-155": 1550, "key-156": 1560, "key-157": 1570, "key-158": 1580, "key-159": 1590, "key-160": 1600, "key-161": 1610, "key-162": 1620, "key-163": 1630, "key-164": 1640, "key-165": 1650, "key-166": 1660, "key-167": 1670, "key-168": 1680, "key-169": 1690, "key-170": 1700, "key-171": 1710, "key-172": 1720, "key-173": 1730, "key-174": 1740, "key-175": 1750, "key-176": 1760, "key-177": 1770, "key-178": 1780, "key-179": 1790, "key-180": 1800, "key-181": 1810, "key-182": 1820, "key-183": 1830, "key-184": 1840, "key-185": 1850, "key-186": 1860, "key-187": 1870, "key-188": 1880, "key-189": 1890, "key-190": 1900, "key-191": 1910, "key-192": 1920, "key-193": 1930, "key-194": 1940, "key-195": 1950, "key-196": 1960, "key-197": 1970, "key-198": 1980, "key-199": 1990 }
STEP5:{ "key-0": 0, "key-1": 10, "key-2": 20, "key-3": 30, "key-4": 40, "key-5": 50, "key-6": 60, "key-7": 70, "key-8": 80, "key-9": 90, "key-10": 100, "key-11": 110, "key-12": 120, "key-13": 130, "key-14": 140, "key-15": 150, "key-16": 160, "key-17": 170, "key-18": 180, "key-19": 190, "key-20": 200, "key-21": 210, "key-22": 220, "key-23": 230, "key-24": 240, "key-25": 250, "key-26": 260, "key-27": 270, "key-28": 280, "key-29": 290, "key-30": 300, "key-31": 310, "key-32": 320, "key-33": 330, "key-34": 340, "key-35": 350, "key-36": 360, "key-37": 370, "key-38": 380, "key-39": 390, "key-40": 400, "key-41": 410, "key-42": 420, "key-43": 430, "key-44": 440, "key-45": 450, "key-46": 460, "key-47": 470, "key-48": 480, "key-49": 490, "key-50": 500, "key-51": 510, "key-52": 520, "key-53": 530, "key-54": 540, "key-55": 550, "key-56": 560, "key-57": 570, "key-58": 580, "key-59": 590, "key-60": 600, "key-61": 610, "key-62": 620, "key-63": 630, "key-64": 640, "key-65": 650, "key-66": 660, "key-67": 670, "key-68": 680, "key-69": 690, "key-70": 700, "key-71": 710, "key-72": 720, "key-73": 730, "key-74": 740, "key-75": 750, "key-76": 760, "key-77": 770, "key-78": 780, "key-79": 790, "key-80": 800, "key-81": 810, "key-82": 820, "key-83": 830, "key-84": 840, "key-85": 850, "key-86": 860, "key-87": 870, "key-88": 880, "key-89": 890, "key-90": 900, "key-91": 910, "key-92": 920, "key-93": 930, "key-94": 940, "key-95": 950, "key-96": 960, "key-97": 970, "key-98": 980, "key-99": 990, "key-100": 1000, "key-101": 1010, "key-102": 1020, "key-103": 1030, "key-104": 1040, "key-105": 1050, "key-106": 1060, "key-107": 1070, "key-108": 1080, "key-109": 1090, "key-110": 1100, "key-111": 1110, "key-112": 1120, "key-113": 1130, "key-114": 1140, "key-115": 1150, "key-116": 1160, "key-117": 1170, "key-118": 1180, "key-119": 1190, "key-120": 1200, "key-121": 1210, "key-122": 1220, "key-123": 1230, "key-124": 1240, "key-125": 1250, "key-126": 1260, "key-127": 1270, "key-128": 1280, "key-129": 1290, "key-130": 1300, "key-131": 1310, "key-132": 1320, "key-133": 1330, "key-134": 1340, "key-135": 1350, "key-136": 1360, "key-137": 1370, "key-138": 1380, "key-139": 1390, "key-140": 1400, "key-141": 1410, "key-142": 1420, "key-143": 1430, "key-144": 1440, "key-145": 1450, "key-146": 1460, "key-147": 1470, "key-148": 1480, "key-149": 1490, "key-150": 1500, "key-151": 1510, "key-152": 1520, "key-153": 1530, "key-154": 1540, "key-155": 1550, "key-156": 1560, "key-157": 1570, "key-158": 1580, "key-159": 1590, "key-160": 1600, "key-161": 1610, "key-162": 1620, "key-163": 1630, "key-164": 1640, "key-165": 1650, "key-166": 1660, "key-167": 1670, "key-168": 1680, "key-169": 1690, "key-170": 1700, "key-171": 1710, "key-172": 1720, "key-173": 1730, "key-174": 1740, "key-175": 1750, "key-176": 1760, "key-177": 1770, "key-178": 1780, "key-179": 1790, "key-180": 1800, "key-181": 1810, "key-182": 1820, "key-183": 1830, "key-184": 1840, "key-185": 1850, "key-186": 1860, "key-187": 1870, "key-188": 1880, "key-189": 1890, "key-190": 1900, "key-191": 1910, "key-192": 1920, "key-193": 1930, "key-194": 1940, "key-195": 1950, "key-196": 1960, "key-197": 1970, "key-198": 1980, "key-199": 1990, "key-200": 200 }

14
tests/test_many_subobj.test Executable file
View File

@ -0,0 +1,14 @@
#!/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_many_subobj
_err=$?
exit $_err

3
tests/test_null.expected Normal file
View File

@ -0,0 +1,3 @@
JSON write result is correct: " \u0000 "
PASS
Re-parsed object string len=3, chars=[32, 0, 32]

51
tests/test_obj_iter-del.c Normal file
View File

@ -0,0 +1,51 @@
/* libfastjson testbench tool
*
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include "../json.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
struct fjson_object *my_object = fjson_object_new_object();
if (my_object == NULL) {
perror("malloc ptr table failed:");
exit(1);
}
/* add some keys */
fjson_object_object_add_ex (my_object, "a", fjson_object_new_string("a"), 0);
fjson_object_object_add_ex (my_object, "b", fjson_object_new_string("b"), 0);
fjson_object_object_add_ex (my_object, "c", fjson_object_new_string("c"), 0);
fjson_object_object_add_ex (my_object, "d", fjson_object_new_string("d"), 0);
/* delete some keys */
fjson_object_object_del (my_object, "a");
fjson_object_object_del (my_object, "c");
/* check that iteration properly skips the deleted keys */
struct fjson_object_iterator it = fjson_object_iter_begin(my_object);
struct fjson_object_iterator itEnd = fjson_object_iter_end(my_object);
while (!fjson_object_iter_equal (&it, &itEnd)) {
printf("%s: %s\n",
fjson_object_iter_peek_name (&it),
fjson_object_to_json_string (fjson_object_iter_peek_value(&it)));
fjson_object_iter_next (&it);
}
fjson_object_put (my_object);
return 0;
}

View File

@ -0,0 +1,2 @@
b: "b"
d: "d"

14
tests/test_obj_iter-del.test Executable file
View File

@ -0,0 +1,14 @@
#!/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_obj_iter-del
_err=$?
exit $_err

View File

@ -0,0 +1,40 @@
/* libfastjson testbench tool
*
* Copyright (c) 2016 Adiscon GmbH
* Rainer Gerhards <rgerhards@adiscon.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../json.h"
#include "../debug.h"
#include "parse_flags.h"
/* this is a work-around until we manage to fix configure.ac */
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#define DEBUG_SEED(s)
int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
{
fjson_object *my_object;
MC_SET_DEBUG(1);
my_object = fjson_object_new_object();
fjson_object_object_add_ex(my_object, "a", fjson_object_new_int(1), 0);
int found = fjson_object_object_get_ex(my_object, "a", NULL);
printf("found=%d\n", found);
fjson_object_put(my_object);
return 0;
}

View File

@ -0,0 +1 @@
found=1

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