Import Upstream version 0.99.8
This commit is contained in:
commit
aa677ab317
|
@ -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)
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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><at></i> googlegroups <i><dot></i> com</code></strong></p>
|
||||
|
||||
<h3><a href="COPYING">License</a></h3>
|
||||
<p>This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..</p>
|
||||
<hr/>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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:
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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:
|
|
@ -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:
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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];
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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@
|
|
@ -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
|
|
@ -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
|
||||
|
||||
])
|
|
@ -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
|
||||
|
||||
])
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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])])
|
|
@ -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
|
||||
])
|
|
@ -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)
|
||||
])
|
|
@ -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])])
|
|
@ -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:
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # 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:
|
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef __parse_flags_h
|
||||
#define __parse_flags_h
|
||||
int parse_flags(int argc, char **argv);
|
||||
#endif
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 }
|
|
@ -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
|
|
@ -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}
|
|
@ -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
|
||||
}
|
|
@ -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 }
|
|
@ -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;
|
||||
}
|
|
@ -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" ] } ] } } }
|
|
@ -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
|
|
@ -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"]}]}}}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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" ] } ] } } }
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27"
|
||||
JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧
|
||||
PASS
|
|
@ -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 $?
|
|
@ -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;
|
||||
}
|
|
@ -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]
|
|
@ -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 $?
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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 $?
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
OK
|
|
@ -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 $?
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
json = 1.0
|
||||
json = 1.23
|
||||
json = 123456789.0
|
||||
json = 123456789.123
|
|
@ -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 $?
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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]
|
|
@ -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 $?
|
|
@ -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;
|
||||
}
|
|
@ -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 }
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
JSON write result is correct: " \u0000 "
|
||||
PASS
|
||||
Re-parsed object string len=3, chars=[32, 0, 32]
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
b: "b"
|
||||
d: "d"
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
found=1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue