125 Commits
v1.1.3 ... v1.3

Author SHA1 Message Date
Petri Lehtinen
2caac965d4 jansson 1.3 2010-06-13 20:37:33 +03:00
Petri Lehtinen
1347686dbf Remove the C++ interface 2010-06-12 22:45:49 +03:00
Petri Lehtinen
8b2b12e05f Merge branch '1.2' 2010-06-12 22:45:45 +03:00
Petri Lehtinen
1a090bbcd3 Fix a few memory leaks in tests
No changes to the actual library code.
2010-06-10 21:16:07 +03:00
Petri Lehtinen
dec3ad498e Merge branch '1.2' 2010-05-20 18:47:30 +03:00
Petri Lehtinen
978a47e2c5 Clarify the documentation on reference stealing
Provide an example usage pattern for reference stealing functions.
This way the user (hopely) sees more clearly how the reference
stealing functions are meant to be used.
2010-05-20 18:45:24 +03:00
Petri Lehtinen
453e4c0aa2 Zero the visited flag after an encoding error
When encoding an array or object ends in an error, the visited flag
wasn't zeroed, causing subsequent encoding attempts to fail. This
patch fixes the problem by always zeroing the visited flag.
2010-05-14 09:23:35 +03:00
Petri Lehtinen
2630980f49 Zero the visited flag after encoding an empty array or object
Encoding an empty array or object worked, but encoding it again
(possibly after adding some items) failed, because the visited flag
(used for detecting circular references) wasn't zeroed.
2010-05-14 09:05:56 +03:00
Petri Lehtinen
782acfe378 Merge branch '1.2' 2010-05-07 07:36:01 +03:00
Petri Lehtinen
f9475f9577 load.c: Make stream_init() static 2010-05-07 07:35:11 +03:00
Petri Lehtinen
8857aeadfd Merge branch '1.2'
Conflicts:
	CHANGES
	configure.ac
	doc/conf.py
2010-04-03 14:00:59 +03:00
Petri Lehtinen
047a1417fb jansson 1.2.1 2010-04-03 13:49:56 +03:00
Petri Lehtinen
ce42e30b8c doc: Distribute conformance.rst 2010-04-03 13:49:56 +03:00
Petri Lehtinen
4e63fcd55d Merge branch '1.2'
Conflicts:
	configure.ac
2010-03-28 21:44:41 +03:00
Petri Lehtinen
024106bbfb Require autoconf 2.60
The AC_TYPE_INT32_T macro first appeared in autoconf 2.60.
2010-03-28 21:19:40 +03:00
Petri Lehtinen
29ee3832cf Support compilers that don't have the "inline" keyword
Use AC_C_INLINE autoconf macro, include config.h where needed, and add
a define of JSON_INLINE to jansson.h that has the correct "inline"
keyword.
2010-03-28 21:14:08 +03:00
Petri Lehtinen
c7c2edae8a doc: Add chapter on RFC conformance
Thanks to Deron Meranda for providing the initial text.
2010-03-26 22:03:26 +02:00
Petri Lehtinen
bb89a5d4d3 Estimate real number underflows with 0.0
Earlier it was a decoding error.
2010-03-26 21:59:56 +02:00
Petri Lehtinen
f76966b438 Enhance tests for null byte 2010-03-26 21:29:36 +02:00
Petri Lehtinen
49880cbabe Merge branch '1.2' 2010-03-23 08:15:19 +02:00
Petri Lehtinen
f284e3c069 Fix reference counting on true, false and null
Initialize their reference counts to (unsigned int)-1 to disable
reference counting on them. It already was meant to work like this,
but the reference counts were just initialized to 1 instead of -1.

Thanks to Andrew Thompson for reporting this issue.
2010-03-23 08:12:32 +02:00
Petri Lehtinen
66a69f3f10 Ignore temporary files *~ 2010-03-19 08:11:48 +02:00
Andres Freund
7d5982e6fe c++ wrapper: add missing 'inline' statements to various constructors
the missing 'inline' leads to duplicated symbols if the header is
included into two separately compiled files.
2010-03-18 14:35:09 +01:00
Petri Lehtinen
a2a9107600 Don't include stdint.h anywhere
This should have fixed by commit 28682322, but there was one #include
left in utf.c. It now includes utf.h instead of stdint.h.
2010-03-18 07:22:43 +02:00
Petri Lehtinen
42621370c3 hashtable: Fix typo in comment 2010-02-11 21:17:19 +02:00
Petri Lehtinen
8e61b7c0f0 Merge branch 'c++-enhance-proxies' 2010-02-11 21:06:19 +02:00
Petri Lehtinen
35ddd2de20 Update CHANGES, change version to 1.2+ 2010-02-11 20:55:56 +02:00
Petri Lehtinen
f18ef5144a Implement JSON_PRESERVE_ORDER encoding flag
With this encoding flag, the object key-value pairs in output are in
the same order in which they were first inserted into the object.

To make this possible, a key of an object is now a serial number plus
a string. An object keeps an increasing counter which is used to
assign serial number to the keys. Hashing, comparison and public API
functions were changed to act only on the string part, i.e. the serial
number is ignored everywhere else but in the encoder, where it's used
to order object keys if JSON_PRESERVE_ORDER flag is used.
2010-02-11 20:48:56 +02:00
Petri Lehtinen
307167fb66 Optimize hashtable_set()
If a key already exists in the hashtable, use the existing pair
changing its value instead of removing the old one and allocating a
new pair.
2010-02-09 20:51:25 +02:00
Petri Lehtinen
7e8b128740 C++: Optimize PropertyProxy
When the property already exists in the object, we can store an
iterator pointing to that property, instead of duplicating the key.

When the property (key) is not present in the object, we still have to
duplicate the key.
2010-02-08 20:51:09 +02:00
Petri Lehtinen
acec2559a5 C++: Make proxies safer
If a user happens to store an ElementProxy or a PropertyProxy
instance, we need to take a reference to the JSON value they point to.
With PropertyProxy, the key needs to be copied as well.
2010-02-07 14:08:54 +02:00
Petri Lehtinen
286823227c Make int32_t available on all systems
Use AC_TYPE_INT32_T and include inttypes.h (if it exists) instead of
stdint.h for maximum portability.
2010-02-06 21:11:41 +02:00
Petri Lehtinen
8d75235ff2 Merge branch '1.2'
Conflicts:
	LICENSE
2010-02-04 21:13:57 +02:00
Petri Lehtinen
79e9dae9a0 Merge branch 'cleanup-c++-code' 2010-02-04 21:12:36 +02:00
Petri Lehtinen
f021ba00a2 C++: Fix test_cpp.cpp to work with VPATH builds
It reads an input file, and the file location is different with VPATH
builds. Read top_srcdir from environment and use it to find the file.
2010-02-04 21:10:04 +02:00
Petri Lehtinen
adb1b58627 C++: Add Value::dump_file(), load_file() and loads() that take an std::string 2010-02-04 21:08:42 +02:00
Petri Lehtinen
b8059a1880 C++: Rename some functions to better match the C API
Value::save_file -> Value::dump_file
Value::save_string -> Value::dumps
load_string -> loads
2010-02-04 21:08:38 +02:00
Petri Lehtinen
49d40f020b C++: #include <cstdio> in jansson.hpp
This is to avoid standard C functions ending up in namespace json, as
jansson.h is #included in there, and jansson.h in turn #includes
stdio.h.
2010-02-04 20:50:02 +02:00
Petri Lehtinen
910a2f318b C++: Rename test.json to test_cpp.json 2010-02-04 20:49:01 +02:00
Petri Lehtinen
08dc8d9baf Add year 2010 to copyright notices 2010-02-02 21:26:11 +02:00
Petri Lehtinen
c9fc055351 Add myself as another copyright holder for jansson.hpp and jansson.ipp 2010-02-02 21:14:50 +02:00
Petri Lehtinen
d1a0c3ffc2 C++: Rename jansson-impl.hpp to jansson.ipp
The .ipp suffix is for inlined template implementation code.

While at it, use #ifdef and #ifndef instead of #if defined().
2010-02-02 21:10:58 +02:00
Petri Lehtinen
b07e69c37a C++: Rename namespace json::_private to json::detail 2010-02-02 21:01:50 +02:00
Petri Lehtinen
2b43e7dbda C++: Untabify, reindent, delete trailing whitespace 2010-02-02 21:00:10 +02:00
Petri Lehtinen
5b1a666cf1 test/suites/api: Detect tests correctly
The C++ test case didn't work correctly in VPATH builds or with
VALGRIND=1.
2010-02-02 20:37:02 +02:00
Petri Lehtinen
b495b96547 Add functions json_object_iter_{at,set,set_new} 2010-02-01 21:07:19 +02:00
Petri Lehtinen
72e3948438 Merge branch '1.2' 2010-01-28 21:05:19 +02:00
Petri Lehtinen
f5662a82cd test/suites/api/test_object.c: Enhance tests for iterators 2010-01-28 21:04:21 +02:00
Petri Lehtinen
ab2e567685 test/suites/api: Fail when a test fails
The valgrind fix a while back apparently made the test system not
notice normal failures in suites/api.
2010-01-28 20:58:26 +02:00
Petri Lehtinen
d8ea2f8c4b run-tests.sh: Print the test name correctly when VERBOSE=1 2010-01-28 20:57:52 +02:00
Petri Lehtinen
aaae37afba doc/Makefile.am: Don't remove changes.rst in clean 2010-01-26 21:19:48 +02:00
Petri Lehtinen
04f7e27877 Update LICENSE 2010-01-21 22:31:06 +02:00
Petri Lehtinen
3dd29366b8 Merge branch 'c++-api' 2010-01-21 22:29:26 +02:00
Petri Lehtinen
8c2ca3fae6 jansson 1.2 2010-01-21 21:49:10 +02:00
Petri Lehtinen
2ae279e0d4 test/run-suites: Be less picky when searching for tests
This is to better catch distribution errors. It's easier to notice
that run-tests fails than to notice that one of many test suites is
silently skipped.
2010-01-21 21:49:04 +02:00
Petri Lehtinen
4c6cb6afd1 Distribute some missing files 2010-01-21 21:48:31 +02:00
Petri Lehtinen
78594e9bd3 Remove CHANGES preprocessing, as it didn't work with VPATH builds
The problem is that Sphinx can only read input files from a single
directory. In VPATH builds, the source and build trees are separate,
and the changes.rst went into the build tree.

This patch solves the issue by using cfunc as the Sphinx default role.
2010-01-21 20:53:05 +02:00
Petri Lehtinen
e921e63b54 CHANGES: Update for v1.2 2010-01-19 21:19:37 +02:00
Sean Middleditch
38950b081c add meaningful copyright to jansson-impl.hpp too 2010-01-18 21:55:41 -08:00
Sean Middleditch
56687e9b56 add meaningful copyright to jansson.hpp 2010-01-18 21:55:25 -08:00
Sean Middleditch
c9b33e3386 integrate jansson.hpp into build and test suite 2010-01-18 21:36:02 -08:00
Sean Middleditch
2ad4634de5 Merge branch 'master' of /home/elanthis/Source/janssonxx
Conflicts:
	.gitignore
2010-01-18 21:26:10 -08:00
Sean Middleditch
e080667729 replace json::from() with explicit Value() constructors 2010-01-18 19:24:25 -08:00
Sean Middleditch
ef6c35ae1b move static functions out of Value, add test driver to ensure linking works properly 2010-01-18 18:50:13 -08:00
Sean Middleditch
95bf762eeb rename jansson namespace to json 2010-01-18 18:37:13 -08:00
Petri Lehtinen
f9febb64c5 Merge branch '1.1'
Conflicts:
	Makefile.am
2010-01-17 13:57:20 +02:00
Sean Middleditch
dd36e4e838 rename files to match upstream's preferences 2010-01-16 20:27:13 -08:00
Sean Middleditch
df35adc438 add comments noting inefficiency of stream ops 2010-01-16 20:21:52 -08:00
Sean Middleditch
f88a5a0e6b added a couple minor comments 2010-01-16 20:17:48 -08:00
Sean Middleditch
cc06bc334a cleanup code 2010-01-16 20:15:33 -08:00
Sean Middleditch
2dc2b6bab7 rename ArrayProxy to ElementProxy and ObjectProxy to PropertyProxy 2010-01-16 01:40:16 -08:00
Sean Middleditch
49a64a6edf rename and move the _* private classes to _private namespace 2010-01-16 01:36:13 -08:00
Sean Middleditch
f0be52f9f8 add object property proxy support 2010-01-16 01:31:37 -08:00
Sean Middleditch
1bc0225441 add array element proxy support 2010-01-16 01:24:27 -08:00
Sean Middleditch
87df8bb0fe templatize janssonxx functionality to prepare for proxy setters 2010-01-16 01:13:19 -08:00
Petri Lehtinen
b76ee75aad doc: Convert CHANGES to reStructuredText and add it to HTML docs
CHANGES is preprocessed to convert json_*() function names to Sphinx
:cfunc: cross references. This is to keep CHANGES more readable in
both plain text and HTML.
2010-01-14 22:03:48 +02:00
Sean Middleditch
69437a7183 dont attempt to create a std::string from NULL in as_string() 2010-01-13 18:35:07 -08:00
Sean Middleditch
63f762bc48 save flags default to 0 2010-01-13 18:34:17 -08:00
Sean Middleditch
5a0efe6536 add a safeguard against NULL return output stream 2010-01-13 18:33:19 -08:00
Sean Middleditch
01759517aa add Value::from(float) 2010-01-13 18:32:44 -08:00
Sean Middleditch
17805e5829 insert and remove methods 2010-01-12 16:17:11 -08:00
Sean Middleditch
492d95329a add proper attribution to janssonxx.h 2010-01-12 16:07:57 -08:00
Sean Middleditch
7ba18d3f0a use different temporaries in tests instead of reusing e3 2010-01-12 16:03:27 -08:00
Sean Middleditch
7d09af38c1 remove auto type conversion on array/object assignment 2010-01-12 15:38:47 -08:00
Sean Middleditch
8d3a9e347c rename as_json_t to as_json 2010-01-12 15:33:36 -08:00
Sean Middleditch
f79a81dad9 add (ugly) stream support 2010-01-12 15:29:45 -08:00
Sean Middleditch
b98e9d180c rename the set() methods 2010-01-12 15:14:57 -08:00
Petri Lehtinen
b077d7988e Update documentation
* Python is no longer required to run the tests
* Mention pkg-config support
* Fix some errors
2010-01-12 21:29:16 +02:00
Sean Middleditch
8d5d2a93d5 remove some unnecessary checks 2010-01-12 04:30:02 -08:00
Sean Middleditch
d77c2e3fb0 cleanup the take_ownership function a bit 2010-01-12 04:26:30 -08:00
Sean Middleditch
7ef3202f83 added save_file and save_string methods 2010-01-12 04:20:17 -08:00
Sean Middleditch
36085ab49a include jansson.h inside the jansson namespace 2010-01-12 04:13:26 -08:00
Sean Middleditch
f743c4ee7f test object property assignment and clear 2010-01-12 01:41:17 -08:00
Sean Middleditch
c994eddec4 expand array assignment tests 2010-01-12 01:34:58 -08:00
Sean Middleditch
5a20e2695b add link to Jansson web to README 2010-01-12 01:31:08 -08:00
Sean Middleditch
cd18aa97f0 added README 2010-01-12 01:29:44 -08:00
Sean Middleditch
bd09127859 cleaner assignment behavior 2010-01-12 01:26:47 -08:00
Sean Middleditch
6818c117ee ignore test-bin output file 2010-01-12 01:10:38 -08:00
Sean Middleditch
39601c183a add tests 2010-01-12 01:10:20 -08:00
Sean Middleditch
1e3b41e8ea initial commit of janssonxx.h 2010-01-12 01:10:09 -08:00
Petri Lehtinen
7f8684828d Fix memory leaks in json_equal() tests 2010-01-10 21:02:08 +02:00
Petri Lehtinen
93ac06c902 Fix memory leaks in json_*_deep_copy() 2010-01-10 21:01:07 +02:00
Petri Lehtinen
b21f07b35c Enable Valgrind support in the API suite
It was accidentally left out when the test system was refactored.
2010-01-10 16:18:46 +02:00
Petri Lehtinen
508873de9b Use _nocheck functions internally for speed
There are some places where we copy a string from an existing JSON
value. In these cases the string has already been checked for valid
UTF-8.
2010-01-10 14:39:11 +02:00
Petri Lehtinen
aeb5b481c9 Add pkg-config support
Thanks to Sean Middleditch for contributing.
2010-01-07 19:30:20 +02:00
Petri Lehtinen
9db34dc31a Add functions for shallow and deep copying JSON values 2009-12-31 18:50:39 +02:00
Petri Lehtinen
95a468cebb Add equality test for JSON values 2009-12-31 18:50:36 +02:00
Petri Lehtinen
22173c1d8b Add check-exports test 2009-12-23 22:29:59 +02:00
Petri Lehtinen
dd2fe1ebe8 Add _nocheck functions
Added functions are:

* json_string_nocheck()
* json_string_set_nocheck()
* json_object_set_nocheck()
* json_object_set_new_nocheck()

These functions don't check that their string argument is valid UTF-8,
but assume that the user has already performed the check.
2009-12-23 22:28:24 +02:00
Petri Lehtinen
6637b976ed Merge branch '1.1' 2009-12-21 14:13:05 +02:00
Petri Lehtinen
f5202bedef Remove const qualifier from the json_t parameter in json_*_set() functions.
It's incorrect as these functions modify the value.
2009-12-21 14:12:06 +02:00
Petri Lehtinen
2db2f2cfb6 Fix tests for real
The tests were broken by the "%.17g" fix that was merged from the 1.1
branch.
2009-12-21 12:52:29 +02:00
Petri Lehtinen
e7a5dc58e6 Merge branch '1.1'
Conflicts:
	configure.ac
	doc/conf.py
2009-12-21 12:52:25 +02:00
Petri Lehtinen
3889af476b Enhance tests
* Now that JSON_SORT_KEYS is implemented, take it into use with the
  valid and valid-strip suites. This is to ensure that the tests
  remain valid even if the string hash function is changed in the
  future.

* Remove test_dump API test. Instead, implement the same tests more
  elegantly in the encoding-flags suite.
2009-12-21 12:50:49 +02:00
Petri Lehtinen
19a606d736 Implement JSON_SORT_KEYS encoding flag
With this flag, the objects are sorted by key when encoding.
2009-12-16 23:12:39 +02:00
Petri Lehtinen
3add1cf361 Refactor the test system 2009-12-16 22:45:29 +02:00
Petri Lehtinen
50031440a3 Implement JSON_ENSURE_ASCII encoding flag
With this flag, all Unicode characters outside the ASCII range are
escaped.
2009-12-05 22:55:30 +02:00
Petri Lehtinen
d67aeb9739 Use int32_t instead of plain int with Unicode code points
On some architectures, int just isn't big enough to hold all Unicode
code points.
2009-12-02 23:53:54 +02:00
Petri Lehtinen
e0a88d19d1 Merge branch '1.1'
Conflicts:
	configure.ac
	doc/conf.py
2009-11-08 22:01:02 +02:00
Petri Lehtinen
17d913307e Merge branch '1.1'
Conflicts:
	test/.gitignore
	test/testprogs/Makefile.am
2009-11-04 22:10:46 +02:00
Petri Lehtinen
f236c14dc5 dump: Revise whitespace usage
- Never append newline to output
- By default, add spaces between array and object items for more
  readable output
- Introduce the flag JSON_COMPACT to not add the aforementioned spaces
2009-11-04 22:09:40 +02:00
Petri Lehtinen
bf01067a8a Build documentation in make html target
To keep the distchecks for the documentation, the documentation has to
be built in the check target instead of distcheck-hook.

While at it, rename doc/.build to doc/_build. This naming is the
default with sphinx 0.6.2.
2009-11-03 23:09:04 +02:00
Petri Lehtinen
d1b07171cc Merge branch '1.1'
Conflicts:
	CHANGES
	configure.ac
	doc/conf.py
2009-10-26 21:33:03 +02:00
Petri Lehtinen
5ff8ae8052 Fix version 1.1 release date in CHANGES 2009-10-21 08:52:34 +03:00
Petri Lehtinen
8d53f447bf Set the version number to 1.1+ 2009-10-21 08:51:43 +03:00
458 changed files with 3165 additions and 1336 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*~
*.o
*.a
.libs
@@ -22,3 +23,5 @@ missing
*.la
stamp-h1
*.pyc
*.pc
/src/jansson.h

165
CHANGES
View File

@@ -1,54 +1,172 @@
Version 1.1.3, released 2009-12-18
Version 1.3
===========
Released 2010-06-13
* New encoding flags:
- ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object
keys.
* Bug fixes:
- Fix an error that occured when an array or object was first
encoded as empty, then populated with some data, and then
re-encoded
- Fix the situation like above, but when the first encoding resulted
in an error
* Documentation:
- Clarify the documentation on reference stealing, providing an
example usage pattern
Version 1.2.1
=============
Released 2010-04-03
* Bug fixes:
- Fix reference counting on ``true``, ``false`` and ``null``
- Estimate real number underflows in decoder with 0.0 instead of
issuing an error
* Portability:
- Make ``int32_t`` available on all systems
- Support compilers that don't have the ``inline`` keyword
- Require Autoconf 2.60 (for ``int32_t``)
* Tests:
- Print test names correctly when ``VERBOSE=1``
- ``test/suites/api``: Fail when a test fails
- Enhance tests for iterators
- Enhance tests for decoding texts that contain null bytes
* Documentation:
- Don't remove ``changes.rst`` in ``make clean``
- Add a chapter on RFC conformance
Version 1.2
===========
Released 2010-01-21
* New functions:
- `json_equal()`: Test whether two JSON values are equal
- `json_copy()` and `json_deep_copy()`: Make shallow and deep copies
of JSON values
- Add a version of all functions taking a string argument that
doesn't check for valid UTF-8: `json_string_nocheck()`,
`json_string_set_nocheck()`, `json_object_set_nocheck()`,
`json_object_set_new_nocheck()`
* New encoding flags:
- ``JSON_SORT_KEYS``: Sort objects by key
- ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters
- ``JSON_COMPACT``: Use a compact representation with all unneeded
whitespace stripped
* Bug fixes:
- Revise and unify whitespace usage in encoder: Add spaces between
array and object items, never append newline to output.
- Remove const qualifier from the ``json_t`` parameter in
`json_string_set()`, `json_integer_set()` and `json_real_set`.
- Use ``int32_t`` internally for representing Unicode code points
(int is not enough on all platforms)
* Other changes:
- Convert ``CHANGES`` (this file) to reStructured text and add it to
HTML documentation
- The test system has been refactored. Python is no longer required
to run the tests.
- Documentation can now be built by invoking ``make html``
- Support for pkg-config
Version 1.1.3
=============
Released 2009-12-18
* Encode reals correctly, so that first encoding and then decoding a
real always produces the same value
* Don't export private symbols in libjansson.so
* Don't export private symbols in ``libjansson.so``
Version 1.1.2, released 2009-11-08
Version 1.1.2
=============
Released 2009-11-08
* Fix a bug where an error message was not produced if the input file
could not be opened in json_load_file()
could not be opened in `json_load_file()`
* Fix an assertion failure in decoder caused by a minus sign without a
digit after it
* Remove an unneeded include for stdint.h in jansson.h
* Remove an unneeded include of ``stdint.h`` in ``jansson.h``
Version 1.1.1, released 2009-10-26
Version 1.1.1
=============
Released 2009-10-26
* All documentation files were not distributed with v1.1; build
documentation in make distcheck to prevent this in the future
* Fix v1.1 release date in CHANGES
* Fix v1.1 release date in ``CHANGES``
Version 1.1, released 2009-10-20
Version 1.1
===========
Released 2009-10-20
* API additions and improvements:
- Extend array and object APIs
- Add functions to modify integer, real and string values
- Improve argument validation
- Use unsigned int instead of uint32_t for encoding flags
- Use unsigned int instead of ``uint32_t`` for encoding flags
* Enhance documentation
- Add getting started guide and tutorial
- Fix some typos
- General clarifications and cleanup
* Check for integer and real overflows and underflows in decoder
* Make singleton values thread-safe (true, false and null)
* Make singleton values thread-safe (``true``, ``false`` and ``null``)
* Enhance circular reference handling
* Don't define -std=c99 in AM_CFLAGS
* Add C++ guards to jansson.h
* Don't define ``-std=c99`` in ``AM_CFLAGS``
* Add C++ guards to ``jansson.h``
* Minor performance and portability improvements
* Expand test coverage
Version 1.0.4, released 2009-10-11
Version 1.0.4
=============
Released 2009-10-11
* Relax Autoconf version requirement to 2.59
* Make Jansson compile on platforms where plain char is unsigned
* Make Jansson compile on platforms where plain ``char`` is unsigned
* Fix API tests for object
Version 1.0.3, released 2009-09-14
Version 1.0.3
=============
Released 2009-09-14
* Check for integer and real overflows and underflows in decoder
* Use the Python json module for tests, or simplejson if the json
@@ -56,16 +174,25 @@ Version 1.0.3, released 2009-09-14
* Distribute changelog (this file)
Version 1.0.2, released 2009-09-08
Version 1.0.2
=============
Released 2009-09-08
* Handle EOF correctly in decoder
Version 1.0.1, released 2009-09-04
Version 1.0.1
=============
* Fixed broken json_is_boolean()
Released 2009-09-04
* Fixed broken `json_is_boolean()`
Version 1.0, released 2009-08-25
Version 1.0
===========
Released 2009-08-25
* Initial release

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,7 +1,7 @@
EXTRA_DIST = CHANGES LICENSE README.rst
SUBDIRS = doc src test
distcheck-hook:
sphinx-build -b html -W \
$(distdir)/doc \
$(distdir)/_build/doc/.build/html
check-local: html
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = jansson.pc

View File

@@ -36,8 +36,6 @@ To run the test suite, invoke::
$ make check
Python_ is required to run the tests.
Documentation
-------------
@@ -49,15 +47,13 @@ available at http://www.digip.org/jansson/doc/.
To generate HTML documentation yourself, invoke::
cd doc/
sphinx-build . .build/html
make html
... and point your browser to ``.build/html/index.html``. Sphinx_ is
and point your browser to ``doc/_build/html/index.html``. Sphinx_ is
required to generate the documentation.
.. _Jansson: http://www.digip.org/jansson/
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _Python: http://www.python.org/
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _Sphinx: http://sphinx.pocoo.org/

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.59])
AC_INIT([jansson], [1.1.3], [petri@digip.org])
AC_PREREQ([2.60])
AC_INIT([jansson], [1.3], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
@@ -8,6 +8,7 @@ AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_LIBTOOL
# Checks for libraries.
@@ -15,15 +16,27 @@ AC_PROG_LIBTOOL
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
AC_C_INLINE
case $ac_cv_c_inline in
yes) json_inline=inline;;
no) json_inline=;;
*) json_inline=$ac_cv_c_inline;;
esac
AC_SUBST([json_inline])
# Checks for library functions.
AC_CONFIG_FILES([
jansson.pc
Makefile
doc/Makefile
src/Makefile
src/jansson.h
test/Makefile
test/testdata/Makefile
test/testprogs/Makefile
test/bin/Makefile
test/suites/Makefile
test/suites/api/Makefile
])
AC_OUTPUT

2
doc/.gitignore vendored
View File

@@ -1 +1 @@
.build/
_build/

View File

@@ -1,7 +1,20 @@
EXTRA_DIST = \
conf.py apiref.rst gettingstarted.rst github_commits.c index.rst \
tutorial.rst ext/refcounting.py
EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \
gettingstarted.rst github_commits.c index.rst tutorial.rst \
ext/refcounting.py
SPHINXBUILD = sphinx-build
SPHINXOPTS = -d _build/doctrees -W
html-local:
$(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html
install-html-local: html
mkdir -p $(DESTDIR)$(htmldir)
cp -r _build/html $(DESTDIR)$(htmldir)
uninstall-local:
rm -rf $(DESTDIR)$(htmldir)
clean-local:
rm -rf .build
rm -rf _build
rm -f ext/refcounting.pyc

View File

@@ -1,5 +1,5 @@
To build the documentation, invoke
sphinx-build . .build/html
make html
in this directory. Then point your browser to .build/html/index.html.
Then point your browser to _build/html/index.html.

View File

@@ -154,9 +154,31 @@ Normally, all functions accepting a JSON value as an argument will
manage the reference, i.e. increase and decrease the reference count
as needed. However, some functions **steal** the reference, i.e. they
have the same result as if the user called :cfunc:`json_decref()` on
the argument right after calling the function. These are usually
convenience functions for adding new references to containers and not
to worry about the reference count.
the argument right after calling the function. These functions are
suffixed with ``_new`` or have ``_new_`` somewhere in their name.
For example, the following code creates a new JSON array and appends
an integer to it::
json_t *array, *integer;
array = json_array();
integer = json_integer(42);
json_array_append(array, integer);
json_decref(integer);
Note how the caller has to release the reference to the integer value
by calling :cfunc:`json_decref()`. By using a reference stealing
function :cfunc:`json_array_append_new()` instead of
:cfunc:`json_array_append()`, the code becomes much simpler::
json_t *array = json_array();
json_array_append_new(array, json_integer(42));
In this case, the user doesn't have to explicitly release the
reference to the integer value, as :cfunc:`json_array_append_new()`
steals the reference when appending the value to the array.
In the following sections it is clearly documented whether a function
will return a new or borrowed reference or steal a reference to its
@@ -229,6 +251,16 @@ String
Returns a new JSON string, or *NULL* on error. *value* must be a
valid UTF-8 encoded Unicode string.
.. cfunction:: json_t *json_string_nocheck(const char *value)
.. refcounting:: new
Like :cfunc:`json_string`, but doesn't check that *value* is valid
UTF-8. Use this function only if you are certain that this really
is the case (e.g. you have already checked it by other means).
.. versionadded:: 1.2
.. cfunction:: const char *json_string_value(const json_t *string)
Returns the associated value of *string* as a null terminated UTF-8
@@ -242,6 +274,15 @@ String
.. versionadded:: 1.1
.. cfunction:: int json_string_set_nocheck(const json_t *string, const char *value)
Like :cfunc:`json_string_set`, but doesn't check that *value* is
valid UTF-8. Use this function only if you are certain that this
really is the case (e.g. you have already checked it by other
means).
.. versionadded:: 1.2
Number
======
@@ -420,6 +461,15 @@ Unicode string and the value is any JSON value.
already is a value for *key*, it is replaced by the new value.
Returns 0 on success and -1 on error.
.. cfunction:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
Like :cfunc:`json_object_set`, but doesn't check that *key* is
valid UTF-8. Use this function only if you are certain that this
really is the case (e.g. you have already checked it by other
means).
.. versionadded:: 1.2
.. cfunction:: int json_object_set_new(json_t *object, const char *key, json_t *value)
Like :cfunc:`json_object_set()` but steals the reference to
@@ -428,6 +478,15 @@ Unicode string and the value is any JSON value.
.. versionadded:: 1.1
.. cfunction:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value)
Like :cfunc:`json_object_set_new`, but doesn't check that *key* is
valid UTF-8. Use this function only if you are certain that this
really is the case (e.g. you have already checked it by other
means).
.. versionadded:: 1.2
.. cfunction:: int json_object_del(json_t *object, const char *key)
Delete *key* from *object* if it exists. Returns 0 on success, or
@@ -456,6 +515,16 @@ The following functions implement an iteration protocol for objects:
Returns an opaque iterator which can be used to iterate over all
key-value pairs in *object*, or *NULL* if *object* is empty.
.. cfunction:: void *json_object_iter_at(json_t *object, const char *key)
Like :cfunc:`json_object_iter()`, but returns an iterator to the
key-value pair in *object* whose key is equal to *key*, or NULL if
*key* is not found in *object*. Iterating forward to the end of
*object* only yields all key-value pairs of the object if *key*
happens to be the first key in the underlying hash table.
.. versionadded:: 1.3
.. cfunction:: void *json_object_iter_next(json_t *object, void *iter)
Returns an iterator pointing to the next key-value pair in *object*
@@ -472,6 +541,21 @@ The following functions implement an iteration protocol for objects:
Extract the associated value from *iter*.
.. cfunction:: int json_object_iter_set(json_t *object, void *iter, json_t *value)
Set the value of the key-value pair in *object*, that is pointed to
by *iter*, to *value*.
.. versionadded:: 1.3
.. cfunction:: int json_object_iter_set_new(json_t *object, void *iter, json_t *value)
Like :cfunc:`json_object_iter_set()`, but steals the reference to
*value*. This is useful when *value* is newly created and not used
after the call.
.. versionadded:: 1.3
The iteration protocol can be used for example as follows::
/* obj is a JSON object */
@@ -494,16 +578,52 @@ This sections describes the functions that can be used to encode
values to JSON. Only objects and arrays can be encoded, since they are
the only valid "root" values of a JSON text.
By default, the output has no newlines, and spaces are used between
array and object elements for a readable output. This behavior can be
altered by using the ``JSON_INDENT`` and ``JSON_COMPACT`` flags
described below. A newline is never appended to the end of the encoded
JSON data.
Each function takes a *flags* parameter that controls some aspects of
how the data is encoded. Its default value is 0. The following macros
can be ORed together to obtain *flags*.
``JSON_INDENT(n)``
Pretty-print the result, indenting arrays and objects by *n*
spaces. The valid range for *n* is between 0 and 255, other values
result in an undefined output. If ``JSON_INDENT`` is not used or
*n* is 0, no pretty-printing is done and the result is a compact
representation.
Pretty-print the result, using newlines between array and object
items, and indenting with *n* spaces. The valid range for *n* is
between 0 and 255, other values result in an undefined output. If
``JSON_INDENT`` is not used or *n* is 0, no newlines are inserted
between array and object items.
``JSON_COMPACT``
This flag enables a compact representation, i.e. sets the separator
between array and object items to ``","`` and between object keys
and values to ``":"``. Without this flag, the corresponding
separators are ``", "`` and ``": "`` for more readable output.
.. versionadded:: 1.2
``JSON_ENSURE_ASCII``
If this flag is used, the output is guaranteed to consist only of
ASCII characters. This is achived by escaping all Unicode
characters outside the ASCII range.
.. versionadded:: 1.2
``JSON_SORT_KEYS``
If this flag is used, all the objects in output are sorted by key.
This is useful e.g. if two JSON texts are diffed or visually
compared.
.. versionadded:: 1.2
``JSON_PRESERVE_ORDER``
If this flag is used, object keys in the output are sorted into the
same order in which they were first inserted to the object. For
example, decoding a JSON text and then encoding with this flag
preserves the order of object keys.
.. versionadded:: 1.3
The following functions perform the actual JSON encoding. The result
is in UTF-8.
@@ -608,3 +728,75 @@ The following functions perform the actual JSON decoding.
object it contains, or *NULL* on error, in which case *error* is
filled with information about the error. See above for discussion
on the *error* parameter.
Equality
========
Testing for equality of two JSON values cannot, in general, be
achieved using the ``==`` operator. Equality in the terms of the
``==`` operator states that the two :ctype:`json_t` pointers point to
exactly the same JSON value. However, two JSON values can be equal not
only if they are exactly the same value, but also if they have equal
"contents":
* Two integer or real values are equal if their contained numeric
values are equal. An integer value is never equal to a real value,
though.
* Two strings are equal if their contained UTF-8 strings are equal.
* Two arrays are equal if they have the same number of elements and
each element in the first array is equal to the corresponding
element in the second array.
* Two objects are equal if they have exactly the same keys and the
value for each key in the first object is equal to the value of the
corresponding key in the second object.
* Two true, false or null values have no "contents", so they are equal
if their types are equal. (Because these values are singletons,
their equality can actually be tested with ``==``.)
The following function can be used to test whether two JSON values are
equal.
.. cfunction:: int json_equal(json_t *value1, json_t *value2)
Returns 1 if *value1* and *value2* are equal, as defined above.
Returns 0 if they are inequal or one or both of the pointers are
*NULL*.
.. versionadded:: 1.2
Copying
=======
Because of reference counting, passing JSON values around doesn't
require copying them. But sometimes a fresh copy of a JSON value is
needed. For example, if you need to modify an array, but still want to
use the original afterwards, you should take a copy of it first.
Jansson supports two kinds of copying: shallow and deep. There is a
difference between these methods only for arrays and objects. Shallow
copying only copies the first level value (array or object) and uses
the same child values in the copied value. Deep copying makes a fresh
copy of the child values, too. Moreover, all the child values are deep
copied in a recursive fashion.
.. cfunction:: json_t *json_copy(json_t *value)
.. refcounting:: new
Returns a shallow copy of *value*, or *NULL* on error.
.. versionadded:: 1.2
.. cfunction:: json_t *json_deep_copy(json_t *value)
.. refcounting:: new
Returns a deep copy of *value*, or *NULL* on error.
.. versionadded:: 1.2

5
doc/changes.rst Normal file
View File

@@ -0,0 +1,5 @@
******************
Changes in Jansson
******************
.. include:: ../CHANGES

View File

@@ -43,16 +43,16 @@ master_doc = 'index'
# General information about the project.
project = u'Jansson'
copyright = u'2009, Petri Lehtinen'
copyright = u'2009, 2010 Petri Lehtinen'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.1'
version = '1.3'
# The full version, including alpha/beta/rc tags.
release = '1.1.3'
release = '1.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -69,10 +69,10 @@ release = '1.1.3'
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['.build']
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
default_role = 'cfunc'
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

102
doc/conformance.rst Normal file
View File

@@ -0,0 +1,102 @@
***************
RFC Conformance
***************
JSON is specified in :rfc:`4627`, *"The application/json Media Type
for JavaScript Object Notation (JSON)"*. This chapter discusses
Jansson's conformance to this specification.
Character Encoding
==================
Jansson only supports UTF-8 encoded JSON texts. It does not support or
auto-detect any of the other encodings mentioned in the RFC, namely
UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as
it's a subset of UTF-8.
Strings
=======
JSON strings are mapped to C-style null-terminated character arrays,
and UTF-8 encoding is used internally. Strings may not contain
embedded null characters, not even escaped ones.
For example, trying to decode the following JSON text leads to a parse
error::
["this string contains the null character: \u0000"]
All other Unicode codepoints U+0001 through U+10FFFF are allowed.
Numbers
=======
Real vs. Integer
----------------
JSON makes no distinction between real and integer numbers; Jansson
does. Real numbers are mapped to the ``double`` type and integers to
the ``int`` type.
A JSON number is considered to be a real number if its lexical
representation includes one of ``e``, ``E``, or ``.``; regardless if
its actual numeric value is a true integer (e.g., all of ``1E6``,
``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but
will be treated as real values).
All other JSON numbers are considered integers.
When encoding to JSON, real values are always represented
with a fractional part; e.g., the ``double`` value 3.0 will be
represented in JSON as ``3.0``, not ``3``.
Overflow, Underflow & Precision
-------------------------------
Real numbers whose absolute values are too small to be represented in
a C double will be silently estimated with 0.0. Thus, depending on
platform, JSON numbers very close to zero such as 1E-999 may result in
0.0.
Real numbers whose absolute values are too large to be represented in
a C ``double`` type will result in an overflow error (a JSON decoding
error). Thus, depending on platform, JSON numbers like 1E+999 or
-1E+999 may result in a parsing error.
Likewise, integer numbers whose absolute values are too large to be
represented in the ``int`` type will result in an overflow error (a
JSON decoding error). Thus, depending on platform, JSON numbers like
1000000000000000 may result in parsing error.
Parsing JSON real numbers may result in a loss of precision. As long
as overflow does not occur (i.e. a total loss of precision), the
rounded approximate value is silently used. Thus the JSON number
1.000000000000000005 may, depending on platform, result in the
``double`` value 1.0.
Signed zeros
------------
JSON makes no statement about what a number means; however Javascript
(ECMAscript) does state that +0.0 and -0.0 must be treated as being
distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the
underlying floating point library in the C environment in which it is
compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will
be distinct values. Most platforms that use the IEEE 754
floating-point standard will support signed zeros.
Note that this only applies to floating-point; neither JSON, C, or
IEEE support the concept of signed integer zeros.
.. |not-equal| unicode:: U+2260
Types
-----
No support is provided in Jansson for any C numeric types other than
``int`` and ``double``. This excludes things such as unsigned types,
``long``, ``long long``, ``long double``, etc. Obviously, shorter
types like ``short`` and ``float`` are implicitly handled via the
ordinary C type coercion rules (subject to overflow semantics). Also,
no support or hooks are provided for any supplemental "bignum" type
add-on packages.

View File

@@ -19,7 +19,7 @@
<description of the json_object function>
:copyright: Copyright 2009 Petri Lehtinen <petri@digip.org>
:copyright: Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
:license: MIT, see LICENSE for details.
"""

View File

@@ -31,9 +31,9 @@ the ``--prefix=DIR`` argument to ``./configure``. See ``./configure
no options to customize the resulting Jansson binary.)
The command ``make check`` runs the test suite distributed with
Jansson. Python_ is required to run the tests. This step is not
strictly necessary, but it may find possible problems that Jansson has
on your platform. If any problems are found, please report them.
Jansson. This step is not strictly necessary, but it may find possible
problems that Jansson has on your platform. If any problems are found,
please report them.
If you obtained the source from a Git repository (or any other source
control system), there's no ``./configure`` script as it's not kept in
@@ -44,12 +44,11 @@ to use ``autoreconf``::
autoreconf -vi
This command creates the ``./configure`` script, which can then be
used as described in the previous section.
used as described above.
.. _autoconf: http://www.gnu.org/software/autoconf/
.. _automake: http://www.gnu.org/software/automake/
.. _libtool: http://www.gnu.org/software/libtool/
.. _Python: http://www.python.org/
Installing Prebuilt Binary Packages
@@ -76,18 +75,17 @@ Documentation is in the ``doc/`` subdirectory. It's written in
reStructuredText_ with Sphinx_ annotations. To generate the HTML
documentation, invoke::
cd doc/
sphinx-build . .build/html
make html
... and point your browser to ``.build/html/index.html``. Sphinx_ is
and point your browser to ``doc/_build/html/index.html``. Sphinx_ is
required to generate the documentation.
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _Sphinx: http://sphinx.pocoo.org/
Compiling Programs Using Jansson
================================
Compiling Programs That Use Jansson
===================================
Jansson involves one C header file, :file:`jansson.h`, so it's enough
to put the line
@@ -102,3 +100,9 @@ There's also just one library to link with, ``libjansson``. Compile and
link the program as follows::
cc -o prog prog.c -ljansson
Starting from version 1.2, there's also support for pkg-config_::
cc -o prog prog.c `pkg-config --cflags --libs jansson`
.. _pkg-config: http://pkg-config.freedesktop.org/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -34,7 +34,9 @@ Contents
gettingstarted
tutorial
conformance
apiref
changes
Indices and Tables

10
jansson.pc.in Normal file
View File

@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=${prefix}/include
Name: Jansson
Description: Library for encoding, decoding and manipulating JSON data
Version: @VERSION@
Libs: -L${libdir} -ljansson
Cflags: -I${includedir}

View File

@@ -15,6 +15,6 @@ libjansson_la_SOURCES = \
value.c
libjansson_la_LDFLAGS = \
-export-symbols-regex '^json_' \
-version-info 1:2:1
-version-info 3:0:3
AM_CFLAGS = -Wall -Wextra -Werror

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -9,10 +9,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <jansson.h>
#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
@@ -42,7 +44,7 @@ static int dump_to_file(const char *buffer, int size, void *data)
/* 256 spaces (the maximum indentation size) */
static char whitespace[] = " ";
static int dump_indent(unsigned long flags, int depth, dump_func dump, void *data)
static int dump_indent(unsigned long flags, int depth, int space, dump_func dump, void *data)
{
if(JSON_INDENT(flags) > 0)
{
@@ -57,37 +59,56 @@ static int dump_indent(unsigned long flags, int depth, dump_func dump, void *dat
return -1;
}
}
else if(space && !(flags & JSON_COMPACT))
{
return dump(" ", 1, data);
}
return 0;
}
static int dump_string(const char *str, dump_func dump, void *data)
static int dump_string(const char *str, int ascii, dump_func dump, void *data)
{
const char *end;
const char *pos, *end;
int32_t codepoint;
if(dump("\"", 1, data))
return -1;
end = str;
end = pos = str;
while(1)
{
const char *text;
char seq[7];
char seq[13];
int length;
while(*end && *end != '\\' && *end != '"' && (unsigned char)*end > 0x1F)
end++;
while(*end)
{
end = utf8_iterate(pos, &codepoint);
if(!end)
return -1;
if(end != str) {
if(dump(str, end - str, data))
/* mandatory escape or control char */
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break;
/* non-ASCII */
if(ascii && codepoint > 0x7F)
break;
pos = end;
}
if(pos != str) {
if(dump(str, pos - str, data))
return -1;
}
if(!*end)
if(end == pos)
break;
/* handle \, ", and control codes */
length = 2;
switch(*end)
switch(codepoint)
{
case '\\': text = "\\\\"; break;
case '\"': text = "\\\""; break;
@@ -98,9 +119,27 @@ static int dump_string(const char *str, dump_func dump, void *data)
case '\t': text = "\\t"; break;
default:
{
sprintf(seq, "\\u00%02x", *end);
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
sprintf(seq, "\\u%04x", codepoint);
length = 6;
}
/* not in BMP -> construct a UTF-16 surrogate pair */
else
{
int32_t first, last;
codepoint -= 0x10000;
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
sprintf(seq, "\\u%04x\\u%04x", first, last);
length = 12;
}
text = seq;
length = 6;
break;
}
}
@@ -108,16 +147,29 @@ static int dump_string(const char *str, dump_func dump, void *data)
if(dump(text, length, data))
return -1;
end++;
str = end;
str = pos = end;
}
return dump("\"", 1, data);
}
static int object_key_compare_keys(const void *key1, const void *key2)
{
return strcmp((*(const object_key_t **)key1)->key,
(*(const object_key_t **)key2)->key);
}
static int object_key_compare_serials(const void *key1, const void *key2)
{
return (*(const object_key_t **)key1)->serial -
(*(const object_key_t **)key2)->serial;
}
static int do_dump(const json_t *json, unsigned long flags, int depth,
dump_func dump, void *data)
{
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
switch(json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
@@ -168,7 +220,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
}
case JSON_STRING:
return dump_string(json_string_value(json), dump, data);
return dump_string(json_string_value(json), ascii, dump, data);
case JSON_ARRAY:
{
@@ -179,87 +231,181 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
/* detect circular references */
array = json_to_array(json);
if(array->visited)
return -1;
goto array_error;
array->visited = 1;
n = json_array_size(json);
if(dump("[", 1, data))
return -1;
if(n == 0)
goto array_error;
if(n == 0) {
array->visited = 0;
return dump("]", 1, data);
if(dump_indent(flags, depth + 1, dump, data))
return -1;
}
if(dump_indent(flags, depth + 1, 0, dump, data))
goto array_error;
for(i = 0; i < n; ++i) {
if(do_dump(json_array_get(json, i), flags, depth + 1,
dump, data))
return -1;
goto array_error;
if(i < n - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, dump, data))
return -1;
dump_indent(flags, depth + 1, 1, dump, data))
goto array_error;
}
else
{
if(dump_indent(flags, depth, dump, data))
return -1;
if(dump_indent(flags, depth, 0, dump, data))
goto array_error;
}
}
array->visited = 0;
return dump("]", 1, data);
array_error:
array->visited = 0;
return -1;
}
case JSON_OBJECT:
{
json_object_t *object;
void *iter;
const char *separator;
int separator_length;
if(flags & JSON_COMPACT) {
separator = ":";
separator_length = 1;
}
else {
separator = ": ";
separator_length = 2;
}
/* detect circular references */
object = json_to_object(json);
if(object->visited)
return -1;
goto object_error;
object->visited = 1;
iter = json_object_iter((json_t *)json);
if(dump("{", 1, data))
return -1;
if(!iter)
goto object_error;
if(!iter) {
object->visited = 0;
return dump("}", 1, data);
if(dump_indent(flags, depth + 1, dump, data))
return -1;
}
if(dump_indent(flags, depth + 1, 0, dump, data))
goto object_error;
while(iter)
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
{
void *next = json_object_iter_next((json_t *)json, iter);
const object_key_t **keys;
unsigned int size;
unsigned int i;
int (*cmp_func)(const void *, const void *);
dump_string(json_object_iter_key(iter), dump, data);
if(dump(": ", 2, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
return -1;
size = json_object_size(json);
keys = malloc(size * sizeof(object_key_t *));
if(!keys)
goto object_error;
if(next)
i = 0;
while(iter)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, dump, data))
return -1;
keys[i] = jsonp_object_iter_fullkey(iter);
iter = json_object_iter_next((json_t *)json, iter);
i++;
}
assert(i == size);
if(flags & JSON_SORT_KEYS)
cmp_func = object_key_compare_keys;
else
cmp_func = object_key_compare_serials;
qsort(keys, size, sizeof(object_key_t *), cmp_func);
for(i = 0; i < size; i++)
{
if(dump_indent(flags, depth, dump, data))
return -1;
const char *key;
json_t *value;
key = keys[i]->key;
value = json_object_get(json, key);
assert(value);
dump_string(key, ascii, dump, data);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data))
{
free(keys);
goto object_error;
}
if(i < size - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
{
free(keys);
goto object_error;
}
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
{
free(keys);
goto object_error;
}
}
}
iter = next;
free(keys);
}
else
{
/* Don't sort keys */
while(iter)
{
void *next = json_object_iter_next((json_t *)json, iter);
dump_string(json_object_iter_key(iter), ascii, dump, data);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
goto object_error;
if(next)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
goto object_error;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
goto object_error;
}
iter = next;
}
}
object->visited = 0;
return dump("}", 1, data);
object_error:
object->visited = 0;
return -1;
}
default:
@@ -285,11 +431,6 @@ char *json_dumps(const json_t *json, unsigned long flags)
return NULL;
}
if(dump_to_strbuffer("\n", 1, (void *)&strbuff)) {
strbuffer_close(&strbuff);
return NULL;
}
result = strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff);
@@ -301,9 +442,7 @@ int json_dumpf(const json_t *json, FILE *output, unsigned long flags)
if(!json_is_array(json) && !json_is_object(json))
return -1;
if(do_dump(json, flags, 0, dump_to_file, (void *)output))
return -1;
return dump_to_file("\n", 1, (void *)output);
return do_dump(json, flags, 0, dump_to_file, (void *)output);
}
int json_dump_file(const json_t *json, const char *path, unsigned long flags)

View File

@@ -1,10 +1,12 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <config.h>
#include <stdlib.h>
#include "hashtable.h"
@@ -247,31 +249,39 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
bucket_t *bucket;
unsigned int hash, index;
hash = hashtable->hash_key(key);
/* if the key already exists, delete it */
hashtable_do_del(hashtable, key, hash);
/* rehash if the load ratio exceeds 1 */
if(hashtable->size >= num_buckets(hashtable))
if(hashtable_do_rehash(hashtable))
return -1;
pair = malloc(sizeof(pair_t));
if(!pair)
return -1;
pair->key = key;
pair->value = value;
pair->hash = hash;
list_init(&pair->list);
hash = hashtable->hash_key(key);
index = hash % num_buckets(hashtable);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
insert_to_bucket(hashtable, bucket, &pair->list);
if(pair)
{
if(hashtable->free_key)
hashtable->free_key(key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
pair->value = value;
}
else
{
pair = malloc(sizeof(pair_t));
if(!pair)
return -1;
hashtable->size++;
pair->key = key;
pair->value = value;
pair->hash = hash;
list_init(&pair->list);
insert_to_bucket(hashtable, bucket, &pair->list);
hashtable->size++;
}
return 0;
}
@@ -318,6 +328,22 @@ void *hashtable_iter(hashtable_t *hashtable)
return hashtable_iter_next(hashtable, &hashtable->list);
}
void *hashtable_iter_at(hashtable_t *hashtable, const void *key)
{
pair_t *pair;
unsigned int hash;
bucket_t *bucket;
hash = hashtable->hash_key(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
return NULL;
return &pair->list;
}
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
{
list_t *list = (list_t *)iter;
@@ -337,3 +363,13 @@ void *hashtable_iter_value(void *iter)
pair_t *pair = list_to_pair((list_t *)iter);
return pair->value;
}
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value)
{
pair_t *pair = list_to_pair((list_t *)iter);
if(hashtable->free_value)
hashtable->free_value(pair->value);
pair->value = value;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -160,6 +160,17 @@ void hashtable_clear(hashtable_t *hashtable);
*/
void *hashtable_iter(hashtable_t *hashtable);
/**
* hashtable_iter_at - Return an iterator at a specific key
*
* @hashtable: The hashtable object
* @key: The key that the iterator should point to
*
* Like hashtable_iter() but returns an iterator pointing to a
* specific key.
*/
void *hashtable_iter_at(hashtable_t *hashtable, const void *key);
/**
* hashtable_iter_next - Advance an iterator
*
@@ -185,4 +196,12 @@ void *hashtable_iter_key(void *iter);
*/
void *hashtable_iter_value(void *iter);
/**
* hashtable_iter_set - Set the value pointed by an iterator
*
* @iter: The iterator
* @value: The value to set
*/
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value);
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -10,7 +10,10 @@
#include <stdio.h>
#ifdef __cplusplus
#ifndef __cplusplus
#define JSON_INLINE @json_inline@
#else
#define JSON_INLINE inline
extern "C" {
#endif
@@ -49,13 +52,15 @@ typedef struct {
json_t *json_object(void);
json_t *json_array(void);
json_t *json_string(const char *value);
json_t *json_string_nocheck(const char *value);
json_t *json_integer(int value);
json_t *json_real(double value);
json_t *json_true(void);
json_t *json_false(void);
json_t *json_null(void);
static inline json_t *json_incref(json_t *json)
static JSON_INLINE
json_t *json_incref(json_t *json)
{
if(json && json->refcount != (unsigned int)-1)
++json->refcount;
@@ -65,7 +70,8 @@ static inline json_t *json_incref(json_t *json)
/* do not call json_delete directly */
void json_delete(json_t *json);
static inline void json_decref(json_t *json)
static JSON_INLINE
void json_decref(json_t *json)
{
if(json && json->refcount != (unsigned int)-1 && --json->refcount == 0)
json_delete(json);
@@ -77,20 +83,35 @@ static inline void json_decref(json_t *json)
unsigned int json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
static inline
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
return json_object_set_new(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
{
return json_object_set_new_nocheck(object, key, json_incref(value));
}
static inline
int json_object_iter_set(json_t *object, void *iter, json_t *value)
{
return json_object_iter_set_new(object, iter, json_incref(value));
}
unsigned int json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, unsigned int index);
int json_array_set_new(json_t *array, unsigned int index, json_t *value);
@@ -100,19 +121,19 @@ int json_array_remove(json_t *array, unsigned int index);
int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other);
static inline
static JSON_INLINE
int json_array_set(json_t *array, unsigned int index, json_t *value)
{
return json_array_set_new(array, index, json_incref(value));
}
static inline
static JSON_INLINE
int json_array_append(json_t *array, json_t *value)
{
return json_array_append_new(array, json_incref(value));
}
static inline
static JSON_INLINE
int json_array_insert(json_t *array, unsigned int index, json_t *value)
{
return json_array_insert_new(array, index, json_incref(value));
@@ -123,9 +144,21 @@ int json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(const json_t *string, const char *value);
int json_integer_set(const json_t *integer, int value);
int json_real_set(const json_t *real, double value);
int json_string_set(json_t *string, const char *value);
int json_string_set_nocheck(json_t *string, const char *value);
int json_integer_set(json_t *integer, int value);
int json_real_set(json_t *real, double value);
/* equality */
int json_equal(json_t *value1, json_t *value2);
/* copying */
json_t *json_copy(json_t *value);
json_t *json_deep_copy(json_t *value);
/* loading, printing */
@@ -141,7 +174,11 @@ json_t *json_loads(const char *input, json_error_t *error);
json_t *json_loadf(FILE *input, json_error_t *error);
json_t *json_load_file(const char *path, json_error_t *error);
#define JSON_INDENT(n) (n & 0xFF)
#define JSON_INDENT(n) (n & 0xFF)
#define JSON_COMPACT 0x100
#define JSON_ENSURE_ASCII 0x200
#define JSON_SORT_KEYS 0x400
#define JSON_PRESERVE_ORDER 0x800
char *json_dumps(const json_t *json, unsigned long flags);
int json_dumpf(const json_t *json, FILE *output, unsigned long flags);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -17,6 +17,7 @@
typedef struct {
json_t json;
hashtable_t hashtable;
unsigned long serial;
int visited;
} json_object_t;
@@ -49,7 +50,11 @@ typedef struct {
#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
int json_object_set_nocheck(json_t *json, const char *key, json_t *value);
json_t *json_string_nocheck(const char *value);
typedef struct {
unsigned long serial;
char key[];
} object_key_t;
const object_key_t *jsonp_object_iter_fullkey(void *iter);
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -113,7 +113,8 @@ static void error_set(json_error_t *error, const lex_t *lex,
/*** lexical analyzer ***/
void stream_init(stream_t *stream, get_func get, eof_func eof, void *data)
static void
stream_init(stream_t *stream, get_func get, eof_func eof, void *data)
{
stream->get = get;
stream->eof = eof;
@@ -148,7 +149,7 @@ static char stream_get(stream_t *stream, json_error_t *error)
for(i = 1; i < count; i++)
stream->buffer[i] = stream->get(stream->data);
if(!utf8_check_full(stream->buffer, count))
if(!utf8_check_full(stream->buffer, count, NULL))
goto out;
stream->stream_pos += count;
@@ -221,10 +222,10 @@ static void lex_save_cached(lex_t *lex)
}
/* assumes that str points to 'u' plus at least 4 valid hex digits */
static int decode_unicode_escape(const char *str)
static int32_t decode_unicode_escape(const char *str)
{
int i;
int value = 0;
int32_t value = 0;
assert(str[0] == 'u');
@@ -325,7 +326,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(*p == 'u') {
char buffer[4];
int length;
int value;
int32_t value;
value = decode_unicode_escape(p);
p += 5;
@@ -333,7 +334,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(0xD800 <= value && value <= 0xDBFF) {
/* surrogate pair */
if(*p == '\\' && *(p + 1) == 'u') {
int value2 = decode_unicode_escape(++p);
int32_t value2 = decode_unicode_escape(++p);
p += 5;
if(0xDC00 <= value2 && value2 <= 0xDFFF) {
@@ -483,14 +484,7 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
value = strtod(saved_text, &end);
assert(end == saved_text + lex->saved_text.length);
if(value == 0 && errno == ERANGE) {
error_set(error, lex, "real number underflow");
goto out;
}
/* Cannot test for +/-HUGE_VAL because the HUGE_VAL constant is
only defined in C99 mode. So let's trust in sole errno. */
else if(errno == ERANGE) {
if(errno == ERANGE && value != 0) {
error_set(error, lex, "real number overflow");
goto out;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -1,13 +1,14 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "utf.h"
int utf8_encode(int codepoint, char *buffer, int *size)
int utf8_encode(int32_t codepoint, char *buffer, int *size)
{
if(codepoint < 0)
return -1;
@@ -79,9 +80,10 @@ int utf8_check_first(char byte)
}
}
int utf8_check_full(const char *buffer, int size)
int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
{
int i, value = 0;
int i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
if(size == 2)
@@ -128,9 +130,38 @@ int utf8_check_full(const char *buffer, int size)
return 0;
}
if(codepoint)
*codepoint = value;
return 1;
}
const char *utf8_iterate(const char *buffer, int32_t *codepoint)
{
int count;
int32_t value;
if(!*buffer)
return buffer;
count = utf8_check_first(buffer[0]);
if(count <= 0)
return NULL;
if(count == 1)
value = (unsigned char)buffer[0];
else
{
if(!utf8_check_full(buffer, count, &value))
return NULL;
}
if(codepoint)
*codepoint = value;
return buffer + count;
}
int utf8_check_string(const char *string, int length)
{
int i;
@@ -148,7 +179,7 @@ int utf8_check_string(const char *string, int length)
if(i + count > length)
return 0;
if(!utf8_check_full(&string[i], count))
if(!utf8_check_full(&string[i], count, NULL))
return 0;
i += count - 1;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -8,10 +8,20 @@
#ifndef UTF_H
#define UTF_H
#include <config.h>
#ifdef HAVE_INTTYPES_H
/* inttypes.h includes stdint.h in a standard environment, so there's
no need to include stdint.h separately. If inttypes.h doesn't define
int32_t, it's defined in config.h. */
#include <inttypes.h>
#endif
int utf8_encode(int codepoint, char *buffer, int *size);
int utf8_check_first(char byte);
int utf8_check_full(const char *buffer, int size);
int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
const char *utf8_iterate(const char *buffer, int32_t *codepoint);
int utf8_check_string(const char *string, int length);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -1,11 +1,14 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#define _GNU_SOURCE
#include <config.h>
#include <stdlib.h>
#include <string.h>
@@ -25,9 +28,16 @@ static inline void json_init(json_t *json, json_type type)
/*** object ***/
static unsigned int hash_string(const void *key)
/* This macro just returns a pointer that's a few bytes backwards from
string. This makes it possible to pass a pointer to object_key_t
when only the string inside it is used, without actually creating
an object_key_t instance. */
#define string_to_key(string) container_of(string, object_key_t, key)
static unsigned int hash_key(const void *ptr)
{
const char *str = (const char *)key;
const char *str = ((const object_key_t *)ptr)->key;
unsigned int hash = 5381;
unsigned int c;
@@ -40,9 +50,10 @@ static unsigned int hash_string(const void *key)
return hash;
}
static int string_equal(const void *key1, const void *key2)
static int key_equal(const void *ptr1, const void *ptr2)
{
return strcmp((const char *)key1, (const char *)key2) == 0;
return strcmp(((const object_key_t *)ptr1)->key,
((const object_key_t *)ptr2)->key) == 0;
}
static void value_decref(void *value)
@@ -57,13 +68,14 @@ json_t *json_object(void)
return NULL;
json_init(&object->json, JSON_OBJECT);
if(hashtable_init(&object->hashtable, hash_string, string_equal,
if(hashtable_init(&object->hashtable, hash_key, key_equal,
free, value_decref))
{
free(object);
return NULL;
}
object->serial = 0;
object->visited = 0;
return &object->json;
@@ -94,12 +106,13 @@ json_t *json_object_get(const json_t *json, const char *key)
return NULL;
object = json_to_object(json);
return hashtable_get(&object->hashtable, key);
return hashtable_get(&object->hashtable, string_to_key(key));
}
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
{
json_object_t *object;
object_key_t *k;
if(!key || !value)
return -1;
@@ -111,7 +124,14 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
}
object = json_to_object(json);
if(hashtable_set(&object->hashtable, strdup(key), value))
k = malloc(sizeof(object_key_t) + strlen(key) + 1);
if(!k)
return -1;
k->serial = object->serial++;
strcpy(k->key, key);
if(hashtable_set(&object->hashtable, k, value))
{
json_decref(value);
return -1;
@@ -120,11 +140,6 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
return 0;
}
int json_object_set_nocheck(json_t *json, const char *key, json_t *value)
{
return json_object_set_new_nocheck(json, key, json_incref(value));
}
int json_object_set_new(json_t *json, const char *key, json_t *value)
{
if(!key || !utf8_check_string(key, -1))
@@ -144,7 +159,7 @@ int json_object_del(json_t *json, const char *key)
return -1;
object = json_to_object(json);
return hashtable_del(&object->hashtable, key);
return hashtable_del(&object->hashtable, string_to_key(key));
}
int json_object_clear(json_t *json)
@@ -175,7 +190,7 @@ int json_object_update(json_t *object, json_t *other)
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
if(json_object_set(object, key, value))
if(json_object_set_nocheck(object, key, value))
return -1;
iter = json_object_iter_next(other, iter);
@@ -195,6 +210,17 @@ void *json_object_iter(json_t *json)
return hashtable_iter(&object->hashtable);
}
void *json_object_iter_at(json_t *json, const char *key)
{
json_object_t *object;
if(!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
return hashtable_iter_at(&object->hashtable, string_to_key(key));
}
void *json_object_iter_next(json_t *json, void *iter)
{
json_object_t *object;
@@ -206,12 +232,20 @@ void *json_object_iter_next(json_t *json, void *iter)
return hashtable_iter_next(&object->hashtable, iter);
}
const object_key_t *jsonp_object_iter_fullkey(void *iter)
{
if(!iter)
return NULL;
return hashtable_iter_key(iter);
}
const char *json_object_iter_key(void *iter)
{
if(!iter)
return NULL;
return (const char *)hashtable_iter_key(iter);
return jsonp_object_iter_fullkey(iter)->key;
}
json_t *json_object_iter_value(void *iter)
@@ -222,6 +256,95 @@ json_t *json_object_iter_value(void *iter)
return (json_t *)hashtable_iter_value(iter);
}
int json_object_iter_set_new(json_t *json, void *iter, json_t *value)
{
json_object_t *object;
if(!json_is_object(json) || !iter || !value)
return -1;
object = json_to_object(json);
hashtable_iter_set(&object->hashtable, iter, value);
return 0;
}
static int json_object_equal(json_t *object1, json_t *object2)
{
void *iter;
if(json_object_size(object1) != json_object_size(object2))
return 0;
iter = json_object_iter(object1);
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
value2 = json_object_get(object2, key);
if(!json_equal(value1, value2))
return 0;
iter = json_object_iter_next(object1, iter);
}
return 1;
}
static json_t *json_object_copy(json_t *object)
{
json_t *result;
void *iter;
result = json_object();
if(!result)
return NULL;
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_set_nocheck(result, key, value);
iter = json_object_iter_next(object, iter);
}
return result;
}
static json_t *json_object_deep_copy(json_t *object)
{
json_t *result;
void *iter;
result = json_object();
if(!result)
return NULL;
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next(object, iter);
}
return result;
}
/*** array ***/
@@ -468,6 +591,57 @@ int json_array_extend(json_t *json, json_t *other_json)
return 0;
}
static int json_array_equal(json_t *array1, json_t *array2)
{
unsigned int i, size;
size = json_array_size(array1);
if(size != json_array_size(array2))
return 0;
for(i = 0; i < size; i++)
{
json_t *value1, *value2;
value1 = json_array_get(array1, i);
value2 = json_array_get(array2, i);
if(!json_equal(value1, value2))
return 0;
}
return 1;
}
static json_t *json_array_copy(json_t *array)
{
json_t *result;
unsigned int i;
result = json_array();
if(!result)
return NULL;
for(i = 0; i < json_array_size(array); i++)
json_array_append(result, json_array_get(array, i));
return result;
}
static json_t *json_array_deep_copy(json_t *array)
{
json_t *result;
unsigned int i;
result = json_array();
if(!result)
return NULL;
for(i = 0; i < json_array_size(array); i++)
json_array_append_new(result, json_deep_copy(json_array_get(array, i)));
return result;
}
/*** string ***/
@@ -508,14 +682,11 @@ const char *json_string_value(const json_t *json)
return json_to_string(json)->value;
}
int json_string_set(const json_t *json, const char *value)
int json_string_set_nocheck(json_t *json, const char *value)
{
char *dup;
json_string_t *string;
if(!json_is_string(json) || !value || !utf8_check_string(value, -1))
return -1;
dup = strdup(value);
if(!dup)
return -1;
@@ -527,12 +698,30 @@ int json_string_set(const json_t *json, const char *value)
return 0;
}
int json_string_set(json_t *json, const char *value)
{
if(!value || !utf8_check_string(value, -1))
return -1;
return json_string_set_nocheck(json, value);
}
static void json_delete_string(json_string_t *string)
{
free(string->value);
free(string);
}
static int json_string_equal(json_t *string1, json_t *string2)
{
return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
}
static json_t *json_string_copy(json_t *string)
{
return json_string_nocheck(json_string_value(string));
}
/*** integer ***/
@@ -555,7 +744,7 @@ int json_integer_value(const json_t *json)
return json_to_integer(json)->value;
}
int json_integer_set(const json_t *json, int value)
int json_integer_set(json_t *json, int value)
{
if(!json_is_integer(json))
return -1;
@@ -570,6 +759,16 @@ static void json_delete_integer(json_integer_t *integer)
free(integer);
}
static int json_integer_equal(json_t *integer1, json_t *integer2)
{
return json_integer_value(integer1) == json_integer_value(integer2);
}
static json_t *json_integer_copy(json_t *integer)
{
return json_integer(json_integer_value(integer));
}
/*** real ***/
@@ -592,7 +791,7 @@ double json_real_value(const json_t *json)
return json_to_real(json)->value;
}
int json_real_set(const json_t *json, double value)
int json_real_set(json_t *json, double value)
{
if(!json_is_real(json))
return 0;
@@ -607,6 +806,16 @@ static void json_delete_real(json_real_t *real)
free(real);
}
static int json_real_equal(json_t *real1, json_t *real2)
{
return json_real_value(real1) == json_real_value(real2);
}
static json_t *json_real_copy(json_t *real)
{
return json_real(json_real_value(real));
}
/*** number ***/
@@ -627,7 +836,7 @@ json_t *json_true(void)
{
static json_t the_true = {
.type = JSON_TRUE,
.refcount = (unsigned int)1
.refcount = (unsigned int)-1
};
return &the_true;
}
@@ -637,7 +846,7 @@ json_t *json_false(void)
{
static json_t the_false = {
.type = JSON_FALSE,
.refcount = (unsigned int)1
.refcount = (unsigned int)-1
};
return &the_false;
}
@@ -647,7 +856,7 @@ json_t *json_null(void)
{
static json_t the_null = {
.type = JSON_NULL,
.refcount = (unsigned int)1
.refcount = (unsigned int)-1
};
return &the_null;
}
@@ -674,3 +883,94 @@ void json_delete(json_t *json)
/* json_delete is not called for true, false or null */
}
/*** equality ***/
int json_equal(json_t *json1, json_t *json2)
{
if(!json1 || !json2)
return 0;
if(json_typeof(json1) != json_typeof(json2))
return 0;
/* this covers true, false and null as they are singletons */
if(json1 == json2)
return 1;
if(json_is_object(json1))
return json_object_equal(json1, json2);
if(json_is_array(json1))
return json_array_equal(json1, json2);
if(json_is_string(json1))
return json_string_equal(json1, json2);
if(json_is_integer(json1))
return json_integer_equal(json1, json2);
if(json_is_real(json1))
return json_real_equal(json1, json2);
return 0;
}
/*** copying ***/
json_t *json_copy(json_t *json)
{
if(!json)
return NULL;
if(json_is_object(json))
return json_object_copy(json);
if(json_is_array(json))
return json_array_copy(json);
if(json_is_string(json))
return json_string_copy(json);
if(json_is_integer(json))
return json_integer_copy(json);
if(json_is_real(json))
return json_real_copy(json);
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
return json;
return NULL;
}
json_t *json_deep_copy(json_t *json)
{
if(!json)
return NULL;
if(json_is_object(json))
return json_object_deep_copy(json);
if(json_is_array(json))
return json_array_deep_copy(json);
/* for the rest of the types, deep copying doesn't differ from
shallow copying */
if(json_is_string(json))
return json_string_copy(json);
if(json_is_integer(json))
return json_integer_copy(json);
if(json_is_real(json))
return json_real_copy(json);
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
return json;
return NULL;
}

20
test/.gitignore vendored
View File

@@ -1,9 +1,11 @@
loadf_dumpf
loads_dumps
load_file_dump_file
testlogs
testprogs/test_array
testprogs/test_load
testprogs/test_number
testprogs/test_object
testprogs/test_simple
logs
bin/json_process
suites/api/test_array
suites/api/test_equal
suites/api/test_copy
suites/api/test_dump
suites/api/test_load
suites/api/test_number
suites/api/test_object
suites/api/test_simple
suites/api/test_cpp

View File

@@ -1,22 +1,10 @@
DIST_SUBDIRS = testprogs testdata
SUBDIRS = testprogs
SUBDIRS = bin suites
EXTRA_DIST = scripts run-suites
check_PROGRAMS = loadf_dumpf loads_dumps load_file_dump_file
AM_CPPFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -Wall -Werror
LDFLAGS = -static # for speed and Valgrind
LDADD = ../src/libjansson.la
TESTS = test-api test-invalid test-valid
EXTRA_DIST = \
test-api \
test-invalid \
test-valid \
run-test \
json-compare.py \
split-testfile.py
TESTS = run-suites
TESTS_ENVIRONMENT = \
top_srcdir=$(top_srcdir) \
top_builddir=$(top_builddir)
clean-local:
rm -rf testlogs
rm -rf logs

6
test/bin/Makefile.am Normal file
View File

@@ -0,0 +1,6 @@
check_PROGRAMS = json_process
AM_CPPFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -Wall -Werror
LDFLAGS = -static # for speed and Valgrind
LDADD = $(top_builddir)/src/libjansson.la

72
test/bin/json_process.c Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>
static int getenv_int(const char *name)
{
char *value, *end;
long result;
value = getenv(name);
if(!value)
return 0;
result = strtol(value, &end, 10);
if(*end != '\0')
return 0;
return (int)result;
}
int main(int argc, char *argv[])
{
int indent = 0;
unsigned int flags = 0;
json_t *json;
json_error_t error;
if(argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 2;
}
indent = getenv_int("JSON_INDENT");
if(indent < 0 || indent > 255) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
return 2;
}
if(indent > 0)
flags |= JSON_INDENT(indent);
if(getenv_int("JSON_COMPACT") > 0)
flags |= JSON_COMPACT;
if(getenv_int("JSON_ENSURE_ASCII"))
flags |= JSON_ENSURE_ASCII;
if(getenv_int("JSON_PRESERVE_ORDER"))
flags |= JSON_PRESERVE_ORDER;
if(getenv_int("JSON_SORT_KEYS"))
flags |= JSON_SORT_KEYS;
json = json_loadf(stdin, &error);
if(!json) {
fprintf(stderr, "%d\n%s\n", error.line, error.text);
return 1;
}
json_dumpf(json, stdout, flags);
json_decref(json);
return 0;
}

View File

@@ -1,45 +0,0 @@
#!/usr/bin/python
#
# Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
import sys
try:
import json
except ImportError:
import simplejson as json
def load(filename):
try:
jsonfile = open(filename)
except IOError, err:
print >>sys.stderr, "unable to load %s: %s" % \
(filename, err.strerror)
sys.exit(1)
try:
jsondata = json.load(jsonfile)
except ValueError, err:
print "%s is malformed: %s" % (filename, err)
sys.exit(1)
finally:
jsonfile.close()
return jsondata
def main():
if len(sys.argv) != 3:
print >>sys.stderr, "usage: %s json1 json2" % sys.argv[0]
return 2
json1 = load(sys.argv[1])
json2 = load(sys.argv[2])
if json1 == json2:
return 0
else:
return 1
if __name__ == '__main__':
sys.exit(main() or 0)

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <jansson.h>
int main(int argc, char *argv[])
{
json_t *json;
json_error_t error;
if(argc != 3) {
fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
return 2;
}
json = json_load_file(argv[1], &error);
if(!json) {
fprintf(stderr, "%d\n%s\n", error.line, error.text);
return 1;
}
json_dump_file(json, argv[2], 0);
json_decref(json);
return 0;
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <jansson.h>
int main(int argc, char *argv[])
{
json_t *json;
json_error_t error;
if(argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 2;
}
json = json_loadf(stdin, &error);
if(!json) {
fprintf(stderr, "%d\n%s\n", error.line, error.text);
return 1;
}
/* loadf_dumpf indents, others don't, so dumping with and without
indenting is tested */
json_dumpf(json, stdout, JSON_INDENT(4));
json_decref(json);
return 0;
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>
#define BUFFER_SIZE (256 * 1024)
int main(int argc, char *argv[])
{
json_t *json;
json_error_t error;
int count;
char buffer[BUFFER_SIZE];
char *result;
if(argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 2;
}
count = fread(buffer, 1, BUFFER_SIZE, stdin);
if(count < 0 || count >= BUFFER_SIZE) {
fprintf(stderr, "unable to read input\n");
return 1;
}
buffer[count] = '\0';
json = json_loads(buffer, &error);
if(!json) {
fprintf(stderr, "%d\n%s\n", error.line, error.text);
return 1;
}
result = json_dumps(json, 0);
json_decref(json);
puts(result);
free(result);
return 0;
}

46
test/run-suites Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/sh
while [ -n "$1" ]; do
suite=$1
if [ -x $top_srcdir/test/suites/$suite/run ]; then
SUITES="$SUITES $suite"
else
echo "No such suite: $suite"
exit 1
fi
shift
done
if [ -z "$SUITES" ]; then
suitedirs=$top_srcdir/test/suites/*
for suitedir in $suitedirs; do
if [ -d $suitedir ]; then
SUITES="$SUITES `basename $suitedir`"
fi
done
fi
export suites_srcdir=$top_srcdir/test/suites
export suites_builddir=suites
export scriptdir=$top_srcdir/test/scripts
export logdir=logs
export bindir=bin
passed=0
failed=0
for suite in $SUITES; do
echo "Suite: $suite"
if $suites_srcdir/$suite/run $suite; then
passed=$(($passed+1))
else
failed=$(($failed+1))
fi
done
if [ $failed -gt 0 ]; then
echo "$failed of $((passed+failed)) test suites failed"
exit 1
else
echo "$passed test suites passed"
rm -rf $logdir
fi

View File

@@ -1,57 +0,0 @@
# Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q"
run_testprog() {
local prog=$1
local prefix=$2
if [ -n "$VALGRIND" ]; then
local runner="$VALGRIND_CMDLINE "
fi
case "$prog" in
load_file_dump_file)
$runner./$prog \
$prefix.in \
$prefix.$prog.stdout \
2>$prefix.$prog.stderr
;;
*)
$runner./$prog \
<$prefix.in \
>$prefix.$prog.stdout \
2>$prefix.$prog.stderr
;;
esac
if [ -n "$VALGRIND" ]; then
# Check for Valgrind error output. The valgrind option
# --error-exitcode is not enough because Valgrind doesn't
# think unfreed allocs are errors.
if grep -E -q '^==[0-9]+== ' $prefix.$prog.stderr; then
echo "### $prefix ($prog) failed:" >&2
echo "valgrind detected an error" >&2
echo "for details, see test/$prefix.$prog.stderr" >&2
exit 1
fi
fi
}
for testfile in $TESTFILES; do
tmpdir="testlogs/`basename $testfile`"
rm -rf $tmpdir
mkdir -p $tmpdir
if echo "$testfile" | grep -q -E -e '-strip$'; then
opts="--strip"
fi
${srcdir}/split-testfile.py $opts $testfile $tmpdir | while read name; do
run_test loadf_dumpf $tmpdir/$name
run_test loads_dumps $tmpdir/$name
run_test load_file_dump_file $tmpdir/$name
echo -n '.'
done || exit 1
echo
done

71
test/scripts/run-tests.sh Normal file
View File

@@ -0,0 +1,71 @@
# Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
json_process=$bindir/json_process
suite_name=$1
suite_srcdir=$suites_srcdir/$suite_name
suite_builddir=$suites_builddir/$suite_name
suite_log=$logdir/$suite_name
[ -z "$VERBOSE" ] && VERBOSE=0
. $scriptdir/valgrind.sh
rm -rf $suite_log
mkdir -p $suite_log
for test_path in $suite_srcdir/*; do
test_name=$(basename $test_path)
test_builddir=$suite_builddir/$test_name
test_log=$suite_log/$test_name
[ "$test_name" = "run" ] && continue
is_test || continue
rm -rf $test_log
mkdir -p $test_log
if [ $VERBOSE -eq 1 ]; then
echo -n "$test_name... "
fi
if run_test; then
# Success
if [ $VERBOSE -eq 1 ]; then
echo "ok"
else
echo -n "."
fi
rm -rf $test_log
else
# Failure
if [ $VERBOSE -eq 1 ]; then
echo "FAILED"
else
echo -n "F"
fi
fi
done
if [ $VERBOSE -eq 0 ]; then
echo
fi
if [ -n "$(ls -A $suite_log)" ]; then
for test_log in $suite_log/*; do
test_name=$(basename $test_log)
test_path=$suite_srcdir/$test_name
echo "================================================================="
echo "$suite_name/$test_name"
echo "================================================================="
show_error
echo
done
echo "================================================================="
exit 1
else
rm -rf $suite_log
fi

35
test/scripts/valgrind.sh Normal file
View File

@@ -0,0 +1,35 @@
# Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
[ -z "$VALGRIND" ] && VALGRIND=0
VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q"
if [ $VALGRIND -eq 1 ]; then
test_runner="$VALGRIND_CMDLINE"
json_process="$VALGRIND_CMDLINE $json_process"
else
test_runner=""
fi
valgrind_check() {
if [ $VALGRIND -eq 1 ]; then
# Check for Valgrind error output. The valgrind option
# --error-exitcode is not enough because Valgrind doesn't
# think unfreed allocs are errors.
if grep -E -q '^==[0-9]+== ' $1; then
touch $test_log/valgrind_error
return 1
fi
fi
}
valgrind_show_error() {
if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then
echo "valgrind detected an error"
return 0
fi
return 1
}

View File

@@ -1,68 +0,0 @@
#!/usr/bin/python
#
# Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
import os
import sys
from optparse import OptionParser
def strip_file(filename):
with open(filename) as fobj:
data = fobj.read()
with open(filename, 'w') as fobj:
fobj.write(data.strip())
def open_files(outdir, i, name):
basename = '%02d_%s' % (i, name)
print basename
input_path = os.path.join(outdir, basename + '.in')
output_path = os.path.join(outdir, basename + '.out')
return open(input_path, 'w'), open(output_path, 'w')
def main():
parser = OptionParser('usage: %prog [options] inputfile outputdir')
parser.add_option('--strip', help='strip whitespace from input',
action='store_true', default=False)
options, args = parser.parse_args()
if len(args) != 2:
parser.print_help()
return 2
infile = os.path.normpath(args[0])
outdir = os.path.normpath(args[1])
if not os.path.exists(outdir):
print >>sys.stderr, 'output directory %r does not exist!' % outdir
return 1
n = 0
current = None
input, output = None, None
for line in open(infile):
if line.startswith('==== '):
n += 1
if input is not None and output is not None:
input.close()
output.close()
if options.strip:
strip_file(input.name)
input, output = open_files(outdir, n, line[5:line.find(' ====\n')])
current = input
elif line == '====\n':
current = output
else:
current.write(line)
if input is not None and output is not None:
input.close()
output.close()
print >>sys.stderr, "%s: %d test cases" % (infile, n)
if __name__ == '__main__':
sys.exit(main() or 0)

View File

@@ -1 +1,2 @@
SUBDIRS = api
EXTRA_DIST = invalid invalid-strip invalid-unicode valid valid-strip

View File

@@ -1,6 +1,18 @@
check_PROGRAMS = test_array test_load test_simple test_number test_object
EXTRA_DIST = run
check_PROGRAMS = \
test_array \
test_equal \
test_copy \
test_dump \
test_load \
test_simple \
test_number \
test_object
test_array_SOURCES = test_array.c util.h
test_copy_SOURCES = test_copy.c util.h
test_dump_SOURCES = test_dump.c util.h
test_load_SOURCES = test_load.c util.h
test_simple_SOURCES = test_simple.c util.h
test_number_SOURCES = test_number.c util.h
@@ -9,4 +21,4 @@ test_object_SOURCES = test_object.c util.h
AM_CPPFLAGS = -I$(top_srcdir)/src
AM_CFLAGS = -Wall -Werror
LDFLAGS = -static # for speed and Valgrind
LDADD = ../../src/libjansson.la
LDADD = $(top_builddir)/src/libjansson.la

90
test/suites/api/check-exports Executable file
View File

@@ -0,0 +1,90 @@
#!/bin/sh
# This tests checks that the libjansson.so exports the correct
# symbols.
# The list of symbols that the shared object should export
sort >$test_log/exports <<EOF
json_delete
json_true
json_false
json_null
json_string
json_string_nocheck
json_string_value
json_string_set
json_string_set_nocheck
json_integer
json_integer_value
json_integer_set
json_real
json_real_value
json_real_set
json_number_value
json_array
json_array_size
json_array_get
json_array_set_new
json_array_append_new
json_array_insert_new
json_array_remove
json_array_clear
json_array_extend
json_object
json_object_size
json_object_get
json_object_set_new
json_object_set_new_nocheck
json_object_del
json_object_clear
json_object_update
json_object_iter
json_object_iter_at
json_object_iter_next
json_object_iter_key
json_object_iter_value
json_object_iter_set_new
json_dumps
json_dumpf
json_dump_file
json_loads
json_loadf
json_load_file
json_equal
json_copy
json_deep_copy
EOF
# The list of functions are not exported in the library because they
# are macros or static inline functions. This is only the make the
# list complete, there are not used by the test.
sort >$test_log/macros_or_inline <<EOF
json_typeof
json_incref
json_decref
json_is_object
json_is_object
json_is_array
json_is_string
json_is_integer
json_is_real
json_is_true
json_is_false
json_is_null
json_is_number
json_is_boolean
json_array_set
json_array_append
json_array_insert
json_object_set
json_object_set_nocheck
EOF
SOFILE="../src/.libs/libjansson.so"
nm -D $SOFILE | grep ' T ' | cut -d' ' -f3 | sort >$test_log/output
if ! cmp -s $test_log/exports $test_log/output; then
diff -u $test_log/exports $test_log/output >&2
exit 1
fi

36
test/suites/api/run Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh
#
# Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
is_test() {
case "$test_name" in
*.c|check-exports)
return 0
;;
*)
return 1
;;
esac
}
run_test() {
if [ "$test_name" = "check-exports" ]; then
test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr
else
$test_runner $suite_builddir/${test_name%.c} \
>$test_log/stdout \
2>$test_log/stderr \
|| return 1
valgrind_check $test_log/stderr || return 1
fi
}
show_error() {
valgrind_show_error && return
cat $test_log/stderr
}
. $top_srcdir/test/scripts/run-tests.sh

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

319
test/suites/api/test_copy.c Normal file
View File

@@ -0,0 +1,319 @@
/*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include <jansson.h>
#include "util.h"
static void test_copy_simple(void)
{
json_t *value, *copy;
if(json_copy(NULL))
fail("copying NULL doesn't return NULL");
/* true */
value = json_true();
copy = json_copy(value);
if(value != copy)
fail("copying true failed");
json_decref(value);
json_decref(copy);
/* false */
value = json_false();
copy = json_copy(value);
if(value != copy)
fail("copying false failed");
json_decref(value);
json_decref(copy);
/* null */
value = json_null();
copy = json_copy(value);
if(value != copy)
fail("copying null failed");
json_decref(value);
json_decref(copy);
/* string */
value = json_string("foo");
if(!value)
fail("unable to create a string");
copy = json_copy(value);
if(!copy)
fail("unable to copy a string");
if(copy == value)
fail("copying a string doesn't copy");
if(!json_equal(copy, value))
fail("copying a string produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* integer */
value = json_integer(543);
if(!value)
fail("unable to create an integer");
copy = json_copy(value);
if(!copy)
fail("unable to copy an integer");
if(copy == value)
fail("copying an integer doesn't copy");
if(!json_equal(copy, value))
fail("copying an integer produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* real */
value = json_real(123e9);
if(!value)
fail("unable to create a real");
copy = json_copy(value);
if(!copy)
fail("unable to copy a real");
if(copy == value)
fail("copying a real doesn't copy");
if(!json_equal(copy, value))
fail("copying a real produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
}
static void test_deep_copy_simple(void)
{
json_t *value, *copy;
if(json_deep_copy(NULL))
fail("deep copying NULL doesn't return NULL");
/* true */
value = json_true();
copy = json_deep_copy(value);
if(value != copy)
fail("deep copying true failed");
json_decref(value);
json_decref(copy);
/* false */
value = json_false();
copy = json_deep_copy(value);
if(value != copy)
fail("deep copying false failed");
json_decref(value);
json_decref(copy);
/* null */
value = json_null();
copy = json_deep_copy(value);
if(value != copy)
fail("deep copying null failed");
json_decref(value);
json_decref(copy);
/* string */
value = json_string("foo");
if(!value)
fail("unable to create a string");
copy = json_deep_copy(value);
if(!copy)
fail("unable to deep copy a string");
if(copy == value)
fail("deep copying a string doesn't copy");
if(!json_equal(copy, value))
fail("deep copying a string produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* integer */
value = json_integer(543);
if(!value)
fail("unable to create an integer");
copy = json_deep_copy(value);
if(!copy)
fail("unable to deep copy an integer");
if(copy == value)
fail("deep copying an integer doesn't copy");
if(!json_equal(copy, value))
fail("deep copying an integer produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* real */
value = json_real(123e9);
if(!value)
fail("unable to create a real");
copy = json_deep_copy(value);
if(!copy)
fail("unable to deep copy a real");
if(copy == value)
fail("deep copying a real doesn't copy");
if(!json_equal(copy, value))
fail("deep copying a real produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
}
static void test_copy_array(void)
{
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
json_t *array, *copy;
unsigned int i;
array = json_loads(json_array_text, NULL);
if(!array)
fail("unable to parse an array");
copy = json_copy(array);
if(!copy)
fail("unable to copy an array");
if(copy == array)
fail("copying an array doesn't copy");
if(!json_equal(copy, array))
fail("copying an array produces an inequal copy");
for(i = 0; i < json_array_size(copy); i++)
{
if(json_array_get(array, i) != json_array_get(copy, i))
fail("copying an array modifies its elements");
}
json_decref(array);
json_decref(copy);
}
static void test_deep_copy_array(void)
{
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
json_t *array, *copy;
unsigned int i;
array = json_loads(json_array_text, NULL);
if(!array)
fail("unable to parse an array");
copy = json_deep_copy(array);
if(!copy)
fail("unable to deep copy an array");
if(copy == array)
fail("deep copying an array doesn't copy");
if(!json_equal(copy, array))
fail("deep copying an array produces an inequal copy");
for(i = 0; i < json_array_size(copy); i++)
{
if(json_array_get(array, i) == json_array_get(copy, i))
fail("deep copying an array doesn't copy its elements");
}
json_decref(array);
json_decref(copy);
}
static void test_copy_object(void)
{
const char *json_object_text =
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
json_t *object, *copy;
void *iter;
object = json_loads(json_object_text, NULL);
if(!object)
fail("unable to parse an object");
copy = json_copy(object);
if(!copy)
fail("unable to copy an object");
if(copy == object)
fail("copying an object doesn't copy");
if(!json_equal(copy, object))
fail("copying an object produces an inequal copy");
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
value2 = json_object_get(copy, key);
if(value1 != value2)
fail("deep copying an object modifies its items");
iter = json_object_iter_next(object, iter);
}
json_decref(object);
json_decref(copy);
}
static void test_deep_copy_object(void)
{
const char *json_object_text =
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
json_t *object, *copy;
void *iter;
object = json_loads(json_object_text, NULL);
if(!object)
fail("unable to parse an object");
copy = json_deep_copy(object);
if(!copy)
fail("unable to deep copy an object");
if(copy == object)
fail("deep copying an object doesn't copy");
if(!json_equal(copy, object))
fail("deep copying an object produces an inequal copy");
iter = json_object_iter(object);
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
value2 = json_object_get(copy, key);
if(value1 == value2)
fail("deep copying an object doesn't copy its items");
iter = json_object_iter_next(object, iter);
}
json_decref(object);
json_decref(copy);
}
int main()
{
test_copy_simple();
test_deep_copy_simple();
test_copy_array();
test_deep_copy_array();
test_copy_object();
test_deep_copy_object();
return 0;
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include <string.h>
#include "util.h"
int main()
{
json_t *json;
char *result;
/* Encode an empty object/array, add an item, encode again */
json = json_object();
result = json_dumps(json, 0);
if(!result || strcmp(result, "{}"))
fail("json_dumps failed");
free(result);
json_object_set_new(json, "foo", json_integer(5));
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"foo\": 5}"))
fail("json_dumps failed");
free(result);
json_decref(json);
json = json_array();
result = json_dumps(json, 0);
if(!result || strcmp(result, "[]"))
fail("json_dumps failed");
free(result);
json_array_append_new(json, json_integer(5));
result = json_dumps(json, 0);
if(!result || strcmp(result, "[5]"))
fail("json_dumps failed");
free(result);
json_decref(json);
/* Construct a JSON object/array with a circular reference:
object: {"a": {"b": {"c": <circular reference to $.a>}}}
array: [[[<circular reference to the $[0] array>]]]
Encode it, remove the circular reference and encode again.
*/
json = json_object();
json_object_set_new(json, "a", json_object());
json_object_set_new(json_object_get(json, "a"), "b", json_object());
json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
json_object_get(json, "a"));
if(json_dumps(json, 0))
fail("json_dumps encoded a circular reference!");
json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
fail("json_dumps failed!");
free(result);
json_decref(json);
json = json_array();
json_array_append_new(json, json_array());
json_array_append_new(json_array_get(json, 0), json_array());
json_array_append(json_array_get(json_array_get(json, 0), 0),
json_array_get(json, 0));
if(json_dumps(json, 0))
fail("json_dumps encoded a circular reference!");
json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
result = json_dumps(json, 0);
if(!result || strcmp(result, "[[[]]]"))
fail("json_dumps failed!");
free(result);
json_decref(json);
return 0;
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include "util.h"
static void test_equal_simple()
{
json_t *value1, *value2;
if(json_equal(NULL, NULL))
fail("json_equal fails for two NULLs");
value1 = json_true();
if(json_equal(value1, NULL) || json_equal(NULL, value1))
fail("json_equal fails for NULL");
/* this covers true, false and null as they are singletons */
if(!json_equal(value1, value1))
fail("identical objects are not equal");
json_decref(value1);
/* integer */
value1 = json_integer(1);
value2 = json_integer(1);
if(!value1 || !value2)
fail("unable to create integers");
if(!json_equal(value1, value2))
fail("json_equal fails for two equal integers");
json_decref(value2);
value2 = json_integer(2);
if(!value2)
fail("unable to create an integer");
if(json_equal(value1, value2))
fail("json_equal fails for two inequal integers");
json_decref(value1);
json_decref(value2);
/* real */
value1 = json_real(1.2);
value2 = json_real(1.2);
if(!value1 || !value2)
fail("unable to create reals");
if(!json_equal(value1, value2))
fail("json_equal fails for two equal reals");
json_decref(value2);
value2 = json_real(3.141592);
if(!value2)
fail("unable to create an real");
if(json_equal(value1, value2))
fail("json_equal fails for two inequal reals");
json_decref(value1);
json_decref(value2);
/* string */
value1 = json_string("foo");
value2 = json_string("foo");
if(!value1 || !value2)
fail("unable to create strings");
if(!json_equal(value1, value2))
fail("json_equal fails for two equal strings");
json_decref(value2);
value2 = json_string("bar");
if(!value2)
fail("unable to create an string");
if(json_equal(value1, value2))
fail("json_equal fails for two inequal strings");
json_decref(value1);
json_decref(value2);
}
static void test_equal_array()
{
json_t *array1, *array2;
array1 = json_array();
array2 = json_array();
if(!array1 || !array2)
fail("unable to create arrays");
if(!json_equal(array1, array2))
fail("json_equal fails for two empty arrays");
json_array_append_new(array1, json_integer(1));
json_array_append_new(array2, json_integer(1));
json_array_append_new(array1, json_string("foo"));
json_array_append_new(array2, json_string("foo"));
json_array_append_new(array1, json_integer(2));
json_array_append_new(array2, json_integer(2));
if(!json_equal(array1, array2))
fail("json_equal fails for two equal arrays");
json_array_remove(array2, 2);
if(json_equal(array1, array2))
fail("json_equal fails for two inequal arrays");
json_array_append_new(array2, json_integer(3));
if(json_equal(array1, array2))
fail("json_equal fails for two inequal arrays");
json_decref(array1);
json_decref(array2);
}
static void test_equal_object()
{
json_t *object1, *object2;
object1 = json_object();
object2 = json_object();
if(!object1 || !object2)
fail("unable to create objects");
if(!json_equal(object1, object2))
fail("json_equal fails for two empty objects");
json_object_set_new(object1, "a", json_integer(1));
json_object_set_new(object2, "a", json_integer(1));
json_object_set_new(object1, "b", json_string("foo"));
json_object_set_new(object2, "b", json_string("foo"));
json_object_set_new(object1, "c", json_integer(2));
json_object_set_new(object2, "c", json_integer(2));
if(!json_equal(object1, object2))
fail("json_equal fails for two equal objects");
json_object_del(object2, "c");
if(json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_object_set_new(object2, "c", json_integer(3));
if(json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_object_del(object2, "c");
json_object_set_new(object2, "d", json_integer(2));
if(json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_decref(object1);
json_decref(object2);
}
static void test_equal_complex()
{
json_t *value1, *value2;
const char *complex_json =
"{"
" \"integer\": 1, "
" \"real\": 3.141592, "
" \"string\": \"foobar\", "
" \"true\": true, "
" \"object\": {"
" \"array-in-object\": [1,true,\"foo\",{}],"
" \"object-in-object\": {\"foo\": \"bar\"}"
" },"
" \"array\": [\"foo\", false, null, 1.234]"
"}";
value1 = json_loads(complex_json, NULL);
value2 = json_loads(complex_json, NULL);
if(!value1 || !value2)
fail("unable to parse JSON");
if(!json_equal(value1, value2))
fail("json_equal fails for two inequal strings");
json_decref(value1);
json_decref(value2);
/* TODO: There's no negative test case here */
}
int main()
{
test_equal_simple();
test_equal_array();
test_equal_object();
test_equal_complex();
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -167,10 +167,136 @@ static void test_circular()
json_decref(object1);
}
static void test_set_nocheck()
{
json_t *object, *string;
object = json_object();
string = json_string("bar");
if(!object)
fail("unable to create object");
if(!string)
fail("unable to create string");
if(json_object_set_nocheck(object, "foo", string))
fail("json_object_set_nocheck failed");
if(json_object_get(object, "foo") != string)
fail("json_object_get after json_object_set_nocheck failed");
/* invalid UTF-8 in key */
if(json_object_set_nocheck(object, "a\xefz", string))
fail("json_object_set_nocheck failed for invalid UTF-8");
if(json_object_get(object, "a\xefz") != string)
fail("json_object_get after json_object_set_nocheck failed");
if(json_object_set_new_nocheck(object, "bax", json_integer(123)))
fail("json_object_set_new_nocheck failed");
if(json_integer_value(json_object_get(object, "bax")) != 123)
fail("json_object_get after json_object_set_new_nocheck failed");
/* invalid UTF-8 in key */
if(json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321)))
fail("json_object_set_new_nocheck failed for invalid UTF-8");
if(json_integer_value(json_object_get(object, "asdf\xfe")) != 321)
fail("json_object_get after json_object_set_new_nocheck failed");
json_decref(string);
json_decref(object);
}
static void test_iterators()
{
json_t *object, *foo, *bar, *baz;
void *iter;
if(json_object_iter(NULL))
fail("able to iterate over NULL");
if(json_object_iter_next(NULL, NULL))
fail("able to increment an iterator on a NULL object");
object = json_object();
foo = json_string("foo");
bar = json_string("bar");
baz = json_string("baz");
if(!object || !foo || !bar || !bar)
fail("unable to create values");
if(json_object_iter_next(object, NULL))
fail("able to increment a NULL iterator");
if(json_object_set(object, "a", foo) ||
json_object_set(object, "b", bar) ||
json_object_set(object, "c", baz))
fail("unable to populate object");
iter = json_object_iter(object);
if(!iter)
fail("unable to get iterator");
if(strcmp(json_object_iter_key(iter), "a"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != foo)
fail("iterating failed: wrong value");
iter = json_object_iter_next(object, iter);
if(!iter)
fail("unable to increment iterator");
if(strcmp(json_object_iter_key(iter), "b"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != bar)
fail("iterating failed: wrong value");
iter = json_object_iter_next(object, iter);
if(!iter)
fail("unable to increment iterator");
if(strcmp(json_object_iter_key(iter), "c"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != baz)
fail("iterating failed: wrong value");
if(json_object_iter_next(object, iter) != NULL)
fail("able to iterate over the end");
if(json_object_iter_at(object, "foo"))
fail("json_object_iter_at() succeeds for non-existent key");
iter = json_object_iter_at(object, "b");
if(!iter)
fail("json_object_iter_at() fails for an existing key");
if(strcmp(json_object_iter_key(iter), "b"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != bar)
fail("iterating failed: wrong value");
iter = json_object_iter_next(object, iter);
if(!iter)
fail("unable to increment iterator");
if(strcmp(json_object_iter_key(iter), "c"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != baz)
fail("iterating failed: wrong value");
if(json_object_iter_set(object, iter, bar))
fail("unable to set value at iterator");
if(strcmp(json_object_iter_key(iter), "c"))
fail("json_object_iter_key() fails after json_object_iter_set()");
if(json_object_iter_value(iter) != bar)
fail("json_object_iter_value() fails after json_object_iter_set()");
if(json_object_get(object, "c") != bar)
fail("json_object_get() fails after json_object_iter_set()");
json_decref(object);
json_decref(foo);
json_decref(bar);
json_decref(baz);
}
static void test_misc()
{
json_t *object, *string, *other_string, *value;
void *iter;
object = json_object();
string = json_string("test");
@@ -193,17 +319,6 @@ static void test_misc()
if(!json_object_set(object, "a", NULL))
fail("able to set NULL value");
iter = json_object_iter(object);
if(!iter)
fail("unable to get iterator");
if(strcmp(json_object_iter_key(iter), "a"))
fail("iterating failed: wrong key");
if(json_object_iter_value(iter) != string)
fail("iterating failed: wrong value");
if(json_object_iter_next(object, iter) != NULL)
fail("able to iterate over the end");
/* invalid UTF-8 in key */
if(!json_object_set(object, "a\xefz", string))
fail("able to set invalid unicode key");
@@ -287,12 +402,50 @@ static void test_misc()
json_decref(object);
}
static void test_preserve_order()
{
json_t *object;
char *result;
const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": 3, \"sit amet\": 5, \"helicopter\": 7}";
object = json_object();
json_object_set_new(object, "foobar", json_integer(1));
json_object_set_new(object, "bazquux", json_integer(2));
json_object_set_new(object, "lorem ipsum", json_integer(3));
json_object_set_new(object, "dolor", json_integer(4));
json_object_set_new(object, "sit amet", json_integer(5));
/* changing a value should preserve the order */
json_object_set_new(object, "bazquux", json_integer(6));
/* deletion shouldn't change the order of others */
json_object_del(object, "dolor");
/* add a new item just to make sure */
json_object_set_new(object, "helicopter", json_integer(7));
result = json_dumps(object, JSON_PRESERVE_ORDER);
if(strcmp(expected, result) != 0) {
fprintf(stderr, "%s != %s", expected, result);
fail("JSON_PRESERVE_ORDER doesn't work");
}
free(result);
json_decref(object);
}
int main()
{
test_misc();
test_clear();
test_update();
test_circular();
test_set_nocheck();
test_iterators();
test_preserve_order();
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -73,6 +73,33 @@ int main()
if(value)
fail("json_string(<invalid utf-8>) failed");
value = json_string_nocheck("foo");
if(!value)
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "foo"))
fail("invalid string value");
if(json_string_set_nocheck(value, "bar"))
fail("json_string_set_nocheck failed");
if(strcmp(json_string_value(value), "bar"))
fail("invalid string value");
json_decref(value);
/* invalid UTF-8 */
value = json_string_nocheck("qu\xff");
if(!value)
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "qu\xff"))
fail("invalid string value");
if(json_string_set_nocheck(value, "\xfd\xfe\xff"))
fail("json_string_set_nocheck failed");
if(strcmp(json_string_value(value), "\xfd\xfe\xff"))
fail("invalid string value");
json_decref(value);
value = json_integer(123);
if(!value)
@@ -123,5 +150,36 @@ int main()
fail("json_null failed");
json_decref(value);
/* Test reference counting on singletons (true, false, null) */
value = json_true();
if(value->refcount != (unsigned int)-1)
fail("refcounting true works incorrectly");
json_decref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting true works incorrectly");
json_incref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting true works incorrectly");
value = json_false();
if(value->refcount != (unsigned int)-1)
fail("refcounting false works incorrectly");
json_decref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting false works incorrectly");
json_incref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting false works incorrectly");
value = json_null();
if(value->refcount != (unsigned int)-1)
fail("refcounting null works incorrectly");
json_decref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting null works incorrectly");
json_incref(value);
if(value->refcount != (unsigned int)-1)
fail("refcounting null works incorrectly");
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

View File

@@ -0,0 +1 @@
[1, 2]

View File

@@ -0,0 +1 @@
[1, 2]

View File

@@ -0,0 +1 @@
export JSON_COMPACT=1

View File

@@ -0,0 +1 @@
[1, 2]

View File

@@ -0,0 +1 @@
[1,2]

View File

@@ -0,0 +1 @@
export JSON_COMPACT=1

View File

@@ -0,0 +1 @@
{"a": 1, "b": 2}

View File

@@ -0,0 +1 @@
{"a":1,"b":2}

View File

@@ -0,0 +1 @@
export JSON_ENSURE_ASCII=1

View File

@@ -0,0 +1,8 @@
[
"foo",
"å ä ö",
"foo åä",
"åä foo",
"å foo ä",
"clef g: 𝄞"
]

View File

@@ -0,0 +1 @@
["foo", "\u00e5 \u00e4 \u00f6", "foo \u00e5\u00e4", "\u00e5\u00e4 foo", "\u00e5 foo \u00e4", "clef g: \ud834\udd1e"]

View File

@@ -0,0 +1 @@
export JSON_INDENT=4

View File

@@ -0,0 +1 @@
[1, 2]

View File

@@ -0,0 +1,4 @@
[
1,
2
]

View File

@@ -0,0 +1,2 @@
export JSON_INDENT=4
export JSON_COMPACT=1

View File

@@ -0,0 +1 @@
[1, 2]

View File

@@ -0,0 +1,4 @@
[
1,
2
]

View File

@@ -0,0 +1,2 @@
export JSON_INDENT=4
export JSON_COMPACT=1

View File

@@ -0,0 +1 @@
{"a": 1, "b": 2}

View File

@@ -0,0 +1,4 @@
{
"a":1,
"b":2
}

View File

@@ -0,0 +1 @@
export JSON_INDENT=4

View File

@@ -0,0 +1 @@
{"a": 1, "b": 2}

View File

@@ -0,0 +1,4 @@
{
"a": 1,
"b": 2
}

View File

@@ -0,0 +1 @@
{"a": 1, "b": 2}

View File

@@ -0,0 +1 @@
{"a": 1, "b": 2}

View File

@@ -0,0 +1 @@
export JSON_PRESERVE_ORDER=1

View File

@@ -0,0 +1 @@
{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6}

View File

@@ -0,0 +1 @@
{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6}

32
test/suites/encoding-flags/run Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
#
# Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
is_test() {
test -d $test_path
}
run_test() {
(
if [ -f $test_path/env ]; then
. $test_path/env
fi
$json_process <$test_path/input >$test_log/stdout 2>$test_log/stderr
)
valgrind_check $test_log/stderr || return 1
cmp -s $test_path/output $test_log/stdout
}
show_error() {
valgrind_show_error && return
echo "EXPECTED OUTPUT:"
nl -bn $test_path/output
echo "ACTUAL OUTPUT:"
nl -bn $test_log/stdout
}
. $top_srcdir/test/scripts/run-tests.sh

View File

@@ -0,0 +1 @@
export JSON_SORT_KEYS=1

View File

@@ -0,0 +1 @@
{"foo": 1, "bar": 2, "baz": 3, "quux": 4}

View File

@@ -0,0 +1 @@
{"bar": 2, "baz": 3, "foo": 1, "quux": 4}

View File

@@ -0,0 +1,2 @@
1
invalid token near '''

View File

@@ -0,0 +1 @@
['

View File

@@ -0,0 +1,2 @@
1
'[' or '{' expected near 'a'

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,2 @@
1
string or '}' expected near ','

View File

@@ -0,0 +1 @@
{,

View File

@@ -0,0 +1,2 @@
1
unexpected token near ','

View File

@@ -0,0 +1 @@
[,

View File

@@ -0,0 +1,2 @@
1
']' expected near end of file

View File

@@ -0,0 +1 @@
[1,

View File

@@ -0,0 +1,2 @@
1
'[' or '{' expected near end of file

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