137 Commits
v2.0.1 ... v2.4

Author SHA1 Message Date
Petri Lehtinen
3279aacdee jansson 2.4 2012-09-23 12:52:41 +03:00
Petri Lehtinen
2158670177 Distribute win32 files 2012-09-23 12:52:40 +03:00
Petri Lehtinen
4cff593dd4 Update CHANGES for v2.4 2012-09-22 14:26:16 +03:00
Petri Lehtinen
597423ea80 doc: Add versionadded directive for json_boolean() 2012-09-22 14:25:29 +03:00
Petri Lehtinen
c3fc1d7382 Merge pull request #90 from luke-jr/patch-1
Add -no-undefined to LDFLAGS
2012-09-18 21:11:26 -07:00
Luke Dashjr
c922354076 Add -no-undefined to LDFLAGS
This tells libtool that jansson does not require any external symbols, and allows building it as a shared library (DLL) on Windows.
2012-09-15 08:45:29 +00:00
Petri Lehtinen
4118315afa Disallow NaN or Inf real values 2012-09-13 21:30:19 +03:00
Petri Lehtinen
ee13c667f1 Fix json_real_set() to return -1 on error 2012-09-13 08:46:56 +03:00
Petri Lehtinen
23d563434a Fix a typo on doc/apiref.rst 2012-09-06 12:06:41 +03:00
Petri Lehtinen
6142dbd8d0 Fix a typo in README.rst 2012-09-05 21:16:43 +03:00
Petri Lehtinen
0dac319bc4 CHANGES entry for #88 2012-08-11 20:45:25 +03:00
Petri Lehtinen
0b871a113c Merge branch '2.3' 2012-08-11 20:45:15 +03:00
Alessandro Ghedini
8176527f56 fix check-exports test on ppc64 2012-08-11 20:42:21 +03:00
Petri Lehtinen
ec7bb71d75 Add an initial CHANGES entry for v2.4 2012-07-30 07:52:41 +03:00
Petri Lehtinen
b6a1d8cfd4 Add json_boolean() macro
Mostly for symmetry reasons. Makes it easier e.g. to:

  int ok = 0;
  if(something)
      ok = 1;

  json_object_set_new(obj, "ok", json_boolean(ok));

Fixes #86.
2012-07-30 07:20:37 +03:00
Petri Lehtinen
52924288b9 Merge branch '2.3' 2012-07-27 07:28:40 +03:00
Petri Lehtinen
7892ecce1c Fix a small error in tutorial
Fixes #84.
2012-07-27 07:28:18 +03:00
Petri Lehtinen
a501a39626 Document the JSON_ESCAPE_SLASH encoding flag 2012-06-29 13:32:17 +03:00
Petri Lehtinen
37bc3bbf4b Tweak slash escaping 2012-06-29 13:25:02 +03:00
Petri Lehtinen
2d46ea069b Merge branch 'fix-slash' of git://github.com/jrbasso/jansson
Fixes #81.
2012-06-29 13:24:55 +03:00
Juan Basso
b217cd6689 Created flag to dump escaping slash 2012-06-28 22:04:36 -04:00
Juan Basso
a0c262d08b Escaping the slash when dump 2012-06-27 23:54:08 -04:00
Petri Lehtinen
6ce273e2e6 Merge branch '2.3' 2012-06-06 21:10:28 +03:00
Paul Harris
f62b1f5d69 Bugfix: must cast void* to do pointer math
Fixes #78.
2012-06-06 21:09:47 +03:00
Paul Harris
2b87fdcb43 Bugfix: Changed all use of ssize_t to size_t.
ssize_t is only used in a test, and its comparing to a size_t variable.

Fixes #77.
2012-06-06 08:47:17 +03:00
Petri Lehtinen
c0139681cd Update the documentation to mention Visual Studio 2010 support 2012-05-19 21:22:59 +03:00
Petri Lehtinen
9d6f9511f5 Merge pull request #74 from rogerz/contrib
Add vs2010 solution and project, fix warnings under MinGW
2012-05-03 11:31:19 -07:00
Rogerz Zhang
a79f64e155 Fix build warnings under MinGW 2012-05-01 08:02:12 +08:00
Rogerz Zhang
7ca783c3bc Add vs2010 solution and project 2012-04-30 21:51:07 +08:00
Petri Lehtinen
ff0c05b8f1 Support building on Windows
Jansson now builds correctly with Visual C++ Express 2010.
2012-04-29 22:09:29 +03:00
Petri Lehtinen
4601bf71e5 Merge branch '2.3' 2012-04-26 22:11:22 +03:00
Jack Mitchell
c7f86abf6d fix slight typo in json_pack apiref example
Fixes #73.
2012-04-26 22:10:46 +03:00
Petri Lehtinen
f309e30320 Merge branch '2.3' 2012-04-26 22:09:48 +03:00
Jack Mitchell
233574e8e0 fix slight typo in json_pack apiref example
Fixes #73.
2012-04-26 22:09:29 +03:00
Petri Lehtinen
4a6939ef87 Merge branch '2.3' 2012-04-26 09:00:49 +03:00
Petri Lehtinen
42bc7a3c50 Check for missing args and envvars in run-tests.sh
Fixes #71.
2012-04-26 08:58:36 +03:00
Petri Lehtinen
abdb8d99d7 Merge branch '2.3'
Conflicts:
	configure.ac
	doc/conf.py
	src/jansson.h
2012-04-20 21:41:25 +03:00
Petri Lehtinen
ff6e6ee293 jansson 2.3.1 2012-04-20 21:35:00 +03:00
Petri Lehtinen
8b2bfd5586 Merge branch '2.3' 2012-04-18 21:59:10 +03:00
Petri Lehtinen
e46b912f53 Fix tutorial to use Github API v3
The v2 API will be shut down on May 1st 2012.

Fixes #65.
2012-04-18 21:58:52 +03:00
Petri Lehtinen
1581f26a7f Merge branch '2.3'
Closes #70.
2012-04-18 21:27:26 +03:00
Janne Kulmala
aabfd493d3 load: Change buffer_pos to be a size_t
buffer_pos should be type size_t, because it's used to store the
current position in the read buffer. Also, it never can be negative.
2012-04-18 21:21:17 +03:00
Janne Kulmala
bd72efbd80 load: Avoid unexpected behaviour in macro expansion
Macros can be dangerous if the inserted arguments are not properly
parenthesised. As macro expansion does a simple replacement, inserting
a certain expression can cause the evaluation order of the macro expression
to change.
2012-04-18 21:21:17 +03:00
Petri Lehtinen
e8fd3e3085 Document and tweak json_load_callback()
Change the return value of json_load_callback_t to size_t, as it's
feels more correct. The callback should return (size_t)-1 on failure.

Issue #57.
2012-03-26 21:53:21 +03:00
Petri Lehtinen
873eddaf19 Merge pull request #60 from rogerz/contrib
Ignore the binary test_load_callback
2012-03-25 10:46:45 -07:00
Rogerz
bd2c0c730d Ignore the binary test_load_callback 2012-03-25 13:22:09 +00:00
Petri Lehtinen
17a51a4bf0 Merge branch '2.3' 2012-03-22 09:02:51 +02:00
Petri Lehtinen
09c39adc55 Add json_load_callback to the list of exported symbols 2012-03-22 09:02:49 +02:00
Petri Lehtinen
cbb80baf03 Merge pull request #57 from rogerz/contrib
Add json_load_callback()
2012-03-22 00:00:24 -07:00
Rogerz Zhang
040bd7b0fa Add json_load_callback() 2012-03-22 14:52:57 +08:00
Petri Lehtinen
2637faa450 Make test stripping locale independent 2012-03-22 08:48:28 +02:00
Petri Lehtinen
952e1d4ba9 Merge branch '2.3'
Closes #56.
2012-03-21 14:03:51 +02:00
Rogerz Zhang
353b5e08ba Ignore *.exe 2012-03-21 14:03:46 +02:00
Petri Lehtinen
d286e7b753 Merge branch '2.3' 2012-03-20 20:56:00 +02:00
Petri Lehtinen
3c6e36ba2d Update copyright notices for 2012 2012-03-20 20:55:55 +02:00
Petri Lehtinen
9af64480e1 Merge branch '2.3' 2012-03-20 20:48:36 +02:00
Petri Lehtinen
4ae5736bd0 Make sure strtoll() is available when using long long 2012-03-20 20:47:57 +02:00
Petri Lehtinen
56039ed596 Merge branch '2.3' 2012-03-11 21:16:41 +02:00
Petri Lehtinen
02b915af54 Remove unused declarations 2012-03-11 21:12:52 +02:00
Petri Lehtinen
1eb274c555 Merge branch '2.3' 2012-03-08 15:03:03 +02:00
Petri Lehtinen
6ac6f311b5 Fix tests on shells that don't support the export FOO=bar syntax 2012-03-08 15:01:52 +02:00
Petri Lehtinen
f736e705b2 Merge branch '2.3' 2012-02-12 16:05:35 +02:00
Petri Lehtinen
54d88753a6 Disribute the check-exports tests 2012-02-12 16:05:27 +02:00
Petri Lehtinen
98a99fb2bd Merge branch '2.3' 2012-02-02 17:03:03 +02:00
Petri Lehtinen
ac97f6f225 doc: Fix the names of library version constants
Fixes #52.
2012-02-02 17:00:35 +02:00
Petri Lehtinen
60fd7ab781 Merge branch '2.3' 2012-01-30 21:23:49 +02:00
Petri Lehtinen
0d64e8ef89 Make test_load.c not depend on the C locale
Fixes #51.
2012-01-30 21:23:18 +02:00
Petri Lehtinen
a894980258 Set master to 2.4 development mode 2012-01-30 20:59:32 +02:00
Petri Lehtinen
f227483846 jansson 2.3 2012-01-27 21:02:12 +02:00
Petri Lehtinen
6cb14dd337 Add support for optional object keys for json_unpack() and friends
Initial patch by Andrew Thompson.
2012-01-26 21:16:36 +02:00
Petri Lehtinen
fa268b5017 Add json_object_update_{existing,missing}
Closes #37.
2012-01-24 21:03:36 +02:00
Petri Lehtinen
a307974731 Implement json_object_foreach()
Also change many places to use it internally to replace hand-crafted
iteration.

Closes #45, #46.
2012-01-24 21:01:24 +02:00
Petri Lehtinen
a2381948bb Make hashtable less generic
This will make it possible to implement json_object_foreach(). It
should also have some (positive) effect on speed.
2012-01-24 21:01:23 +02:00
Petri Lehtinen
5eb2c442a9 Fix a potential memory leak 2012-01-24 20:35:59 +02:00
Petri Lehtinen
f471e63bb3 Write number of bytes read to error position on successful decode
Closes #49.
2012-01-23 21:18:04 +02:00
Petri Lehtinen
bb24697d9b Merge branch '2.2' 2011-11-14 21:16:42 +02:00
Petri Lehtinen
c4a7bf90cf Revert "json_dump_file: Open the output file in wb mode"
JSON is read as text, so line endings should be preserved.

This reverts commit 32cd821273.
2011-11-14 21:16:36 +02:00
Petri Lehtinen
bef87fc258 Merge branch '2.2'
Closes GH-43.
2011-11-14 21:11:18 +02:00
Petri Lehtinen
68d6410da0 Update the documentation of JSON_DECODE_ANY 2011-11-14 21:10:16 +02:00
Andrea Marchesini
1e36667193 JSON_DECODE_ANY
Closes GH-4.
2011-11-14 21:10:09 +02:00
Petri Lehtinen
0931d938b0 doc: The same JSON values must not be encoded in parallel
Closes GH-42.
2011-11-14 21:01:34 +02:00
Petri Lehtinen
0f2cdd70ff Avoid problems with object's serial number growing too big
Transform serial key comparison from substraction to real comparison.
Reset serial to zero in json_object_clear() to avoid it growing out of
bounds when reusing objects.

Closes GH-40.
Closes GH-41.
2011-11-14 21:01:13 +02:00
Andrea Marchesini
5ec101ec21 json_load* return NULL if the first argument is NULL 2011-11-14 20:57:41 +02:00
Petri Lehtinen
72cd84b92a doc: The configure script can be used on MinGW 2011-11-02 08:01:49 +02:00
Petri Lehtinen
6799c8e4c9 Distribute jansson_config.h.win32 2011-11-02 07:57:19 +02:00
Petri Lehtinen
8484ea3fb2 Remove '+' and leading zeros from exponents in the encoder
Fixes GH-39.
2011-11-01 20:50:16 +02:00
Petri Lehtinen
92d9b89d59 Fix test file comparisons on MinGW
Don't output any DOS line terminators from json_process.

Issue GH-39.
2011-11-01 20:49:52 +02:00
Petri Lehtinen
bc98ab6a69 Use %I64d format for printing long longs on Windows
Fixes GH-38.
2011-11-01 20:49:28 +02:00
Petri Lehtinen
32cd821273 json_dump_file: Open the output file in wb mode
For maximum compatibility.
2011-10-07 20:52:54 +03:00
Petri Lehtinen
9c6cb42f17 jansson 2.2.1 2011-10-06 21:23:09 +03:00
Petri Lehtinen
ed06777937 Distribute doc/portability.rst 2011-10-06 21:23:09 +03:00
Petri Lehtinen
6362032513 json_load_file: Open the input file in rb mode
For maximum compatibility.
2011-10-04 21:11:31 +03:00
Petri Lehtinen
84f739036d Documentation fixes 2011-10-04 21:04:56 +03:00
Petri Lehtinen
0f358c8eaa doc: Add project status to introduction, add portability chapter
Move the multithreading-and-setlocale documentation to the new
portability chapter.

Fixes GH-36.
2011-10-03 22:42:39 +03:00
Petri Lehtinen
f0d5c04734 Make identifier decoding work under all locales
Replace isxxx() functions from ctype.h with locale-independent macros.

Fixes GH-35.
2011-10-03 21:43:16 +03:00
Petri Lehtinen
fd56deb7dd Use strchr() when searching for a single character 2011-10-03 08:52:30 +03:00
Petri Lehtinen
d7ddbf3661 Make real number encoding and decoding work under all locales
The decimal point '.' is changed to locale's decimal point
before/after JSON conversion to make C standard library's
locale-specific string conversion functions work correctly.

All the tests now call setlocale(LC_ALL, "") on startup to use the
locale set in the environment.

Fixes GH-32.
2011-10-02 21:31:17 +03:00
Petri Lehtinen
b6d0191e51 Implement all other encoding functions using json_dump_callback
This way we can check for JSON_ENCODE_ANY flag in one place only.
2011-09-24 21:10:34 +03:00
Petri Lehtinen
2a70d62251 Merge pull request #33 from bakulf/master
Little fixes
2011-09-20 11:11:55 -07:00
Andrea Marchesini
909874b1b9 scope error. result points to a out-of-score variable. 2011-09-20 13:10:32 +02:00
Andrea Marchesini
ff57dee13d unsed static variable removed 2011-09-20 11:46:29 +02:00
Petri Lehtinen
e4cc77ce52 doc: Clarify the result of 's' format of json_unpack()
Fixes GH-31.
2011-09-12 21:22:20 +03:00
Petri Lehtinen
889f295958 jansson 2.2 2011-09-02 21:39:40 +03:00
Petri Lehtinen
68809cd913 doc: json_dump_callback was added in v2.2 2011-09-02 21:29:01 +03:00
Petri Lehtinen
910fb92267 Merge branch '2.1' 2011-08-08 21:00:47 +03:00
Petri Lehtinen
f241e14cab doc: Explain the non-constness of the first parameter of json_unpack() et al
Fixes GH-30.
2011-08-08 20:59:10 +03:00
Petri Lehtinen
7e9c293986 Merge branch '2.1' 2011-06-30 21:48:51 +03:00
Petri Lehtinen
d43464a1ec Merge branch 'issue-29'
Fixes GH-29.
2011-06-30 21:48:33 +03:00
Petri Lehtinen
c7079a25eb doc: Add documentation for json_dump_callback() 2011-06-30 21:47:37 +03:00
JKL
54f38d250c test file for new json_dump_callback function 2011-06-30 21:47:12 +03:00
JKL
c7d543d36c new typedef json_dump_callback_t, function json_dump_callback 2011-06-30 21:47:12 +03:00
Petri Lehtinen
7fab57dcef doc: Fix several typos and other little errors 2011-06-30 21:04:49 +03:00
JKL
cd9757512d use size_t for strbuffer writes, and avoid integer overflow 2011-06-30 20:45:18 +03:00
Petri Lehtinen
c0193bfb7f Check that target is string and value is not NULL in json_string_set() 2011-06-17 21:42:19 +03:00
Petri Lehtinen
6e1f4bb560 doc: Clarify that removing from containers decrements the refcount
While at it, reword the object iteration protocol description a bit.
2011-06-17 20:53:32 +03:00
Petri Lehtinen
1358d0bfac CHANGES: Fix v2.1 release date 2011-06-10 21:53:14 +03:00
Petri Lehtinen
86d17a8dc2 jansson 2.1 2011-06-10 21:30:11 +03:00
Petri Lehtinen
3988ab2d27 Use `literal` syntax with macro and flag names in CHANGES 2011-06-07 21:40:09 +03:00
Petri Lehtinen
f7f7bf5ab2 Prepare for relase: Add CHANGES entry for v2.1 2011-06-07 21:33:59 +03:00
Petri Lehtinen
a76ba52f34 Add JSON_DISABLE_EOF_CHECK decoding flag
With this flag enabled, the decoder stops after a valid JSON input and
thus allows extra data after it.

Fixes GH-25.
2011-05-29 21:27:15 +03:00
Petri Lehtinen
9febdf333c Reduce code duplication in the decoder 2011-05-29 12:53:25 +03:00
Petri Lehtinen
013b8b3f60 Clear errno before calling strtod()
Fixes GH-27.
2011-05-24 09:59:41 +03:00
Petri Lehtinen
49fc708d4c Add JSON_REJECT_DUPLICATES decoding flag
With this flag, a decoding error is issued if any JSON object in the
input contains duplicate keys.

Fixes GH-3.
2011-05-15 13:57:49 +03:00
Petri Lehtinen
92f6f0f22c doc: Clarify that Unicode normalization or comparison algorithms are not used 2011-05-15 12:39:10 +03:00
Petri Lehtinen
e9e34f430e doc: Add "New in version 2.1" notes to new features 2011-05-14 20:52:14 +03:00
Petri Lehtinen
ab723c7fb5 docs: Add a note that object iteration doesn't give any particular order
Closes GH-15.
2011-05-14 13:04:35 +03:00
Petri Lehtinen
636d5f60f9 Add JSON_ENCODE_ANY flag to allow encoding any JSON value
Closes GH-19.
2011-05-14 12:57:12 +03:00
Petri Lehtinen
c3492973e1 Merge branch '2.0' 2011-04-21 13:15:58 +03:00
Petri Lehtinen
e20619e071 Fix a leak when memory allocation fails in json_object_set() & friends 2011-04-21 13:15:22 +03:00
Petri Lehtinen
b44e2be032 Add json_loadb() for decoding possibly non null-terminated strings
Thanks to Jonathan Landis for the initial patch.
2011-04-10 21:01:50 +03:00
Petri Lehtinen
76d6d700ad Merge branch '2.0' 2011-04-05 15:38:37 +03:00
Jim Meyering
c96763215d Avoid set-but-not-used warning/error in a test
Closes GH-20.
2011-04-05 15:36:13 +03:00
Petri Lehtinen
4a76900bd7 Merge branch '2.0'
Conflicts:
	doc/conf.py
	src/jansson.h
2011-03-31 21:26:19 +03:00
Petri Lehtinen
056702e541 Merge branch '2.0' 2011-03-31 16:39:33 +03:00
Petri Lehtinen
a5a43caa9a Merge branch '2.0' 2011-03-27 21:04:29 +03:00
Petri Lehtinen
5456fc59ab Set JANSSON_MICRO_VERSION to 255 (0xFF) for git master
Also, set documentation release to "2.0+git". This shows up in the
automatically built HTML documentation.

These changes makes it easier for library users to know that this
version is under development.

Closes GH-14.
2011-03-27 21:03:04 +03:00
Petri Lehtinen
af18578928 Use the correct number of parens in JANSSON_VERSION_HEX macro 2011-03-23 08:25:50 +02:00
78 changed files with 2353 additions and 787 deletions

1
.gitignore vendored
View File

@@ -25,3 +25,4 @@ stamp-h1
*.pyc
*.pc
/src/jansson_config.h
*.exe

200
CHANGES
View File

@@ -1,3 +1,201 @@
Version 2.4
===========
Released 2012-09-23
* New features:
- Add `json_boolean()` macro that returns the JSON true or false
value based on its argument (#86).
- Add `json_load_callback()` that calls a callback function
repeatedly to read the JSON input (#57).
- Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of
``/`` with ``\/``.
* Bug fixes:
- Check for and reject NaN and Inf values for reals. Encoding these
values resulted in invalid JSON.
- Fix `json_real_set()` to return -1 on error.
* Build:
- Jansson now builds on Windows with Visual Studio 2010, and
includes solution and project files in ``win32/vs2010/``
directory.
- Fix build warnings (#77, #78).
- Add ``-no-undefined`` to LDFLAGS (#90).
* Tests:
- Fix the symbol exports test on Linux/PPC64 (#88).
* Documentation:
- Fix typos (#73, #84).
Version 2.3.1
=============
Released 2012-04-20
* Build issues:
- Only use ``long long`` if ``strtoll()`` is also available.
* Documentation:
- Fix the names of library version constants in documentation. (#52)
- Change the tutorial to use GitHub API v3. (#65)
* Tests:
- Make some tests locale independent. (#51)
- Distribute the library exports test in the tarball.
- Make test run on shells that don't support the ``export FOO=bar``
syntax.
Version 2.3
===========
Released 2012-01-27
* New features:
- `json_unpack()` and friends: Add support for optional object keys
with the ``{s?o}`` syntax.
- Add `json_object_update_existing()` and
`json_object_update_missing()`, for updating only existing keys or
only adding missing keys to an object. (#37)
- Add `json_object_foreach()` for more convenient iteration over
objects. (#45, #46)
- When decoding JSON, write the number of bytes that were read from
input to ``error.position`` also on success. This is handy with
``JSON_DISABLE_EOF_CHECK``.
- Add support for decoding any JSON value, not just arrays or
objects. The support is enabled with the new ``JSON_DECODE_ANY``
flag. Patch by Andrea Marchesini. (#4)
* Bug fixes
- Avoid problems with object's serial number growing too big. (#40,
#41)
- Decoding functions now return NULL if the first argument is NULL.
Patch by Andrea Marchesini.
- Include ``jansson_config.h.win32`` in the distribution tarball.
- Remove ``+`` and leading zeros from exponents in the encoder.
(#39)
- Make Jansson build and work on MinGW. (#39, #38)
* Documentation
- Note that the same JSON values must not be encoded in parallel by
separate threads. (#42)
- Document MinGW support.
Version 2.2.1
=============
Released 2011-10-06
* Bug fixes:
- Fix real number encoding and decoding under non-C locales. (#32)
- Fix identifier decoding under non-UTF-8 locales. (#35)
- `json_load_file()`: Open the input file in binary mode for maximum
compatiblity.
* Documentation:
- Clarify the lifecycle of the result of the ``s`` fromat of
`json_unpack()`. (#31)
- Add some portability info. (#36)
- Little clarifications here and there.
* Other:
- Some style fixes, issues detected by static analyzers.
Version 2.2
===========
Released 2011-09-03
* New features:
- `json_dump_callback()`: Pass the encoder output to a callback
function in chunks.
* Bug fixes:
- `json_string_set()`: Check that target is a string and value is
not NULL.
* Other:
- Documentation typo fixes and clarifications.
Version 2.1
===========
Released 2011-06-10
* New features:
- `json_loadb()`: Decode a string with a given size, useful if the
string is not null terminated.
- Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON
value. By default, only arrays and objects can be encoded. (#19)
- Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding
error if any JSON object in the input contins duplicate keys. (#3)
- Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a
valid JSON input. This allows other data after the JSON data.
* Bug fixes:
- Fix an additional memory leak when memory allocation fails in
`json_object_set()` and friends.
- Clear errno before calling `strtod()` for better portability. (#27)
* Building:
- Avoid set-but-not-used warning/error in a test. (#20)
* Other:
- Minor clarifications to documentation.
Version 2.0.1
=============
@@ -10,7 +208,7 @@ Released 2011-03-31
- Fix object key hashing in json_unpack() strict checking mode.
- Fix the parentheses in JANSSON_VERSION_HEX macro.
- Fix the parentheses in ``JANSSON_VERSION_HEX`` macro.
- Fix `json_object_size()` return value.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
Copyright (c) 2009-2012 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,4 +1,4 @@
EXTRA_DIST = CHANGES LICENSE README.rst
EXTRA_DIST = CHANGES LICENSE README.rst win32
SUBDIRS = doc src test
# "make distcheck" builds the dvi target, so use it to check that the

View File

@@ -33,8 +33,8 @@ To run the test suite, invoke::
$ make check
If the source has been checked out from a Git repository, the
./configure script has to be generated fist. The easiest way is to use
autoreconf::
./configure script has to be generated first. The easiest way is to
use autoreconf::
$ autoreconf -i

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([jansson], [2.0.1], [petri@digip.org])
AC_INIT([jansson], [2.4], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
@@ -14,16 +14,11 @@ AM_CONDITIONAL([GCC], [test x$GCC = xyes])
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([locale.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
AC_TYPE_LONG_LONG_INT
case $ac_cv_type_long_long_int in
yes) json_have_long_long=1;;
*) json_have_long_long=0;;
esac
AC_SUBST([json_have_long_long])
AC_C_INLINE
case $ac_cv_c_inline in
@@ -34,6 +29,19 @@ esac
AC_SUBST([json_inline])
# Checks for library functions.
AC_CHECK_FUNCS([strtoll localeconv])
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
yesyes) json_have_long_long=1;;
*) json_have_long_long=0;;
esac
AC_SUBST([json_have_long_long])
case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in
yesyes) json_have_localeconv=1;;
*) json_have_localeconv=0;;
esac
AC_SUBST([json_have_localeconv])
AC_CONFIG_FILES([
jansson.pc

View File

@@ -1,6 +1,6 @@
EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \
gettingstarted.rst github_commits.c index.rst tutorial.rst \
upgrading.rst ext/refcounting.py
gettingstarted.rst github_commits.c index.rst portability.rst \
tutorial.rst upgrading.rst ext/refcounting.py
SPHINXBUILD = sphinx-build
SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA)

View File

@@ -41,7 +41,7 @@ set to zero.
The following preprocessor constants specify the current version of
the library:
``JANSSON_VERSION_MAJOR``, ``JANSSON_VERSION_MINOR``, ``JANSSON_VERSION_MICRO``
``JANSSON_MAJOR_VERSION``, ``JANSSON_MINOR_VERSION``, ``JANSSON_MICRO_VERSION``
Integers specifying the major, minor and micro versions,
respectively.
@@ -255,8 +255,8 @@ returns an error status.
True, False and Null
====================
These values are implemented as singletons, so each of these functions
returns the same value each time.
These three values are implemented as singletons, so the returned
pointers won't change between invocations of these functions.
.. function:: json_t *json_true(void)
@@ -270,6 +270,17 @@ returns the same value each time.
Returns the JSON false value.
.. function:: json_t *json_boolean(val)
.. refcounting:: new
Returns JSON false if ``val`` is zero, and JSON true otherwise.
This is a macro, and equivalent to ``val ? json_true() :
json_false()``.
.. versionadded:: 2.4
.. function:: json_t *json_null(void)
.. refcounting:: new
@@ -481,12 +492,13 @@ A JSON array is an ordered collection of other JSON values.
Removes the element in *array* at position *index*, shifting the
elements after *index* one position towards the start of the array.
Returns 0 on success and -1 on error.
Returns 0 on success and -1 on error. The reference count of the
removed value is decremented.
.. function:: int json_array_clear(json_t *array)
Removes all elements from *array*. Returns 0 on sucess and -1 on
error.
error. The reference count of all removed values are decremented.
.. function:: int json_array_extend(json_t *array, json_t *other_array)
@@ -549,21 +561,70 @@ Unicode string and the value is any JSON value.
.. function:: int json_object_del(json_t *object, const char *key)
Delete *key* from *object* if it exists. Returns 0 on success, or
-1 if *key* was not found.
-1 if *key* was not found. The reference count of the removed value
is decremented.
.. function:: int json_object_clear(json_t *object)
Remove all elements from *object*. Returns 0 on success and -1 if
*object* is not a JSON object.
*object* is not a JSON object. The reference count of all removed
values are decremented.
.. function:: int json_object_update(json_t *object, json_t *other)
Update *object* with the key-value pairs from *other*, overwriting
existing keys. Returns 0 on success or -1 on error.
.. function:: int json_object_update_existing(json_t *object, json_t *other)
The following functions implement an iteration protocol for objects:
Like :func:`json_object_update()`, but only the values of existing
keys are updated. No new keys are created. Returns 0 on success or
-1 on error.
.. versionadded:: 2.3
.. function:: int json_object_update_missing(json_t *object, json_t *other)
Like :func:`json_object_update()`, but only new keys are created.
The value of any existing key is not changed. Returns 0 on success
or -1 on error.
.. versionadded:: 2.3
The following macro can be used to iterate through all key-value pairs
in an object.
.. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block
of code that follows each time with the proper values set to
variables ``key`` and ``value``, of types :type:`const char *` and
:type:`json_t *` respectively. Example::
/* obj is a JSON object */
const char *key;
json_t *value;
json_object_foreach(obj, key, value) {
/* block of code that uses key and value */
}
The items are not returned in any particular order.
This macro expands to an ordinary ``for`` statement upon
preprocessing, so its performance is equivalent to that of
hand-written iteration code using the object iteration protocol
(see below). The main advantage of this macro is that it abstracts
away the complexity behind iteration, and makes for shorter, more
concise code.
.. versionadded:: 2.3
The following functions implement an iteration protocol for objects,
allowing to iterate through all key-value pairs in an object. The
items are not returned in any particular order, as this would require
sorting due to the internal hashtable implementation.
.. function:: void *json_object_iter(json_t *object)
@@ -605,11 +666,21 @@ The following functions implement an iteration protocol for objects:
*value*. This is useful when *value* is newly created and not used
after the call.
.. function:: void *json_object_key_to_iter(const char *key)
Like :func:`json_object_iter_at()`, but much faster. Only works for
values returned by :func:`json_object_iter_key()`. Using other keys
will lead to segfaults. This function is used internally to
implement :func:`json_object_foreach`.
.. versionadded:: 2.3
The iteration protocol can be used for example as follows::
/* obj is a JSON object */
const char *key;
json_t *value;
void *iter = json_object_iter(obj);
while(iter)
{
@@ -670,7 +741,9 @@ and pass a pointer to a function. Example::
}
Also note that if the call succeeded (``json != NULL`` in the above
example), the contents of ``error`` are unspecified.
example), the contents of ``error`` are generally left unspecified.
The decoding functions write to the ``position`` member also on
success. See :ref:`apiref-decoding` for more info.
All functions also accept *NULL* as the :type:`json_error_t` pointer,
in which case no error information is returned to the caller.
@@ -680,8 +753,10 @@ Encoding
========
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.
values to JSON. By default, only objects and arrays can be encoded
directly, since they are the only valid *root* values of a JSON text.
To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see
below).
By default, the output has no newlines, and spaces are used between
array and object elements for a readable output. This behavior can be
@@ -696,9 +771,9 @@ can be ORed together to obtain *flags*.
``JSON_INDENT(n)``
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 32, 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.
between 0 and 31 (inclusive), 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
@@ -722,6 +797,23 @@ can be ORed together to obtain *flags*.
example, decoding a JSON text and then encoding with this flag
preserves the order of object keys.
``JSON_ENCODE_ANY``
Specifying this flag makes it possible to encode any JSON value on
its own. Without it, only objects and arrays can be passed as the
*root* value to the encoding functions.
**Note:** Encoding any value may be useful in some scenarios, but
it's generally discouraged as it violates strict compatiblity with
:rfc:`4627`. If you use this flag, don't expect interoperatibility
with other JSON systems.
.. versionadded:: 2.1
``JSON_ESCAPE_SLASH``
Escape the ``/`` characters in strings with ``\/``.
.. versionadded:: 2.4
The following functions perform the actual JSON encoding. The result
is in UTF-8.
@@ -745,6 +837,30 @@ is in UTF-8.
*path* already exists, it is overwritten. *flags* is described
above. Returns 0 on success and -1 on error.
.. type:: json_dump_callback_t
A typedef for a function that's called by
:func:`json_dump_callback()`::
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
*buffer* points to a buffer containing a chunk of output, *size* is
the length of the buffer, and *data* is the corresponding
:func:`json_dump_callback()` argument passed through.
On error, the function should return -1 to stop the encoding
process. On success, it should return 0.
.. versionadded:: 2.2
.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
Call *callback* repeatedly, passing a chunk of the JSON
representation of *root* each time. *flags* is described above.
Returns 0 on success and -1 on error.
.. versionadded:: 2.2
.. _apiref-decoding:
@@ -756,20 +872,88 @@ text to the Jansson representation of JSON data. The JSON
specification requires that a JSON text is either a serialized array
or object, and this requirement is also enforced with the following
functions. In other words, the top level value in the JSON text being
decoded must be either array or object.
decoded must be either array or object. To decode any JSON value, use
the ``JSON_DECODE_ANY`` flag (see below).
See :ref:`rfc-conformance` for a discussion on Jansson's conformance
to the JSON specification. It explains many design decisions that
affect especially the behavior of the decoder.
Each function takes a *flags* parameter that can be used to control
the behavior of the decoder. Its default value is 0. The following
macros can be ORed together to obtain *flags*.
``JSON_REJECT_DUPLICATES``
Issue a decoding error if any JSON object in the input text
contains duplicate keys. Without this flag, the value of the last
occurence of each key ends up in the result. Key equivalence is
checked byte-by-byte, without special Unicode comparison
algorithms.
.. versionadded:: 2.1
``JSON_DECODE_ANY``
By default, the decoder expects an array or object as the input.
With this flag enabled, the decoder accepts any valid JSON value.
**Note:** Decoding any value may be useful in some scenarios, but
it's generally discouraged as it violates strict compatiblity with
:rfc:`4627`. If you use this flag, don't expect interoperatibility
with other JSON systems.
.. versionadded:: 2.3
``JSON_DISABLE_EOF_CHECK``
By default, the decoder expects that its whole input constitutes a
valid JSON text, and issues an error if there's extra data after
the otherwise valid JSON input. With this flag enabled, the decoder
stops after decoding a valid JSON array or object, and thus allows
extra data after the JSON text.
Normally, reading will stop when the last ``]`` or ``}`` in the
JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and
``JSON_DECODE_ANY`` flags are used, the decoder may read one extra
UTF-8 code unit (up to 4 bytes of input). For example, decoding
``4true`` correctly decodes the integer 4, but also reads the
``t``. For this reason, if reading multiple consecutive values that
are not arrays or objects, they should be separated by at least one
whitespace character.
.. versionadded:: 2.1
Each function also takes an optional :type:`json_error_t` parameter
that is filled with error information if decoding fails. It's also
updated on success; the number of bytes of input read is written to
its ``position`` field. This is especially useful when using
``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts.
.. versionadded:: 2.3
Number of bytes of input read is written to the ``position`` field
of the :type:`json_error_t` structure.
If no error or position information is needed, you can pass *NULL*.
The following functions perform the actual JSON decoding.
.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON string *input* and returns the array or object it
contains, or *NULL* on error, in which case *error* is filled with
information about the error. *flags* is currently unused, and
should be set to 0.
information about the error. *flags* is described above.
.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON string *buffer*, whose length is *buflen*, and
returns the array or object it contains, or *NULL* on error, in
which case *error* is filled with information about the error. This
is similar to :func:`json_loads()` except that the string doesn't
need to be null-terminated. *flags* is described above.
.. versionadded:: 2.1
.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
@@ -777,8 +961,18 @@ affect especially the behavior of the decoder.
Decodes the JSON text in stream *input* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
filled with information about the error. *flags* is currently
unused, and should be set to 0.
filled with information about the error. *flags* is described
above.
This function will start reading the input from whatever position
the input file was, without attempting to seek first. If an error
occurs, the file position will be left indeterminate. On success,
the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK``
flag was used. In this case, the file position will be at the first
character after the last ``]`` or ``}`` in the JSON input. This
allows calling :func:`json_loadf()` on the same ``FILE`` object
multiple times, if the input consists of consecutive JSON texts,
possibly separated by whitespace.
.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
@@ -786,8 +980,36 @@ affect especially the behavior of the decoder.
Decodes the JSON text in file *path* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
filled with information about the error. *flags* is currently
unused, and should be set to 0.
filled with information about the error. *flags* is described
above.
.. type:: json_load_callback_t
A typedef for a function that's called by
:func:`json_load_callback()` to read a chunk of input data::
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
*buffer* points to a buffer of *buflen* bytes, and *data* is the
corresponding :func:`json_load_callback()` argument passed through.
On error, the function should return ``(size_t)-1`` to abort the
decoding process. When there's no data left, it should return 0 to
report that the end of input has been reached.
.. versionadded:: 2.4
.. function:: json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON text produced by repeated calls to *callback*, and
returns the array or object it contains, or *NULL* on error, in
which case *error* is filled with information about the error.
*data* is passed through to *callback* on each call. *flags* is
described above.
.. versionadded:: 2.4
.. _apiref-pack:
@@ -795,14 +1017,14 @@ affect especially the behavior of the decoder.
Building Values
===============
This sectinon describes functions that help to create, or *pack*,
This section describes functions that help to create, or *pack*,
complex JSON values, especially nested objects and arrays. Value
building is based on a *format string* that is used to tell the
functions about the expected arguments.
For example, the format string ``"i"`` specifies a single integer
value, while the format string ``"[ssb]"`` or the equivalent ``"[s, s,
b]"`` specifies an array value with two integers and a boolean as its
b]"`` specifies an array value with two strings and a boolean as its
items::
/* Create the JSON integer 42 */
@@ -837,7 +1059,7 @@ denotes the C type that is expected as the corresponding argument.
``o`` (any value) [json_t \*]
Output any given JSON value as-is. If the value is added to an
array or object, the reference to the value passed to ``o`` is
stealed by the container.
stolen by the container.
``O`` (any value) [json_t \*]
Like ``o``, but the argument's reference count is incremented.
@@ -857,6 +1079,8 @@ denotes the C type that is expected as the corresponding argument.
fourth, etc. format character represent a value. Any value may be
an object or array, i.e. recursive value building is supported.
Whitespace, ``:`` and ``,`` are ignored.
The following functions compose the value building API:
.. function:: json_t *json_pack(const char *fmt, ...)
@@ -887,13 +1111,13 @@ More examples::
json_pack("{}");
/* Build the JSON object {"foo": 42, "bar": 7} */
json_pack("{sisb}", "foo", 42, "bar", 7);
json_pack("{sisi}", "foo", 42, "bar", 7);
/* Like above, ':', ',' and whitespace are ignored */
json_pack("{s:i, s:b}", "foo", 42, "bar", 7);
json_pack("{s:i, s:i}", "foo", 42, "bar", 7);
/* Build the JSON array [[1, 2], {"cool": true}] */
json_pack("[[i,i],{s:b]]", 1, 2, "cool", 1);
json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1);
.. _apiref-unpack:
@@ -918,7 +1142,9 @@ type whose address should be passed.
``s`` (string) [const char \*]
Convert a JSON string to a pointer to a NULL terminated UTF-8
string.
string. The resulting string is extracted by using
:func:`json_string_value()` internally, so it exists as long as
there are still references to the corresponding JSON string.
``n`` (null)
Expect a JSON null value. Nothing is extracted.
@@ -962,6 +1188,11 @@ type whose address should be passed.
``fmt`` may contain objects and arrays as values, i.e. recursive
value extraction is supporetd.
.. versionadded:: 2.3
Any ``s`` representing a key may be suffixed with a ``?`` to
make the key optional. If the key is not found, nothing is
extracted. See below for an example.
``!``
This special format character is used to enable the check that
all object and array items are accessed, on a per-value basis. It
@@ -976,6 +1207,8 @@ type whose address should be passed.
or object as the last format character before the closing bracket
or brace.
Whitespace, ``:`` and ``,`` are ignored.
The following functions compose the parsing and validation API:
.. function:: int json_unpack(json_t *root, const char *fmt, ...)
@@ -992,6 +1225,20 @@ The following functions compose the parsing and validation API:
behaviour of the unpacker, see below for the flags. Returns 0 on
success and -1 on failure.
.. note::
The first argument of all unpack functions is ``json_t *root``
instead of ``const json_t *root``, because the use of ``O`` format
character causes the reference count of ``root``, or some value
reachable from ``root``, to be increased. Furthermore, the ``o``
format character may be used to extract a value as-is, which allows
modifying the structure or contents of a value reachable from
``root``.
If the ``O`` and ``o`` format characters are not used, it's
perfectly safe to cast a ``const json_t *`` variable to plain
``json_t *`` when used with these functions.
The following unpacking flags are available:
``JSON_STRICT``
@@ -1028,6 +1275,13 @@ Examples::
json_unpack(root, "[ii!]", &myint1, &myint2);
/* returns -1 for failed validation */
/* root is an empty JSON object */
int myint = 0, myint2 = 0;
json_unpack(root, "{s?i, s?[ii]}",
"foo", &myint1,
"bar", &myint2, &myint3);
/* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */
Equality
========
@@ -1096,6 +1350,8 @@ copied in a recursive fashion.
Returns a deep copy of *value*, or *NULL* on error.
.. _apiref-custom-memory-allocation:
Custom Memory Allocation
========================
@@ -1164,5 +1420,5 @@ JSON structures by zeroing all memory when freed::
For more information about the issues of storing sensitive data in
memory, see
http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html.
The page also examplains the :func:`guaranteed_memset()` function used
The page also explains the :func:`guaranteed_memset()` function used
in the example and gives a sample implementation for it.

View File

@@ -41,16 +41,16 @@ master_doc = 'index'
# General information about the project.
project = u'Jansson'
copyright = u'2009-2011, Petri Lehtinen'
copyright = u'2009-2012, 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 = '2.0'
version = '2.4'
# The full version, including alpha/beta/rc tags.
release = '2.0.1'
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -5,8 +5,7 @@ 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.
for JavaScript Object Notation (JSON)"*.
Character Encoding
==================
@@ -30,6 +29,12 @@ error::
All other Unicode codepoints U+0001 through U+10FFFF are allowed.
Unicode normalization or any other transformation is never performed
on any strings (string values or object keys). When checking for
equivalence of strings or object keys, the comparison is performed
byte by byte between the original UTF-8 representations of the
strings.
Numbers
=======

View File

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

View File

@@ -10,8 +10,8 @@ Compiling and Installing Jansson
The Jansson source is available at
http://www.digip.org/jansson/releases/.
Unix-like systems
-----------------
Unix-like systems (including MinGW)
-----------------------------------
Unpack the source tarball and change to the source directory:
@@ -54,22 +54,25 @@ used as described above.
.. _libtool: http://www.gnu.org/software/libtool/
Windows
-------
Jansson can be built with Visual Studio 2010 (and probably newer
versions, too). The solution and project files are in the
``win32/vs2010/`` directory in the source distribution.
Other Systems
-------------
On Windows and other non Unix-like systems, you may be unable to run
the ``./configure`` script. In this case, follow these steps. All the
files mentioned can be found in the ``src/`` directory.
On non Unix-like systems, you may be unable to run the ``./configure``
script. In this case, follow these steps. All the files mentioned can
be found in the ``src/`` directory.
1. Create ``jansson_config.h``. This file has some platform-specific
1. Create ``jansson_config.h`` (which has some platform-specific
parameters that are normally filled in by the ``./configure``
script:
- On Windows, rename ``jansson_config.h.win32`` to ``jansson_config.h``.
- On other systems, edit ``jansson_config.h.in``, replacing all
``@variable@`` placeholders, and rename the file to
``jansson_config.h``.
script). Edit ``jansson_config.h.in``, replacing all ``@variable@``
placeholders, and rename the file to ``jansson_config.h``.
2. Make ``jansson.h`` and ``jansson_config.h`` available to the
compiler, so that they can be found when compiling programs that

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -13,7 +13,7 @@
#define BUFFER_SIZE (256 * 1024) /* 256 KB */
#define URL_FORMAT "http://github.com/api/v2/json/commits/list/%s/%s/master"
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
/* Return the offset of the first newline in text or the length of
@@ -102,7 +102,6 @@ int main(int argc, char *argv[])
json_t *root;
json_error_t error;
json_t *commits;
if(argc != 3)
{
@@ -126,29 +125,35 @@ int main(int argc, char *argv[])
return 1;
}
commits = json_object_get(root, "commits");
if(!json_is_array(commits))
if(!json_is_array(root))
{
fprintf(stderr, "error: commits is not an array\n");
fprintf(stderr, "error: root is not an array\n");
return 1;
}
for(i = 0; i < json_array_size(commits); i++)
for(i = 0; i < json_array_size(root); i++)
{
json_t *commit, *id, *message;
json_t *data, *sha, *commit, *message;
const char *message_text;
commit = json_array_get(commits, i);
if(!json_is_object(commit))
data = json_array_get(root, i);
if(!json_is_object(data))
{
fprintf(stderr, "error: commit %d is not an object\n", i + 1);
fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
return 1;
}
id = json_object_get(commit, "id");
if(!json_is_string(id))
sha = json_object_get(data, "sha");
if(!json_is_string(sha))
{
fprintf(stderr, "error: commit %d: id is not a string\n", i + 1);
fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1);
return 1;
}
commit = json_object_get(data, "commit");
if(!json_is_object(commit))
{
fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1);
return 1;
}
@@ -161,7 +166,7 @@ int main(int argc, char *argv[])
message_text = json_string_value(message);
printf("%.8s %.*s\n",
json_string_value(id),
json_string_value(sha),
newline_offset(message_text),
message_text);
}

View File

@@ -22,6 +22,11 @@ data. Its main features and design principles are:
Jansson is licensed under the `MIT license`_; see LICENSE in the
source distribution for details.
Jansson is used in production and its API is stable. It works on
numerous platforms, including numerous Unix like systems and Windows.
It's suitable for use on any system, including desktop, server, and
small embedded systems.
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _Jansson: http://www.digip.org/jansson/
@@ -36,6 +41,7 @@ Contents
upgrading
tutorial
conformance
portability
apiref
changes

52
doc/portability.rst Normal file
View File

@@ -0,0 +1,52 @@
***********
Portability
***********
Thread safety
-------------
Jansson is thread safe and has no mutable global state. The only
exception are the memory allocation functions, that should be set at
most once, and only on program startup. See
:ref:`apiref-custom-memory-allocation`.
There's no locking performed inside Jansson's code, so a multithreaded
program must perform its own locking if JSON values are shared by
multiple threads. Jansson's reference counting semantics may make this
a bit harder than it seems, as it's possible to have a reference to a
value that's also stored inside a list or object. Modifying the
container (adding or removing values) may trigger concurrent access to
such values, as containers manage the reference count of their
contained values. Bugs involving concurrent incrementing or
decrementing of deference counts may be hard to track.
The encoding functions (:func:`json_dumps()` and friends) track
reference loops by modifying the internal state of objects and arrays.
For this reason, encoding functions must not be run on the same JSON
values in two separate threads at the same time. As already noted
above, be especially careful if two arrays or objects share their
contained values with another array or object.
If you want to make sure that two JSON value hierarchies do not
contain shared values, use :func:`json_deep_copy()` to make copies.
Locale
------
Jansson works fine under any locale.
However, if the host program is multithreaded and uses ``setlocale()``
to switch the locale in one thread while Jansson is currently encoding
or decoding JSON data in another thread, the result may be wrong or
the program may even crash.
Jansson uses locale specific functions for certain string conversions
in the encoder and decoder, and then converts the locale specific
values to/from the JSON representation. This fails if the locale
changes between the string conversion and the locale-to-JSON
conversion. This can only happen in multithreaded programs that use
``setlocale()``, because ``setlocale()`` switches the locale for all
running threads, not only the thread that calls ``setlocale()``.
If your program uses ``setlocale()`` as described above, consider
using the thread-safe ``uselocale()`` instead.

View File

@@ -7,9 +7,8 @@ Tutorial
.. highlight:: c
In this tutorial, we create a program that fetches the latest commits
of a repository in GitHub_ over the web. One of the response formats
supported by `GitHub API`_ is JSON, so the result can be parsed using
Jansson.
of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so
the result can be parsed using Jansson.
To stick to the the scope of this tutorial, we will only cover the the
parts of the program related to handling JSON data. For the best user
@@ -31,42 +30,44 @@ name. Please note that the GitHub API is rate limited, so if you run
the program too many times within a short period of time, the sever
starts to respond with an error.
.. _GitHub: http://github.com/
.. _GitHub API: http://develop.github.com/
.. _GitHub: https://github.com/
.. _GitHub API: http://developer.github.com/
.. _libcurl: http://curl.haxx.se/
.. _tutorial-github-commits-api:
The GitHub Commits API
======================
The GitHub Repo Commits API
===========================
The `GitHub commits API`_ is used by sending HTTP requests to URLs
starting with ``http://github.com/api/v2/json/commits/``. Our program
only lists the latest commits, so the rest of the URL is
``list/USER/REPOSITORY/BRANCH``, where ``USER``, ``REPOSITORY`` and
``BRANCH`` are the GitHub user ID, the name of the repository, and the
name of the branch whose commits are to be listed, respectively.
The `GitHub Repo Commits API`_ is used by sending HTTP requests to
URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``,
where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name
of the repository whose commits are to be listed, respectively.
GitHub responds with a JSON object of the following form:
GitHub responds with a JSON array of the following form:
.. code-block:: none
{
"commits": [
{
"id": "<the commit ID>",
[
{
"sha": "<the commit ID>",
"commit": {
"message": "<the commit message>",
<more fields, not important to this tutorial>
<more fields, not important to this tutorial...>
},
{
"id": "<the commit ID>",
<more fields...>
},
{
"sha": "<the commit ID>",
"commit": {
"message": "<the commit message>",
<more fields, not important to this tutorial>
<more fields...>
},
<more commits...>
]
}
<more fields...>
},
<more commits...>
]
In our program, the HTTP request is sent using the following
function::
@@ -80,7 +81,7 @@ return value is *NULL*. For full details, refer to :download:`the code
<github_commits.c>`, as the actual implementation is not important
here.
.. _GitHub commits API: http://develop.github.com/p/commits.html
.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/
.. _tutorial-the-program:
@@ -95,10 +96,10 @@ First the includes::
Like all the programs using Jansson, we need to include
:file:`jansson.h`.
The following definitions are used to build the GitHub commits API
request URL::
The following definitions are used to build the GitHub API request
URL::
#define URL_FORMAT "http://github.com/api/v2/json/commits/list/%s/%s/master"
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
The following function is used when formatting the result to find the
@@ -118,20 +119,21 @@ first newline in the commit message::
The main function follows. In the beginning, we first declare a bunch
of variables and check the command line parameters::
size_t i;
char *text;
char url[URL_SIZE];
json_t *root;
json_error_t error;
json_t *commits;
if(argc != 3)
int main(int argc, char *argv[])
{
fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]);
fprintf(stderr, "List commits at USER's REPOSITORY.\n\n");
return 2;
}
size_t i;
char *text;
char url[URL_SIZE];
json_t *root;
json_error_t error;
if(argc != 3)
{
fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]);
fprintf(stderr, "List commits at USER's REPOSITORY.\n\n");
return 2;
}
Then we build the request URL using the user and repository names
given as command line parameters::
@@ -171,47 +173,49 @@ Now we're ready to extract the data out of the decoded JSON response.
The structure of the response JSON was explained in section
:ref:`tutorial-github-commits-api`.
First, we'll extract the ``commits`` array from the JSON response::
We check that the returned value really is an array::
commits = json_object_get(root, "commits");
if(!json_is_array(commits))
if(!json_is_array(root))
{
fprintf(stderr, "error: commits is not an array\n");
fprintf(stderr, "error: root is not an array\n");
return 1;
}
This is the array that contains objects describing latest commits in
the repository. We check that the returned value really is an array.
If the key ``commits`` doesn't exist, :func:`json_object_get()`
returns *NULL*, but :func:`json_is_array()` handles this case, too.
Then we proceed to loop over all the commits in the array::
for(i = 0; i < json_array_size(commits); i++)
for(i = 0; i < json_array_size(root); i++)
{
json_t *commit, *id, *message;
json_t *data, *sha, *commit, *message;
const char *message_text;
commit = json_array_get(commits, i);
if(!json_is_object(commit))
data = json_array_get(root, i);
if(!json_is_object(data))
{
fprintf(stderr, "error: commit %d is not an object\n", i + 1);
fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
return 1;
}
...
The function :func:`json_array_size()` returns the size of a JSON
array. First, we again declare some variables and then extract the
i'th element of the ``commits`` array using :func:`json_array_get()`.
i'th element of the ``root`` array using :func:`json_array_get()`.
We also check that the resulting value is a JSON object.
Next we'll extract the commit ID and commit message, and check that
they both are JSON strings::
Next we'll extract the commit ID (a hexadecimal SHA-1 sum),
intermediate commit info object, and the commit message from that
object. We also do proper type checks::
id = json_object_get(commit, "id");
if(!json_is_string(id))
sha = json_object_get(data, "sha");
if(!json_is_string(sha))
{
fprintf(stderr, "error: commit %d: id is not a string\n", i + 1);
fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1);
return 1;
}
commit = json_object_get(data, "commit");
if(!json_is_object(commit))
{
fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1);
return 1;
}
@@ -250,25 +254,27 @@ The program's ready, let's test it and view the latest commits in
Jansson's repository::
$ ./github_commits akheron jansson
86dc1d62 Fix indentation
b67e130f json_dumpf: Document the output shortage on error
4cd77771 Enhance handling of circular references
79009e62 json_dumps: Close the strbuffer if dumping fails
76999799 doc: Fix a small typo in apiref
22af193a doc/Makefile.am: Remove *.pyc in clean
951d091f Make integer, real and string mutable
185e107d Don't use non-portable asprintf()
ca7703fb Merge branch '1.0'
12cd4e8c jansson 1.0.4
<etc...>
1581f26a Merge branch '2.3'
aabfd493 load: Change buffer_pos to be a size_t
bd72efbd load: Avoid unexpected behaviour in macro expansion
e8fd3e30 Document and tweak json_load_callback()
873eddaf Merge pull request #60 from rogerz/contrib
bd2c0c73 Ignore the binary test_load_callback
17a51a4b Merge branch '2.3'
09c39adc Add json_load_callback to the list of exported symbols
cbb80baf Merge pull request #57 from rogerz/contrib
040bd7b0 Add json_load_callback()
2637faa4 Make test stripping locale independent
<...>
Conclusion
==========
In this tutorial, we implemented a program that fetches the latest
commits of a GitHub repository using the GitHub commits API. Jansson
was used to decode the JSON response and to extract the commit data.
commits of a GitHub repository using the GitHub Repo Commits API.
Jansson was used to decode the JSON response and to extract the commit
data.
This tutorial only covered a small part of Jansson. For example, we
did not create or manipulate JSON values at all. Proceed to

View File

@@ -1,3 +1,5 @@
EXTRA_DIST = jansson.def
include_HEADERS = jansson.h jansson_config.h
lib_LTLIBRARIES = libjansson.la
@@ -12,12 +14,14 @@ libjansson_la_SOURCES = \
pack_unpack.c \
strbuffer.c \
strbuffer.h \
strconv.c \
utf.c \
utf.h \
value.c
libjansson_la_LDFLAGS = \
-no-undefined \
-export-symbols-regex '^json_' \
-version-info 4:1:0
-version-info 8:0:4
if GCC
# These flags are gcc specific

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -11,7 +11,7 @@
#include <string.h>
#include <assert.h>
#include <jansson.h>
#include "jansson.h"
#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -19,21 +19,17 @@
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
typedef int (*dump_func)(const char *buffer, int size, void *data);
struct string
{
char *buffer;
int length;
int size;
struct object_key {
size_t serial;
const char *key;
};
static int dump_to_strbuffer(const char *buffer, int size, void *data)
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
static int dump_to_file(const char *buffer, int size, void *data)
static int dump_to_file(const char *buffer, size_t size, void *data)
{
FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1)
@@ -44,7 +40,7 @@ static int dump_to_file(const char *buffer, int size, void *data)
/* 32 spaces (the maximum indentation size) */
static char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, dump_func dump, void *data)
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(JSON_INDENT(flags) > 0)
{
@@ -66,7 +62,7 @@ static int dump_indent(size_t flags, int depth, int space, dump_func dump, void
return 0;
}
static int dump_string(const char *str, int ascii, dump_func dump, void *data)
static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
{
const char *pos, *end;
int32_t codepoint;
@@ -91,8 +87,12 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break;
/* slash */
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */
if(ascii && codepoint > 0x7F)
if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break;
pos = end;
@@ -106,7 +106,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(end == pos)
break;
/* handle \, ", and control codes */
/* handle \, /, ", and control codes */
length = 2;
switch(codepoint)
{
@@ -117,6 +117,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break;
case '/': text = "\\/"; break;
default:
{
/* codepoint is in BMP */
@@ -155,21 +156,21 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *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);
return strcmp(((const struct object_key *)key1)->key,
((const struct object_key *)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;
size_t a = ((const struct object_key *)key1)->serial;
size_t b = ((const struct object_key *)key2)->serial;
return a < b ? -1 : a == b ? 0 : 1;
}
static int do_dump(const json_t *json, size_t flags, int depth,
dump_func dump, void *data)
json_dump_callback_t dump, void *data)
{
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
switch(json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
@@ -188,7 +189,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if(size >= MAX_INTEGER_STR_LENGTH)
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;
return dump(buffer, size, data);
@@ -198,31 +199,17 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{
char buffer[MAX_REAL_STR_LENGTH];
int size;
double value = json_real_value(json);
size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g",
json_real_value(json));
if(size >= MAX_REAL_STR_LENGTH)
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
if(size < 0)
return -1;
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(size + 2 >= MAX_REAL_STR_LENGTH) {
/* No space to append ".0" */
return -1;
}
buffer[size] = '.';
buffer[size + 1] = '0';
size += 2;
}
return dump(buffer, size, data);
}
case JSON_STRING:
return dump_string(json_string_value(json), ascii, dump, data);
return dump_string(json_string_value(json), dump, data, flags);
case JSON_ARRAY:
{
@@ -308,19 +295,20 @@ static int do_dump(const json_t *json, size_t flags, int depth,
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
{
const object_key_t **keys;
struct object_key *keys;
size_t size, i;
int (*cmp_func)(const void *, const void *);
size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(object_key_t *));
keys = jsonp_malloc(size * sizeof(struct object_key));
if(!keys)
goto object_error;
i = 0;
while(iter)
{
keys[i] = jsonp_object_iter_fullkey(iter);
keys[i].serial = hashtable_iter_serial(iter);
keys[i].key = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter);
i++;
}
@@ -331,18 +319,18 @@ static int do_dump(const json_t *json, size_t flags, int depth,
else
cmp_func = object_key_compare_serials;
qsort(keys, size, sizeof(object_key_t *), cmp_func);
qsort(keys, size, sizeof(struct object_key), cmp_func);
for(i = 0; i < size; i++)
{
const char *key;
json_t *value;
key = keys[i]->key;
key = keys[i].key;
value = json_object_get(json, key);
assert(value);
dump_string(key, ascii, dump, data);
dump_string(key, dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data))
{
@@ -379,7 +367,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{
void *next = json_object_iter_next((json_t *)json, iter);
dump_string(json_object_iter_key(iter), ascii, dump, data);
dump_string(json_object_iter_key(iter), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
@@ -415,35 +403,26 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
}
char *json_dumps(const json_t *json, size_t flags)
{
strbuffer_t strbuff;
char *result;
if(!json_is_array(json) && !json_is_object(json))
return NULL;
if(strbuffer_init(&strbuff))
return NULL;
if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) {
strbuffer_close(&strbuff);
return NULL;
}
if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
result = NULL;
else
result = jsonp_strdup(strbuffer_value(&strbuff));
result = jsonp_strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff);
return result;
}
int json_dumpf(const json_t *json, FILE *output, size_t flags)
{
if(!json_is_array(json) && !json_is_object(json))
return -1;
return do_dump(json, flags, 0, dump_to_file, (void *)output);
return json_dump_callback(json, dump_to_file, (void *)output, flags);
}
int json_dump_file(const json_t *json, const char *path, size_t flags)
@@ -459,3 +438,13 @@ int json_dump_file(const json_t *json, const char *path, size_t flags)
fclose(output);
return result;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
return do_dump(json, flags, 0, callback, data);
}

View File

@@ -59,4 +59,5 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
error->position = position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap);
error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
}

View File

@@ -1,11 +1,12 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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 <stdlib.h>
#include <string.h>
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h"
@@ -16,6 +17,23 @@ typedef struct hashtable_bucket bucket_t;
#define list_to_pair(list_) container_of(list_, pair_t, list)
/* From http://www.cse.yorku.ca/~oz/hash.html */
static size_t hash_str(const void *ptr)
{
const char *str = (const char *)ptr;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
static JSON_INLINE void list_init(list_t *list)
{
list->next = list;
@@ -62,7 +80,6 @@ static size_t primes[] = {
12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
static const size_t num_primes = sizeof(primes) / sizeof(size_t);
static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
{
@@ -71,7 +88,7 @@ static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const void *key, size_t hash)
const char *key, size_t hash)
{
list_t *list;
pair_t *pair;
@@ -83,7 +100,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
while(1)
{
pair = list_to_pair(list);
if(pair->hash == hash && hashtable->cmp_keys(pair->key, key))
if(pair->hash == hash && strcmp(pair->key, key) == 0)
return pair;
if(list == bucket->last)
@@ -97,7 +114,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
/* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable,
const void *key, size_t hash)
const char *key, size_t hash)
{
pair_t *pair;
bucket_t *bucket;
@@ -120,11 +137,7 @@ static int hashtable_do_del(hashtable_t *hashtable,
bucket->last = pair->list.prev;
list_remove(&pair->list);
if(hashtable->free_key)
hashtable->free_key(pair->key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
json_decref(pair->value);
jsonp_free(pair);
hashtable->size--;
@@ -141,10 +154,7 @@ static void hashtable_do_clear(hashtable_t *hashtable)
{
next = list->next;
pair = list_to_pair(list);
if(hashtable->free_key)
hashtable->free_key(pair->key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
json_decref(pair->value);
jsonp_free(pair);
}
}
@@ -184,31 +194,7 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
}
hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value)
{
hashtable_t *hashtable = jsonp_malloc(sizeof(hashtable_t));
if(!hashtable)
return NULL;
if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value))
{
jsonp_free(hashtable);
return NULL;
}
return hashtable;
}
void hashtable_destroy(hashtable_t *hashtable)
{
hashtable_close(hashtable);
jsonp_free(hashtable);
}
int hashtable_init(hashtable_t *hashtable,
key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value)
int hashtable_init(hashtable_t *hashtable)
{
size_t i;
@@ -220,11 +206,6 @@ int hashtable_init(hashtable_t *hashtable,
list_init(&hashtable->list);
hashtable->hash_key = hash_key;
hashtable->cmp_keys = cmp_keys;
hashtable->free_key = free_key;
hashtable->free_value = free_value;
for(i = 0; i < num_buckets(hashtable); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
@@ -240,7 +221,9 @@ void hashtable_close(hashtable_t *hashtable)
jsonp_free(hashtable->buckets);
}
int hashtable_set(hashtable_t *hashtable, void *key, void *value)
int hashtable_set(hashtable_t *hashtable,
const char *key, size_t serial,
json_t *value)
{
pair_t *pair;
bucket_t *bucket;
@@ -251,28 +234,29 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
if(hashtable_do_rehash(hashtable))
return -1;
hash = hashtable->hash_key(key);
hash = hash_str(key);
index = hash % num_buckets(hashtable);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(pair)
{
if(hashtable->free_key)
hashtable->free_key(key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
json_decref(pair->value);
pair->value = value;
}
else
{
pair = jsonp_malloc(sizeof(pair_t));
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
if(!pair)
return -1;
pair->key = key;
pair->value = value;
pair->hash = hash;
pair->serial = serial;
strcpy(pair->key, key);
pair->value = value;
list_init(&pair->list);
insert_to_bucket(hashtable, bucket, &pair->list);
@@ -282,13 +266,13 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
return 0;
}
void *hashtable_get(hashtable_t *hashtable, const void *key)
void *hashtable_get(hashtable_t *hashtable, const char *key)
{
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hashtable->hash_key(key);
hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
@@ -298,9 +282,9 @@ void *hashtable_get(hashtable_t *hashtable, const void *key)
return pair->value;
}
int hashtable_del(hashtable_t *hashtable, const void *key)
int hashtable_del(hashtable_t *hashtable, const char *key)
{
size_t hash = hashtable->hash_key(key);
size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash);
}
@@ -325,13 +309,13 @@ void *hashtable_iter(hashtable_t *hashtable)
return hashtable_iter_next(hashtable, &hashtable->list);
}
void *hashtable_iter_at(hashtable_t *hashtable, const void *key)
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
{
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hashtable->hash_key(key);
hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
@@ -355,18 +339,22 @@ void *hashtable_iter_key(void *iter)
return pair->key;
}
size_t hashtable_iter_serial(void *iter)
{
pair_t *pair = list_to_pair((list_t *)iter);
return pair->serial;
}
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)
void hashtable_iter_set(void *iter, json_t *value)
{
pair_t *pair = list_to_pair((list_t *)iter);
if(hashtable->free_value)
hashtable->free_value(pair->value);
json_decref(pair->value);
pair->value = value;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -8,20 +8,20 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
typedef size_t (*key_hash_fn)(const void *key);
typedef int (*key_cmp_fn)(const void *key1, const void *key2);
typedef void (*free_fn)(void *key);
struct hashtable_list {
struct hashtable_list *prev;
struct hashtable_list *next;
};
/* "pair" may be a bit confusing a name, but think of it as a
key-value pair. In this case, it just encodes some extra data,
too */
struct hashtable_pair {
void *key;
void *value;
size_t hash;
struct hashtable_list list;
json_t *value;
size_t serial;
char key[1];
};
struct hashtable_bucket {
@@ -34,56 +34,23 @@ typedef struct hashtable {
struct hashtable_bucket *buckets;
size_t num_buckets; /* index to primes[] */
struct hashtable_list list;
key_hash_fn hash_key;
key_cmp_fn cmp_keys; /* returns non-zero for equal keys */
free_fn free_key;
free_fn free_value;
} hashtable_t;
/**
* hashtable_create - Create a hashtable object
*
* @hash_key: The key hashing function
* @cmp_keys: The key compare function. Returns non-zero for equal and
* zero for unequal unequal keys
* @free_key: If non-NULL, called for a key that is no longer referenced.
* @free_value: If non-NULL, called for a value that is no longer referenced.
*
* Returns a new hashtable object that should be freed with
* hashtable_destroy when it's no longer used, or NULL on failure (out
* of memory).
*/
hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value);
/**
* hashtable_destroy - Destroy a hashtable object
*
* @hashtable: The hashtable
*
* Destroys a hashtable created with hashtable_create().
*/
void hashtable_destroy(hashtable_t *hashtable);
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->list))
/**
* hashtable_init - Initialize a hashtable object
*
* @hashtable: The (statically allocated) hashtable object
* @hash_key: The key hashing function
* @cmp_keys: The key compare function. Returns non-zero for equal and
* zero for unequal unequal keys
* @free_key: If non-NULL, called for a key that is no longer referenced.
* @free_value: If non-NULL, called for a value that is no longer referenced.
*
* Initializes a statically allocated hashtable object. The object
* should be cleared with hashtable_close when it's no longer used.
*
* Returns 0 on success, -1 on error (out of memory).
*/
int hashtable_init(hashtable_t *hashtable,
key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value);
int hashtable_init(hashtable_t *hashtable);
/**
* hashtable_close - Release all resources used by a hashtable object
@@ -99,20 +66,19 @@ void hashtable_close(hashtable_t *hashtable);
*
* @hashtable: The hashtable object
* @key: The key
* @serial: For addition order of keys
* @value: The value
*
* If a value with the given key already exists, its value is replaced
* with the new value.
*
* Key and value are "stealed" in the sense that hashtable frees them
* automatically when they are no longer used. The freeing is
* accomplished by calling free_key and free_value functions that were
* supplied to hashtable_new. In case one or both of the free
* functions is NULL, the corresponding item is not "stealed".
* with the new value. Value is "stealed" in the sense that hashtable
* doesn't increment its refcount but decreases the refcount when the
* value is no longer needed.
*
* Returns 0 on success, -1 on failure (out of memory).
*/
int hashtable_set(hashtable_t *hashtable, void *key, void *value);
int hashtable_set(hashtable_t *hashtable,
const char *key, size_t serial,
json_t *value);
/**
* hashtable_get - Get a value associated with a key
@@ -122,7 +88,7 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value);
*
* Returns value if it is found, or NULL otherwise.
*/
void *hashtable_get(hashtable_t *hashtable, const void *key);
void *hashtable_get(hashtable_t *hashtable, const char *key);
/**
* hashtable_del - Remove a value from the hashtable
@@ -132,7 +98,7 @@ void *hashtable_get(hashtable_t *hashtable, const void *key);
*
* Returns 0 on success, or -1 if the key was not found.
*/
int hashtable_del(hashtable_t *hashtable, const void *key);
int hashtable_del(hashtable_t *hashtable, const char *key);
/**
* hashtable_clear - Clear hashtable
@@ -169,7 +135,7 @@ void *hashtable_iter(hashtable_t *hashtable);
* Like hashtable_iter() but returns an iterator pointing to a
* specific key.
*/
void *hashtable_iter_at(hashtable_t *hashtable, const void *key);
void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
/**
* hashtable_iter_next - Advance an iterator
@@ -189,6 +155,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
*/
void *hashtable_iter_key(void *iter);
/**
* hashtable_iter_serial - Retrieve the serial number pointed to by an iterator
*
* @iter: The iterator
*/
size_t hashtable_iter_serial(void *iter);
/**
* hashtable_iter_value - Retrieve the value pointed by an iterator
*
@@ -202,6 +175,6 @@ void *hashtable_iter_value(void *iter);
* @iter: The iterator
* @value: The value to set
*/
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value);
void hashtable_iter_set(void *iter, json_t *value);
#endif

65
src/jansson.def Normal file
View File

@@ -0,0 +1,65 @@
LIBRARY "jansson"
EXPORTS
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_update_existing
json_object_update_missing
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_object_key_to_iter
json_dumps
json_dumpf
json_dump_file
json_dump_callback
json_loads
json_loadb
json_loadf
json_load_file
json_load_callback
json_equal
json_copy
json_deep_copy
json_pack
json_pack_ex
json_vpack_ex
json_unpack
json_unpack_ex
json_vunpack_ex
json_set_alloc_funcs

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -21,11 +21,11 @@ extern "C" {
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 0
#define JANSSON_MICRO_VERSION 1
#define JANSSON_MINOR_VERSION 4
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.0.1"
#define JANSSON_VERSION "2.4"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@@ -53,7 +53,11 @@ typedef struct {
} json_t;
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _WIN32
#define JSON_INTEGER_FORMAT "I64d"
#else
#define JSON_INTEGER_FORMAT "lld"
#endif
typedef long long json_int_t;
#else
#define JSON_INTEGER_FORMAT "ld"
@@ -82,6 +86,7 @@ json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
static JSON_INLINE
@@ -126,13 +131,21 @@ 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);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(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_key_to_iter(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);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
@@ -214,22 +227,37 @@ json_t *json_copy(json_t *value);
json_t *json_deep_copy(json_t *value);
/* loading, printing */
/* decoding */
#define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
/* encoding */
#define JSON_INDENT(n) (n & 0x1F)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
/* custom memory allocation */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 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.
@@ -27,8 +27,13 @@
#define JSON_INLINE @json_inline@
#endif
/* If your compiler supports the `long long` type,
JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -11,6 +11,7 @@
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_)))
@@ -66,16 +67,6 @@ 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)
size_t jsonp_hash_str(const void *ptr);
int jsonp_str_equal(const void *ptr1, const void *ptr2);
typedef struct {
size_t serial;
char key[1];
} object_key_t;
const object_key_t *jsonp_object_iter_fullkey(void *iter);
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
@@ -83,9 +74,19 @@ void jsonp_error_set(json_error_t *error, int line, int column,
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, const char *msg, va_list ap);
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strdup(const char *str);
/* Windows compatibility */
#ifdef _WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#endif

View File

@@ -1,12 +1,11 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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 <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@@ -14,7 +13,7 @@
#include <string.h>
#include <assert.h>
#include <jansson.h>
#include "jansson.h"
#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -32,6 +31,14 @@
#define TOKEN_FALSE 260
#define TOKEN_NULL 261
/* Locale independent versions of isxxx() functions */
#define l_isupper(c) ('A' <= (c) && (c) <= 'Z')
#define l_islower(c) ('a' <= (c) && (c) <= 'z')
#define l_isalpha(c) (l_isupper(c) || l_islower(c))
#define l_isdigit(c) ('0' <= (c) && (c) <= '9')
#define l_isxdigit(c) \
(l_isdigit(c) || 'A' <= (c) || (c) <= 'F' || 'a' <= (c) || (c) <= 'f')
/* Read one byte from stream, convert to unsigned char, then int, and
return. return EOF on end of file. This corresponds to the
behaviour of fgetc(). */
@@ -41,7 +48,7 @@ typedef struct {
get_func get;
void *data;
char buffer[5];
int buffer_pos;
size_t buffer_pos;
int state;
int line;
int column, last_column;
@@ -69,6 +76,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
{
va_list ap;
char msg_text[JSON_ERROR_TEXT_LENGTH];
char msg_with_context[JSON_ERROR_TEXT_LENGTH];
int line = -1, col = -1;
size_t pos = 0;
@@ -79,12 +87,12 @@ static void error_set(json_error_t *error, const lex_t *lex,
va_start(ap, msg);
vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap);
msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
va_end(ap);
if(lex)
{
const char *saved_text = strbuffer_value(&lex->saved_text);
char msg_with_context[JSON_ERROR_TEXT_LENGTH];
line = lex->stream.line;
col = lex->stream.column;
@@ -95,6 +103,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
if(lex->saved_text.length <= 20) {
snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near '%s'", msg_text, saved_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context;
}
}
@@ -107,6 +116,7 @@ static void error_set(json_error_t *error, const lex_t *lex,
else {
snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near end of file", msg_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context;
}
}
@@ -268,11 +278,11 @@ static int32_t decode_unicode_escape(const char *str)
for(i = 1; i <= 4; i++) {
char c = str[i];
value <<= 4;
if(isdigit(c))
if(l_isdigit(c))
value += c - '0';
else if(islower(c))
else if(l_islower(c))
value += c - 'a' + 10;
else if(isupper(c))
else if(l_isupper(c))
value += c - 'A' + 10;
else
assert(0);
@@ -317,7 +327,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(c == 'u') {
c = lex_get_save(lex, error);
for(i = 0; i < 4; i++) {
if(!isxdigit(c)) {
if(!l_isxdigit(c)) {
error_set(error, lex, "invalid escape");
goto out;
}
@@ -437,7 +447,11 @@ out:
}
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _MSC_VER // Microsoft Visual Studio
#define json_strtoint _strtoi64
#else
#define json_strtoint strtoll
#endif
#else
#define json_strtoint strtol
#endif
@@ -455,14 +469,14 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '0') {
c = lex_get_save(lex, error);
if(isdigit(c)) {
if(l_isdigit(c)) {
lex_unget_unsave(lex, c);
goto out;
}
}
else if(isdigit(c)) {
else if(l_isdigit(c)) {
c = lex_get_save(lex, error);
while(isdigit(c))
while(l_isdigit(c))
c = lex_get_save(lex, error);
}
else {
@@ -496,14 +510,14 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '.') {
c = lex_get(lex, error);
if(!isdigit(c)) {
if(!l_isdigit(c)) {
lex_unget(lex, c);
goto out;
}
lex_save(lex, c);
c = lex_get_save(lex, error);
while(isdigit(c))
while(l_isdigit(c))
c = lex_get_save(lex, error);
}
@@ -512,23 +526,19 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
if(c == '+' || c == '-')
c = lex_get_save(lex, error);
if(!isdigit(c)) {
if(!l_isdigit(c)) {
lex_unget_unsave(lex, c);
goto out;
}
c = lex_get_save(lex, error);
while(isdigit(c))
while(l_isdigit(c))
c = lex_get_save(lex, error);
}
lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text);
value = strtod(saved_text, &end);
assert(end == saved_text + lex->saved_text.length);
if(errno == ERANGE && value != 0) {
if(jsonp_strtod(&lex->saved_text, &value)) {
error_set(error, lex, "real number overflow");
goto out;
}
@@ -574,17 +584,17 @@ static int lex_scan(lex_t *lex, json_error_t *error)
else if(c == '"')
lex_scan_string(lex, error);
else if(isdigit(c) || c == '-') {
else if(l_isdigit(c) || c == '-') {
if(lex_scan_number(lex, c, error))
goto out;
}
else if(isupper(c) || islower(c)) {
else if(l_isalpha(c)) {
/* eat up the whole identifier for clearer error messages */
const char *saved_text;
c = lex_get_save(lex, error);
while(isupper(c) || islower(c))
while(l_isalpha(c))
c = lex_get_save(lex, error);
lex_unget_unsave(lex, c);
@@ -642,9 +652,9 @@ static void lex_close(lex_t *lex)
/*** parser ***/
static json_t *parse_value(lex_t *lex, json_error_t *error);
static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error);
static json_t *parse_object(lex_t *lex, json_error_t *error)
static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *object = json_object();
if(!object)
@@ -667,6 +677,14 @@ static json_t *parse_object(lex_t *lex, json_error_t *error)
if(!key)
return NULL;
if(flags & JSON_REJECT_DUPLICATES) {
if(json_object_get(object, key)) {
jsonp_free(key);
error_set(error, lex, "duplicate object key");
goto error;
}
}
lex_scan(lex, error);
if(lex->token != ':') {
jsonp_free(key);
@@ -675,7 +693,7 @@ static json_t *parse_object(lex_t *lex, json_error_t *error)
}
lex_scan(lex, error);
value = parse_value(lex, error);
value = parse_value(lex, flags, error);
if(!value) {
jsonp_free(key);
goto error;
@@ -709,7 +727,7 @@ error:
return NULL;
}
static json_t *parse_array(lex_t *lex, json_error_t *error)
static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *array = json_array();
if(!array)
@@ -720,7 +738,7 @@ static json_t *parse_array(lex_t *lex, json_error_t *error)
return array;
while(lex->token) {
json_t *elem = parse_value(lex, error);
json_t *elem = parse_value(lex, flags, error);
if(!elem)
goto error;
@@ -749,7 +767,7 @@ error:
return NULL;
}
static json_t *parse_value(lex_t *lex, json_error_t *error)
static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *json;
@@ -782,11 +800,11 @@ static json_t *parse_value(lex_t *lex, json_error_t *error)
break;
case '{':
json = parse_object(lex, error);
json = parse_object(lex, flags, error);
break;
case '[':
json = parse_array(lex, error);
json = parse_array(lex, flags, error);
break;
case TOKEN_INVALID:
@@ -804,15 +822,37 @@ static json_t *parse_value(lex_t *lex, json_error_t *error)
return json;
}
static json_t *parse_json(lex_t *lex, json_error_t *error)
static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *result;
lex_scan(lex, error);
if(lex->token != '[' && lex->token != '{') {
error_set(error, lex, "'[' or '{' expected");
return NULL;
if(!(flags & JSON_DECODE_ANY)) {
if(lex->token != '[' && lex->token != '{') {
error_set(error, lex, "'[' or '{' expected");
return NULL;
}
}
return parse_value(lex, error);
result = parse_value(lex, flags, error);
if(!result)
return NULL;
if(!(flags & JSON_DISABLE_EOF_CHECK)) {
lex_scan(lex, error);
if(lex->token != TOKEN_EOF) {
error_set(error, lex, "end of file expected");
json_decref(result);
return NULL;
}
}
if(error) {
/* Save the position even though there was no error */
error->position = lex->stream.position;
}
return result;
}
typedef struct
@@ -841,7 +881,12 @@ json_t *json_loads(const char *string, size_t flags, json_error_t *error)
json_t *result;
string_data_t stream_data;
(void)flags; /* unused */
jsonp_error_init(error, "<string>");
if (string == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
stream_data.data = string;
stream_data.pos = 0;
@@ -849,20 +894,53 @@ json_t *json_loads(const char *string, size_t flags, json_error_t *error)
if(lex_init(&lex, string_get, (void *)&stream_data))
return NULL;
jsonp_error_init(error, "<string>");
result = parse_json(&lex, flags, error);
result = parse_json(&lex, error);
if(!result)
goto out;
lex_close(&lex);
return result;
}
lex_scan(&lex, error);
if(lex.token != TOKEN_EOF) {
error_set(error, &lex, "end of file expected");
json_decref(result);
result = NULL;
typedef struct
{
const char *data;
size_t len;
size_t pos;
} buffer_data_t;
static int buffer_get(void *data)
{
char c;
buffer_data_t *stream = data;
if(stream->pos >= stream->len)
return EOF;
c = stream->data[stream->pos];
stream->pos++;
return (unsigned char)c;
}
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
{
lex_t lex;
json_t *result;
buffer_data_t stream_data;
jsonp_error_init(error, "<buffer>");
if (buffer == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
out:
stream_data.data = buffer;
stream_data.pos = 0;
stream_data.len = buflen;
if(lex_init(&lex, buffer_get, (void *)&stream_data))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}
@@ -872,10 +950,6 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
lex_t lex;
const char *source;
json_t *result;
(void)flags; /* unused */
if(lex_init(&lex, (get_func)fgetc, input))
return NULL;
if(input == stdin)
source = "<stdin>";
@@ -884,18 +958,16 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
jsonp_error_init(error, source);
result = parse_json(&lex, error);
if(!result)
goto out;
lex_scan(&lex, error);
if(lex.token != TOKEN_EOF) {
error_set(error, &lex, "end of file expected");
json_decref(result);
result = NULL;
if (input == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
out:
if(lex_init(&lex, (get_func)fgetc, input))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}
@@ -907,7 +979,12 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
jsonp_error_init(error, path);
fp = fopen(path, "r");
if (path == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
fp = fopen(path, "rb");
if(!fp)
{
error_set(error, NULL, "unable to open %s: %s",
@@ -920,3 +997,58 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
fclose(fp);
return result;
}
#define MAX_BUF_LEN 1024
typedef struct
{
char data[MAX_BUF_LEN];
size_t len;
size_t pos;
json_load_callback_t callback;
void *arg;
} callback_data_t;
static int callback_get(void *data)
{
char c;
callback_data_t *stream = data;
if(stream->pos >= stream->len) {
stream->pos = 0;
stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg);
if(stream->len == 0 || stream->len == (size_t)-1)
return EOF;
}
c = stream->data[stream->pos];
stream->pos++;
return (unsigned char)c;
}
json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error)
{
lex_t lex;
json_t *result;
callback_data_t stream_data;
memset(&stream_data, 0, sizeof(stream_data));
stream_data.callback = callback;
stream_data.arg = arg;
jsonp_error_init(error, "<callback>");
if (callback == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
if(lex_init(&lex, (get_func)callback_get, &stream_data))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011 Basile Starynkevitch <basile@starynkevitch.net>
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
@@ -9,7 +9,7 @@
#include <stdlib.h>
#include <string.h>
#include <jansson.h>
#include "jansson.h"
#include "jansson_private.h"
/* memory function pointers */

View File

@@ -1,13 +1,13 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* 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 "jansson.h"
#include "jansson_private.h"
#include "utf.h"
@@ -233,12 +233,12 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
*/
hashtable_t key_set;
if(hashtable_init(&key_set, jsonp_hash_str, jsonp_str_equal, NULL, NULL)) {
if(hashtable_init(&key_set)) {
set_error(s, "<internal>", "Out of memory");
return -1;
}
if(!json_is_object(root)) {
if(root && !json_is_object(root)) {
set_error(s, "<validation>", "Expected object, got %s",
type_name(root));
goto out;
@@ -248,6 +248,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
while(s->token != '}') {
const char *key;
json_t *value;
int opt = 0;
if(strict != 0) {
set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
@@ -279,23 +280,34 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
next_token(s);
value = json_object_get(root, key);
if(!value) {
set_error(s, "<validation>", "Object item not found: %s", key);
goto out;
if(s->token == '?') {
opt = 1;
next_token(s);
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_object_get(root, key);
if(!value && !opt) {
set_error(s, "<validation>", "Object item not found: %s", key);
goto out;
}
}
if(unpack(s, value, ap))
goto out;
hashtable_set(&key_set, (void *)key, NULL);
hashtable_set(&key_set, key, 0, json_null());
next_token(s);
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(strict == 1 && key_set.size != json_object_size(root)) {
if(root && strict == 1 && key_set.size != json_object_size(root)) {
long diff = (long)json_object_size(root) - (long)key_set.size;
set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
goto out;
@@ -313,7 +325,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
size_t i = 0;
int strict = 0;
if(!json_is_array(root)) {
if(root && !json_is_array(root)) {
set_error(s, "<validation>", "Expected array, got %s", type_name(root));
return -1;
}
@@ -346,11 +358,17 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
return -1;
}
value = json_array_get(root, i);
if(!value) {
set_error(s, "<validation>", "Array index %lu out of range",
(unsigned long)i);
return -1;
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_array_get(root, i);
if(!value) {
set_error(s, "<validation>", "Array index %lu out of range",
(unsigned long)i);
return -1;
}
}
if(unpack(s, value, ap))
@@ -363,7 +381,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(strict == 1 && i != json_array_size(root)) {
if(root && strict == 1 && i != json_array_size(root)) {
long diff = (long)json_array_size(root) - (long)i;
set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
return -1;
@@ -383,99 +401,118 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
return unpack_array(s, root, ap);
case 's':
if(!json_is_string(root)) {
if(root && !json_is_string(root)) {
set_error(s, "<validation>", "Expected string, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
const char **str;
const char **target;
str = va_arg(*ap, const char **);
if(!str) {
target = va_arg(*ap, const char **);
if(!target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
*str = json_string_value(root);
if(root)
*target = json_string_value(root);
}
return 0;
case 'i':
if(!json_is_integer(root)) {
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, int*) = json_integer_value(root);
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = (int)json_integer_value(root);
}
return 0;
case 'I':
if(!json_is_integer(root)) {
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, json_int_t*) = json_integer_value(root);
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_int_t *target = va_arg(*ap, json_int_t*);
if(root)
*target = json_integer_value(root);
}
return 0;
case 'b':
if(!json_is_boolean(root)) {
if(root && !json_is_boolean(root)) {
set_error(s, "<validation>", "Expected true or false, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, int*) = json_is_true(root);
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = json_is_true(root);
}
return 0;
case 'f':
if(!json_is_real(root)) {
if(root && !json_is_real(root)) {
set_error(s, "<validation>", "Expected real, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, double*) = json_real_value(root);
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_real_value(root);
}
return 0;
case 'F':
if(!json_is_number(root)) {
if(root && !json_is_number(root)) {
set_error(s, "<validation>", "Expected real or integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, double*) = json_number_value(root);
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_number_value(root);
}
return 0;
case 'O':
if(!(s->flags & JSON_VALIDATE_ONLY))
if(root && !(s->flags & JSON_VALIDATE_ONLY))
json_incref(root);
/* Fall through */
case 'o':
if(!(s->flags & JSON_VALIDATE_ONLY))
*va_arg(*ap, json_t**) = root;
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_t **target = va_arg(*ap, json_t**);
if(root)
*target = root;
}
return 0;
case 'n':
/* Never assign, just validate */
if(!json_is_null(root)) {
if(root && !json_is_null(root)) {
set_error(s, "<validation>", "Expected null, got %s",
type_name(root));
return -1;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -13,6 +13,7 @@
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff)
{
@@ -64,13 +65,19 @@ int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
return strbuffer_append_bytes(strbuff, &byte, 1);
}
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size)
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{
if(strbuff->length + size >= strbuff->size)
if(size >= strbuff->size - strbuff->length)
{
size_t new_size;
char *new_value;
/* avoid integer overflow */
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
|| size > STRBUFFER_SIZE_MAX - 1
|| strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
return -1;
new_size = max(strbuff->size * STRBUFFER_FACTOR,
strbuff->length + size + 1);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,8 +10,8 @@
typedef struct {
char *value;
int length; /* bytes used */
int size; /* bytes allocated */
size_t length; /* bytes used */
size_t size; /* bytes allocated */
} strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff);
@@ -24,7 +24,7 @@ char *strbuffer_steal_value(strbuffer_t *strbuff);
int strbuffer_append(strbuffer_t *strbuff, const char *string);
int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff);

129
src/strconv.c Normal file
View File

@@ -0,0 +1,129 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "jansson_private.h"
#include "strbuffer.h"
#if JSON_HAVE_LOCALECONV
#include <locale.h>
/*
- This code assumes that the decimal separator is exactly one
character.
- If setlocale() is called by another thread between the call to
localeconv() and the call to sprintf() or strtod(), the result may
be wrong. setlocale() is not thread-safe and should not be used
this way. Multi-threaded programs should use uselocale() instead.
*/
static void to_locale(strbuffer_t *strbuffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if(pos)
*pos = *point;
}
static void from_locale(char *buffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if(pos)
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out)
{
double value;
char *end;
#if JSON_HAVE_LOCALECONV
to_locale(strbuffer);
#endif
errno = 0;
value = strtod(strbuffer->value, &end);
assert(end == strbuffer->value + strbuffer->length);
if(errno == ERANGE && value != 0) {
/* Overflow */
return -1;
}
*out = value;
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value)
{
int ret;
char *start, *end;
size_t length;
ret = snprintf(buffer, size, "%.17g", value);
if(ret < 0)
return -1;
length = (size_t)ret;
if(length >= size)
return -1;
#if JSON_HAVE_LOCALECONV
from_locale(buffer);
#endif
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(length + 3 >= size) {
/* No space to append ".0" */
return -1;
}
buffer[length] = '.';
buffer[length + 1] = '0';
buffer[length + 2] = '\0';
length += 2;
}
/* Remove leading '+' from positive exponent. Also remove leading
zeros from exponents (added by some printf() implementations) */
start = strchr(buffer, 'e');
if(start) {
start++;
end = start + 1;
if(*start == '-')
start++;
while(*end == '0')
end++;
if(end != start) {
memmove(start, end, length - (size_t)(end - buffer));
length -= (size_t)(end - start);
}
}
return (int)length;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,12 +10,20 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <jansson.h>
#include "jansson.h"
#include "hashtable.h"
#include "jansson_private.h"
#include "utf.h"
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
#ifndef isinf
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
static JSON_INLINE void json_init(json_t *json, json_type type)
{
@@ -26,50 +34,6 @@ static JSON_INLINE void json_init(json_t *json, json_type type)
/*** object ***/
/* From http://www.cse.yorku.ca/~oz/hash.html */
size_t jsonp_hash_str(const void *ptr)
{
const char *str = (const char *)ptr;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
int jsonp_str_equal(const void *ptr1, const void *ptr2)
{
return strcmp((const char *)ptr1, (const char *)ptr2) == 0;
}
/* 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 size_t hash_key(const void *ptr)
{
return jsonp_hash_str(((const object_key_t *)ptr)->key);
}
static int key_equal(const void *ptr1, const void *ptr2)
{
return jsonp_str_equal(((const object_key_t *)ptr1)->key,
((const object_key_t *)ptr2)->key);
}
static void value_decref(void *value)
{
json_decref((json_t *)value);
}
json_t *json_object(void)
{
json_object_t *object = jsonp_malloc(sizeof(json_object_t));
@@ -77,9 +41,7 @@ json_t *json_object(void)
return NULL;
json_init(&object->json, JSON_OBJECT);
if(hashtable_init(&object->hashtable,
hash_key, key_equal,
jsonp_free, value_decref))
if(hashtable_init(&object->hashtable))
{
jsonp_free(object);
return NULL;
@@ -116,35 +78,24 @@ json_t *json_object_get(const json_t *json, const char *key)
return NULL;
object = json_to_object(json);
return hashtable_get(&object->hashtable, string_to_key(key));
return hashtable_get(&object->hashtable, 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)
if(!value)
return -1;
if(!json_is_object(json) || json == value)
if(!key || !json_is_object(json) || json == value)
{
json_decref(value);
return -1;
}
object = json_to_object(json);
/* offsetof(...) returns the size of object_key_t without the
last, flexible member. This way, the correct amount is
allocated. */
k = jsonp_malloc(offsetof(object_key_t, key) + strlen(key) + 1);
if(!k)
return -1;
k->serial = object->serial++;
strcpy(k->key, key);
if(hashtable_set(&object->hashtable, k, value))
if(hashtable_set(&object->hashtable, key, object->serial++, value))
{
json_decref(value);
return -1;
@@ -172,7 +123,7 @@ int json_object_del(json_t *json, const char *key)
return -1;
object = json_to_object(json);
return hashtable_del(&object->hashtable, string_to_key(key));
return hashtable_del(&object->hashtable, key);
}
int json_object_clear(json_t *json)
@@ -183,30 +134,56 @@ int json_object_clear(json_t *json)
return -1;
object = json_to_object(json);
hashtable_clear(&object->hashtable);
object->serial = 0;
return 0;
}
int json_object_update(json_t *object, json_t *other)
{
void *iter;
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
iter = json_object_iter(other);
while(iter) {
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_foreach(other, key, value) {
if(json_object_set_nocheck(object, key, value))
return -1;
}
iter = json_object_iter_next(other, iter);
return 0;
}
int json_object_update_existing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
json_object_foreach(other, key, value) {
if(json_object_get(object, key))
json_object_set_nocheck(object, key, value);
}
return 0;
}
int json_object_update_missing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
json_object_foreach(other, key, value) {
if(!json_object_get(object, key))
json_object_set_nocheck(object, key, value);
}
return 0;
@@ -231,7 +208,7 @@ void *json_object_iter_at(json_t *json, const char *key)
return NULL;
object = json_to_object(json);
return hashtable_iter_at(&object->hashtable, string_to_key(key));
return hashtable_iter_at(&object->hashtable, key);
}
void *json_object_iter_next(json_t *json, void *iter)
@@ -245,20 +222,12 @@ 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 jsonp_object_iter_fullkey(iter)->key;
return hashtable_iter_key(iter);
}
json_t *json_object_iter_value(void *iter)
@@ -271,38 +240,34 @@ json_t *json_object_iter_value(void *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);
hashtable_iter_set(iter, value);
return 0;
}
void *json_object_key_to_iter(const char *key)
{
if(!key)
return NULL;
return hashtable_key_to_iter(key);
}
static int json_object_equal(json_t *object1, json_t *object2)
{
void *iter;
const char *key;
json_t *value1, *value2;
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);
json_object_foreach(object1, key, value1) {
value2 = json_object_get(object2, key);
if(!json_equal(value1, value2))
return 0;
iter = json_object_iter_next(object1, iter);
}
return 1;
@@ -311,50 +276,34 @@ static int json_object_equal(json_t *object1, json_t *object2)
static json_t *json_object_copy(json_t *object)
{
json_t *result;
void *iter;
const char *key;
json_t *value;
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_foreach(object, key, value)
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;
const char *key;
json_t *value;
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_foreach(object, key, value)
json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next(object, iter);
}
return result;
}
@@ -700,6 +649,9 @@ int json_string_set_nocheck(json_t *json, const char *value)
char *dup;
json_string_t *string;
if(!json_is_string(json) || !value)
return -1;
dup = jsonp_strdup(value);
if(!dup)
return -1;
@@ -787,7 +739,12 @@ static json_t *json_integer_copy(json_t *integer)
json_t *json_real(double value)
{
json_real_t *real = jsonp_malloc(sizeof(json_real_t));
json_real_t *real;
if(isnan(value) || isinf(value))
return NULL;
real = jsonp_malloc(sizeof(json_real_t));
if(!real)
return NULL;
json_init(&real->json, JSON_REAL);
@@ -806,8 +763,8 @@ double json_real_value(const json_t *json)
int json_real_set(json_t *json, double value)
{
if(!json_is_real(json))
return 0;
if(!json_is_real(json) || isnan(value) || isinf(value))
return -1;
json_to_real(json)->value = value;
@@ -835,7 +792,7 @@ static json_t *json_real_copy(json_t *real)
double json_number_value(const json_t *json)
{
if(json_is_integer(json))
return json_integer_value(json);
return (double)json_integer_value(json);
else if(json_is_real(json))
return json_real_value(json);
else

3
test/.gitignore vendored
View File

@@ -4,11 +4,14 @@ suites/api/test_array
suites/api/test_copy
suites/api/test_cpp
suites/api/test_dump
suites/api/test_dump_callback
suites/api/test_equal
suites/api/test_load
suites/api/test_loadb
suites/api/test_memory_funcs
suites/api/test_number
suites/api/test_object
suites/api/test_pack
suites/api/test_simple
suites/api/test_unpack
suites/api/test_load_callback

View File

@@ -1,16 +1,31 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <jansson.h>
#if HAVE_LOCALE_H
#include <locale.h>
#endif
#if _WIN32
#include <io.h> /* for _setmode() */
#include <fcntl.h> /* for _O_BINARY */
#endif
#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
static int getenv_int(const char *name)
{
char *value, *end;
@@ -34,14 +49,14 @@ static const char *strip(char *str)
{
size_t length;
char *result = str;
while(*result && isspace(*result))
while(*result && l_isspace(*result))
result++;
length = strlen(result);
if(length == 0)
return result;
while(isspace(result[length - 1]))
while(l_isspace(result[length - 1]))
result[--length] = '\0';
return result;
@@ -55,11 +70,22 @@ int main(int argc, char *argv[])
json_t *json;
json_error_t error;
#if HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
if(argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 2;
}
#ifdef _WIN32
/* On Windows, set stdout and stderr to binary mode to avoid
outputting DOS line terminators */
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
indent = getenv_int("JSON_INDENT");
if(indent < 0 || indent > 255) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);

View File

@@ -22,11 +22,12 @@ fi
[ -z "$STOP" ] && STOP=0
export suites_srcdir=$top_srcdir/test/suites
export suites_builddir=suites
export scriptdir=$top_srcdir/test/scripts
export logdir=logs
export bindir=bin
suites_srcdir=$top_srcdir/test/suites
suites_builddir=suites
scriptdir=$top_srcdir/test/scripts
logdir=logs
bindir=bin
export suites_srcdir suites_builddir scriptdir logdir bindir
passed=0
failed=0

View File

@@ -1,8 +1,20 @@
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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.
die() {
echo "$1" >&2
exit 1
}
[ -n "$1" ] || die "Usage: $0 suite-name"
[ -n "$bindir" ] || die "Set bindir"
[ -n "$logdir" ] || die "Set logdir"
[ -n "$scriptdir" ] || die "Set scriptdir"
[ -n "$suites_srcdir" ] || die "Set suites_srcdir"
[ -n "$suites_builddir" ] || die "Set suites_builddir"
json_process=$bindir/json_process
suite_name=$1
@@ -10,7 +22,6 @@ suite_srcdir=$suites_srcdir/$suite_name
suite_builddir=$suites_builddir/$suite_name
suite_log=$logdir/$suite_name
[ -z "$VERBOSE" ] && VERBOSE=0
[ -z "$STOP" ] && STOP=0

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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 @@
EXTRA_DIST = run
EXTRA_DIST = run check-exports
check_PROGRAMS = \
test_array \
test_copy \
test_dump \
test_dump_callback \
test_equal \
test_load \
test_loadb \
test_load_callback \
test_memory_funcs \
test_number \
test_object \
@@ -16,7 +19,9 @@ check_PROGRAMS = \
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_dump_callback_SOURCES = test_dump_callback.c util.h
test_load_SOURCES = test_load.c util.h
test_loadb_SOURCES = test_loadb.c util.h
test_memory_funcs_SOURCES = test_memory_funcs.c util.h
test_number_SOURCES = test_number.c util.h
test_object_SOURCES = test_object.c util.h

View File

@@ -1,98 +1,21 @@
#!/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
json_pack
json_pack_ex
json_vpack_ex
json_unpack
json_unpack_ex
json_vunpack_ex
json_set_alloc_funcs
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
#
# This test checks that libjansson.so exports the correct symbols.
#
SOFILE="../src/.libs/libjansson.so"
# The list of symbols, which the shared object should export, is read
# from the def file, which is used in Windows builds
grep 'json_' $top_srcdir/src/jansson.def \
| sed -e 's/ //g' \
| sort \
>$test_log/exports
nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \
|| exit 77 # Skip if "nm -D" doesn't seem to work
grep ' T ' $test_log/symbols | cut -d' ' -f3 | sort >$test_log/output
grep ' [DT] ' $test_log/symbols | 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

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -387,7 +387,7 @@ static void test_circular()
}
int main()
static void run_tests()
{
test_misc();
test_insert();
@@ -395,6 +395,4 @@ int main()
test_clear();
test_extend();
test_circular();
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -307,7 +307,7 @@ static void test_deep_copy_object(void)
json_decref(copy);
}
int main()
static void run_tests()
{
test_copy_simple();
test_deep_copy_simple();
@@ -315,5 +315,4 @@ int main()
test_deep_copy_array();
test_copy_object();
test_deep_copy_object();
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,13 +9,13 @@
#include <string.h>
#include "util.h"
int main()
static void encode_twice()
{
/* Encode an empty object/array, add an item, encode again */
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, "{}"))
@@ -43,7 +43,10 @@ int main()
free(result);
json_decref(json);
}
static void circular_references()
{
/* Construct a JSON object/array with a circular reference:
object: {"a": {"b": {"c": <circular reference to $.a>}}}
@@ -51,6 +54,10 @@ int main()
Encode it, remove the circular reference and encode again.
*/
json_t *json;
char *result;
json = json_object();
json_object_set_new(json, "a", json_object());
json_object_set_new(json_object_get(json, "a"), "b", json_object());
@@ -86,6 +93,74 @@ int main()
free(result);
json_decref(json);
return 0;
}
static void encode_other_than_array_or_object()
{
/* Encoding anything other than array or object should only
* succeed if the JSON_ENCODE_ANY flag is used */
json_t *json;
FILE *fp = NULL;
char *result;
json = json_string("foo");
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded a string!");
if(json_dumpf(json, fp, 0) == 0)
fail("json_dumpf encoded a string!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "\"foo\"") != 0)
fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
free(result);
json_decref(json);
json = json_integer(42);
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded an integer!");
if(json_dumpf(json, fp, 0) == 0)
fail("json_dumpf encoded an integer!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "42") != 0)
fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
free(result);
json_decref(json);
}
static void escape_slashes()
{
/* Test dump escaping slashes */
json_t *json;
char *result;
json = json_object();
json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
fail("json_dumps failed to not escape slashes");
free(result);
result = json_dumps(json, JSON_ESCAPE_SLASH);
if(!result || strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
fail("json_dumps failed to escape slashes");
free(result);
json_decref(json);
}
static void run_tests()
{
encode_twice();
circular_references();
encode_other_than_array_or_object();
escape_slashes();
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2009-2012 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 <stdlib.h>
#include "util.h"
struct my_sink {
char *buf;
size_t off;
size_t cap;
};
static int my_writer(const char *buffer, size_t len, void *data) {
struct my_sink *s = data;
if (len > s->cap - s->off) {
return -1;
}
memcpy(s->buf + s->off, buffer, len);
s->off += len;
return 0;
}
static void run_tests()
{
struct my_sink s;
json_t *json;
const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
char *dumped_to_string;
json = json_loads(str, 0, NULL);
if(!json) {
fail("json_loads failed");
}
dumped_to_string = json_dumps(json, 0);
if (!dumped_to_string) {
json_decref(json);
fail("json_dumps failed");
}
s.off = 0;
s.cap = strlen(dumped_to_string);
s.buf = malloc(s.cap);
if (!s.buf) {
json_decref(json);
free(dumped_to_string);
fail("malloc failed");
}
if (json_dump_callback(json, my_writer, &s, 0) == -1) {
json_decref(json);
free(dumped_to_string);
free(s.buf);
fail("json_dump_callback failed on an exact-length sink buffer");
}
if (strncmp(dumped_to_string, s.buf, s.off) != 0) {
json_decref(json);
free(dumped_to_string);
free(s.buf);
fail("json_dump_callback and json_dumps did not produce identical output");
}
s.off = 1;
if (json_dump_callback(json, my_writer, &s, 0) != -1) {
json_decref(json);
free(dumped_to_string);
free(s.buf);
fail("json_dump_callback succeeded on a short buffer when it should have failed");
}
json_decref(json);
free(dumped_to_string);
free(s.buf);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -180,11 +180,10 @@ static void test_equal_complex()
/* TODO: There's no negative test case here */
}
int main()
static void run_tests()
{
test_equal_simple();
test_equal_array();
test_equal_object();
test_equal_complex();
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,16 +9,129 @@
#include <string.h>
#include "util.h"
int main()
static void file_not_found()
{
json_t *json;
json_error_t error;
char *pos;
json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
if(json)
fail("json_load_file returned non-NULL for a nonexistent file");
if(error.line != -1)
fail("json_load_file returned an invalid line number");
/* The error message is locale specific, only check the beginning
of the error message. */
pos = strchr(error.text, ':');
if(!pos)
fail("json_load_file returne an invalid error message");
*pos = '\0';
if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
fail("json_load_file returned an invalid error message");
}
static void reject_duplicates()
{
json_error_t error;
if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
fail("json_loads did not detect a duplicate key");
check_error("duplicate object key near '\"foo\"'", "<string>", 1, 16, 16);
}
static void disable_eof_check()
{
json_error_t error;
json_t *json;
const char *text = "{\"foo\": 1} garbage";
if(json_loads(text, 0, &error))
fail("json_loads did not detect garbage after JSON text");
check_error("end of file expected near 'garbage'", "<string>", 1, 18, 18);
json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
if(!json)
fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
json_decref(json);
}
static void decode_any()
{
json_t *json;
json_error_t error;
json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
if(error.line != -1)
fail("json_load_file returned an invalid line number");
if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json: No such file or directory") != 0)
fail("json_load_file returned an invalid error message");
json = json_loads("\"foo\"", JSON_DECODE_ANY, &error);
if (!json || !json_is_string(json))
fail("json_load decoded any failed - string");
json_decref(json);
return 0;
json = json_loads("42", JSON_DECODE_ANY, &error);
if (!json || !json_is_integer(json))
fail("json_load decoded any failed - integer");
json_decref(json);
json = json_loads("true", JSON_DECODE_ANY, &error);
if (!json || !json_is_true(json))
fail("json_load decoded any failed - boolean");
json_decref(json);
json = json_loads("null", JSON_DECODE_ANY, &error);
if (!json || !json_is_null(json))
fail("json_load decoded any failed - null");
json_decref(json);
}
static void load_wrong_args()
{
json_t *json;
json_error_t error;
json = json_loads(NULL, 0, &error);
if (json)
fail("json_loads should return NULL if the first argument is NULL");
json = json_loadb(NULL, 0, 0, &error);
if (json)
fail("json_loadb should return NULL if the first argument is NULL");
json = json_loadf(NULL, 0, &error);
if (json)
fail("json_loadf should return NULL if the first argument is NULL");
json = json_load_file(NULL, 0, &error);
if (json)
fail("json_loadf should return NULL if the first argument is NULL");
}
static void position()
{
json_t *json;
size_t flags = JSON_DISABLE_EOF_CHECK;
json_error_t error;
json = json_loads("{\"foo\": \"bar\"}", 0, &error);
if(error.position != 14)
fail("json_loads returned a wrong position");
json_decref(json);
json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
if(error.position != 14)
fail("json_loads returned a wrong position");
json_decref(json);
}
static void run_tests()
{
file_not_found();
reject_duplicates();
disable_eof_check();
decode_any();
load_wrong_args();
position();
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2009-2011 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 <stdlib.h>
#include "util.h"
struct my_source {
const char *buf;
size_t off;
size_t cap;
};
static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
static size_t greedy_reader(void *buf, size_t buflen, void *arg)
{
struct my_source *s = arg;
if (buflen > s->cap - s->off)
buflen = s->cap - s->off;
if (buflen > 0) {
memcpy(buf, s->buf + s->off, buflen);
s->off += buflen;
return buflen;
} else {
return 0;
}
}
static void run_tests()
{
struct my_source s;
json_t *json;
json_error_t error;
s.off = 0;
s.cap = strlen(my_str);
s.buf = my_str;
json = json_load_callback(greedy_reader, &s, 0, &error);
if (!json)
fail("json_load_callback failed on a valid callback");
json_decref(json);
s.off = 0;
s.cap = strlen(my_str) - 1;
s.buf = my_str;
json = json_load_callback(greedy_reader, &s, 0, &error);
if (json) {
json_decref(json);
fail("json_load_callback should have failed on an incomplete stream, but it didn't");
}
if (strcmp(error.source, "<callback>") != 0) {
fail("json_load_callback returned an invalid error source");
}
if (strcmp(error.text, "']' expected near end of file") != 0) {
fail("json_load_callback returned an invalid error message for an unclosed top-level array");
}
json = json_load_callback(NULL, NULL, 0, &error);
if (json) {
json_decref(json);
fail("json_load_callback should have failed on NULL load callback, but it didn't");
}
if (strcmp(error.text, "wrong arguments") != 0) {
fail("json_load_callback returned an invalid error message for a NULL load callback");
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2009-2012 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"
static void run_tests()
{
json_t *json;
json_error_t error;
const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
size_t len = strlen(str) - strlen("garbage");
json = json_loadb(str, len, 0, &error);
if(!json) {
fail("json_loadb failed on a valid JSON buffer");
}
json_decref(json);
json = json_loadb(str, len - 1, 0, &error);
if (json) {
json_decref(json);
fail("json_loadb should have failed on an incomplete buffer, but it didn't");
}
if(error.line != 1) {
fail("json_loadb returned an invalid line number on fail");
}
if(strcmp(error.text, "']' expected near end of file") != 0) {
fail("json_loadb returned an invalid error message for an unclosed top-level array");
}
}

View File

@@ -39,7 +39,7 @@ static void test_simple()
json_set_alloc_funcs(my_malloc, my_free);
create_and_free_complex_object();
if(malloc_called != 27 || free_called != 27)
if(malloc_called != 20 || free_called != 20)
fail("Custom allocation failed");
}
@@ -55,14 +55,14 @@ static void *secure_malloc(size_t size)
/* Store the memory area size in the beginning of the block */
void *ptr = malloc(size + 8);
*((size_t *)ptr) = size;
return ptr + 8;
return (char *)ptr + 8;
}
static void secure_free(void *ptr)
{
size_t size;
ptr -= 8;
ptr = (char *)ptr - 8;
size = *((size_t *)ptr);
/*guaranteed_*/memset(ptr, 0, size);
@@ -75,10 +75,8 @@ static void test_secure_funcs(void)
create_and_free_complex_object();
}
int main()
static void run_tests()
{
test_simple();
test_secure_funcs();
return 0;
}

View File

@@ -1,14 +1,15 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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 <math.h>
#include <jansson.h>
#include "util.h"
int main()
static void run_tests()
{
json_t *integer, *real;
int i;
@@ -40,5 +41,33 @@ int main()
json_decref(integer);
json_decref(real);
return 0;
#ifdef NAN
real = json_real(NAN);
if(real != NULL)
fail("could construct a real from NaN");
real = json_real(1.0);
if(json_real_set(real, NAN) != -1)
fail("could set a real to NaN");
if(json_real_value(real) != 1.0)
fail("real value changed unexpectedly");
json_decref(real);
#endif
#ifdef INFINITY
real = json_real(INFINITY);
if(real != NULL)
fail("could construct a real from Inf");
real = json_real(1.0);
if(json_real_set(real, INFINITY) != -1)
fail("could set a real to Inf");
if(json_real_value(real) != 1.0)
fail("real value changed unexpectedly");
json_decref(real);
#endif
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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.
@@ -139,6 +139,48 @@ static void test_update()
json_decref(object);
}
static void test_conditional_updates()
{
json_t *object, *other;
object = json_pack("{sisi}", "foo", 1, "bar", 2);
other = json_pack("{sisi}", "foo", 3, "baz", 4);
if(json_object_update_existing(object, other))
fail("json_object_update_existing failed");
if(json_object_size(object) != 2)
fail("json_object_update_existing added new items");
if(json_integer_value(json_object_get(object, "foo")) != 3)
fail("json_object_update_existing failed to update existing key");
if(json_integer_value(json_object_get(object, "bar")) != 2)
fail("json_object_update_existing updated wrong key");
json_decref(object);
object = json_pack("{sisi}", "foo", 1, "bar", 2);
if(json_object_update_missing(object, other))
fail("json_object_update_missing failed");
if(json_object_size(object) != 3)
fail("json_object_update_missing didn't add new items");
if(json_integer_value(json_object_get(object, "foo")) != 1)
fail("json_object_update_missing updated existing key");
if(json_integer_value(json_object_get(object, "bar")) != 2)
fail("json_object_update_missing updated wrong key");
if(json_integer_value(json_object_get(object, "baz")) != 4)
fail("json_object_update_missing didn't add new items");
json_decref(object);
json_decref(other);
}
static void test_circular()
{
json_t *object1, *object2;
@@ -437,15 +479,33 @@ static void test_preserve_order()
json_decref(object);
}
int main()
static void test_foreach()
{
const char *key;
json_t *object1, *object2, *value;
object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
object2 = json_object();
json_object_foreach(object1, key, value)
json_object_set(object2, key, value);
if(!json_equal(object1, object2))
fail("json_object_foreach failed to iterate all key-value pairs");
json_decref(object1);
json_decref(object2);
}
static void run_tests()
{
test_misc();
test_clear();
test_update();
test_conditional_updates();
test_circular();
test_set_nocheck();
test_iterators();
test_preserve_order();
return 0;
test_foreach();
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -11,7 +11,7 @@
#include <stdio.h>
#include "util.h"
int main()
static void run_tests()
{
json_t *value;
int i;
@@ -25,7 +25,7 @@ int main()
value = json_pack("b", 1);
if(!json_is_true(value))
fail("json_pack boolean failed");
if(value->refcount != (ssize_t)-1)
if(value->refcount != (size_t)-1)
fail("json_pack boolean refcount failed");
json_decref(value);
@@ -33,7 +33,7 @@ int main()
value = json_pack("b", 0);
if(!json_is_false(value))
fail("json_pack boolean failed");
if(value->refcount != (ssize_t)-1)
if(value->refcount != (size_t)-1)
fail("json_pack boolean refcount failed");
json_decref(value);
@@ -41,7 +41,7 @@ int main()
value = json_pack("n");
if(!json_is_null(value))
fail("json_pack null failed");
if(value->refcount != (ssize_t)-1)
if(value->refcount != (size_t)-1)
fail("json_pack null refcount failed");
json_decref(value);
@@ -49,7 +49,7 @@ int main()
value = json_pack("i", 1);
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack integer failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
@@ -57,7 +57,7 @@ int main()
value = json_pack("I", (json_int_t)555555);
if(!json_is_integer(value) || json_integer_value(value) != 555555)
fail("json_pack json_int_t failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
@@ -65,7 +65,7 @@ int main()
value = json_pack("f", 1.0);
if(!json_is_real(value) || json_real_value(value) != 1.0)
fail("json_pack real failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack real refcount failed");
json_decref(value);
@@ -73,7 +73,7 @@ int main()
value = json_pack("s", "test");
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
fail("json_pack string failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack string refcount failed");
json_decref(value);
@@ -81,7 +81,7 @@ int main()
value = json_pack("{}", 1.0);
if(!json_is_object(value) || json_object_size(value) != 0)
fail("json_pack empty object failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack empty object refcount failed");
json_decref(value);
@@ -89,7 +89,7 @@ int main()
value = json_pack("[]", 1.0);
if(!json_is_array(value) || json_array_size(value) != 0)
fail("json_pack empty list failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack empty list failed");
json_decref(value);
@@ -97,7 +97,7 @@ int main()
value = json_pack("o", json_integer(1));
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack object failed");
if(value->refcount != (ssize_t)1)
if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
@@ -105,7 +105,7 @@ int main()
value = json_pack("O", json_integer(1));
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack object failed");
if(value->refcount != (ssize_t)2)
if(value->refcount != (size_t)2)
fail("json_pack integer refcount failed");
json_decref(value);
json_decref(value);
@@ -116,7 +116,7 @@ int main()
fail("json_pack array failed");
if(!json_is_array(json_object_get(value, "foo")))
fail("json_pack array failed");
if(json_object_get(value, "foo")->refcount != (ssize_t)1)
if(json_object_get(value, "foo")->refcount != (size_t)1)
fail("json_pack object refcount failed");
json_decref(value);
@@ -227,6 +227,4 @@ int main()
if(json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff"))
fail("json_pack failed to catch invalid UTF-8 in a string");
check_error("Invalid UTF-8 string", "<args>", 1, 4, 4);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,10 +10,26 @@
#include "util.h"
/* Call the simple functions not covered by other tests of the public API */
int main()
static void run_tests()
{
json_t *value;
value = json_boolean(1);
if(!json_is_true(value))
fail("json_boolean(1) failed");
json_decref(value);
value = json_boolean(-123);
if(!json_is_true(value))
fail("json_boolean(-123) failed");
json_decref(value);
value = json_boolean(0);
if(!json_is_false(value))
fail("json_boolean(0) failed");
json_decref(value);
value = json_integer(1);
if(json_typeof(value) != JSON_INTEGER)
fail("json_typeof failed");
@@ -180,6 +196,4 @@ int main()
json_incref(value);
if(value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -11,7 +11,7 @@
#include <stdio.h>
#include "util.h"
int main()
static void run_tests()
{
json_t *j, *j2;
int i1, i2, i3;
@@ -337,5 +337,37 @@ int main()
check_error("1 array item(s) left unpacked", "<validation>", 1, 5, 5);
json_decref(j);
return 0;
/* Optional values */
j = json_object();
i1 = 0;
if(json_unpack(j, "{s?i}", "foo", &i1))
fail("json_unpack failed for optional key");
if(i1 != 0)
fail("json_unpack unpacked an optional key");
json_decref(j);
i1 = 0;
j = json_pack("{si}", "foo", 42);
if(json_unpack(j, "{s?i}", "foo", &i1))
fail("json_unpack failed for an optional value");
if(i1 != 42)
fail("json_unpack failed to unpack an optional value");
json_decref(j);
j = json_object();
i1 = i2 = i3 = 0;
if(json_unpack(j, "{s?[ii]s?{s{si}}}",
"foo", &i1, &i2,
"bar", "baz", "quux", &i3))
fail("json_unpack failed for complex optional values");
if(i1 != 0 || i2 != 0 || i3 != 0)
fail("json_unpack unexpectedly unpacked something");
json_decref(j);
j = json_pack("{s{si}}", "foo", "bar", 42);
if(json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1))
fail("json_unpack failed for complex optional values");
if(i1 != 42)
fail("json_unpack failed to unpack");
json_decref(j);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2012 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,8 +8,16 @@
#ifndef UTIL_H
#define UTIL_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if HAVE_LOCALE_H
#include <locale.h>
#endif
#include <jansson.h>
#define failhdr fprintf(stderr, "%s:%s:%d: ", __FILE__, __FUNCTION__, __LINE__)
@@ -52,4 +60,15 @@
} \
} while(0)
static void run_tests();
int main() {
#ifdef HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
run_tests();
return 0;
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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 +1,2 @@
export JSON_SORT_KEYS=1
JSON_SORT_KEYS=1
export JSON_SORT_KEYS

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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,6 +1,6 @@
#!/bin/sh
#
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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 +1 @@
[1e+22]
[1e22]

View File

@@ -1 +1 @@
[1.2299999999999999e+47]
[1.2299999999999999e47]

View File

@@ -1 +1 @@
[1.23456e+80]
[1.23456e80]

View File

@@ -1,11 +1,12 @@
#!/bin/sh
#
# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
# Copyright (c) 2009-2012 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.
export JSON_SORT_KEYS=1
JSON_SORT_KEYS=1
export JSON_SORT_KEYS
is_test() {
test -d $test_path

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 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.
@@ -24,11 +24,16 @@
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE
#define JSON_INLINE __inline
#endif
/* If your compiler supports the `long long` type,
JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 1
#endif

20
win32/vs2010/jansson.sln Normal file
View File

@@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jansson", "jansson.vcxproj", "{76226D20-1972-4789-A595-EDACC7A76DC3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.ActiveCfg = Debug|Win32
{76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.Build.0 = Debug|Win32
{76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.ActiveCfg = Release|Win32
{76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dump.c" />
<ClCompile Include="..\..\src\error.c" />
<ClCompile Include="..\..\src\hashtable.c" />
<ClCompile Include="..\..\src\load.c" />
<ClCompile Include="..\..\src\memory.c" />
<ClCompile Include="..\..\src\pack_unpack.c" />
<ClCompile Include="..\..\src\strbuffer.c" />
<ClCompile Include="..\..\src\strconv.c" />
<ClCompile Include="..\..\src\utf.c" />
<ClCompile Include="..\..\src\value.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\hashtable.h" />
<ClInclude Include="..\..\src\jansson.h" />
<ClInclude Include="..\..\src\jansson_private.h" />
<ClInclude Include="..\..\src\strbuffer.h" />
<ClInclude Include="..\..\src\utf.h" />
<ClInclude Include="..\jansson_config.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{76226D20-1972-4789-A595-EDACC7A76DC3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>jansson_dll</RootNamespace>
<ProjectName>jansson</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>Output\$(Configuration)\</OutDir>
<IntDir>Build\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>Output\$(Configuration)\</OutDir>
<IntDir>Build\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>../../src/jansson.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>../../src/jansson.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\dump.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\error.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\hashtable.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\load.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\memory.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\pack_unpack.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\strbuffer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\strconv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\utf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\value.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\hashtable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\jansson.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\jansson_private.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\strbuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\utf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\jansson_config.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>