├── NEWS
├── README
├── tests
├── test_charcase.expected
├── test_obj_obj_get_ex-null.expected
├── test_obj_iter-del.expected
├── ucs_copyright_char.expected
├── test_float.expected
├── parse_flags.h
├── test_null.expected
├── test4.expected
├── test_locale.expected
├── test_object_object_add_ex.expected
├── test_object_object_add_exFormatted_plain.expected
├── test_object_object_add_exFormatted_spaced.expected
├── test_object_object_add_exFormatted_pretty.expected
├── test4.test
├── test_cast.test
├── test_float.test
├── test_null.test
├── test_parse.test
├── test_locale.test
├── test_charcase.test
├── test_printbuf.test
├── test_parse_int64.test
├── testReplaceExisting.test
├── test_set_serializer.test
├── test_many_subobj.test
├── test_obj_iter-del.test
├── test_obj_obj_get_ex-null.test
├── test2Formatted_plain.expected
├── test2.expected
├── test2Formatted_spaced.expected
├── ucs_copyright_char.test
├── test1.test
├── test2.test
├── ucs_copyright_char.c
├── testReplaceExisting.expected
├── test_object_object_add_ex.test
├── test_set_serializer.expected
├── test2Formatted_pretty.expected
├── chk_version.c
├── test1Formatted_plain.expected
├── test1.expected
├── test1Formatted_spaced.expected
├── test_locale.c
├── test1Formatted_pretty.expected
├── test_float.c
├── parse_flags.c
├── test_obj_obj_get_ex-null.c
├── test_charcase.c
├── cr_obj_multi.c
├── test_printbuf.expected
├── test2.c
├── test_parse_int64.expected
├── test4.c
├── test_null.c
├── test_obj_iter-del.c
├── test_object_object_add_ex.c
├── test_many_subobj.c
├── test_cast.expected
├── test_parse_int64.c
├── Makefile.am
├── testReplaceExisting.c
├── test-defs.sh
├── test_cast.c
├── test_parse.expected
├── test1.c
├── test_printbuf.c
├── test_many_subobj.expected
└── test_parse.c
├── ChangeLog
├── CI
├── README
├── check_codestyle.sh
├── clang-check-sanitizer.sh
└── try_merge.sh
├── autoconf-archive
└── README.txt
├── AUTHORS
├── libfastjson-uninstalled.pc.in
├── libfastjson.pc.in
├── autogen.sh
├── json_version.c
├── .travis.yml
├── CONTRIBUTING.md
├── Makefile.am
├── m4
├── ax_require_defined.m4
├── atomic_operations.m4
├── atomic_operations_64bit.m4
├── ax_append_flag.m4
├── ax_append_compile_flags.m4
└── ax_check_compile_flag.m4
├── .gitignore
├── arraylist.h
├── json_util.h
├── README.html
├── debug.c
├── debug.h
├── README.md
├── DIFFERENCES
├── json_object_private.h
├── printbuf.h
├── json.h
├── COPYING
├── RELEASE_CHECKLIST.txt
├── arraylist.c
├── configure.ac
├── json_object_iterator.c
├── printbuf.c
├── json_tokener.h
├── json_util.c
├── atomic.h
└── json_object_iterator.h
/NEWS:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test_charcase.expected:
--------------------------------------------------------------------------------
1 | OK
2 |
--------------------------------------------------------------------------------
/tests/test_obj_obj_get_ex-null.expected:
--------------------------------------------------------------------------------
1 | found=1
2 |
--------------------------------------------------------------------------------
/tests/test_obj_iter-del.expected:
--------------------------------------------------------------------------------
1 | b: "b"
2 | d: "d"
3 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsyslog/libfastjson/HEAD/ChangeLog
--------------------------------------------------------------------------------
/tests/ucs_copyright_char.expected:
--------------------------------------------------------------------------------
1 | string = { "foo" : "©" }
2 | json = {
3 | "foo":"©"
4 | }
5 |
--------------------------------------------------------------------------------
/tests/test_float.expected:
--------------------------------------------------------------------------------
1 | json = 1.0
2 | json = 1.23
3 | json = 123456789.0
4 | json = 123456789.123
5 |
--------------------------------------------------------------------------------
/CI/README:
--------------------------------------------------------------------------------
1 | This directory contains scripts and other files
2 | related to the various Continous Integration
3 | environments.
4 |
--------------------------------------------------------------------------------
/tests/parse_flags.h:
--------------------------------------------------------------------------------
1 | #ifndef __parse_flags_h
2 | #define __parse_flags_h
3 | int parse_flags(int argc, char **argv);
4 | #endif
5 |
--------------------------------------------------------------------------------
/tests/test_null.expected:
--------------------------------------------------------------------------------
1 | JSON write result is correct: " \u0000 "
2 | PASS
3 | Re-parsed object string len=3, chars=[32, 0, 32]
4 |
--------------------------------------------------------------------------------
/tests/test4.expected:
--------------------------------------------------------------------------------
1 | input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27"
2 | JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧
3 | PASS
4 |
--------------------------------------------------------------------------------
/tests/test_locale.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()=[ 1.2, 3.4, 123456.78, 5.0, 2.3e10 ]
2 | new_obj.to_string()=[1.2,3.4,123456.78,5.0,2.3e10]
3 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_ex.expected:
--------------------------------------------------------------------------------
1 | my_object=
2 | abc: 12
3 | foo: "bar"
4 | bool0: false
5 | bool1: true
6 | my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
7 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_exFormatted_plain.expected:
--------------------------------------------------------------------------------
1 | my_object=
2 | abc: 12
3 | foo: "bar"
4 | bool0: false
5 | bool1: true
6 | my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true}
7 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_exFormatted_spaced.expected:
--------------------------------------------------------------------------------
1 | my_object=
2 | abc: 12
3 | foo: "bar"
4 | bool0: false
5 | bool1: true
6 | my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
7 |
--------------------------------------------------------------------------------
/autoconf-archive/README.txt:
--------------------------------------------------------------------------------
1 |
2 | Autoconf Archive fetched from:
3 |
4 | http://gnu.mirror.iweb.com/autoconf-archive/autoconf-archive-2015.09.25.tar.xz
5 |
6 | Grabbed the minimum files needed for the AX_APPEND_COMPILE_FLAGS macro.
7 |
8 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_exFormatted_pretty.expected:
--------------------------------------------------------------------------------
1 | my_object=
2 | abc: 12
3 | foo: "bar"
4 | bool0: false
5 | bool1: true
6 | my_object.to_string()={
7 | "abc":12,
8 | "foo":"bar",
9 | "bool0":false,
10 | "bool1":true
11 | }
12 |
--------------------------------------------------------------------------------
/CI/check_codestyle.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | mkdir _tmp_stylecheck
3 | cd _tmp_stylecheck
4 | git clone https://github.com/rsyslog/codestyle
5 | cd codestyle
6 | gcc --std=c99 stylecheck.c -o stylecheck
7 | cd ../..
8 | find *.[ch] | xargs _tmp_stylecheck/codestyle/stylecheck -l 130
9 |
--------------------------------------------------------------------------------
/CI/clang-check-sanitizer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -v
3 |
4 | export CC=gcc # clang --> package currently broken in fedora 23
5 | export CFLAGS="-g -fsanitize=address"
6 | ./autogen.sh
7 | ./configure
8 | cat config.log
9 | make clean
10 | export VERBOSE=1
11 | make check
12 |
--------------------------------------------------------------------------------
/tests/test4.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test4
12 | exit $?
13 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Rainer Gerhards
2 |
3 | With special thanks for the original json-c library:
4 | Michael Clark
5 | Jehiah Czebotar
6 | Eric Haszlakiewicz
7 | C. Watford (christopher.watford@gmail.com)
8 |
9 |
--------------------------------------------------------------------------------
/tests/test_cast.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_cast
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_float.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_float
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_null.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_null
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_parse.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_parse
12 | exit $?
13 |
--------------------------------------------------------------------------------
/libfastjson-uninstalled.pc.in:
--------------------------------------------------------------------------------
1 | prefix=
2 | exec_prefix=
3 | libdir=@abs_top_builddir@
4 | includedir=@abs_top_srcdir@
5 |
6 | Name: json
7 | Description: JSON implementation in C
8 | Version: @VERSION@
9 | Requires:
10 | Libs: -L@abs_top_builddir@ -ljson-c
11 | Cflags: -I@abs_top_srcdir@
12 |
--------------------------------------------------------------------------------
/tests/test_locale.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_locale
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_charcase.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_charcase
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_printbuf.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_printbuf
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_parse_int64.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_parse_int64
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/testReplaceExisting.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test testReplaceExisting
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_set_serializer.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_set_serializer
12 | exit $?
13 |
--------------------------------------------------------------------------------
/tests/test_many_subobj.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_many_subobj
12 | _err=$?
13 |
14 | exit $_err
15 |
--------------------------------------------------------------------------------
/tests/test_obj_iter-del.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_obj_iter-del
12 | _err=$?
13 |
14 | exit $_err
15 |
--------------------------------------------------------------------------------
/libfastjson.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@prefix@
2 | exec_prefix=@exec_prefix@
3 | libdir=@libdir@
4 | includedir=@includedir@
5 |
6 | Name: libfastjson
7 | Description: a fast JSON implementation in C
8 | Version: @VERSION@
9 | Requires:
10 | Libs.private: @LIBS@
11 | Libs: -L${libdir} -lfastjson -lm
12 | Cflags: -I${includedir}/libfastjson
13 |
--------------------------------------------------------------------------------
/tests/test_obj_obj_get_ex-null.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_obj_obj_get_ex-null
12 | _err=$?
13 |
14 | exit $_err
15 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | autoreconf -v --install || exit 1
3 |
4 | # If there are any options, assume the user wants to run configure.
5 | # To run configure w/o any options, use ./autogen.sh --configure
6 | if [ $# -gt 0 ] ; then
7 | case "$1" in
8 | --conf*)
9 | shift 1
10 | ;;
11 | esac
12 | exec ./configure "$@"
13 | fi
14 |
--------------------------------------------------------------------------------
/tests/test2Formatted_plain.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":[{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML","markup"]}]}}}
2 |
--------------------------------------------------------------------------------
/tests/test2.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }
2 |
--------------------------------------------------------------------------------
/tests/test2Formatted_spaced.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()={ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": [ "GML", "XML", "markup" ] } ] } } }
2 |
--------------------------------------------------------------------------------
/json_version.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012 Eric Haszlakiewicz
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | */
9 | #include "config.h"
10 | #include "json.h"
11 |
12 | const char *fjson_version(void)
13 | {
14 | return VERSION;
15 | }
16 |
--------------------------------------------------------------------------------
/tests/ucs_copyright_char.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Common definitions
3 | if test -z "$srcdir"; then
4 | srcdir="${0%/*}"
5 | test "$srcdir" = "$0" && srcdir=.
6 | test -z "$srcdir" && srcdir=.
7 | fi
8 | . "$srcdir/test-defs.sh"
9 |
10 | #if [ "x$CI_SOLARIS" = "xyes" ] ; then
11 | uname
12 | if [ `uname` = "SunOS" ] ; then
13 | echo "This test currently does not work on all flavors of Solaris."
14 | exit 77
15 | fi
16 |
17 |
18 | run_output_test ucs_copyright_char
19 | exit $?
20 |
--------------------------------------------------------------------------------
/tests/test1.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test1
12 | _err=$?
13 |
14 | for flag in plain spaced pretty ; do
15 | run_output_test -o test1Formatted_${flag} test1Formatted ${flag}
16 | _err2=$?
17 | if [ $_err -eq 0 ] ; then
18 | _err=$_err2
19 | fi
20 | done
21 |
22 | exit $_err
23 |
--------------------------------------------------------------------------------
/tests/test2.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test2
12 | _err=$?
13 |
14 | for flag in plain spaced pretty ; do
15 | run_output_test -o test2Formatted_${flag} test2Formatted ${flag}
16 | _err2=$?
17 | if [ $_err -eq 0 ] ; then
18 | _err=$_err2
19 | fi
20 | done
21 |
22 | exit $_err
23 |
--------------------------------------------------------------------------------
/tests/ucs_copyright_char.c:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 2016 by Rainer Gerhards
2 | * Released under ASL 2.0 */
3 | #include "config.h"
4 | #include
5 | #include "../json_object.h"
6 | #include "../json_tokener.h"
7 | int main(void)
8 | {
9 | const char *s;
10 | json_object *json;
11 |
12 | s = "{ \"foo\" : \"\u00a9\" }";
13 |
14 | printf("string = %s\n", s);
15 | json = json_tokener_parse(s);
16 | printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
17 |
18 | json_object_put(json);
19 | }
20 |
--------------------------------------------------------------------------------
/tests/testReplaceExisting.expected:
--------------------------------------------------------------------------------
1 | ==== delete-in-loop test starting ====
2 | Key at index 0 is [foo1] (kept)
3 | Key at index 1 is [foo2] (kept)
4 | Key at index 2 is [deleteme] (deleted)
5 | Key at index 3 is [foo3] (kept)
6 | ==== replace-value first loop starting ====
7 | Key at index 0 is [foo1]
8 | Key at index 1 is [foo2]
9 | replacing value for key [foo2]
10 | Key at index 2 is [foo3]
11 | ==== second loop starting ====
12 | Key at index 0 is [foo1]
13 | Key at index 1 is [foo2]
14 | pointer for key [foo2] does match
15 | Key at index 2 is [foo3]
16 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_ex.test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Common definitions
4 | if test -z "$srcdir"; then
5 | srcdir="${0%/*}"
6 | test "$srcdir" = "$0" && srcdir=.
7 | test -z "$srcdir" && srcdir=.
8 | fi
9 | . "$srcdir/test-defs.sh"
10 |
11 | run_output_test test_object_object_add_ex
12 | _err=$?
13 |
14 | for flag in plain spaced pretty ; do
15 | run_output_test -o test_object_object_add_exFormatted_${flag} test_object_object_add_exFormatted ${flag}
16 | _err2=$?
17 | if [ $_err -eq 0 ] ; then
18 | _err=$_err2
19 | fi
20 | done
21 |
22 | exit $_err
23 |
--------------------------------------------------------------------------------
/tests/test_set_serializer.expected:
--------------------------------------------------------------------------------
1 | Test setting, then resetting a custom serializer:
2 | my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
3 | my_object.to_string(custom serializer)=Custom Output
4 | Next line of output should be from the custom freeit function:
5 | freeit, value=123
6 | my_object.to_string(standard)={ "abc": 12, "foo": "bar" }
7 | Check that the custom serializer isn't free'd until the last fjson_object_put:
8 | my_object.to_string(custom serializer)=Custom Output
9 | Next line of output should be from the custom freeit function:
10 | freeit, value=123
11 |
--------------------------------------------------------------------------------
/tests/test2Formatted_pretty.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()={
2 | "glossary":{
3 | "title":"example glossary",
4 | "GlossDiv":{
5 | "title":"S",
6 | "GlossList":[
7 | {
8 | "ID":"SGML",
9 | "SortAs":"SGML",
10 | "GlossTerm":"Standard Generalized Markup Language",
11 | "Acronym":"SGML",
12 | "Abbrev":"ISO 8879:1986",
13 | "GlossDef":"A meta-markup language, used to create markup languages such as DocBook.",
14 | "GlossSeeAlso":[
15 | "GML",
16 | "XML",
17 | "markup"
18 | ]
19 | }
20 | ]
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/chk_version.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 |
12 | #include "../json.h"
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
19 | {
20 | if(strcmp(fjson_version(), VERSION)) {
21 | fprintf(stderr, "ERROR: fjson_version reports '%s', VERSION is '%s'.\n",
22 | fjson_version(), VERSION);
23 | exit(1);
24 | }
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/tests/test1Formatted_plain.expected:
--------------------------------------------------------------------------------
1 | my_string=
2 | my_string.to_string()="\t"
3 | my_string=\
4 | my_string.to_string()="\\"
5 | my_string=foo
6 | my_string.to_string()="foo"
7 | my_int=9
8 | my_int.to_string()=9
9 | my_array=
10 | [0]=1
11 | [1]=2
12 | [2]=3
13 | [3]=null
14 | [4]=5
15 | my_array.to_string()=[1,2,3,null,5]
16 | my_array=
17 | [0]=3
18 | [1]=1
19 | [2]=2
20 | [3]=null
21 | [4]=0
22 | my_array.to_string()=[3,1,2,null,0]
23 | my_array=
24 | [0]=null
25 | [1]=0
26 | [2]=1
27 | [3]=2
28 | [4]=3
29 | my_array.to_string()=[null,0,1,2,3]
30 | baz_obj.to_string()="fark"
31 | my_object=
32 | abc: 12
33 | foo: "bar"
34 | bool0: false
35 | bool1: true
36 | my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true}
37 |
--------------------------------------------------------------------------------
/tests/test1.expected:
--------------------------------------------------------------------------------
1 | my_string=
2 | my_string.to_string()="\t"
3 | my_string=\
4 | my_string.to_string()="\\"
5 | my_string=foo
6 | my_string.to_string()="foo"
7 | my_int=9
8 | my_int.to_string()=9
9 | my_array=
10 | [0]=1
11 | [1]=2
12 | [2]=3
13 | [3]=null
14 | [4]=5
15 | my_array.to_string()=[ 1, 2, 3, null, 5 ]
16 | my_array=
17 | [0]=3
18 | [1]=1
19 | [2]=2
20 | [3]=null
21 | [4]=0
22 | my_array.to_string()=[ 3, 1, 2, null, 0 ]
23 | my_array=
24 | [0]=null
25 | [1]=0
26 | [2]=1
27 | [3]=2
28 | [4]=3
29 | my_array.to_string()=[ null, 0, 1, 2, 3 ]
30 | baz_obj.to_string()="fark"
31 | my_object=
32 | abc: 12
33 | foo: "bar"
34 | bool0: false
35 | bool1: true
36 | my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
37 |
--------------------------------------------------------------------------------
/tests/test1Formatted_spaced.expected:
--------------------------------------------------------------------------------
1 | my_string=
2 | my_string.to_string()="\t"
3 | my_string=\
4 | my_string.to_string()="\\"
5 | my_string=foo
6 | my_string.to_string()="foo"
7 | my_int=9
8 | my_int.to_string()=9
9 | my_array=
10 | [0]=1
11 | [1]=2
12 | [2]=3
13 | [3]=null
14 | [4]=5
15 | my_array.to_string()=[ 1, 2, 3, null, 5 ]
16 | my_array=
17 | [0]=3
18 | [1]=1
19 | [2]=2
20 | [3]=null
21 | [4]=0
22 | my_array.to_string()=[ 3, 1, 2, null, 0 ]
23 | my_array=
24 | [0]=null
25 | [1]=0
26 | [2]=1
27 | [3]=2
28 | [4]=3
29 | my_array.to_string()=[ null, 0, 1, 2, 3 ]
30 | baz_obj.to_string()="fark"
31 | my_object=
32 | abc: 12
33 | foo: "bar"
34 | bool0: false
35 | bool1: true
36 | my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true }
37 |
--------------------------------------------------------------------------------
/tests/test_locale.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../json_tokener.h"
9 | #include "../debug.h"
10 |
11 | #ifdef HAVE_LOCALE_H
12 | #include
13 | #endif /* HAVE_LOCALE_H */
14 |
15 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
16 | {
17 | fjson_object *new_obj;
18 | #ifdef HAVE_SETLOCALE
19 | setlocale(LC_NUMERIC, "de_DE");
20 | #else
21 | printf("No locale\n");
22 | #endif
23 |
24 | MC_SET_DEBUG(1);
25 |
26 | new_obj = fjson_tokener_parse("[1.2,3.4,123456.78,5.0,2.3e10]");
27 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
28 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string_ext(new_obj,FJSON_TO_STRING_NOZERO));
29 | fjson_object_put(new_obj);
30 | return 0;
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/tests/test1Formatted_pretty.expected:
--------------------------------------------------------------------------------
1 | my_string=
2 | my_string.to_string()="\t"
3 | my_string=\
4 | my_string.to_string()="\\"
5 | my_string=foo
6 | my_string.to_string()="foo"
7 | my_int=9
8 | my_int.to_string()=9
9 | my_array=
10 | [0]=1
11 | [1]=2
12 | [2]=3
13 | [3]=null
14 | [4]=5
15 | my_array.to_string()=[
16 | 1,
17 | 2,
18 | 3,
19 | null,
20 | 5
21 | ]
22 | my_array=
23 | [0]=3
24 | [1]=1
25 | [2]=2
26 | [3]=null
27 | [4]=0
28 | my_array.to_string()=[
29 | 3,
30 | 1,
31 | 2,
32 | null,
33 | 0
34 | ]
35 | my_array=
36 | [0]=null
37 | [1]=0
38 | [2]=1
39 | [3]=2
40 | [4]=3
41 | my_array.to_string()=[
42 | null,
43 | 0,
44 | 1,
45 | 2,
46 | 3
47 | ]
48 | baz_obj.to_string()="fark"
49 | my_object=
50 | abc: 12
51 | foo: "bar"
52 | bool0: false
53 | bool1: true
54 | my_object.to_string()={
55 | "abc":12,
56 | "foo":"bar",
57 | "bool0":false,
58 | "bool1":true
59 | }
60 |
--------------------------------------------------------------------------------
/tests/test_float.c:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 2016 by Rainer Gerhards
2 | * Released under ASL 2.0 */
3 | #include "config.h"
4 | #include
5 | #include "../json_object.h"
6 | #include "../json_tokener.h"
7 | int main(void)
8 | {
9 | fjson_object *json;
10 |
11 | json = fjson_object_new_double(1.0);
12 | printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
13 | json_object_put(json);
14 | json = fjson_object_new_double(1.23);
15 | printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
16 | json_object_put(json);
17 | json = fjson_object_new_double(123456789.0);
18 | printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
19 | json_object_put(json);
20 | json = fjson_object_new_double(123456789.123);
21 | printf("json = %s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
22 | json_object_put(json);
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | sudo: required
3 | dist: trusty
4 |
5 | compiler:
6 | - gcc
7 | - clang
8 |
9 | os:
10 | - linux
11 | - osx
12 |
13 | addons:
14 | apt:
15 | packages:
16 | - clang-3.6
17 | - autoconf-archive
18 | - valgrind
19 |
20 | env:
21 | - CFLAGS="-g"
22 |
23 | before_install:
24 | - echo $LANG
25 | - echo $LC_ALL
26 |
27 | install:
28 | - sh autogen.sh
29 |
30 | before_script:
31 | - # note: valgrind is only available on Linux
32 | - if [ "$CC" == "gcc" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then export ENA_VG="--enable-valgrind"; fi
33 | - if [ "$CC" == "clang" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then export SANITIZER="-fsanitize=address" ; fi
34 | - if [ "$CC" == "clang" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then export CFLAGS="$CFLAGS -fsanitize=address" ; fi
35 | - ./CI/check_codestyle.sh
36 | - ./configure $ENA_VG
37 |
38 | script:
39 | - if [ "$CC" == "clang" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then scan-build-3.6 --status-bugs make check TESTS="" && make clean ; fi
40 | - make
41 | - export VERBOSE=1
42 | - make check
43 | - make distcheck
44 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | CI Tests
2 | ========
3 | We use various continous integration platforms and a testbench to
4 | ensure good code quality.
5 |
6 | All pull request MUST pass all CI tests in order to be considered
7 | for merging.
8 |
9 | If bugs are fixed or new functionality is provided, it is highly
10 | suggested to add a related test to the testbench. If not done,
11 | the merge may be rejected. This is not a hard rule as for some
12 | situations it may be very hard and even impossible to craft an
13 | automatic tests. This should not be used as an excuse for
14 | lazyness.
15 |
16 | Code Style
17 | ==========
18 | Unfortunaly, code style has not been officially described in the
19 | past. As such, some parts of the code do not yet fully conform to
20 | what we really want.
21 |
22 | Also, the rsyslog team has not yet fully agreed on a formal description
23 | of the coding style. This is currently under discussion.
24 |
25 | Here are the minimal style guidelines to ensure code will pass
26 | automatted code style checks during CI runs:
27 |
28 | * indentions are done via TAB, not spaces
29 | * no trailing whitespace is permitted at the end of line
30 |
--------------------------------------------------------------------------------
/tests/parse_flags.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "parse_flags.h"
9 |
10 | #if !defined(HAVE_STRCASECMP)
11 | # error You do not have strcasecmp on your system.
12 | #endif /* HAVE_STRNCASECMP */
13 |
14 | static struct {
15 | const char *arg;
16 | int flag;
17 | } format_args[] = {
18 | { "plain", FJSON_TO_STRING_PLAIN },
19 | { "spaced", FJSON_TO_STRING_SPACED },
20 | { "pretty", FJSON_TO_STRING_PRETTY },
21 | };
22 |
23 | #ifndef NELEM
24 | #define NELEM(x) (sizeof(x) / sizeof(&x[0]))
25 | #endif
26 |
27 | int parse_flags(int argc, char **argv)
28 | {
29 | int arg_idx;
30 | int sflags = 0;
31 | for (arg_idx = 1; arg_idx < argc ; arg_idx++)
32 | {
33 | int jj;
34 | for (jj = 0; jj < (int)NELEM(format_args); jj++)
35 | {
36 | if (strcasecmp(argv[arg_idx], format_args[jj].arg) == 0)
37 | {
38 | sflags |= format_args[jj].flag;
39 | break;
40 | }
41 | }
42 | if (jj == NELEM(format_args))
43 | {
44 | printf("Unknown arg: %s\n", argv[arg_idx]);
45 | exit(1);
46 | }
47 | }
48 | return sflags;
49 | }
50 |
--------------------------------------------------------------------------------
/tests/test_obj_obj_get_ex-null.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include "../json.h"
17 | #include "../debug.h"
18 | #include "parse_flags.h"
19 |
20 | /* this is a work-around until we manage to fix configure.ac */
21 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
22 |
23 | #define DEBUG_SEED(s)
24 |
25 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
26 | {
27 | fjson_object *my_object;
28 |
29 | MC_SET_DEBUG(1);
30 |
31 | my_object = fjson_object_new_object();
32 | fjson_object_object_add_ex(my_object, "a", fjson_object_new_int(1), 0);
33 |
34 | int found = fjson_object_object_get_ex(my_object, "a", NULL);
35 | printf("found=%d\n", found);
36 |
37 | fjson_object_put(my_object);
38 |
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/tests/test_charcase.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../json_tokener.h"
9 | #include "../debug.h"
10 |
11 | #define CHK(x) if (!(x)) { \
12 | printf("%s:%d: unexpected result with '%s'\n", \
13 | __FILE__, __LINE__, #x); \
14 | exit(1); \
15 | }
16 |
17 | static void test_case_parse(void);
18 |
19 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
20 | {
21 | MC_SET_DEBUG(1);
22 |
23 | test_case_parse();
24 | return 0;
25 | }
26 |
27 | /* make sure only lowercase forms are parsed in strict mode */
28 | static void test_case_parse(void)
29 | {
30 | struct fjson_tokener *tok;
31 | fjson_object *new_obj;
32 |
33 | tok = fjson_tokener_new();
34 | fjson_tokener_set_flags(tok, FJSON_TOKENER_STRICT);
35 |
36 | new_obj = fjson_tokener_parse_ex(tok, "True", 4);
37 | CHK(new_obj == NULL);
38 |
39 | new_obj = fjson_tokener_parse_ex(tok, "False", 5);
40 | CHK(new_obj == NULL);
41 |
42 | new_obj = fjson_tokener_parse_ex(tok, "Null", 4);
43 | CHK(new_obj == NULL);
44 |
45 | printf("OK\n");
46 |
47 | fjson_tokener_free(tok);
48 | }
49 |
--------------------------------------------------------------------------------
/tests/cr_obj_multi.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 |
12 | #include "../json.h"
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | #define NUM_CREATIONS 1000000
19 |
20 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
21 | {
22 | int i;
23 | char pb[64];
24 | struct fjson_object **json = calloc(NUM_CREATIONS, sizeof(struct fjson_object *));
25 |
26 | if(json == NULL) {
27 | perror("malloc ptr table failed:");
28 | exit(1);
29 | }
30 |
31 | for(i = 0 ; i < NUM_CREATIONS ; ++i) {
32 | json[i] = fjson_object_new_object();
33 | //fprintf(stderr, "main: json[%d] %p\n", i, json[i]);
34 | snprintf(pb, sizeof(pb), "%d", i);
35 | fjson_object_object_add(json[i], pb, fjson_object_new_string(pb));
36 |
37 | }
38 |
39 | /* free all objects again */
40 | for(i = 0 ; i < NUM_CREATIONS ; ++i) {
41 | fjson_object_put(json[i]);
42 | }
43 |
44 | free(json);
45 | return 0;
46 | }
47 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 |
2 | EXTRA_DIST = README.html
3 |
4 | SUBDIRS = . tests
5 |
6 | lib_LTLIBRARIES = libfastjson.la
7 | noinst_LTLIBRARIES = libfastjson-internal.la
8 |
9 | pkgconfigdir = $(libdir)/pkgconfig
10 | pkgconfig_DATA = libfastjson.pc
11 |
12 | libfastjsonincludedir = $(includedir)/libfastjson
13 | libfastjsoninclude_HEADERS = \
14 | atomic.h \
15 | json.h \
16 | json_object.h \
17 | json_object_iterator.h \
18 | json_object_private.h \
19 | json_tokener.h \
20 | json_util.h
21 |
22 | libfastjson_la_CFLAGS = $(WARN_CFLAGS)
23 | # info on version-info:
24 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
25 | libfastjson_la_LDFLAGS = \
26 | -version-info 7:0:3 \
27 | -export-symbols-regex '^fjson_.*' \
28 | -no-undefined \
29 | @JSON_BSYMBOLIC_LDFLAGS@
30 | libfastjson_la_LIBADD = libfastjson-internal.la
31 |
32 | libfastjson_la_SOURCES = \
33 | json_version.c \
34 | json_object.c \
35 | json_print.c \
36 | json_object_iterator.c \
37 | json_tokener.c \
38 | json_util.c
39 |
40 | libfastjson_internal_la_CFLAGS = $(WARN_CFLAGS)
41 | libfastjson_internal_la_SOURCES = \
42 | arraylist.h \
43 | arraylist.c \
44 | debug.h \
45 | debug.c \
46 | printbuf.h \
47 | printbuf.c
48 |
49 | ACLOCAL_AMFLAGS = -I m4
50 |
--------------------------------------------------------------------------------
/tests/test_printbuf.expected:
--------------------------------------------------------------------------------
1 | test_basic_printbuf_memset: starting test
2 | Buffer contents:blue:1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3 | test_basic_printbuf_memset: end test
4 | ========================================
5 | test_printbuf_memset_length: starting test
6 | Buffer length: 0
7 | Buffer length: 12
8 | Buffer length: 18
9 | Buffer length: 76
10 | Buffer length: 76
11 | Buffer length: 77
12 | test_printbuf_memset_length: end test
13 | ========================================
14 | test_printbuf_memappend: starting test
15 | Buffer length: 0
16 | Appended 32 bytes for resize: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
17 | Partial append: 3, [blu]
18 | With embedded \0 character: 4, [ab]
19 | Append to just before resize: 31, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
20 | Append to just after resize: 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
21 | test_printbuf_memappend: end test
22 | ========================================
23 | test_sprintbuf: starting test
24 | Buffer length: 0
25 | sprintbuf to just after resize(31+1): 32, [XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX], strlen(buf)=32
26 | 5, [plain]
27 | 6, [plain1]
28 | 16, [plain12147483647]
29 | 27, [plain12147483647-2147483648]
30 | 29, [plain12147483647-2147483648%s]
31 | test_sprintbuf: end test
32 | ========================================
33 |
--------------------------------------------------------------------------------
/tests/test2.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../debug.h"
9 | #include "parse_flags.h"
10 |
11 | #ifdef TEST_FORMATTED
12 | #define fjson_object_to_json_string(obj) fjson_object_to_json_string_ext(obj,sflags)
13 | #else
14 | /* no special define */
15 | #endif
16 |
17 |
18 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
19 | {
20 | fjson_object *new_obj;
21 | #ifdef TEST_FORMATTED
22 | int sflags = 0;
23 | #endif
24 |
25 | MC_SET_DEBUG(1);
26 |
27 | #ifdef TEST_FORMATTED
28 | sflags = parse_flags(argc, argv);
29 | #endif
30 |
31 | new_obj = fjson_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }");
32 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
33 | fjson_object_put(new_obj);
34 |
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/tests/test_parse_int64.expected:
--------------------------------------------------------------------------------
1 | buf=x parseit=1, value=-666
2 | buf=0 parseit=0, value=0
3 | buf=-0 parseit=0, value=0
4 | buf=00000000 parseit=0, value=0
5 | buf=-00000000 parseit=0, value=0
6 | buf=1 parseit=0, value=1
7 | buf=2147483647 parseit=0, value=2147483647
8 | buf=-1 parseit=0, value=-1
9 | buf= -1 parseit=0, value=-1
10 | buf=00001234 parseit=0, value=1234
11 | buf=0001234x parseit=0, value=1234
12 | buf=-00001234 parseit=0, value=-1234
13 | buf=-00001234x parseit=0, value=-1234
14 | buf=21474836470 parseit=0, value=21474836470
15 | buf=31474836470 parseit=0, value=31474836470
16 | buf=-2147483647 parseit=0, value=-2147483647
17 | buf=-2147483648 parseit=0, value=-2147483648
18 | buf=-2147483649 parseit=0, value=-2147483649
19 | buf=-21474836480 parseit=0, value=-21474836480
20 | buf=9223372036854775806 parseit=0, value=9223372036854775806
21 | buf=9223372036854775807 parseit=0, value=9223372036854775807
22 | buf=9223372036854775808 parseit=0, value=9223372036854775807
23 | buf=-9223372036854775808 parseit=0, value=-9223372036854775808
24 | buf=-9223372036854775809 parseit=0, value=-9223372036854775808
25 | buf=18446744073709551614 parseit=0, value=9223372036854775807
26 | buf=18446744073709551615 parseit=0, value=9223372036854775807
27 | buf=123 parseit=0, value=123
28 |
--------------------------------------------------------------------------------
/m4/ax_require_defined.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_REQUIRE_DEFINED(MACRO)
8 | #
9 | # DESCRIPTION
10 | #
11 | # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
12 | # been defined and thus are available for use. This avoids random issues
13 | # where a macro isn't expanded. Instead the configure script emits a
14 | # non-fatal:
15 | #
16 | # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
17 | #
18 | # It's like AC_REQUIRE except it doesn't expand the required macro.
19 | #
20 | # Here's an example:
21 | #
22 | # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
23 | #
24 | # LICENSE
25 | #
26 | # Copyright (c) 2014 Mike Frysinger
27 | #
28 | # Copying and distribution of this file, with or without modification, are
29 | # permitted in any medium without royalty provided the copyright notice
30 | # and this notice are preserved. This file is offered as-is, without any
31 | # warranty.
32 |
33 | #serial 1
34 |
35 | AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
36 | m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
37 | ])dnl AX_REQUIRE_DEFINED
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.swp
3 | *.swo
4 | *.tar.gz
5 | callgrind.out.*
6 | tmp
7 | libfastjson-internal.la
8 | /INSTALL
9 | .dirstamp
10 | .deps/
11 | .libs/
12 | /aclocal.m4
13 | /autom4te.cache
14 | m4/libtool.m4
15 | m4/ltoptions.m4
16 | m4/ltsugar.m4
17 | m4/ltversion.m4
18 | m4/lt~obsolete.m4
19 | /config.guess
20 | /json_config.h
21 | /compile
22 | /config.h
23 | /config.h.in
24 | /config.log
25 | /config.status
26 | /config.sub
27 | /configure
28 | /depcomp
29 | /doc
30 | /install-sh
31 | /libfastjson.pc
32 | /libfastjson-uninstalled.pc
33 | /libtool
34 | /ltmain.sh
35 | /Makefile
36 | /Makefile.in
37 | /missing
38 | /stamp-h1
39 | /stamp-h2
40 | /test-driver
41 | /tests/Makefile
42 | /tests/Makefile.in
43 | /tests/test1
44 | /tests/test1Formatted
45 | /tests/test2
46 | /tests/test2Formatted
47 | /tests/test4
48 | /tests/testReplaceExisting
49 | /tests/testSubDir
50 | /tests/test_parse_int64
51 | /tests/test_parse
52 | /tests/test_cast
53 | /tests/test_charcase
54 | /tests/test_locale
55 | /tests/test_null
56 | /tests/test_printbuf
57 | /tests/test_set_serializer
58 | /tests/test_object_object_add_ex
59 | /tests/test_object_object_add_exFormatted
60 | /tests/test_many_subobj
61 | /tests/test_obj_iter-del
62 | /tests/chk_version
63 | /tests/*.vg.out
64 | /tests/*.log
65 | /tests/*.trs
66 | /Debug
67 | /Release
68 | /*/Debug
69 | /*/Release
70 | *.lo
71 | *.o
72 | /libfastjson.la
73 | /libjson.la
74 |
--------------------------------------------------------------------------------
/CI/try_merge.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | oldbranch=`git rev-parse --abbrev-ref HEAD`
3 | git config --global user.email "buildbot@rsyslog.com"
4 | git config --global user.name "buildbot"
5 | git branch -D tmp-CI
6 | git branch tmp-CI
7 | git checkout tmp-CI
8 | git fetch origin
9 | git merge --no-edit origin/master
10 | if [ $? -ne 0 ]; then
11 | echo "======================================================================"
12 | echo "= FAIL: git merge, not doing any tests on the merge result ="
13 | echo "======================================================================"
14 | echo "Note: this is not an error per se, can happen. In this case the user"
15 | echo "must be somewhat more careful when merging."
16 | git merge --abort
17 | git checkout ${oldbranch}
18 | exit 0
19 | fi
20 | echo "======================================================================"
21 | echo "= SUCCESS: git merge; doing some more tests on master+PR ="
22 | echo "======================================================================"
23 | echo "Note: failing tests may not be reproducible if master branch advances."
24 | echo " However, they should not be taken lightly as they point into to"
25 | echo " two conflicting changes to the codebase."
26 |
27 | # from here on, we want to see what's going on and we also want to abort
28 | # on any error.
29 | set -v
30 | set -e
31 |
32 | CI/clang-check-sanitizer.sh
33 |
34 | git checkout ${oldbranch}
35 |
--------------------------------------------------------------------------------
/m4/atomic_operations.m4:
--------------------------------------------------------------------------------
1 | # rsyslog
2 | #
3 | # atomic_operations.m4 - autoconf macro to check if compiler supports atomic
4 | # operations
5 | #
6 | # rgerhards, 2008-09-18, added based on
7 | # http://svn.apache.org/repos/asf/apr/apr/trunk/configure.in
8 | #
9 | #
10 | AC_DEFUN([RS_ATOMIC_OPERATIONS],
11 | [AC_CACHE_CHECK([whether the compiler provides atomic builtins], [ap_cv_atomic_builtins],
12 | [AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
13 | unsigned long val = 1010, tmp, *mem = &val;
14 |
15 | if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020)
16 | return 1;
17 |
18 | tmp = val;
19 |
20 | if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010)
21 | return 1;
22 |
23 | if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0)
24 | return 1;
25 |
26 | tmp = 3030;
27 |
28 | if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp)
29 | return 1;
30 |
31 | if (__sync_lock_test_and_set(&val, 4040) != 3030)
32 | return 1;
33 |
34 | mem = &tmp;
35 |
36 | if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp)
37 | return 1;
38 |
39 | __sync_synchronize();
40 |
41 | if (mem != &val)
42 | return 1;
43 |
44 | return 0;
45 | ]])], [ap_cv_atomic_builtins=yes], [ap_cv_atomic_builtins=no])])
46 |
47 | if test "$ap_cv_atomic_builtins" = "yes"; then
48 | AC_DEFINE(HAVE_ATOMIC_BUILTINS, 1, [Define if compiler provides atomic builtins])
49 | fi
50 |
51 | ])
52 |
--------------------------------------------------------------------------------
/arraylist.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | *
5 | * This library is free software; you can redistribute it and/or modify
6 | * it under the terms of the MIT license. See COPYING for details.
7 | *
8 | */
9 |
10 | #ifndef _fj_arraylist_h_
11 | #define _fj_arraylist_h_
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif
16 |
17 | #define ARRAY_LIST_DEFAULT_SIZE 32
18 |
19 | typedef void (array_list_free_fn) (void *data);
20 |
21 | struct array_list
22 | {
23 | void **array;
24 | int length;
25 | int size;
26 | array_list_free_fn *free_fn;
27 | };
28 |
29 | extern struct array_list*
30 | array_list_new(array_list_free_fn *free_fn);
31 |
32 | extern void
33 | array_list_free(struct array_list *al);
34 |
35 | extern void*
36 | array_list_get_idx(struct array_list *al, int i);
37 |
38 | extern int
39 | array_list_put_idx(struct array_list *al, int i, void *data);
40 |
41 | extern int
42 | array_list_add(struct array_list *al, void *data);
43 |
44 | extern void
45 | array_list_del_idx(struct array_list *const arr, const int idx);
46 |
47 | extern int
48 | array_list_length(struct array_list *al);
49 |
50 | extern void
51 | array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *));
52 |
53 | extern void* array_list_bsearch(const void **key,
54 | struct array_list *arr,
55 | int (*sort_fn)(const void *, const void *));
56 |
57 |
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/json_util.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | *
5 | * This library is free software; you can redistribute it and/or modify
6 | * it under the terms of the MIT license. See COPYING for details.
7 | *
8 | */
9 |
10 | #ifndef _fj_json_util_h_
11 | #define _fj_json_util_h_
12 |
13 | #include "json_object.h"
14 |
15 | #ifndef fjson_min
16 | #define fjson_min(a,b) ((a) < (b) ? (a) : (b))
17 | #endif
18 |
19 | #ifndef fjson_max
20 | #define fjson_max(a,b) ((a) > (b) ? (a) : (b))
21 | #endif
22 |
23 |
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | #define FJSON_FILE_BUF_SIZE 4096
29 |
30 | /* utility functions */
31 | extern struct fjson_object* fjson_object_from_file(const char *filename);
32 | extern struct fjson_object* fjson_object_from_fd(int fd);
33 | extern int fjson_object_to_file(const char *filename, struct fjson_object *obj);
34 | extern int fjson_object_to_file_ext(const char *filename, struct fjson_object *obj, int flags);
35 | extern int fjson_parse_int64(const char *buf, int64_t *retval);
36 | extern int fjson_parse_double(const char *buf, double *retval);
37 |
38 | /**
39 | * Return a string describing the type of the object.
40 | * e.g. "int", or "object", etc...
41 | */
42 | extern const char *fjson_type_to_name(enum fjson_type o_type);
43 |
44 | #ifndef FJSON_NATIVE_API_ONLY
45 | #define json_type_to_name fjson_type_to_name
46 | #endif
47 |
48 | #ifdef __cplusplus
49 | }
50 | #endif
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/m4/atomic_operations_64bit.m4:
--------------------------------------------------------------------------------
1 | # rsyslog
2 | #
3 | # atomic_operations.m4 - autoconf macro to check if compiler supports atomic
4 | # operations
5 | #
6 | # rgerhards, 2008-09-18, added based on
7 | # http://svn.apache.org/repos/asf/apr/apr/trunk/configure.in
8 | #
9 | #
10 | AC_DEFUN([RS_ATOMIC_OPERATIONS_64BIT],
11 | [AC_CACHE_CHECK([whether the compiler provides atomic builtins for 64 bit data types], [ap_cv_atomic_builtins_64],
12 | [AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
13 | unsigned long long val = 1010, tmp, *mem = &val;
14 |
15 | if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020)
16 | return 1;
17 |
18 | tmp = val;
19 |
20 | if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010)
21 | return 1;
22 |
23 | if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0)
24 | return 1;
25 |
26 | tmp = 3030;
27 |
28 | if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp)
29 | return 1;
30 |
31 | if (__sync_lock_test_and_set(&val, 4040) != 3030)
32 | return 1;
33 |
34 | mem = &tmp;
35 |
36 | if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp)
37 | return 1;
38 |
39 | __sync_synchronize();
40 |
41 | if (mem != &val)
42 | return 1;
43 |
44 | return 0;
45 | ]])], [ap_cv_atomic_builtins_64=yes], [ap_cv_atomic_builtins_64=no])])
46 |
47 | if test "$ap_cv_atomic_builtins_64" = "yes"; then
48 | AC_DEFINE(HAVE_ATOMIC_BUILTINS64, 1, [Define if compiler provides 64 bit atomic builtins])
49 | fi
50 |
51 | ])
52 |
--------------------------------------------------------------------------------
/README.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | JSON-C - A JSON implementation in C
5 |
6 |
7 |
8 | JSON-C - A JSON implementation in C
9 |
10 | Overview
11 | JSON-C implements a reference counting object model that allows you to easily
12 | construct JSON objects in C, output them as JSON formatted strings and parse
13 | JSON formatted strings back into the C representation of JSON objects.
14 |
15 | Building
16 | To setup JSON-C to build on your system please run configure and make.
17 |
18 | Documentation
19 | Doxygen generated documentation exists here.
20 |
21 |
22 | git clone https://github.com/json-c/json-c.git
23 |
24 |
25 | Send email to json-c <at> googlegroups <dot> com
26 |
27 |
28 | This program is free software; you can redistribute it and/or modify it under the terms of the MIT License..
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/test4.c:
--------------------------------------------------------------------------------
1 | /*
2 | * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson
3 | */
4 |
5 | #include "config.h"
6 | #include
7 | #include
8 |
9 | /* this is a work-around until we manage to fix configure.ac */
10 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
11 |
12 | #define DEBUG_SEED(s)
13 |
14 | #include "../json_object.h"
15 | #include "../json_tokener.h"
16 |
17 | static void print_hex( const char* s)
18 | {
19 | const char *iter = s;
20 | unsigned char ch;
21 | while ((ch = *iter++) != 0)
22 | {
23 | if( ',' != ch)
24 | printf("%x ", ch);
25 | else
26 | printf( ",");
27 | }
28 | printf("\n");
29 | }
30 |
31 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
32 | {
33 | const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\"";
34 | const char *expected = "\xF0\xA0\x84\xA6,\xF0\xA0\x84\xA7,\xF0\x90\x84\xA6,\xF0\x90\x84\xA7";
35 | struct fjson_object *parse_result = fjson_tokener_parse((char*)input);
36 | const char *unjson = fjson_object_get_string(parse_result);
37 |
38 | printf("input: %s\n", input);
39 |
40 | int strings_match = !strcmp( expected, unjson);
41 | int retval = 0;
42 | if (strings_match)
43 | {
44 | printf("JSON parse result is correct: %s\n", unjson);
45 | printf("PASS\n");
46 | } else {
47 | printf("JSON parse result doesn't match expected string\n");
48 | printf("expected string bytes: ");
49 | print_hex( expected);
50 | printf("parsed string bytes: ");
51 | print_hex( unjson);
52 | printf("FAIL\n");
53 | retval = 1;
54 | }
55 | fjson_object_put(parse_result);
56 | return retval;
57 | }
58 |
--------------------------------------------------------------------------------
/tests/test_null.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tests if binary strings are supported.
3 | */
4 |
5 | #include "config.h"
6 | #include
7 | #include
8 |
9 | #include "json_inttypes.h"
10 | #include "json_object.h"
11 | #include "json_tokener.h"
12 |
13 | int main()
14 | {
15 | // this test has a space after the null character. check that it's still included
16 | const char *input = " \0 ";
17 | const char *expected = "\" \\u0000 \"";
18 | struct fjson_object *string = fjson_object_new_string_len(input, 3);
19 | const char *json = fjson_object_to_json_string(string);
20 |
21 | int strings_match = !strcmp( expected, json);
22 | int retval = 0;
23 | if (strings_match)
24 | {
25 | printf("JSON write result is correct: %s\n", json);
26 | printf("PASS\n");
27 | } else {
28 | printf("JSON write result doesn't match expected string\n");
29 | printf("expected string: ");
30 | printf("%s\n", expected);
31 | printf("parsed string: ");
32 | printf("%s\n", json);
33 | printf("FAIL\n");
34 | retval=1;
35 | }
36 | fjson_object_put(string);
37 |
38 | struct fjson_object *parsed_str = fjson_tokener_parse(expected);
39 | if (parsed_str)
40 | {
41 | int parsed_len = fjson_object_get_string_len(parsed_str);
42 | const char *parsed_cstr = fjson_object_get_string(parsed_str);
43 | int ii;
44 | printf("Re-parsed object string len=%d, chars=[", parsed_len);
45 | for (ii = 0; ii < parsed_len ; ii++)
46 | {
47 | printf("%s%d", (ii ? ", " : ""), (int)parsed_cstr[ii]);
48 | }
49 | printf("]\n");
50 | fjson_object_put(parsed_str);
51 | }
52 | else
53 | {
54 | printf("ERROR: failed to parse\n");
55 | }
56 | return retval;
57 | }
58 |
--------------------------------------------------------------------------------
/debug.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2016 Adiscon GmbH
5 | * Rainer Gerhards
6 | *
7 | * This library is free software; you can redistribute it and/or modify
8 | * it under the terms of the MIT license. See COPYING for details.
9 | *
10 | */
11 |
12 | #include "config.h"
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #if HAVE_SYSLOG_H
20 | # include
21 | #endif /* HAVE_SYSLOG_H */
22 |
23 | #if HAVE_UNISTD_H
24 | # include
25 | #endif /* HAVE_UNISTD_H */
26 |
27 | #if HAVE_SYS_PARAM_H
28 | #include
29 | #endif /* HAVE_SYS_PARAM_H */
30 |
31 | #include "debug.h"
32 |
33 | static int _syslog = 0;
34 | static int _debug = 0;
35 |
36 | void mc_set_debug(int debug) { _debug = debug; }
37 | int mc_get_debug(void) { return _debug; }
38 |
39 | extern void mc_set_syslog(int use_syslog)
40 | {
41 | _syslog = use_syslog;
42 | }
43 |
44 | void mc_debug(const char *msg, ...)
45 | {
46 | va_list ap;
47 | if(_debug) {
48 | va_start(ap, msg);
49 | #if HAVE_VSYSLOG
50 | if(_syslog) {
51 | vsyslog(LOG_DEBUG, msg, ap);
52 | } else
53 | #endif
54 | vprintf(msg, ap);
55 | va_end(ap);
56 | }
57 | }
58 |
59 | void mc_error(const char *msg, ...)
60 | {
61 | va_list ap;
62 | va_start(ap, msg);
63 | #if HAVE_VSYSLOG
64 | if(_syslog) {
65 | vsyslog(LOG_ERR, msg, ap);
66 | } else
67 | #endif
68 | vfprintf(stderr, msg, ap);
69 | va_end(ap);
70 | }
71 |
72 | void mc_info(const char *msg, ...)
73 | {
74 | va_list ap;
75 | va_start(ap, msg);
76 | #if HAVE_VSYSLOG
77 | if(_syslog) {
78 | vsyslog(LOG_INFO, msg, ap);
79 | } else
80 | #endif
81 | vfprintf(stderr, msg, ap);
82 | va_end(ap);
83 | }
84 |
--------------------------------------------------------------------------------
/tests/test_obj_iter-del.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 |
12 | #include "../json.h"
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | /* this is a work-around until we manage to fix configure.ac */
19 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
20 |
21 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
22 | {
23 | struct fjson_object *my_object = fjson_object_new_object();
24 | if (my_object == NULL) {
25 | perror("malloc ptr table failed:");
26 | exit(1);
27 | }
28 |
29 | /* add some keys */
30 | fjson_object_object_add_ex (my_object, "a", fjson_object_new_string("a"), 0);
31 | fjson_object_object_add_ex (my_object, "b", fjson_object_new_string("b"), 0);
32 | fjson_object_object_add_ex (my_object, "c", fjson_object_new_string("c"), 0);
33 | fjson_object_object_add_ex (my_object, "d", fjson_object_new_string("d"), 0);
34 |
35 | /* delete some keys */
36 | fjson_object_object_del (my_object, "a");
37 | fjson_object_object_del (my_object, "c");
38 |
39 | /* check that iteration properly skips the deleted keys */
40 | struct fjson_object_iterator it = fjson_object_iter_begin(my_object);
41 | struct fjson_object_iterator itEnd = fjson_object_iter_end(my_object);
42 | while (!fjson_object_iter_equal (&it, &itEnd)) {
43 | printf("%s: %s\n",
44 | fjson_object_iter_peek_name (&it),
45 | fjson_object_to_json_string (fjson_object_iter_peek_value(&it)));
46 | fjson_object_iter_next (&it);
47 | }
48 |
49 | fjson_object_put (my_object);
50 | return 0;
51 | }
52 |
--------------------------------------------------------------------------------
/debug.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
5 | * Copyright (c) 2016 Adiscon GmbH
6 | * Rainer Gerhards
7 | *
8 | * This library is free software; you can redistribute it and/or modify
9 | * it under the terms of the MIT license. See COPYING for details.
10 | *
11 | */
12 |
13 | #ifndef _FJ_DEBUG_H_
14 | #define _FJ_DEBUG_H_
15 |
16 | #include
17 |
18 | #ifdef __cplusplus
19 | extern "C" {
20 | #endif
21 |
22 | extern void mc_set_debug(int debug);
23 | extern int mc_get_debug(void);
24 |
25 | extern void mc_set_syslog(int syslog);
26 |
27 | extern void mc_debug(const char *msg, ...) __attribute__((format(printf, 1, 2)));
28 | extern void mc_error(const char *msg, ...) __attribute__((format(printf, 1, 2)));
29 | extern void mc_info(const char *msg, ...) __attribute__((format(printf, 1, 2)));
30 |
31 | #ifndef __STRING
32 | #define __STRING(x) #x
33 | #endif
34 |
35 | #ifndef PARSER_BROKEN_FIXED
36 |
37 | #define JASSERT(cond) do {} while(0)
38 |
39 | #else
40 |
41 | #define JASSERT(cond) do { \
42 | if (!(cond)) { \
43 | mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \
44 | *(int *)0 = 1;\
45 | abort(); \
46 | }\
47 | } while(0)
48 |
49 | #endif
50 |
51 | #define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
52 |
53 | #ifdef MC_MAINTAINER_MODE
54 | #define MC_SET_DEBUG(x) mc_set_debug(x)
55 | #define MC_GET_DEBUG() mc_get_debug()
56 | #define MC_SET_SYSLOG(x) mc_set_syslog(x)
57 | #define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
58 | #define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
59 | #else
60 | #define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
61 | #define MC_GET_DEBUG() (0)
62 | #define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
63 | #define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
64 | #define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
65 | #endif
66 |
67 | #ifdef __cplusplus
68 | }
69 | #endif
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | libfastjson
2 | ===========
3 | **NOTE: libfastjson is a fork from json-c, and is currently under development.**
4 |
5 | The aim of this project is **not** to provide a slightly modified clone
6 | of json-c. It's aim is to provide
7 |
8 | * a **small** library with essential json handling functions
9 | * sufficiently good json support (not 100% standards compliant)
10 | * be very fast in processing
11 |
12 | In order to reach these goals, we reduce the features of json-c. For
13 | similarities and differences, see the file DIFFERENCES.
14 |
15 | **IMPORTANT**
16 | The current API is **not** stable and will change until version 1.0.0 is
17 | reached. We plan to reach it by summer 2016 at latest. With 1.0.0, the API
18 | will be stable. Until then, everything may change. Of course, we will not
19 | deliberatly break things but we need freedom to restructure.
20 |
21 |
22 | Building on Unix with `git`, `gcc` and `autotools`
23 | --------------------------------------------------
24 |
25 | Prerequisites:
26 |
27 | - `gcc`, `clang`, or another C compiler
28 | - `libtool`
29 |
30 | If you're not using a release tarball, you'll also need:
31 |
32 | - `autoconf` (`autoreconf`)
33 | - `automake`
34 |
35 | Make sure you have a complete `libtool` install, including `libtoolize`.
36 |
37 | `libfastjson` GitHub repo: https://github.com/rsyslog/libfastjson
38 |
39 | ```bash
40 | $ git clone https://github.com/rsyslog/libfastjson.git
41 | $ cd libfastjson
42 | $ sh autogen.sh
43 | ```
44 |
45 | followed by
46 |
47 | ```bash
48 | $ ./configure
49 | $ make
50 | $ make install
51 | ```
52 |
53 | To build and run the test programs:
54 |
55 | ```bash
56 | $ make check
57 | ```
58 |
59 | Linking to `libfastjson`
60 | ---------------------------
61 |
62 | If your system has `pkgconfig`,
63 | then you can just add this to your `makefile`:
64 |
65 | ```make
66 | CFLAGS += $(shell pkg-config --cflags libfastjson)
67 | LDFLAGS += $(shell pkg-config --libs libfastjson)
68 | ```
69 |
70 | Without `pkgconfig`, you would do something like this:
71 |
72 | ```make
73 | LIBFASTJSON_DIR=/path/to/json_c/install
74 | CFLAGS += -I$(LIBFASTJSON_DIR)/include/libfastjson
75 | LDFLAGS+= -L$(LIBFASTJSON_DIR)/lib -lfastjson
76 | ```
77 |
--------------------------------------------------------------------------------
/tests/test_object_object_add_ex.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include "../json.h"
18 | #include "../debug.h"
19 | #include "parse_flags.h"
20 |
21 | /* this is a work-around until we manage to fix configure.ac */
22 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
23 |
24 | #define DEBUG_SEED(s)
25 |
26 | #ifdef TEST_FORMATTED
27 | #define fjson_object_to_json_string(obj) fjson_object_to_json_string_ext(obj,sflags)
28 | #else
29 | /* no special define */
30 | #endif
31 |
32 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
33 | {
34 | fjson_object *my_object;
35 | #ifdef TEST_FORMATTED
36 | int sflags = 0;
37 | #endif
38 |
39 | MC_SET_DEBUG(1);
40 |
41 | #ifdef TEST_FORMATTED
42 | sflags = parse_flags(argc, argv);
43 | #endif
44 |
45 | my_object = fjson_object_new_object();
46 | fjson_object_object_add_ex(my_object, "abc", fjson_object_new_int(12), 0);
47 | fjson_object_object_add_ex(my_object, "foo", fjson_object_new_string("bar"),
48 | FJSON_OBJECT_ADD_KEY_IS_NEW);
49 | fjson_object_object_add_ex(my_object, "bool0", fjson_object_new_boolean(0),
50 | FJSON_OBJECT_KEY_IS_CONSTANT);
51 | fjson_object_object_add_ex(my_object, "bool1", fjson_object_new_boolean(1),
52 | FJSON_OBJECT_ADD_KEY_IS_NEW | FJSON_OBJECT_KEY_IS_CONSTANT);
53 |
54 | printf("my_object=\n");
55 | struct fjson_object_iterator it = fjson_object_iter_begin(my_object);
56 | struct fjson_object_iterator itEnd = fjson_object_iter_end(my_object);
57 | while (!fjson_object_iter_equal(&it, &itEnd)) {
58 | printf("\t%s: %s\n",
59 | fjson_object_iter_peek_name(&it),
60 | fjson_object_to_json_string(fjson_object_iter_peek_value(&it)));
61 | fjson_object_iter_next(&it);
62 | }
63 |
64 | printf("my_object.to_string()=%s\n", fjson_object_to_json_string(my_object));
65 |
66 | fjson_object_put(my_object);
67 |
68 | return 0;
69 | }
70 |
--------------------------------------------------------------------------------
/DIFFERENCES:
--------------------------------------------------------------------------------
1 | Compatibility Layer
2 | libfastjson offers some limited source code compatiblity to
3 | json-c via preprocessor macros. They are currently primarily
4 | targeted at what the rsyslog family of projects need.
5 | Also, they do not work work properly with ./configure checks.
6 | This is due to the way autotools checks for functions.
7 |
8 | Differences to json-c
9 | ---------------------
10 |
11 | * hash tables are no longer part of the API; we may use them
12 | internally, but we may also use any other data structure. This
13 | is not of concern for the caller.
14 |
15 | * we removed the json_object_object_foreach[C] macros, which
16 | required the caller to known library implementation details.
17 | The same functionality is provided in a clean way via
18 | fjson_object_iter_*()
19 |
20 | * we do NOT handle NUL characters inside strings or names
21 | At the time of fork, json-c did not properly handle this, but
22 | could at least, with tricks, generate outbound json with NUL
23 | in string values. We do not support this.
24 | This also means libfastjson is not 100% JSON compliant. Sorry
25 | for that, but we try to keep things working great in the C
26 | spirit, and that JSON feature simply doesn't play well here.
27 | If you need 100% JSON compliance, look for another library.
28 |
29 | * Windows and Android are not supported. If you want to actively
30 | maintain libfastjson on those platforms, please let us know
31 | and we can work together (a long term commitment) to get this
32 | going again.
33 |
34 | * removed API calls:
35 | If you need any of this API calls urgently, please let us know
36 | why you consider it important enough to become re-added;
37 | especially let us know why you think this is important to the
38 | community at large. Thanks.
39 | * [f]json_c_version_num()
40 | * [f]json_object_get_object()
41 | It returns a hash table, which exposes an implementation detail
42 | that a caller should never know about. Most often, this can cleanly
43 | be replaced by the regular json_object_iter_* API.
44 |
45 | * renamed API calls:
46 | * all calls have been added an "f" in the front
47 | json_* --> fjson_*
48 | * the same holds true for preprocessor defines,
49 | JSON_C_* --> FJSON_* (note removal of "_C")
50 | * json_c_version() -> fjson_version()
51 |
--------------------------------------------------------------------------------
/json_object_private.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2015 Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 |
11 | #ifndef _fj_json_object_private_h_
12 | #define _fj_json_object_private_h_
13 |
14 | #include "atomic.h"
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | /* define a couple of attributes to improve cross-platform builds */
21 | #if __GNUC__ > 6
22 | #define ATTR_FALLTHROUGH __attribute__((fallthrough));
23 | #else
24 | #define ATTR_FALLTHROUGH
25 | #endif
26 |
27 | #define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in fjson_object for strings? */
28 |
29 | /**
30 | * Type of the delete and serialization functions.
31 | */
32 | typedef void (fjson_object_private_delete_fn)(struct fjson_object *o);
33 | typedef int (fjson_object_to_json_string_fn)(struct fjson_object *jso,
34 | struct printbuf *pb,
35 | int level,
36 | int flags);
37 |
38 | struct _fjson_child {
39 | /**
40 | * The key.
41 | */
42 | const char *k;
43 | int k_is_constant;
44 | struct {
45 | unsigned k_is_constant : 1;
46 | } flags;
47 | /**
48 | * The value.
49 | */
50 | struct fjson_object *v;
51 | };
52 |
53 | struct _fjson_child_pg {
54 | struct _fjson_child children[FJSON_OBJECT_CHLD_PG_SIZE];
55 | struct _fjson_child_pg *next;
56 | };
57 |
58 | struct fjson_object
59 | {
60 | enum fjson_type o_type;
61 | fjson_object_private_delete_fn *_delete;
62 | fjson_object_to_json_string_fn *_to_json_string;
63 | int _ref_count;
64 | struct printbuf *_pb;
65 | union data {
66 | fjson_bool c_boolean;
67 | struct {
68 | double value;
69 | char *source;
70 | } c_double;
71 | int64_t c_int64;
72 | struct {
73 | int nelem;
74 | int ndeleted;
75 | struct _fjson_child_pg pg;
76 | struct _fjson_child_pg *lastpg;
77 | } c_obj;
78 | struct array_list *c_array;
79 | struct {
80 | union {
81 | /* optimize: if we have small strings, we can store them
82 | * directly. This saves considerable CPU cycles AND memory.
83 | */
84 | char *ptr;
85 | char data[LEN_DIRECT_STRING_DATA];
86 | } str;
87 | int len;
88 | } c_string;
89 | } o;
90 | DEF_ATOMIC_HELPER_MUT(_mut_ref_count)
91 | };
92 |
93 | #ifdef __cplusplus
94 | }
95 | #endif
96 |
97 | #endif
98 |
--------------------------------------------------------------------------------
/tests/test_many_subobj.c:
--------------------------------------------------------------------------------
1 | /* libfastjson testbench tool
2 | *
3 | * Copyright (c) 2016 Adiscon GmbH
4 | * Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 | #include "config.h"
11 |
12 | #include "../json.h"
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | #define NUM_SUBOBJ 200
19 | #define NUM_SUBOBJ_HALF (NUM_SUBOBJ/2)
20 | #define NUM_SUBOBJ_QUARTER (NUM_SUBOBJ/4)
21 |
22 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
23 | {
24 | int i;
25 | char pb[64];
26 | struct fjson_object *json = fjson_object_new_object();
27 | if (json == NULL) {
28 | perror("malloc ptr table failed:");
29 | exit(1);
30 | }
31 |
32 | /* add some keys */
33 | for (i = 0 ; i < NUM_SUBOBJ ; ++i) {
34 | snprintf(pb, sizeof(pb), "key-%d", i);
35 | fjson_object_object_add_ex(json, pb, fjson_object_new_int(i), 0);
36 |
37 | }
38 | printf("STEP1: %s\n", fjson_object_to_json_string(json));
39 |
40 | /* delete some keys */
41 | for (i = NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
42 | i < NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER ;
43 | ++i) {
44 | snprintf(pb, sizeof(pb), "key-%d", i);
45 | fjson_object_object_del(json, pb);
46 | }
47 | printf("STEP2: %s\n", fjson_object_to_json_string(json));
48 |
49 | /* add new keys */
50 | for (i = NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER - 1;
51 | i >= NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
52 | --i) {
53 | snprintf(pb, sizeof(pb), "KEY-%d", i);
54 | fjson_object_object_add_ex(json, pb, fjson_object_new_int(i), 0);
55 | }
56 | printf("STEP3: %s\n", fjson_object_to_json_string(json));
57 |
58 | /* delete the new keys again, and also update key values */
59 | for (i = NUM_SUBOBJ_HALF - NUM_SUBOBJ_QUARTER ;
60 | i < NUM_SUBOBJ_HALF + NUM_SUBOBJ_QUARTER ;
61 | ++i) {
62 | snprintf(pb, sizeof(pb), "KEY-%d", i);
63 | fjson_object_object_del(json, pb);
64 | }
65 | for (i = 0 ; i < NUM_SUBOBJ ; ++i) {
66 | snprintf(pb, sizeof(pb), "key-%d", i);
67 | fjson_object_object_add_ex(json, pb, fjson_object_new_int(i*10), 0);
68 |
69 | }
70 | printf("STEP4: %s\n", fjson_object_to_json_string(json));
71 |
72 | /* add one more key to see that adding works when extending the array */
73 | snprintf(pb, sizeof(pb), "key-%d", NUM_SUBOBJ);
74 | fjson_object_object_add(json, pb, fjson_object_new_int(NUM_SUBOBJ));
75 | printf("STEP5:%s\n", fjson_object_to_json_string(json));
76 |
77 | fjson_object_put(json);
78 | return 0;
79 | }
80 |
--------------------------------------------------------------------------------
/tests/test_cast.expected:
--------------------------------------------------------------------------------
1 | Parsed input: {
2 | "string_of_digits": "123",
3 | "regular_number": 222,
4 | "decimal_number": 99.55,
5 | "boolean_true": true,
6 | "boolean_false": false,
7 | "big_number": 2147483649,
8 | "a_null": null,
9 | }
10 | Result is not NULL
11 | new_obj.string_of_digits fjson_object_get_type()=string
12 | new_obj.string_of_digits fjson_object_get_int()=123
13 | new_obj.string_of_digits fjson_object_get_int64()=123
14 | new_obj.string_of_digits fjson_object_get_boolean()=1
15 | new_obj.string_of_digits fjson_object_get_double()=123.000000
16 | new_obj.regular_number fjson_object_get_type()=int
17 | new_obj.regular_number fjson_object_get_int()=222
18 | new_obj.regular_number fjson_object_get_int64()=222
19 | new_obj.regular_number fjson_object_get_boolean()=1
20 | new_obj.regular_number fjson_object_get_double()=222.000000
21 | new_obj.decimal_number fjson_object_get_type()=double
22 | new_obj.decimal_number fjson_object_get_int()=99
23 | new_obj.decimal_number fjson_object_get_int64()=99
24 | new_obj.decimal_number fjson_object_get_boolean()=1
25 | new_obj.decimal_number fjson_object_get_double()=99.550000
26 | new_obj.boolean_true fjson_object_get_type()=boolean
27 | new_obj.boolean_true fjson_object_get_int()=1
28 | new_obj.boolean_true fjson_object_get_int64()=1
29 | new_obj.boolean_true fjson_object_get_boolean()=1
30 | new_obj.boolean_true fjson_object_get_double()=1.000000
31 | new_obj.boolean_false fjson_object_get_type()=boolean
32 | new_obj.boolean_false fjson_object_get_int()=0
33 | new_obj.boolean_false fjson_object_get_int64()=0
34 | new_obj.boolean_false fjson_object_get_boolean()=0
35 | new_obj.boolean_false fjson_object_get_double()=0.000000
36 | new_obj.big_number fjson_object_get_type()=int
37 | new_obj.big_number fjson_object_get_int()=2147483647
38 | new_obj.big_number fjson_object_get_int64()=2147483649
39 | new_obj.big_number fjson_object_get_boolean()=1
40 | new_obj.big_number fjson_object_get_double()=2147483649.000000
41 | new_obj.a_null fjson_object_get_type()=null
42 | new_obj.a_null fjson_object_get_int()=0
43 | new_obj.a_null fjson_object_get_int64()=0
44 | new_obj.a_null fjson_object_get_boolean()=0
45 | new_obj.a_null fjson_object_get_double()=0.000000
46 |
47 | ================================
48 | fjson_object_is_type: null,boolean,double,int,object,array,string
49 | new_obj : 0,0,0,0,1,0,0
50 | new_obj.string_of_digits : 0,0,0,0,0,0,1
51 | new_obj.regular_number : 0,0,0,1,0,0,0
52 | new_obj.decimal_number : 0,0,1,0,0,0,0
53 | new_obj.boolean_true : 0,1,0,0,0,0,0
54 | new_obj.boolean_false : 0,1,0,0,0,0,0
55 | new_obj.big_number : 0,0,0,1,0,0,0
56 | new_obj.a_null : 1,0,0,0,0,0,0
57 |
--------------------------------------------------------------------------------
/tests/test_parse_int64.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 |
6 | #include "../json_util.h"
7 |
8 | static void checkit(const char *buf)
9 | {
10 | int64_t cint64 = -666;
11 |
12 | int retval = fjson_parse_int64(buf, &cint64);
13 | printf("buf=%s parseit=%d, value=%" PRId64 " \n", buf, retval, cint64);
14 | }
15 |
16 | /**
17 | * This test calls fjson_parse_int64 with a variety of different strings.
18 | * It's purpose is to ensure that the results are consistent across all
19 | * different environments that it might be executed in.
20 | *
21 | * This always exits with a 0 exit value. The output should be compared
22 | * against previously saved expected output.
23 | */
24 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
25 | {
26 | char buf[100];
27 |
28 | checkit("x");
29 |
30 | checkit("0");
31 | checkit("-0");
32 |
33 | checkit("00000000");
34 | checkit("-00000000");
35 |
36 | checkit("1");
37 |
38 | strcpy(buf, "2147483647"); // aka INT32_MAX
39 | checkit(buf);
40 |
41 | strcpy(buf, "-1");
42 | checkit(buf);
43 |
44 | strcpy(buf, " -1");
45 | checkit(buf);
46 |
47 | strcpy(buf, "00001234");
48 | checkit(buf);
49 |
50 | strcpy(buf, "0001234x");
51 | checkit(buf);
52 |
53 | strcpy(buf, "-00001234");
54 | checkit(buf);
55 |
56 | strcpy(buf, "-00001234x");
57 | checkit(buf);
58 |
59 | strcpy(buf, "4294967295"); // aka UINT32_MAX
60 |
61 | sprintf(buf, "4294967296"); // aka UINT32_MAX + 1
62 |
63 | strcpy(buf, "21474836470"); // INT32_MAX * 10
64 | checkit(buf);
65 |
66 | strcpy(buf, "31474836470"); // INT32_MAX * 10 + a bunch
67 | checkit(buf);
68 |
69 | strcpy(buf, "-2147483647"); // INT32_MIN + 1
70 | checkit(buf);
71 |
72 | strcpy(buf, "-2147483648"); // INT32_MIN
73 | checkit(buf);
74 |
75 | strcpy(buf, "-2147483649"); // INT32_MIN - 1
76 | checkit(buf);
77 |
78 | strcpy(buf, "-21474836480"); // INT32_MIN * 10
79 | checkit(buf);
80 |
81 | strcpy(buf, "9223372036854775806"); // INT64_MAX - 1
82 | checkit(buf);
83 |
84 | strcpy(buf, "9223372036854775807"); // INT64_MAX
85 | checkit(buf);
86 |
87 | strcpy(buf, "9223372036854775808"); // INT64_MAX + 1
88 | checkit(buf);
89 |
90 | strcpy(buf, "-9223372036854775808"); // INT64_MIN
91 | checkit(buf);
92 |
93 | strcpy(buf, "-9223372036854775809"); // INT64_MIN - 1
94 | checkit(buf);
95 |
96 | strcpy(buf, "18446744073709551614"); // UINT64_MAX - 1
97 | checkit(buf);
98 |
99 | strcpy(buf, "18446744073709551615"); // UINT64_MAX
100 | checkit(buf);
101 |
102 | // Ensure we can still parse valid numbers after parsing out of range ones.
103 | strcpy(buf, "123");
104 | checkit(buf);
105 |
106 | return 0;
107 | }
108 |
--------------------------------------------------------------------------------
/printbuf.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | *
5 | * This library is free software; you can redistribute it and/or modify
6 | * it under the terms of the MIT license. See COPYING for details.
7 | *
8 | *
9 | * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
10 | * The copyrights to the contents of this file are licensed under the MIT License
11 | * (http://www.opensource.org/licenses/mit-license.php)
12 | */
13 |
14 | #ifndef _fj_printbuf_h_
15 | #define _fj_printbuf_h_
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | struct printbuf {
22 | char *buf;
23 | int bpos;
24 | int size;
25 | };
26 |
27 | extern struct printbuf*
28 | printbuf_new(void);
29 |
30 | /* As an optimization, printbuf_memappend_fast is defined as a macro
31 | * that handles copying data if the buffer is large enough; otherwise
32 | * it invokes printbuf_memappend_real() which performs the heavy
33 | * lifting of realloc()ing the buffer and copying data.
34 | * Your code should not use printbuf_memappend directly--use
35 | * printbuf_memappend_fast instead.
36 | */
37 | extern int
38 | printbuf_memappend(struct printbuf *p, const char *buf, int size);
39 |
40 | #define printbuf_memappend_fast(p, bufptr, bufsize) \
41 | do { \
42 | if ((p->size - p->bpos) > bufsize) { \
43 | memcpy(p->buf + p->bpos, (bufptr), bufsize); \
44 | p->bpos += bufsize; \
45 | p->buf[p->bpos]= '\0'; \
46 | } else { printbuf_memappend(p, (bufptr), bufsize); }\
47 | } while (0)
48 |
49 | /* The following functions provide a printbuf interface where the
50 | * string terminator '\0' is not always written. This is faster, but
51 | * the string cannot be used with standard functions while being
52 | * constructed. To do so, printbuf_terminate_string() must be
53 | * called first.
54 | */
55 | void printbuf_memappend_no_nul(struct printbuf *p, const char *buf, int size);
56 | void printbuf_memappend_char(struct printbuf *p, const char c);
57 | void printbuf_terminate_string(struct printbuf *const p);
58 |
59 | #define printbuf_length(p) ((p)->bpos)
60 |
61 | /**
62 | * Set len bytes of the buffer to charvalue, starting at offset offset.
63 | * Similar to calling memset(x, charvalue, len);
64 | *
65 | * The memory allocated for the buffer is extended as necessary.
66 | *
67 | * If offset is -1, this starts at the end of the current data in the buffer.
68 | */
69 | extern int
70 | printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len);
71 |
72 | extern int
73 | sprintbuf(struct printbuf *p, const char *msg, ...) __attribute__((__format__(__printf__, 2, 3)));
74 |
75 | extern void
76 | printbuf_reset(struct printbuf *p);
77 |
78 | extern void
79 | printbuf_free(struct printbuf *p);
80 | #ifdef __cplusplus
81 | }
82 | #endif
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/json.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
5 | * Copyright (c) 2016 Adiscon GmbH
6 | * Rainer Gerhards
7 | *
8 | * This library is free software; you can redistribute it and/or modify
9 | * it under the terms of the MIT license. See COPYING for details.
10 | *
11 | */
12 |
13 | #ifndef _fj_json_h_
14 | #define _fj_json_h_
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | #include "json_util.h"
21 | #include "json_object.h"
22 | #include "json_tokener.h"
23 | #include "json_object_iterator.h"
24 |
25 | /**
26 | * Set initial size allocation for memory when creating strings,
27 | * as is done for example in fjson_object_to_json_string(). The
28 | * default size is 32, which is very conservative. If an app
29 | * knows it typically deals with larger strings, performance
30 | * can be improved by setting the initial size to a different
31 | * number, e.g. 1k. Note that this also means that memory
32 | * consumption can increase. How far entriely depens on the
33 | * application and its use of json-c.
34 | *
35 | * Note: each time this function is called, the initial size is
36 | * changed to the given value. Already existing elements are not
37 | * affected. This function is usually meant to be called just once
38 | * at start of an application, but there is no harm calling it more
39 | * than once. Note that the function is NOT thread-safe and must not
40 | * be called on different threads concurrently.
41 | *
42 | * @param size new initial size for printbuf (formatting buffer)
43 | */
44 | extern void fjson_global_set_printbuf_initial_size(int size);
45 |
46 | /**
47 | * Set case sensitive/insensitive comparison mode. If set to 0,
48 | * comparisons for JSON keys will be case-insensitive. Otherwise,
49 | * they will be case-sensitive.
50 | * NOTE: the JSON standard demands case sensitivity. By turning
51 | * this off, the JSON standard is not obeyed. Most importantly,
52 | * if keys exists which only differ in case, only partial data
53 | * access is possible. So use with care and only if you know
54 | * exactly what you are doing!
55 | */
56 | extern void fjson_global_do_case_sensitive_comparison(const int newval);
57 |
58 | /**
59 | * report the current libfastjson version
60 | */
61 | extern const char *fjson_version(void);
62 |
63 | /**
64 | * default string hash function
65 | */
66 | #define FJSON_STR_HASH_DFLT 0
67 |
68 | /**
69 | * perl-like string hash function
70 | */
71 | #define FJSON_STR_HASH_PERLLIKE 1
72 |
73 | #ifndef FJSON_NATIVE_API_ONLY
74 | #define JSON_C_STR_HASH_PERLLIKE FJSON_STR_HASH_PERLLIKE
75 | #define json_global_set_string_hash(x) /**<< no longer exists nor is needed */
76 | #define fjson_global_set_string_hash(x) /**<< no longer exists nor is needed */
77 | #endif
78 |
79 | #ifdef __cplusplus
80 | }
81 | #endif
82 |
83 | #endif
84 |
--------------------------------------------------------------------------------
/m4/ax_append_flag.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
8 | #
9 | # DESCRIPTION
10 | #
11 | # FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
12 | # added in between.
13 | #
14 | # If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
15 | # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
16 | # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
17 | # FLAG.
18 | #
19 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
20 | #
21 | # LICENSE
22 | #
23 | # Copyright (c) 2008 Guido U. Draheim
24 | # Copyright (c) 2011 Maarten Bosmans
25 | #
26 | # This program is free software: you can redistribute it and/or modify it
27 | # under the terms of the GNU General Public License as published by the
28 | # Free Software Foundation, either version 3 of the License, or (at your
29 | # option) any later version.
30 | #
31 | # This program is distributed in the hope that it will be useful, but
32 | # WITHOUT ANY WARRANTY; without even the implied warranty of
33 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
34 | # Public License for more details.
35 | #
36 | # You should have received a copy of the GNU General Public License along
37 | # with this program. If not, see .
38 | #
39 | # As a special exception, the respective Autoconf Macro's copyright owner
40 | # gives unlimited permission to copy, distribute and modify the configure
41 | # scripts that are the output of Autoconf when processing the Macro. You
42 | # need not follow the terms of the GNU General Public License when using
43 | # or distributing such scripts, even though portions of the text of the
44 | # Macro appear in them. The GNU General Public License (GPL) does govern
45 | # all other use of the material that constitutes the Autoconf Macro.
46 | #
47 | # This special exception to the GPL applies to versions of the Autoconf
48 | # Macro released by the Autoconf Archive. When you make and distribute a
49 | # modified version of the Autoconf Macro, you may extend this special
50 | # exception to the GPL to apply to your modified version as well.
51 |
52 | #serial 6
53 |
54 | AC_DEFUN([AX_APPEND_FLAG],
55 | [dnl
56 | AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
57 | AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
58 | AS_VAR_SET_IF(FLAGS,[
59 | AS_CASE([" AS_VAR_GET(FLAGS) "],
60 | [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
61 | [
62 | AS_VAR_APPEND(FLAGS,[" $1"])
63 | AC_RUN_LOG([: FLAGS="$FLAGS"])
64 | ])
65 | ],
66 | [
67 | AS_VAR_SET(FLAGS,[$1])
68 | AC_RUN_LOG([: FLAGS="$FLAGS"])
69 | ])
70 | AS_VAR_POPDEF([FLAGS])dnl
71 | ])dnl AX_APPEND_FLAG
72 |
--------------------------------------------------------------------------------
/m4/ax_append_compile_flags.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
8 | #
9 | # DESCRIPTION
10 | #
11 | # For every FLAG1, FLAG2 it is checked whether the compiler works with the
12 | # flag. If it does, the flag is added FLAGS-VARIABLE
13 | #
14 | # If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
15 | # CFLAGS) is used. During the check the flag is always added to the
16 | # current language's flags.
17 | #
18 | # If EXTRA-FLAGS is defined, it is added to the current language's default
19 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with
20 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
21 | # force the compiler to issue an error when a bad flag is given.
22 | #
23 | # NOTE: This macro depends on the AX_APPEND_FLAG and
24 | # AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
25 | # AX_APPEND_LINK_FLAGS.
26 | #
27 | # LICENSE
28 | #
29 | # Copyright (c) 2011 Maarten Bosmans
30 | #
31 | # This program is free software: you can redistribute it and/or modify it
32 | # under the terms of the GNU General Public License as published by the
33 | # Free Software Foundation, either version 3 of the License, or (at your
34 | # option) any later version.
35 | #
36 | # This program is distributed in the hope that it will be useful, but
37 | # WITHOUT ANY WARRANTY; without even the implied warranty of
38 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
39 | # Public License for more details.
40 | #
41 | # You should have received a copy of the GNU General Public License along
42 | # with this program. If not, see .
43 | #
44 | # As a special exception, the respective Autoconf Macro's copyright owner
45 | # gives unlimited permission to copy, distribute and modify the configure
46 | # scripts that are the output of Autoconf when processing the Macro. You
47 | # need not follow the terms of the GNU General Public License when using
48 | # or distributing such scripts, even though portions of the text of the
49 | # Macro appear in them. The GNU General Public License (GPL) does govern
50 | # all other use of the material that constitutes the Autoconf Macro.
51 | #
52 | # This special exception to the GPL applies to versions of the Autoconf
53 | # Macro released by the Autoconf Archive. When you make and distribute a
54 | # modified version of the Autoconf Macro, you may extend this special
55 | # exception to the GPL to apply to your modified version as well.
56 |
57 | #serial 4
58 |
59 | AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
60 | [AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
61 | AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
62 | for flag in $1; do
63 | AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
64 | done
65 | ])dnl AX_APPEND_COMPILE_FLAGS
66 |
--------------------------------------------------------------------------------
/tests/Makefile.am:
--------------------------------------------------------------------------------
1 | export VALGRIND=@VALGRIND@
2 | LDADD = $(top_builddir)/libfastjson.la \
3 | $(top_builddir)/libfastjson-internal.la
4 |
5 | AM_CFLAGS = $(WARN_CFLAGS)
6 |
7 | TESTS=
8 | TESTS+= ucs_copyright_char.test
9 | TESTS+= test_float.test
10 | TESTS+= test1.test
11 | TESTS+= test2.test
12 | TESTS+= test4.test
13 | TESTS+= testReplaceExisting.test
14 | TESTS+= test_parse_int64.test
15 | TESTS+= test_cast.test
16 | TESTS+= test_parse.test
17 | TESTS+= test_locale.test
18 | TESTS+= test_charcase.test
19 | TESTS+= test_printbuf.test
20 | TESTS+= test_obj_iter-del.test
21 | TESTS+= test_object_object_add_ex.test
22 | TESTS+= test_many_subobj.test
23 | TESTS+= test_obj_obj_get_ex-null.test
24 | # we officially do NOT support NUL bytes (however, we may
25 | # later add a workaround to at least transparently pass them
26 | # through, thus I keep this as reference).
27 | #TESTS+= test_null.test
28 |
29 | check_PROGRAMS=
30 | check_PROGRAMS += $(TESTS:.test=)
31 |
32 | # some programs that do internal checking
33 | check_PROGRAMS += chk_version \
34 | cr_obj_multi
35 |
36 | TESTS += chk_version
37 |
38 | check_PROGRAMS += chk_version \
39 | cr_obj_multi
40 |
41 | cr_obj_multi_SOURCES = cr_obj_multi.c
42 | chk_version_SOURCES = chk_version.c
43 |
44 | test_printbuf_SOURCES = test_printbuf.c
45 |
46 | # Note: handled by test1.test
47 | check_PROGRAMS += test1Formatted
48 | test1Formatted_SOURCES = test1.c parse_flags.c parse_flags.h
49 | test1Formatted_CPPFLAGS = -DTEST_FORMATTED
50 |
51 | # Note: handled by test2.test
52 | check_PROGRAMS += test2Formatted
53 | test2Formatted_SOURCES = test2.c parse_flags.c parse_flags.h
54 | test2Formatted_CPPFLAGS = -DTEST_FORMATTED
55 |
56 | # Note: handled by object_object_add_ex.test
57 | check_PROGRAMS += test_object_object_add_exFormatted
58 | test_object_object_add_exFormatted_SOURCES = test_object_object_add_ex.c parse_flags.c parse_flags.h
59 | test_object_object_add_exFormatted_CPPFLAGS = -DTEST_FORMATTED
60 |
61 | EXTRA_DIST=
62 | EXTRA_DIST += $(TESTS)
63 | EXTRA_DIST += test-defs.sh
64 | EXTRA_DIST += test1.expected
65 | EXTRA_DIST += test1Formatted_plain.expected
66 | EXTRA_DIST += test1Formatted_pretty.expected
67 | EXTRA_DIST += test1Formatted_spaced.expected
68 | EXTRA_DIST += test2.expected
69 | EXTRA_DIST += test2Formatted_plain.expected
70 | EXTRA_DIST += test2Formatted_pretty.expected
71 | EXTRA_DIST += test2Formatted_spaced.expected
72 | EXTRA_DIST += test4.expected
73 | EXTRA_DIST += ucs_copyright_char.expected
74 | EXTRA_DIST += test_float.expected
75 | EXTRA_DIST += test_cast.expected
76 | EXTRA_DIST += test_charcase.expected
77 | EXTRA_DIST += test_locale.expected
78 | EXTRA_DIST += test_null.expected
79 | EXTRA_DIST += test_parse.expected
80 | EXTRA_DIST += test_parse_int64.expected
81 | EXTRA_DIST += test_printbuf.expected
82 | EXTRA_DIST += testReplaceExisting.expected
83 | EXTRA_DIST += test_obj_iter-del.expected
84 | EXTRA_DIST += test_object_object_add_ex.expected
85 | EXTRA_DIST += test_object_object_add_exFormatted_plain.expected
86 | EXTRA_DIST += test_object_object_add_exFormatted_pretty.expected
87 | EXTRA_DIST += test_object_object_add_exFormatted_spaced.expected
88 | EXTRA_DIST += test_many_subobj.expected
89 | EXTRA_DIST += test_obj_obj_get_ex-null.expected
90 |
91 | testsubdir=testSubDir
92 | TESTS_ENVIRONMENT = top_builddir=$(top_builddir)
93 |
--------------------------------------------------------------------------------
/tests/testReplaceExisting.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../debug.h"
9 |
10 | /* this is a work-around until we manage to fix configure.ac */
11 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
12 |
13 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
14 | {
15 | struct fjson_object_iterator it;
16 | struct fjson_object_iterator itEnd;
17 | const char *key;
18 | MC_SET_DEBUG(1);
19 |
20 | /*
21 | * Check that replacing an existing object keeps the key valid,
22 | * and that it keeps the order the same.
23 | */
24 | fjson_object *my_object = fjson_object_new_object();
25 | fjson_object_object_add(my_object, "foo1", fjson_object_new_string("bar1"));
26 | fjson_object_object_add(my_object, "foo2", fjson_object_new_string("bar2"));
27 | fjson_object_object_add(my_object, "deleteme", fjson_object_new_string("bar2"));
28 | fjson_object_object_add(my_object, "foo3", fjson_object_new_string("bar3"));
29 |
30 | printf("==== delete-in-loop test starting ====\n");
31 |
32 | int orig_count = 0;
33 | itEnd = fjson_object_iter_end(my_object);
34 | it = fjson_object_iter_begin(my_object);
35 | while (!fjson_object_iter_equal(&it, &itEnd)) {
36 | key = fjson_object_iter_peek_name(&it);
37 | printf("Key at index %d is [%s]", orig_count, key);
38 | /* need to advance now, as del invalidates "it" */
39 | fjson_object_iter_next(&it);
40 | if (strcmp(key, "deleteme") == 0) {
41 | fjson_object_object_del(my_object, key);
42 | printf(" (deleted)\n");
43 | } else {
44 | printf(" (kept)\n");
45 | }
46 | orig_count++;
47 | }
48 |
49 | printf("==== replace-value first loop starting ====\n");
50 |
51 | const char *original_key = NULL;
52 | orig_count = 0;
53 | itEnd = fjson_object_iter_end(my_object);
54 | it = fjson_object_iter_begin(my_object);
55 | while (!fjson_object_iter_equal(&it, &itEnd)) {
56 | key = fjson_object_iter_peek_name(&it);
57 | /* need to advance now, as modify invalidates "it" */
58 | fjson_object_iter_next(&it);
59 | printf("Key at index %d is [%s]\n", orig_count, key);
60 | orig_count++;
61 | if (strcmp(key, "foo2") != 0)
62 | continue;
63 | printf("replacing value for key [%s]\n", key);
64 | original_key = key;
65 | fjson_object_object_add(my_object, key, fjson_object_new_string("zzz"));
66 | }
67 |
68 | printf("==== second loop starting ====\n");
69 |
70 | int new_count = 0;
71 | int retval = 0;
72 | itEnd = fjson_object_iter_end(my_object);
73 | it = fjson_object_iter_begin(my_object);
74 | while (!fjson_object_iter_equal(&it, &itEnd)) {
75 | key = fjson_object_iter_peek_name(&it);
76 | /* need to advance now, as modify invalidates "it" */
77 | fjson_object_iter_next(&it);
78 | printf("Key at index %d is [%s]\n", new_count, key);
79 | new_count++;
80 | if (strcmp(key, "foo2") != 0)
81 | continue;
82 | printf("pointer for key [%s] does %smatch\n", key,
83 | (key == original_key) ? "" : "NOT ");
84 | if (key != original_key)
85 | retval = 1;
86 | }
87 | if (new_count != orig_count)
88 | {
89 | printf("mismatch between original count (%d) and new count (%d)\n",
90 | orig_count, new_count);
91 | retval = 1;
92 | }
93 |
94 | fjson_object_put( my_object );
95 |
96 | return retval;
97 | }
98 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 |
2 | Copyright (c) 2015 Rainer Gerhards
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a
5 | copy of this software and associated documentation files (the "Software"),
6 | to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 | and/or sell copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included
12 | in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
22 | ----------------------------------------------------------------
23 |
24 | Copyright (c) 2009-2012 Eric Haszlakiewicz
25 |
26 | Permission is hereby granted, free of charge, to any person obtaining a
27 | copy of this software and associated documentation files (the "Software"),
28 | to deal in the Software without restriction, including without limitation
29 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
30 | and/or sell copies of the Software, and to permit persons to whom the
31 | Software is furnished to do so, subject to the following conditions:
32 |
33 | The above copyright notice and this permission notice shall be included
34 | in all copies or substantial portions of the Software.
35 |
36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42 | SOFTWARE.
43 |
44 | ----------------------------------------------------------------
45 |
46 | Copyright (c) 2004, 2005 Metaparadigm Pte Ltd
47 |
48 | Permission is hereby granted, free of charge, to any person obtaining a
49 | copy of this software and associated documentation files (the "Software"),
50 | to deal in the Software without restriction, including without limitation
51 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
52 | and/or sell copies of the Software, and to permit persons to whom the
53 | Software is furnished to do so, subject to the following conditions:
54 |
55 | The above copyright notice and this permission notice shall be included
56 | in all copies or substantial portions of the Software.
57 |
58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
64 | SOFTWARE.
65 |
--------------------------------------------------------------------------------
/m4/ax_check_compile_flag.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
8 | #
9 | # DESCRIPTION
10 | #
11 | # Check whether the given FLAG works with the current language's compiler
12 | # or gives an error. (Warnings, however, are ignored)
13 | #
14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
15 | # success/failure.
16 | #
17 | # If EXTRA-FLAGS is defined, it is added to the current language's default
18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with
19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
20 | # force the compiler to issue an error when a bad flag is given.
21 | #
22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE.
23 | #
24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
26 | #
27 | # LICENSE
28 | #
29 | # Copyright (c) 2008 Guido U. Draheim
30 | # Copyright (c) 2011 Maarten Bosmans
31 | #
32 | # This program is free software: you can redistribute it and/or modify it
33 | # under the terms of the GNU General Public License as published by the
34 | # Free Software Foundation, either version 3 of the License, or (at your
35 | # option) any later version.
36 | #
37 | # This program is distributed in the hope that it will be useful, but
38 | # WITHOUT ANY WARRANTY; without even the implied warranty of
39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
40 | # Public License for more details.
41 | #
42 | # You should have received a copy of the GNU General Public License along
43 | # with this program. If not, see .
44 | #
45 | # As a special exception, the respective Autoconf Macro's copyright owner
46 | # gives unlimited permission to copy, distribute and modify the configure
47 | # scripts that are the output of Autoconf when processing the Macro. You
48 | # need not follow the terms of the GNU General Public License when using
49 | # or distributing such scripts, even though portions of the text of the
50 | # Macro appear in them. The GNU General Public License (GPL) does govern
51 | # all other use of the material that constitutes the Autoconf Macro.
52 | #
53 | # This special exception to the GPL applies to versions of the Autoconf
54 | # Macro released by the Autoconf Archive. When you make and distribute a
55 | # modified version of the Autoconf Macro, you may extend this special
56 | # exception to the GPL to apply to your modified version as well.
57 |
58 | #serial 4
59 |
60 | AC_DEFUN([AX_CHECK_COMPILE_FLAG],
61 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
63 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
64 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
65 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
66 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
67 | [AS_VAR_SET(CACHEVAR,[yes])],
68 | [AS_VAR_SET(CACHEVAR,[no])])
69 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
70 | AS_VAR_IF(CACHEVAR,yes,
71 | [m4_default([$2], :)],
72 | [m4_default([$3], :)])
73 | AS_VAR_POPDEF([CACHEVAR])dnl
74 | ])dnl AX_CHECK_COMPILE_FLAGS
75 |
--------------------------------------------------------------------------------
/RELEASE_CHECKLIST.txt:
--------------------------------------------------------------------------------
1 |
2 | Release checklist:
3 |
4 | release=0.12
5 | git clone https://github.com/json-c/json-c json-c-${release}
6 | cd json-c-${release}
7 |
8 | Check that the compile works on Linux
9 | Check that the compile works on NetBSD
10 | Check ChangeLog to see if anything should be added.
11 | Make any fixes/changes *before* branching.
12 |
13 | git branch json-c-${release}
14 | git checkout json-c-${release}
15 |
16 | ------------
17 |
18 | Update the version in json_c_version.h
19 | Update the version in Doxyfile
20 | Update the version in configure.ac
21 | Use ${release}.
22 |
23 | Update the libjson_la_LDFLAGS line in Makefile.am to the new version.
24 | Generally, unless we're doing a major release, change:
25 | -version-info x:y:z
26 | to
27 | -version-info x:y+1:z
28 |
29 | ------------
30 |
31 | Generate the configure script and other files:
32 | sh autogen.sh
33 | git add -f Makefile.in aclocal.m4 config.guess \
34 | config.sub configure depcomp install-sh \
35 | ltmain.sh missing tests/Makefile.in \
36 | INSTALL
37 |
38 | # check for anything else to be added:
39 | git status --ignored
40 | git commit
41 |
42 | ------------
43 |
44 | Generate the doxygen documentation:
45 | doxygen
46 | git add -f doc
47 | git commit doc
48 |
49 | ------------
50 |
51 | cd ..
52 | echo .git > excludes
53 | echo autom4te.cache >> excludes
54 | tar -czf json-c-${release}.tar.gz -X excludes json-c-${release}
55 |
56 | echo doc >> excludes
57 | tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release}
58 |
59 | ------------
60 |
61 | Tag the branch:
62 | cd json-c-${release}
63 | git tag -a json-c-${release}-$(date +%Y%m%d) -m "Release json-c-${release}"
64 |
65 | git push origin json-c-${release}
66 | git push --tags
67 |
68 | ------------
69 |
70 | Go to Amazon S3 service at:
71 | https://console.aws.amazon.com/s3/
72 |
73 | Upload the two tarballs in the json-c_releases folder.
74 | When uploading, use "Reduced Redundancy", and make the uploaded files publicly accessible.
75 |
76 | Logout of Amazon S3, and verify that the files are visible.
77 | https://s3.amazonaws.com/json-c_releases/releases/index.html
78 |
79 | ===================================
80 |
81 | Post-release checklist:
82 |
83 | git checkout master
84 | Add new section to ChangeLog
85 | Update the version in json_c_version.h
86 | Update the version in Doxyfile
87 | Update the version in configure.ac
88 | Use ${release}.99 to indicate a version "newer" than anything on the branch.
89 |
90 | Leave the libjson_la_LDFLAGS line in Makefile.am alone.
91 | For more details see:
92 | http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
93 |
94 | ------------
95 |
96 | Update the gh-pages branch with new docs:
97 |
98 | cd json-c-${release}
99 | git checkout json-c-${release}
100 | cd ..
101 |
102 | git clone -b gh-pages https://github.com/json-c/json-c json-c-pages
103 | cd json-c-pages
104 | mkdir json-c-${release}
105 | cp -R ../json-c-${release}/doc json-c-${release}/.
106 | cp ../json-c-${release}/README-WIN32.html json-c-${release}/.
107 | git add json-c-${release}
108 | git commit
109 |
110 | vi index.html
111 | Add/change links to current release.
112 |
113 | git commit index.html
114 |
115 | git push
116 |
117 | ------------
118 |
119 | Update checksums on wiki page.
120 |
121 | cd ..
122 | openssl sha -sha256 json-c*gz
123 | openssl md5 json-c*gz
124 |
125 | Copy and paste this output into the wiki page at:
126 | https://github.com/json-c/json-c/wiki
127 |
128 | ------------
129 |
130 | Send an email to the mailing list.
131 |
132 |
--------------------------------------------------------------------------------
/tests/test-defs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Make sure srcdir is an absolute path. Supply the variable
4 | # if it does not exist. We want to be able to run the tests
5 | # stand-alone!!
6 | #
7 | srcdir=${srcdir-.}
8 | if test ! -d $srcdir ; then
9 | echo "test-defs.sh: installation error" 1>&2
10 | exit 1
11 | fi
12 |
13 | # Use absolute paths
14 | case "$srcdir" in
15 | /* | [A-Za-z]:\\*) ;;
16 | *) srcdir=`\cd $srcdir && pwd` ;;
17 | esac
18 |
19 | case "$top_builddir" in
20 | /* | [A-Za-z]:\\*) ;;
21 | *) top_builddir=`\cd ${top_builddir-..} && pwd` ;;
22 | esac
23 |
24 | top_builddir=${top_builddir}/tests
25 |
26 | progname=`echo "$0" | sed 's,^.*/,,'`
27 | testname=`echo "$progname" | sed 's,-.*$,,'`
28 | testsubdir=${testsubdir-testSubDir}
29 | testsubdir=${testsubdir}/${progname}
30 |
31 | # User can set VERBOSE to cause output redirection
32 | case "$VERBOSE" in
33 | [Nn]|[Nn][Oo]|0|"")
34 | VERBOSE=0
35 | exec > /dev/null
36 | ;;
37 | [Yy]|[Yy][Ee][Ss])
38 | VERBOSE=1
39 | ;;
40 | esac
41 |
42 | rm -rf "$testsubdir" > /dev/null 2>&1
43 | mkdir -p "$testsubdir"
44 | CURDIR=`pwd`
45 | cd "$testsubdir" \
46 | || { echo "Cannot make or change into $testsubdir"; exit 1; }
47 |
48 | echo "=== Running test $progname"
49 |
50 | CMP="${CMP-cmp}"
51 |
52 | #
53 | # This is a common function to check the results of a test program
54 | # that is intended to generate consistent output across runs.
55 | #
56 | # ${top_builddir} must be set to the top level build directory.
57 | #
58 | # Output will be written to the current directory.
59 | #
60 | # It must be passed the name of the test command to run, which must be present
61 | # in the ${top_builddir} directory.
62 | #
63 | # It will compare the output of running that against .expected
64 | #
65 | run_output_test()
66 | {
67 | if [ "$1" = "-o" ] ; then
68 | TEST_OUTPUT="$2"
69 | shift
70 | shift
71 | fi
72 | TEST_COMMAND="$1"
73 | shift
74 | if [ -z "${TEST_OUTPUT}" ] ; then
75 | TEST_OUTPUT=${TEST_COMMAND}
76 | fi
77 |
78 | REDIR_OUTPUT="> \"${TEST_OUTPUT}.out\""
79 | if [ $VERBOSE -gt 1 ] ; then
80 | REDIR_OUTPUT="| tee \"${TEST_OUTPUT}.out\""
81 | fi
82 |
83 | if [ "$VALGRIND" = "valgrind" ] ; then
84 | eval valgrind --tool=memcheck \
85 | --trace-children=yes \
86 | --demangle=yes \
87 | --log-file="${TEST_OUTPUT}.vg.out" \
88 | --leak-check=full \
89 | --show-reachable=yes \
90 | --run-libc-freeres=yes \
91 | "\"${top_builddir}/${TEST_COMMAND}\"" \"\$@\" ${REDIR_OUTPUT}
92 | err=$?
93 |
94 | else
95 | eval "\"${top_builddir}/${TEST_COMMAND}"\" \"\$@\" ${REDIR_OUTPUT}
96 | err=$?
97 | fi
98 |
99 | if [ $err -ne 0 ] ; then
100 | echo "ERROR: \"${TEST_COMMAND} $@\" exited with non-zero exit status: $err" 1>&2
101 | fi
102 |
103 | if [ "$VALGRIND" = "valgrind" ] ; then
104 | if ! tail -1 "${TEST_OUTPUT}.vg.out" | grep -q "ERROR SUMMARY: 0 errors" ; then
105 | echo "ERROR: valgrind found errors during execution:" 1>&2
106 | cat "${TEST_OUTPUT}.vg.out"
107 | err=1
108 | fi
109 | fi
110 |
111 | if ! "$CMP" -s "${srcdir}/${TEST_OUTPUT}.expected" "${TEST_OUTPUT}.out" ; then
112 | echo "ERROR: \"${TEST_COMMAND} $@\" (${TEST_OUTPUT}) failed (set VERBOSE=1 to see full output):" 1>&2
113 | (cd "${CURDIR}" ; set -x ; diff "${srcdir}/${TEST_OUTPUT}.expected" "$testsubdir/${TEST_OUTPUT}.out")
114 | echo "cp \"$testsubdir/${TEST_OUTPUT}.out\" \"${srcdir}/${TEST_OUTPUT}.expected\"" 1>&2
115 |
116 | err=1
117 | fi
118 |
119 | # remove temp files for successful builds
120 | # this clanup is required for "make distcheck"
121 | if [ $err -eq 0 ] ; then
122 | rm -rf ${CURDIR}/${testsubdir}/*
123 | fi
124 |
125 | return $err
126 | }
127 |
128 |
129 |
--------------------------------------------------------------------------------
/arraylist.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2016 Rainer Gerhards
5 | *
6 | * This library is free software; you can redistribute it and/or modify
7 | * it under the terms of the MIT license. See COPYING for details.
8 | *
9 | */
10 |
11 | #include "config.h"
12 |
13 | #ifdef STDC_HEADERS
14 | # include
15 | # include
16 | #endif /* STDC_HEADERS */
17 |
18 | #if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD)
19 | # include
20 | #endif /* HAVE_STRINGS_H */
21 |
22 | #include "arraylist.h"
23 |
24 | struct array_list*
25 | array_list_new(array_list_free_fn *free_fn)
26 | {
27 | struct array_list *arr;
28 |
29 | arr = (struct array_list*)calloc(1, sizeof(struct array_list));
30 | if(!arr) return NULL;
31 | arr->size = ARRAY_LIST_DEFAULT_SIZE;
32 | arr->length = 0;
33 | arr->free_fn = free_fn;
34 | if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) {
35 | free(arr);
36 | return NULL;
37 | }
38 | return arr;
39 | }
40 |
41 | extern void
42 | array_list_free(struct array_list *arr)
43 | {
44 | int i;
45 | for(i = 0; i < arr->length; i++)
46 | if(arr->array[i]) arr->free_fn(arr->array[i]);
47 | free(arr->array);
48 | free(arr);
49 | }
50 |
51 | void*
52 | array_list_get_idx(struct array_list *arr, int i)
53 | {
54 | if(i >= arr->length) return NULL;
55 | return arr->array[i];
56 | }
57 |
58 | static int array_list_expand_internal(struct array_list *arr, int max)
59 | {
60 | void *t;
61 | int new_size;
62 |
63 | if(max < arr->size) return 0;
64 | new_size = arr->size << 1;
65 | if (new_size < max)
66 | new_size = max;
67 | if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1;
68 | arr->array = (void**)t;
69 | (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));
70 | arr->size = new_size;
71 | return 0;
72 | }
73 |
74 | int
75 | array_list_put_idx(struct array_list *arr, int idx, void *data)
76 | {
77 | if(array_list_expand_internal(arr, idx+1)) return -1;
78 | if(arr->array[idx]) arr->free_fn(arr->array[idx]);
79 | arr->array[idx] = data;
80 | if(arr->length <= idx) arr->length = idx + 1;
81 | return 0;
82 | }
83 |
84 | int
85 | array_list_add(struct array_list *arr, void *data)
86 | {
87 | return array_list_put_idx(arr, arr->length, data);
88 | }
89 |
90 | /*
91 | * Deleting the idx-th element in the array_list.
92 | */
93 | void
94 | array_list_del_idx(struct array_list *const arr, const int idx)
95 | {
96 | if (idx < 0 || idx >= arr->length) {
97 | return;
98 | }
99 | if(arr->array[idx]) arr->free_fn(arr->array[idx]);
100 | if (--arr->length > idx) {
101 | memmove(arr->array + idx, arr->array + idx + 1, (arr->length - idx) * sizeof(void *));
102 | }
103 | arr->array[arr->length] = NULL;
104 | return;
105 | }
106 |
107 | /* work around wrong compiler message: GCC and clang do
108 | * not handle sort_fn correctly if -Werror is given.
109 | */
110 | #ifndef _AIX
111 | #pragma GCC diagnostic push
112 | #ifdef __clang__
113 | #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
114 | #else
115 | #if __GNUC__ < 6
116 | #pragma GCC diagnostic ignored "-Werror"
117 | #endif
118 | #endif
119 | #endif
120 | void
121 | array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
122 | {
123 | qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn);
124 | }
125 | #ifndef _AIX
126 | #pragma GCC diagnostic pop
127 |
128 | #pragma GCC diagnostic push
129 | #ifdef __clang__
130 | #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
131 | #else
132 | #if __GNUC__ < 6
133 | #pragma GCC diagnostic ignored "-Werror"
134 | #endif
135 | #endif
136 | #endif
137 | void* array_list_bsearch(const void **key, struct array_list *arr,
138 | int (*sort_fn)(const void *, const void *))
139 | {
140 | return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]),
141 | sort_fn);
142 | }
143 | #ifndef _AIX
144 | #pragma GCC diagnostic pop
145 | #endif
146 |
147 | int
148 | array_list_length(struct array_list *arr)
149 | {
150 | return arr->length;
151 | }
152 |
--------------------------------------------------------------------------------
/tests/test_cast.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tests if casting within the fjson_object_get_* functions work correctly.
3 | * Also checks the fjson_object_get_type and fjson_object_is_type functions.
4 | */
5 |
6 | #include "config.h"
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "../json_object.h"
13 | #include "../json_tokener.h"
14 | #include "../json_util.h"
15 |
16 | /* this is a work-around until we manage to fix configure.ac */
17 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
18 |
19 | static void getit(struct fjson_object *new_obj, const char *field);
20 | static void checktype_header(void);
21 | static void checktype(struct fjson_object *new_obj, const char *field);
22 |
23 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
24 | {
25 | const char *input = "{\n\
26 | \"string_of_digits\": \"123\",\n\
27 | \"regular_number\": 222,\n\
28 | \"decimal_number\": 99.55,\n\
29 | \"boolean_true\": true,\n\
30 | \"boolean_false\": false,\n\
31 | \"big_number\": 2147483649,\n\
32 | \"a_null\": null,\n\
33 | }";
34 | /* Note: 2147483649 = INT_MAX + 2 */
35 |
36 | struct fjson_object *new_obj;
37 |
38 | new_obj = fjson_tokener_parse(input);
39 | printf("Parsed input: %s\n", input);
40 | printf("Result is %s\n", (new_obj == NULL) ? "NULL (error!)" : "not NULL");
41 | if (!new_obj)
42 | return 1; // oops, we failed.
43 |
44 | getit(new_obj, "string_of_digits");
45 | getit(new_obj, "regular_number");
46 | getit(new_obj, "decimal_number");
47 | getit(new_obj, "boolean_true");
48 | getit(new_obj, "boolean_false");
49 | getit(new_obj, "big_number");
50 | getit(new_obj, "a_null");
51 |
52 | // Now check the behaviour of the fjson_object_is_type() function.
53 | printf("\n================================\n");
54 | checktype_header();
55 | checktype(new_obj, NULL);
56 | checktype(new_obj, "string_of_digits");
57 | checktype(new_obj, "regular_number");
58 | checktype(new_obj, "decimal_number");
59 | checktype(new_obj, "boolean_true");
60 | checktype(new_obj, "boolean_false");
61 | checktype(new_obj, "big_number");
62 | checktype(new_obj, "a_null");
63 |
64 | fjson_object_put(new_obj);
65 |
66 | return 0;
67 | }
68 |
69 | static void getit(struct fjson_object *new_obj, const char *field)
70 | {
71 | struct fjson_object *o = NULL;
72 | if (!fjson_object_object_get_ex(new_obj, field, &o))
73 | printf("Field %s does not exist\n", field);
74 |
75 | enum fjson_type o_type = fjson_object_get_type(o);
76 | printf("new_obj.%s fjson_object_get_type()=%s\n", field,
77 | fjson_type_to_name(o_type));
78 | printf("new_obj.%s fjson_object_get_int()=%d\n", field,
79 | fjson_object_get_int(o));
80 | printf("new_obj.%s fjson_object_get_int64()=%" PRId64 "\n", field,
81 | fjson_object_get_int64(o));
82 | printf("new_obj.%s fjson_object_get_boolean()=%d\n", field,
83 | fjson_object_get_boolean(o));
84 | printf("new_obj.%s fjson_object_get_double()=%f\n", field,
85 | fjson_object_get_double(o));
86 | }
87 |
88 | static void checktype_header(void)
89 | {
90 | printf("fjson_object_is_type: %s,%s,%s,%s,%s,%s,%s\n",
91 | fjson_type_to_name(fjson_type_null),
92 | fjson_type_to_name(fjson_type_boolean),
93 | fjson_type_to_name(fjson_type_double),
94 | fjson_type_to_name(fjson_type_int),
95 | fjson_type_to_name(fjson_type_object),
96 | fjson_type_to_name(fjson_type_array),
97 | fjson_type_to_name(fjson_type_string));
98 | }
99 | static void checktype(struct fjson_object *new_obj, const char *field)
100 | {
101 | struct fjson_object *o = new_obj;
102 | if (field && !fjson_object_object_get_ex(new_obj, field, &o))
103 | printf("Field %s does not exist\n", field);
104 |
105 | printf("new_obj%s%-18s: %d,%d,%d,%d,%d,%d,%d\n",
106 | field ? "." : " ", field ? field : "",
107 | fjson_object_is_type(o, fjson_type_null),
108 | fjson_object_is_type(o, fjson_type_boolean),
109 | fjson_object_is_type(o, fjson_type_double),
110 | fjson_object_is_type(o, fjson_type_int),
111 | fjson_object_is_type(o, fjson_type_object),
112 | fjson_object_is_type(o, fjson_type_array),
113 | fjson_object_is_type(o, fjson_type_string));
114 | }
115 |
--------------------------------------------------------------------------------
/tests/test_parse.expected:
--------------------------------------------------------------------------------
1 | new_obj.to_string()="\u0003"
2 | new_obj.to_string()="foo"
3 | new_obj.to_string()="foo"
4 | new_obj.to_string()="ABC"
5 | new_obj.to_string()=null
6 | new_obj.to_string()=NaN
7 | new_obj.to_string()=null
8 | new_obj.to_string()=null
9 | new_obj.to_string()=null
10 | new_obj.to_string()=Infinity
11 | new_obj.to_string()=Infinity
12 | new_obj.to_string()=-Infinity
13 | new_obj.to_string()=-Infinity
14 | new_obj.to_string()=true
15 | new_obj.to_string()=12
16 | new_obj.to_string()=12.3
17 | new_obj.to_string()=null
18 | new_obj.to_string()=null
19 | new_obj.to_string()={ "FoO": -12.3E512 }
20 | new_obj.to_string()=null
21 | new_obj.to_string()=[ "\n" ]
22 | new_obj.to_string()=[ "\nabc\n" ]
23 | new_obj.to_string()=[ null ]
24 | new_obj.to_string()=[ ]
25 | new_obj.to_string()=[ false ]
26 | new_obj.to_string()=[ "abc", null, "def", 12 ]
27 | new_obj.to_string()={ }
28 | new_obj.to_string()={ "foo": "bar" }
29 | new_obj.to_string()={ "foo": "bar", "baz": null, "bool0": true }
30 | new_obj.to_string()={ "foo": [ null, "foo" ] }
31 | new_obj.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] }
32 | ==================================
33 | fjson_tokener_parse_versbose() OK
34 | ==================================
35 | Starting incremental tests.
36 | Note: quotes and backslashes seen in the output here are literal values passed
37 | to the parse functions. e.g. this is 4 characters: "\f"
38 | fjson_tokener_parse({ "foo) ... got error as expected
39 | fjson_tokener_parse_ex(tok, { "foo": 123 }, 14) ... OK: got object of type [object]: { "foo": 123 }
40 | fjson_tokener_parse_ex(tok, { "foo": 456 }, 14) ... OK: got object of type [object]: { "foo": 456 }
41 | fjson_tokener_parse_ex(tok, { "foo": 789 }, 14) ... OK: got object of type [object]: { "foo": 789 }
42 | fjson_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
43 | fjson_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue
44 | fjson_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } }
45 | fjson_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
46 | fjson_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character
47 | fjson_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
48 | fjson_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue
49 | fjson_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } }
50 | fjson_tokener_parse_ex(tok, XXXX , 4) ... OK: got correct error: unexpected character
51 | fjson_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [object]: { "x": 123 }
52 | fjson_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y"
53 | fjson_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue
54 | fjson_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12
55 | fjson_tokener_parse_ex(tok, 2015-01-15 , 10) ... OK: got correct error: number expected
56 | fjson_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue"
57 | fjson_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\""
58 | fjson_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\"
59 | fjson_tokener_parse_ex(tok, "\b" , 4) ... OK: got object of type [string]: "\b"
60 | fjson_tokener_parse_ex(tok, "\f" , 4) ... OK: got object of type [string]: "\f"
61 | fjson_tokener_parse_ex(tok, "\n" , 4) ... OK: got object of type [string]: "\n"
62 | fjson_tokener_parse_ex(tok, "\r" , 4) ... OK: got object of type [string]: "\r"
63 | fjson_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string]: "\t"
64 | fjson_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ]
65 | fjson_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ]
66 | fjson_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character
67 | fjson_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character
68 | fjson_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character
69 | End Incremental Tests OK=30 ERROR=0
70 | ==================================
71 |
--------------------------------------------------------------------------------
/tests/test1.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../debug.h"
9 | #include "parse_flags.h"
10 |
11 | /* this is a work-around until we manage to fix configure.ac */
12 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
13 |
14 | #define DEBUG_SEED(s)
15 |
16 | static int sort_fn (const void *j1, const void *j2)
17 | {
18 | fjson_object * const *jso1, * const *jso2;
19 | int i1, i2;
20 |
21 | jso1 = (fjson_object* const*)j1;
22 | jso2 = (fjson_object* const*)j2;
23 | if (!*jso1 && !*jso2)
24 | return 0;
25 | if (!*jso1)
26 | return -1;
27 | if (!*jso2)
28 | return 1;
29 |
30 | i1 = fjson_object_get_int(*jso1);
31 | i2 = fjson_object_get_int(*jso2);
32 |
33 | return i1 - i2;
34 | }
35 |
36 | #ifdef TEST_FORMATTED
37 | #define fjson_object_to_json_string(obj) fjson_object_to_json_string_ext(obj,sflags)
38 | #else
39 | /* no special define */
40 | #endif
41 |
42 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
43 | {
44 | fjson_object *my_string, *my_int, *my_object, *my_array;
45 | int i;
46 | #ifdef TEST_FORMATTED
47 | int sflags = 0;
48 | #endif
49 |
50 | MC_SET_DEBUG(1);
51 |
52 | #ifdef TEST_FORMATTED
53 | sflags = parse_flags(argc, argv);
54 | #endif
55 |
56 | my_string = fjson_object_new_string("\t");
57 | printf("my_string=%s\n", fjson_object_get_string(my_string));
58 | printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
59 | fjson_object_put(my_string);
60 |
61 | my_string = fjson_object_new_string("\\");
62 | printf("my_string=%s\n", fjson_object_get_string(my_string));
63 | printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
64 | fjson_object_put(my_string);
65 |
66 | my_string = fjson_object_new_string("foo");
67 | printf("my_string=%s\n", fjson_object_get_string(my_string));
68 | printf("my_string.to_string()=%s\n", fjson_object_to_json_string(my_string));
69 |
70 | my_int = fjson_object_new_int(9);
71 | printf("my_int=%d\n", fjson_object_get_int(my_int));
72 | printf("my_int.to_string()=%s\n", fjson_object_to_json_string(my_int));
73 |
74 | my_array = fjson_object_new_array();
75 | fjson_object_array_add(my_array, fjson_object_new_int(1));
76 | fjson_object_array_add(my_array, fjson_object_new_int(2));
77 | fjson_object_array_add(my_array, fjson_object_new_int(3));
78 | fjson_object_array_put_idx(my_array, 4, fjson_object_new_int(5));
79 | printf("my_array=\n");
80 | for(i=0; i < fjson_object_array_length(my_array); i++)
81 | {
82 | fjson_object *obj = fjson_object_array_get_idx(my_array, i);
83 | printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
84 | }
85 | printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
86 |
87 | fjson_object_put(my_array);
88 |
89 | my_array = fjson_object_new_array();
90 | fjson_object_array_add(my_array, fjson_object_new_int(3));
91 | fjson_object_array_add(my_array, fjson_object_new_int(1));
92 | fjson_object_array_add(my_array, fjson_object_new_int(2));
93 | fjson_object_array_put_idx(my_array, 4, fjson_object_new_int(0));
94 | printf("my_array=\n");
95 | for(i=0; i < fjson_object_array_length(my_array); i++)
96 | {
97 | fjson_object *obj = fjson_object_array_get_idx(my_array, i);
98 | printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
99 | }
100 | printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
101 | fjson_object_array_sort(my_array, sort_fn);
102 | printf("my_array=\n");
103 | for(i=0; i < fjson_object_array_length(my_array); i++)
104 | {
105 | fjson_object *obj = fjson_object_array_get_idx(my_array, i);
106 | printf("\t[%d]=%s\n", i, fjson_object_to_json_string(obj));
107 | }
108 | printf("my_array.to_string()=%s\n", fjson_object_to_json_string(my_array));
109 |
110 | my_object = fjson_object_new_object();
111 | fjson_object_object_add(my_object, "abc", fjson_object_new_int(12));
112 | fjson_object_object_add(my_object, "foo", fjson_object_new_string("bar"));
113 | fjson_object_object_add(my_object, "bool0", fjson_object_new_boolean(0));
114 | fjson_object_object_add(my_object, "bool1", fjson_object_new_boolean(1));
115 | fjson_object_object_add(my_object, "baz", fjson_object_new_string("bang"));
116 |
117 | fjson_object *baz_obj = fjson_object_new_string("fark");
118 | fjson_object_get(baz_obj);
119 | fjson_object_object_add(my_object, "baz", baz_obj);
120 | fjson_object_object_del(my_object, "baz");
121 |
122 | /* baz_obj should still be valid */
123 | printf("baz_obj.to_string()=%s\n", fjson_object_to_json_string(baz_obj));
124 | fjson_object_put(baz_obj);
125 |
126 | /*fjson_object_object_add(my_object, "arr", my_array);*/
127 | printf("my_object=\n");
128 | struct fjson_object_iterator it = fjson_object_iter_begin(my_object);
129 | struct fjson_object_iterator itEnd = fjson_object_iter_end(my_object);
130 | while (!fjson_object_iter_equal(&it, &itEnd)) {
131 | printf("\t%s: %s\n",
132 | fjson_object_iter_peek_name(&it),
133 | fjson_object_to_json_string(fjson_object_iter_peek_value(&it)));
134 | fjson_object_iter_next(&it);
135 | }
136 |
137 | printf("my_object.to_string()=%s\n", fjson_object_to_json_string(my_object));
138 |
139 | fjson_object_put(my_string);
140 | fjson_object_put(my_int);
141 | fjson_object_put(my_object);
142 | fjson_object_put(my_array);
143 |
144 | return 0;
145 | }
146 |
--------------------------------------------------------------------------------
/tests/test_printbuf.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "../debug.h"
9 | #include "../printbuf.h"
10 |
11 | /* this is a work-around until we manage to fix configure.ac */
12 | #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
13 |
14 | static void test_basic_printbuf_memset(void)
15 | {
16 | struct printbuf *pb;
17 |
18 | printf("%s: starting test\n", __func__);
19 | pb = printbuf_new();
20 | sprintbuf(pb, "blue:%d", 1);
21 | printbuf_memset(pb, -1, 'x', 52);
22 | printf("Buffer contents:%.*s\n", printbuf_length(pb), pb->buf);
23 | printbuf_free(pb);
24 | printf("%s: end test\n", __func__);
25 | }
26 |
27 | static void test_printbuf_memset_length(void)
28 | {
29 | struct printbuf *pb;
30 |
31 | printf("%s: starting test\n", __func__);
32 | pb = printbuf_new();
33 | printbuf_memset(pb, -1, ' ', 0);
34 | printbuf_memset(pb, -1, ' ', 0);
35 | printbuf_memset(pb, -1, ' ', 0);
36 | printbuf_memset(pb, -1, ' ', 0);
37 | printbuf_memset(pb, -1, ' ', 0);
38 | printf("Buffer length: %d\n", printbuf_length(pb));
39 | printbuf_memset(pb, -1, ' ', 2);
40 | printbuf_memset(pb, -1, ' ', 4);
41 | printbuf_memset(pb, -1, ' ', 6);
42 | printf("Buffer length: %d\n", printbuf_length(pb));
43 | printbuf_memset(pb, -1, ' ', 6);
44 | printf("Buffer length: %d\n", printbuf_length(pb));
45 | printbuf_memset(pb, -1, ' ', 8);
46 | printbuf_memset(pb, -1, ' ', 10);
47 | printbuf_memset(pb, -1, ' ', 10);
48 | printbuf_memset(pb, -1, ' ', 10);
49 | printbuf_memset(pb, -1, ' ', 20);
50 | printf("Buffer length: %d\n", printbuf_length(pb));
51 |
52 | // No length change should occur
53 | printbuf_memset(pb, 0, 'x', 30);
54 | printf("Buffer length: %d\n", printbuf_length(pb));
55 |
56 | // This should extend it by one.
57 | printbuf_memset(pb, 0, 'x', printbuf_length(pb) + 1);
58 | printf("Buffer length: %d\n", printbuf_length(pb));
59 |
60 | printbuf_free(pb);
61 | printf("%s: end test\n", __func__);
62 | }
63 |
64 | static void test_printbuf_memappend(int *before_resize);
65 | static void test_printbuf_memappend(int *before_resize)
66 | {
67 | struct printbuf *pb;
68 | int initial_size;
69 |
70 | printf("%s: starting test\n", __func__);
71 | pb = printbuf_new();
72 | printf("Buffer length: %d\n", printbuf_length(pb));
73 |
74 | initial_size = pb->size;
75 |
76 | while(pb->size == initial_size)
77 | {
78 | printbuf_memappend_fast(pb, "x", 1);
79 | }
80 | *before_resize = printbuf_length(pb) - 1;
81 | printf("Appended %d bytes for resize: [%s]\n", *before_resize + 1, pb->buf);
82 |
83 | printbuf_reset(pb);
84 | printbuf_memappend_fast(pb, "bluexyz123", 3);
85 | printf("Partial append: %d, [%s]\n", printbuf_length(pb), pb->buf);
86 |
87 | char with_nulls[] = { 'a', 'b', '\0', 'c' };
88 | printbuf_reset(pb);
89 | printbuf_memappend_fast(pb, with_nulls, (int)sizeof(with_nulls));
90 | printf("With embedded \\0 character: %d, [%s]\n", printbuf_length(pb), pb->buf);
91 |
92 | printbuf_free(pb);
93 | pb = printbuf_new();
94 | char *data = malloc(*before_resize);
95 | memset(data, 'X', *before_resize);
96 | printbuf_memappend_fast(pb, data, *before_resize);
97 | printf("Append to just before resize: %d, [%s]\n", printbuf_length(pb), pb->buf);
98 |
99 | free(data);
100 | printbuf_free(pb);
101 |
102 | pb = printbuf_new();
103 | data = malloc(*before_resize + 1);
104 | memset(data, 'X', *before_resize + 1);
105 | printbuf_memappend_fast(pb, data, *before_resize + 1);
106 | printf("Append to just after resize: %d, [%s]\n", printbuf_length(pb), pb->buf);
107 |
108 | free(data);
109 |
110 | printbuf_free(pb);
111 | printf("%s: end test\n", __func__);
112 | }
113 |
114 | static void test_sprintbuf(int before_resize);
115 | static void test_sprintbuf(int before_resize)
116 | {
117 | struct printbuf *pb;
118 |
119 | printf("%s: starting test\n", __func__);
120 | pb = printbuf_new();
121 | printf("Buffer length: %d\n", printbuf_length(pb));
122 |
123 | char *data = malloc(before_resize + 1 + 1);
124 | memset(data, 'X', before_resize + 1 + 1);
125 | data[before_resize + 1] = '\0';
126 | sprintbuf(pb, "%s", data);
127 | free(data);
128 | printf("sprintbuf to just after resize(%d+1): %d, [%s], strlen(buf)=%d\n", before_resize, printbuf_length(pb), pb->buf, (int)strlen(pb->buf));
129 |
130 | printbuf_reset(pb);
131 | sprintbuf(pb, "plain");
132 | printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
133 |
134 | sprintbuf(pb, "%d", 1);
135 | printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
136 |
137 | sprintbuf(pb, "%d", INT_MAX);
138 | printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
139 |
140 | sprintbuf(pb, "%d", INT_MIN);
141 | printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
142 |
143 | sprintbuf(pb, "%s", "%s");
144 | printf("%d, [%s]\n", printbuf_length(pb), pb->buf);
145 |
146 | printbuf_free(pb);
147 | printf("%s: end test\n", __func__);
148 | }
149 |
150 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
151 | {
152 | int before_resize = 0;
153 |
154 | mc_set_debug(1);
155 |
156 | test_basic_printbuf_memset();
157 | printf("========================================\n");
158 | test_printbuf_memset_length();
159 | printf("========================================\n");
160 | test_printbuf_memappend(&before_resize);
161 | printf("========================================\n");
162 | test_sprintbuf(before_resize);
163 | printf("========================================\n");
164 |
165 | return 0;
166 | }
167 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_PREREQ(2.52)
2 |
3 | # Process this file with autoconf to produce a configure script.
4 | AC_INIT([libfastjson], [1.2305.0.master], [rsyslog@lists.adiscon.com])
5 | # AIXPORT START: Detect the underlying OS
6 | unamestr=$(uname)
7 | AM_CONDITIONAL([AIX], [test x$unamestr = xAIX])
8 | # AIXPORT END
9 |
10 | # AIXPORT : Set the required variables for AIX config script
11 | if test "$unamestr" = "AIX"; then
12 | export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
13 | LIBS="-lbsd -lm"
14 | CPPFLAGS="-D_AIX -D_THREAD_SAFE -D_BSD=43"
15 | LDFLAGS="-qcpluscmt -brtl -bexpall "
16 | CC="xlc"
17 | AC_PREFIX_DEFAULT(/usr)
18 | fi
19 | # AIXPORT END
20 |
21 |
22 | AC_CONFIG_HEADER(config.h)
23 |
24 | AM_INIT_AUTOMAKE([subdir-objects])
25 | AC_CONFIG_MACRO_DIR([m4])
26 |
27 | AC_PROG_CC_C99
28 | AC_PROG_MAKE_SET
29 | m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], [AC_USE_SYSTEM_EXTENSIONS])
30 |
31 | if test "$GCC" = "yes"
32 | then
33 | m4_ifdef([AX_IS_RELEASE], [
34 | AX_IS_RELEASE([git-directory])
35 | m4_ifdef([AX_COMPILER_FLAGS], [
36 | AX_COMPILER_FLAGS()
37 | ], [
38 | CFLAGS="$CFLAGS -W -Wall -Wformat-security -Wshadow -Wcast-align -Wpointer-arith -Wmissing-format-attribute -g"
39 | AC_MSG_WARN([missing AX_COMPILER_FLAGS macro, not using it])
40 | ])
41 | ], [
42 | CFLAGS="$CFLAGS -W -Wall -Wformat-security -Wshadow -Wcast-align -Wpointer-arith -Wmissing-format-attribute -g"
43 | AC_MSG_WARN([missing AX_IS_RELEASE macro, not using AX_COMPILER_FLAGS macro because of this])
44 | ])
45 | else
46 | AC_MSG_WARN([compiler is not GCC or close compatible, not using ax_compiler_flags because of this (CC=$CC)])
47 | fi
48 |
49 | AC_ARG_ENABLE(rdrand,
50 | AS_HELP_STRING([--enable-rdrand],
51 | [Enable RDRAND Hardware RNG Hash Seed generation on supported x86/x64 platforms.]),
52 | [if test x$enableval = xyes; then
53 | enable_rdrand=yes
54 | AC_DEFINE(ENABLE_RDRAND, 1, [Enable RDRANR Hardware RNG Hash Seed])
55 | fi])
56 |
57 | if test "x$enable_rdrand" = "xyes"; then
58 | AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed enabled on supported x86/x64 platforms])
59 | else
60 | AC_MSG_RESULT([RDRAND Hardware RNG Hash Seed disabled. Use --enable-rdrand to enable])
61 | fi
62 |
63 | # enable silent build by default
64 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
65 |
66 | AC_ARG_ENABLE(valgrind,
67 | [AS_HELP_STRING([--enable-valgrind],[enable running the testbench under valgrind memcheck tool @<:@default=no@:>@])],
68 | [case "${enableval}" in
69 | yes) enable_valgrind="yes" ;;
70 | no) enable_valgrind="no" ;;
71 | *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;;
72 | esac],
73 | [enable_valgrind="no"]
74 | )
75 | if test "$enable_valgrind" = "yes"; then
76 | AC_CHECK_PROG(VALGRIND, [valgrind], [valgrind], [no])
77 | if test "x$VALGRIND" = "xno"; then
78 | AC_MSG_ERROR([--enable-valgrind given, but valgrind is not present on system])
79 | fi
80 | AC_SUBST(VALGRIND)
81 | AC_DEFINE(VALGRIND, 1, [valgrind enabled])
82 | fi
83 |
84 | # Checks for programs.
85 |
86 | # Checks for libraries.
87 |
88 | # Checks for header files.
89 | AM_PROG_CC_C_O
90 | AC_HEADER_STDC
91 | AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h endian.h)
92 |
93 | # Checks for typedefs, structures, and compiler characteristics.
94 | AC_C_CONST
95 | AC_TYPE_SIZE_T
96 |
97 |
98 | # check for availability of atomic operations
99 | RS_ATOMIC_OPERATIONS
100 | RS_ATOMIC_OPERATIONS_64BIT
101 |
102 |
103 | # Checks for library functions.
104 | AC_FUNC_VPRINTF
105 | AC_FUNC_MEMCMP
106 | AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
107 |
108 | if test "$ac_cv_have_decl_isnan" = "yes" ; then
109 | AC_TRY_LINK([#include ], [float f = 0.0; return isnan(f)], [], [LIBS="$LIBS -lm"])
110 | fi
111 |
112 | #check if .section.gnu.warning accepts long strings (for __warn_references)
113 | AC_LANG_PUSH([C])
114 |
115 | AC_MSG_CHECKING([if .gnu.warning accepts long strings])
116 | AC_LINK_IFELSE([AC_LANG_SOURCE([[
117 | extern void json_object_get();
118 | __asm__(".section .gnu.json_object_get,\n\t.ascii \"Please link against libfastjson instead of libjson\"\n\t.text");
119 |
120 | int main(int c,char* v) {return 0;}
121 | ]])], [
122 | AC_DEFINE(HAS_GNU_WARNING_LONG, 1, [Define if .gnu.warning accepts long strings.])
123 | AC_MSG_RESULT(yes)
124 | ], [
125 | AC_MSG_RESULT(no)
126 | ])
127 |
128 | AC_LANG_POP([C])
129 |
130 | AM_PROG_LIBTOOL
131 |
132 | # Check for the -Bsymbolic-functions linker flag
133 | AC_ARG_ENABLE([Bsymbolic],
134 | [AS_HELP_STRING([--disable-Bsymbolic], [Avoid linking with -Bsymbolic-function])],
135 | [],
136 | [enable_Bsymbolic=check])
137 |
138 | AS_IF([test "x$enable_Bsymbolic" = "xcheck"],
139 | [
140 | saved_LDFLAGS="${LDFLAGS}"
141 | AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
142 | LDFLAGS=-Wl,-Bsymbolic-functions
143 | AC_TRY_LINK([], [int main (void) { return 0; }],
144 | [
145 | AC_MSG_RESULT([yes])
146 | enable_Bsymbolic=yes
147 | ],
148 | [
149 | AC_MSG_RESULT([no])
150 | enable_Bsymbolic=no
151 | ])
152 | LDFLAGS="${saved_LDFLAGS}"
153 | ])
154 |
155 | AS_IF([test "x$enable_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
156 | AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
157 |
158 | AC_CONFIG_FILES([
159 | Makefile
160 | libfastjson.pc
161 | libfastjson-uninstalled.pc
162 | tests/Makefile
163 | ])
164 |
165 | AC_OUTPUT
166 |
167 |
--------------------------------------------------------------------------------
/json_object_iterator.c:
--------------------------------------------------------------------------------
1 | /**
2 | *******************************************************************************
3 | * @file fjson_object_iterator.c
4 | *
5 | * Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
6 | * Copyright (c) 2016 Adiscon GmbH
7 | * Rainer Gerhards
8 | *
9 | * This library is free software; you can redistribute it and/or modify
10 | * it under the terms of the MIT license. See COPYING for details.
11 | *
12 | * @brief json-c forces clients to use its private data
13 | * structures for JSON Object iteration. This API
14 | * implementation corrects that by abstracting the
15 | * private json-c details.
16 | *
17 | *******************************************************************************
18 | */
19 |
20 | #include "config.h"
21 | #include
22 | #include "json.h"
23 | #include "json_object_private.h"
24 | #include "json_object_iterator.h"
25 | #include "debug.h"
26 |
27 | /**
28 | * How It Works
29 | *
30 | * For each JSON Object, json-c maintains a linked list of zero
31 | * or more lh_entry (link-hash entry) structures inside the
32 | * Object's link-hash table (lh_table).
33 | *
34 | * Each lh_entry structure on the JSON Object's linked list
35 | * represents a single name/value pair. The "next" field of the
36 | * last lh_entry in the list is set to NULL, which terminates
37 | * the list.
38 | *
39 | * We represent a valid iterator that refers to an actual
40 | * name/value pair via a pointer to the pair's lh_entry
41 | * structure set as the iterator's opaque_ field.
42 | *
43 | * We follow json-c's current pair list representation by
44 | * representing a valid "end" iterator (one that refers past the
45 | * last pair) with a NULL value in the iterator's opaque_ field.
46 | *
47 | * A JSON Object without any pairs in it will have the "head"
48 | * field of its lh_table structure set to NULL. For such an
49 | * object, fjson_object_iter_begin will return an iterator with
50 | * the opaque_ field set to NULL, which is equivalent to the
51 | * "end" iterator.
52 | *
53 | * When iterating, we simply update the iterator's opaque_ field
54 | * to point to the next lh_entry structure in the linked list.
55 | * opaque_ will become NULL once we iterate past the last pair
56 | * in the list, which makes the iterator equivalent to the "end"
57 | * iterator.
58 | */
59 |
60 |
61 | /**
62 | * ****************************************************************************
63 | */
64 | struct fjson_object_iterator
65 | fjson_object_iter_begin(struct fjson_object *const __restrict__ obj)
66 | {
67 | struct fjson_object_iterator iter = {
68 | .objs_remain = 0,
69 | .curr_idx = 0,
70 | .pg = NULL
71 | };
72 |
73 | if(obj->o_type == fjson_type_object) {
74 | iter.objs_remain = obj->o.c_obj.nelem;
75 | if(iter.objs_remain > 0) {
76 | iter.curr_idx = 0;
77 | iter.pg = &obj->o.c_obj.pg;
78 | /* check if first slot is empty, if so, advance */
79 | if(iter.pg->children[0].k == NULL) {
80 | ++iter.objs_remain; /* correct _iter_next decrement */
81 | fjson_object_iter_next(&iter);
82 | }
83 | }
84 | }
85 | return iter;
86 | }
87 |
88 | /**
89 | * ****************************************************************************
90 | */
91 | struct fjson_object_iterator
92 | fjson_object_iter_end(const struct fjson_object __attribute__((unused)) *obj)
93 | {
94 | struct fjson_object_iterator iter = {
95 | .objs_remain = 0,
96 | .curr_idx = 0,
97 | .pg = NULL
98 | };
99 | return iter;
100 | }
101 |
102 | /**
103 | * ****************************************************************************
104 | */
105 | void
106 | fjson_object_iter_next(struct fjson_object_iterator *const __restrict__ iter)
107 | {
108 | JASSERT(NULL != iter);
109 |
110 | if(iter->objs_remain > 0) {
111 | --iter->objs_remain;
112 | if(iter->objs_remain > 0) {
113 | ++iter->curr_idx;
114 | if(iter->curr_idx == FJSON_OBJECT_CHLD_PG_SIZE) {
115 | iter->pg = iter->pg->next;
116 | iter->curr_idx = 0;
117 | }
118 | /* check empty slots; TODO: recurse or iterate? */
119 | if(iter->pg->children[iter->curr_idx].k == NULL) {
120 | ++iter->objs_remain; /* correct */
121 | fjson_object_iter_next(iter);
122 | }
123 | }
124 | }
125 | }
126 |
127 |
128 | /**
129 | * ****************************************************************************
130 | */
131 | const char*
132 | fjson_object_iter_peek_name(const struct fjson_object_iterator *const __restrict__ iter)
133 | {
134 | JASSERT(NULL != iter);
135 | return iter->pg->children[iter->curr_idx].k;
136 | }
137 |
138 |
139 | /**
140 | * ****************************************************************************
141 | */
142 | struct fjson_object*
143 | fjson_object_iter_peek_value(const struct fjson_object_iterator *const __restrict__ iter)
144 | {
145 | JASSERT(NULL != iter);
146 | return iter->pg->children[iter->curr_idx].v;
147 | }
148 |
149 | /**
150 | * ****************************************************************************
151 | */
152 | struct _fjson_child*
153 | _fjson_object_iter_peek_child(const struct fjson_object_iterator *const __restrict__ iter)
154 | {
155 | JASSERT(NULL != iter);
156 | return (struct _fjson_child*) &(iter->pg->children[iter->curr_idx]);
157 | }
158 |
159 |
160 | /**
161 | * ****************************************************************************
162 | */
163 | fjson_bool
164 | fjson_object_iter_equal(const struct fjson_object_iterator* iter1,
165 | const struct fjson_object_iterator* iter2)
166 | {
167 | int is_eq;
168 | JASSERT(NULL != iter1);
169 | JASSERT(NULL != iter2);
170 |
171 | if (iter1->objs_remain == iter2->objs_remain) {
172 | if (iter1->objs_remain == 0) {
173 | is_eq = 1;
174 | } else {
175 | if ( (iter1->curr_idx == iter2->curr_idx) &&
176 | (iter1->pg == iter2->pg) ) {
177 | is_eq = 1;
178 | } else {
179 | is_eq = 0;
180 | }
181 | }
182 | } else {
183 | is_eq= 0;
184 | }
185 |
186 | return is_eq;
187 | }
188 |
189 |
190 | /**
191 | * ****************************************************************************
192 | */
193 | struct fjson_object_iterator
194 | fjson_object_iter_init_default(void)
195 | {
196 | struct fjson_object_iterator iter;
197 |
198 | /**
199 | * @note Make this an invalid value, such that
200 | * accidental access to it would likely be trapped by the
201 | * hardware as an invalid address.
202 | */
203 | iter.pg = NULL;
204 | iter.curr_idx = 0;
205 | iter.objs_remain = 1;
206 |
207 | return iter;
208 | }
209 |
--------------------------------------------------------------------------------
/printbuf.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | *
5 | * This library is free software; you can redistribute it and/or modify
6 | * it under the terms of the MIT license. See COPYING for details.
7 | *
8 | *
9 | * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
10 | * The copyrights to the contents of this file are licensed under the MIT License
11 | * (http://www.opensource.org/licenses/mit-license.php)
12 | */
13 |
14 | #include "config.h"
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #ifdef HAVE_STDARG_H
22 | # include
23 | #else /* !HAVE_STDARG_H */
24 | # error Not enough var arg support!
25 | #endif /* HAVE_STDARG_H */
26 |
27 | #include "json.h"
28 | #include "debug.h"
29 | #include "printbuf.h"
30 |
31 | static int printbuf_initial_size = 32;
32 | static int printbuf_extend(struct printbuf *p, int min_size);
33 |
34 | void fjson_global_set_printbuf_initial_size(int size)
35 | {
36 | printbuf_initial_size = size;
37 | }
38 |
39 | struct printbuf* printbuf_new(void)
40 | {
41 | struct printbuf *p;
42 |
43 | p = (struct printbuf*)malloc(sizeof(struct printbuf));
44 | if(!p) return NULL;
45 | /* note: *ALL* data items must be initialized! */
46 | p->size = printbuf_initial_size;
47 | p->bpos = 0;
48 | if(!(p->buf = (char*)malloc(p->size))) {
49 | free(p);
50 | return NULL;
51 | }
52 | return p;
53 | }
54 |
55 |
56 | /**
57 | * Extend the buffer p so it has a size of at least min_size.
58 | *
59 | * If the current size is large enough, nothing is changed.
60 | *
61 | * Note: this does not check the available space! The caller
62 | * is responsible for performing those calculations.
63 | */
64 | static int printbuf_extend(struct printbuf *p, int min_size)
65 | {
66 | char *t;
67 | int new_size;
68 |
69 | if (p->size >= min_size)
70 | return 0;
71 |
72 | /* Prevent signed integer overflows with large buffers. */
73 | if (min_size > INT_MAX - 8)
74 | return -1;
75 | if (p->size > INT_MAX / 2)
76 | new_size = min_size + 8;
77 | else {
78 | new_size = p->size * 2;
79 | if (new_size < min_size + 8)
80 | new_size = min_size + 8;
81 | }
82 | #ifdef PRINTBUF_DEBUG
83 | MC_DEBUG("printbuf_memappend: realloc "
84 | "bpos=%d min_size=%d old_size=%d new_size=%d\n",
85 | p->bpos, min_size, p->size, new_size);
86 | #endif /* PRINTBUF_DEBUG */
87 | if(!(t = (char*)realloc(p->buf, new_size)))
88 | return -1;
89 | p->size = new_size;
90 | p->buf = t;
91 | return 0;
92 | }
93 |
94 | int printbuf_memappend(struct printbuf *p, const char *buf, int size)
95 | {
96 | /* Prevent signed integer overflows with large buffers. */
97 | if (size > INT_MAX - p->bpos - 1)
98 | return -1;
99 | if (p->size <= p->bpos + size + 1) {
100 | if (printbuf_extend(p, p->bpos + size + 1) < 0)
101 | return -1;
102 | }
103 | if(size > 1)
104 | memcpy(p->buf + p->bpos, buf, size);
105 | else
106 | p->buf[p->bpos]= *buf;
107 | p->bpos += size;
108 | p->buf[p->bpos]= '\0';
109 | return size;
110 | }
111 |
112 | /* same as printbuf_memappend(), but contains some performance enhancements */
113 | void printbuf_memappend_no_nul(struct printbuf *p, const char *buf, const int size)
114 | {
115 | if (p->size <= p->bpos + size) {
116 | if (printbuf_extend(p, p->bpos + size) < 0)
117 | /* ignore new data, best we can do */
118 | return;
119 | }
120 | memcpy(p->buf + p->bpos, buf, size);
121 | p->bpos += size;
122 | }
123 |
124 | /* add a single character to printbuf */
125 | void printbuf_memappend_char(struct printbuf *p, const char c)
126 | {
127 | if (p->size <= p->bpos + 1) {
128 | if (printbuf_extend(p, p->bpos + 1) < 0)
129 | /* ignore new data, best we can do */
130 | return;
131 | }
132 | p->buf[p->bpos++]= c;
133 | }
134 |
135 | void printbuf_terminate_string(struct printbuf *const p)
136 | {
137 | if (p->size <= p->bpos + 1) {
138 | if (printbuf_extend(p, p->bpos + 1) < 0)
139 | --p->bpos; /* overwrite last byte, best we can do */
140 | }
141 | p->buf[p->bpos]= '\0';
142 | }
143 |
144 | int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
145 | {
146 | int size_needed;
147 |
148 | if (offset == -1)
149 | offset = pb->bpos;
150 | /* Prevent signed integer overflows with large buffers. */
151 | if (len > INT_MAX - offset)
152 | return -1;
153 | size_needed = offset + len;
154 | if (pb->size < size_needed)
155 | {
156 | if (printbuf_extend(pb, size_needed) < 0)
157 | return -1;
158 | }
159 |
160 | memset(pb->buf + offset, charvalue, len);
161 | if (pb->bpos < size_needed)
162 | pb->bpos = size_needed;
163 |
164 | return 0;
165 | }
166 |
167 | #if !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */
168 | # error Need vsnprintf!
169 | #endif /* !HAVE_VSNPRINTF */
170 |
171 | #if !defined(HAVE_VASPRINTF)
172 | /* CAW: compliant version of vasprintf */
173 | /* Note: on OpenCSW, we have vasprintf() inside the headers, but not inside the lib.
174 | * So we need to use a different name, else we get issues with redefinitions. We
175 | * we solve this by using the macro below, which just renames the function BUT
176 | * does not affect the (variadic) arguments.
177 | * rgerhards, 2017-04-11
178 | */
179 | #define vasprintf rs_vasprintf
180 | #ifndef _AIX
181 | #pragma GCC diagnostic push
182 | #pragma GCC diagnostic ignored "-Wformat-nonliteral"
183 | #endif
184 | static int rs_vasprintf(char **buf, const char *fmt, va_list ap)
185 | {
186 | int chars;
187 | char *b;
188 | static char _T_emptybuffer = '\0';
189 |
190 | if(!buf) { return -1; }
191 |
192 | /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
193 | our buffer like on some 64bit sun systems.... but hey, its time to move on */
194 | chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
195 | if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
196 |
197 | b = (char*)malloc(sizeof(char)*chars);
198 | if(!b) { return -1; }
199 |
200 | if((chars = vsprintf(b, fmt, ap)) < 0) {
201 | free(b);
202 | } else {
203 | *buf = b;
204 | }
205 |
206 | return chars;
207 | }
208 | #ifndef _AIX
209 | #pragma GCC diagnostic pop
210 | #endif
211 | #endif /* !HAVE_VASPRINTF */
212 |
213 | int sprintbuf(struct printbuf *p, const char *msg, ...)
214 | {
215 | va_list ap;
216 | char *t;
217 | int size;
218 | char buf[128];
219 |
220 | /* user stack buffer first */
221 | va_start(ap, msg);
222 | size = vsnprintf(buf, 128, msg, ap);
223 | va_end(ap);
224 | /* if string is greater than stack buffer, then use dynamic string
225 | with vasprintf. Note: some implementation of vsnprintf return -1
226 | if output is truncated whereas some return the number of bytes that
227 | would have been written - this code handles both cases. */
228 | if(size == -1 || size > 127) {
229 | va_start(ap, msg);
230 | if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; }
231 | va_end(ap);
232 | printbuf_memappend(p, t, size);
233 | free(t);
234 | return size;
235 | } else {
236 | printbuf_memappend(p, buf, size);
237 | return size;
238 | }
239 | }
240 |
241 | void printbuf_reset(struct printbuf *p)
242 | {
243 | p->buf[0] = '\0';
244 | p->bpos = 0;
245 | }
246 |
247 | void printbuf_free(struct printbuf *p)
248 | {
249 | if(p) {
250 | free(p->buf);
251 | free(p);
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/json_tokener.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | *
5 | * This library is free software; you can redistribute it and/or modify
6 | * it under the terms of the MIT license. See COPYING for details.
7 | *
8 | */
9 |
10 | #ifndef _fj_json_tokener_h_
11 | #define _fj_json_tokener_h_
12 |
13 | #include
14 | #include "json_object.h"
15 |
16 | #ifdef __cplusplus
17 | extern "C" {
18 | #endif
19 |
20 | enum fjson_tokener_error {
21 | fjson_tokener_success,
22 | fjson_tokener_continue,
23 | fjson_tokener_error_depth,
24 | fjson_tokener_error_parse_eof,
25 | fjson_tokener_error_parse_unexpected,
26 | fjson_tokener_error_parse_null,
27 | fjson_tokener_error_parse_boolean,
28 | fjson_tokener_error_parse_number,
29 | fjson_tokener_error_parse_array,
30 | fjson_tokener_error_parse_object_key_name,
31 | fjson_tokener_error_parse_object_key_sep,
32 | fjson_tokener_error_parse_object_value_sep,
33 | fjson_tokener_error_parse_string,
34 | fjson_tokener_error_parse_comment,
35 | fjson_tokener_error_size
36 | };
37 |
38 | enum fjson_tokener_state {
39 | fjson_tokener_state_eatws,
40 | fjson_tokener_state_start,
41 | fjson_tokener_state_finish,
42 | fjson_tokener_state_null,
43 | fjson_tokener_state_comment_start,
44 | fjson_tokener_state_comment,
45 | fjson_tokener_state_comment_eol,
46 | fjson_tokener_state_comment_end,
47 | fjson_tokener_state_string,
48 | fjson_tokener_state_string_escape,
49 | fjson_tokener_state_escape_unicode,
50 | fjson_tokener_state_boolean,
51 | fjson_tokener_state_number,
52 | fjson_tokener_state_array,
53 | fjson_tokener_state_array_add,
54 | fjson_tokener_state_array_sep,
55 | fjson_tokener_state_object_field_start,
56 | fjson_tokener_state_object_field,
57 | fjson_tokener_state_object_field_end,
58 | fjson_tokener_state_object_value,
59 | fjson_tokener_state_object_value_add,
60 | fjson_tokener_state_object_sep,
61 | fjson_tokener_state_array_after_sep,
62 | fjson_tokener_state_object_field_start_after_sep,
63 | fjson_tokener_state_inf
64 | };
65 |
66 | struct fjson_tokener_srec
67 | {
68 | enum fjson_tokener_state state, saved_state;
69 | struct fjson_object *obj;
70 | struct fjson_object *current;
71 | char *obj_field_name;
72 | };
73 |
74 | #define FJSON_TOKENER_DEFAULT_DEPTH 32
75 |
76 | struct fjson_tokener
77 | {
78 | char *str;
79 | struct printbuf *pb;
80 | int max_depth, depth, is_double, st_pos, char_offset;
81 | enum fjson_tokener_error err;
82 | unsigned int ucs_char;
83 | char quote_char;
84 | struct fjson_tokener_srec *stack;
85 | int flags;
86 | };
87 |
88 | /**
89 | * Be strict when parsing JSON input. Use caution with
90 | * this flag as what is considered valid may become more
91 | * restrictive from one release to the next, causing your
92 | * code to fail on previously working input.
93 | *
94 | * This flag is not set by default.
95 | *
96 | * @see fjson_tokener_set_flags()
97 | */
98 | #define FJSON_TOKENER_STRICT 0x01
99 |
100 | /**
101 | * Given an error previously returned by fjson_tokener_get_error(),
102 | * return a human readable description of the error.
103 | *
104 | * @return a generic error message is returned if an invalid error value is provided.
105 | */
106 | const char *fjson_tokener_error_desc(enum fjson_tokener_error jerr);
107 |
108 | /**
109 | * Retrieve the error caused by the last call to fjson_tokener_parse_ex(),
110 | * or fjson_tokener_success if there is no error.
111 | *
112 | * When parsing a JSON string in pieces, if the tokener is in the middle
113 | * of parsing this will return fjson_tokener_continue.
114 | *
115 | * See also fjson_tokener_error_desc().
116 | */
117 | enum fjson_tokener_error fjson_tokener_get_error(struct fjson_tokener *tok);
118 |
119 | extern struct fjson_tokener* fjson_tokener_new(void);
120 | extern struct fjson_tokener* fjson_tokener_new_ex(int depth);
121 | extern void fjson_tokener_free(struct fjson_tokener *tok);
122 | extern void fjson_tokener_reset(struct fjson_tokener *tok);
123 | extern struct fjson_object* fjson_tokener_parse(const char *str);
124 | extern struct fjson_object* fjson_tokener_parse_verbose(const char *str, enum fjson_tokener_error *error);
125 |
126 | /**
127 | * Set flags that control how parsing will be done.
128 | */
129 | extern void fjson_tokener_set_flags(struct fjson_tokener *tok, int flags);
130 |
131 | /**
132 | * Parse a string and return a non-NULL fjson_object if a valid JSON value
133 | * is found. The string does not need to be a JSON object or array;
134 | * it can also be a string, number or boolean value.
135 | *
136 | * A partial JSON string can be parsed. If the parsing is incomplete,
137 | * NULL will be returned and fjson_tokener_get_error() will be return
138 | * fjson_tokener_continue.
139 | * fjson_tokener_parse_ex() can then be called with additional bytes in str
140 | * to continue the parsing.
141 | *
142 | * If fjson_tokener_parse_ex() returns NULL and the error anything other than
143 | * fjson_tokener_continue, a fatal error has occurred and parsing must be
144 | * halted. Then tok object must not be re-used until fjson_tokener_reset() is
145 | * called.
146 | *
147 | * When a valid JSON value is parsed, a non-NULL fjson_object will be
148 | * returned. Also, fjson_tokener_get_error() will return fjson_tokener_success.
149 | * Be sure to check the type with fjson_object_is_type() or
150 | * fjson_object_get_type() before using the object.
151 | *
152 | * @b XXX this shouldn't use internal fields:
153 | * Trailing characters after the parsed value do not automatically cause an
154 | * error. It is up to the caller to decide whether to treat this as an
155 | * error or to handle the additional characters, perhaps by parsing another
156 | * json value starting from that point.
157 | *
158 | * Extra characters can be detected by comparing the tok->char_offset against
159 | * the length of the last len parameter passed in.
160 | *
161 | * The tokener does \b not maintain an internal buffer so the caller is
162 | * responsible for calling fjson_tokener_parse_ex with an appropriate str
163 | * parameter starting with the extra characters.
164 | *
165 | * This interface is presently not 64-bit clean due to the int len argument
166 | * so the function limits the maximum string size to INT32_MAX (2GB).
167 | * If the function is called with len == -1 then strlen is called to check
168 | * the string length is less than INT32_MAX (2GB)
169 | *
170 | * Example:
171 | * @code
172 | fjson_object *jobj = NULL;
173 | const char *mystring = NULL;
174 | int stringlen = 0;
175 | enum fjson_tokener_error jerr;
176 | do {
177 | mystring = ... // get JSON string, e.g. read from file, etc...
178 | stringlen = strlen(mystring);
179 | jobj = fjson_tokener_parse_ex(tok, mystring, stringlen);
180 | } while ((jerr = fjson_tokener_get_error(tok)) == fjson_tokener_continue);
181 | if (jerr != fjson_tokener_success)
182 | {
183 | fprintf(stderr, "Error: %s\n", fjson_tokener_error_desc(jerr));
184 | // Handle errors, as appropriate for your application.
185 | }
186 | if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
187 | {
188 | // Handle extra characters after parsed object as desired.
189 | // e.g. issue an error, parse another object from that point, etc...
190 | }
191 | // Success, use jobj here.
192 |
193 | @endcode
194 | *
195 | * @param tok a fjson_tokener previously allocated with fjson_tokener_new()
196 | * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated.
197 | * @param len the length of str
198 | */
199 | extern struct fjson_object* fjson_tokener_parse_ex(struct fjson_tokener *tok,
200 | const char *str, int len);
201 |
202 | #ifndef FJSON_NATIVE_API_ONLY
203 | #define json_tokener fjson_tokener
204 | #define json_tokener_error fjson_tokener_error
205 | extern const char* fjson_tokener_errors[15];
206 | #define json_tokener_errors fjson_tokener_errors
207 | #define json_tokener_continue fjson_tokener_continue
208 | #define json_tokener_reset fjson_tokener_reset
209 |
210 | #define json_tokener_new() fjson_tokener_new()
211 | #define json_tokener_parse fjson_tokener_parse
212 | #define json_tokener_parse_ex(a, b, c) fjson_tokener_parse_ex((a), (b), (c))
213 | #define json_tokener_free(a) fjson_tokener_free((a))
214 | #define json_tokener_error_desc(a) fjson_tokener_error_desc((a))
215 | #endif
216 |
217 | #ifdef __cplusplus
218 | }
219 | #endif
220 |
221 | #endif
222 |
--------------------------------------------------------------------------------
/json_util.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
3 | * Michael Clark
4 | * Copyright (c) 2016 Adiscon GmbH
5 | * Rainer Gerhards
6 | *
7 | * This library is free software; you can redistribute it and/or modify
8 | * it under the terms of the MIT license. See COPYING for details.
9 | *
10 | */
11 |
12 | #include "config.h"
13 | #undef realloc
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #ifdef HAVE_SYS_TYPES_H
25 | #include
26 | #endif /* HAVE_SYS_TYPES_H */
27 |
28 | #ifdef HAVE_SYS_STAT_H
29 | #include
30 | #endif /* HAVE_SYS_STAT_H */
31 |
32 | #ifdef HAVE_FCNTL_H
33 | #include
34 | #endif /* HAVE_FCNTL_H */
35 |
36 | #ifdef HAVE_UNISTD_H
37 | # include
38 | #endif /* HAVE_UNISTD_H */
39 |
40 | #if !defined(HAVE_SNPRINTF)
41 | # error You do not have snprintf on your system.
42 | #endif /* HAVE_SNPRINTF */
43 |
44 | #include "debug.h"
45 | #include "printbuf.h"
46 | #include "json_object.h"
47 | #include "json_tokener.h"
48 | #include "json_util.h"
49 |
50 | static int sscanf_is_broken = 0;
51 | static int sscanf_is_broken_testdone = 0;
52 | static void sscanf_is_broken_test(void);
53 |
54 | /*
55 | * Create a JSON object from already opened file descriptor.
56 | *
57 | * This function can be helpful, when you opened the file already,
58 | * e.g. when you have a temp file.
59 | * Note, that the fd must be readable at the actual position, i.e.
60 | * use lseek(fd, 0, SEEK_SET) before.
61 | */
62 | struct fjson_object* fjson_object_from_fd(int fd)
63 | {
64 | struct printbuf *pb;
65 | struct fjson_object *obj;
66 | char buf[FJSON_FILE_BUF_SIZE];
67 | int ret;
68 |
69 | if(!(pb = printbuf_new())) {
70 | MC_ERROR("fjson_object_from_file: printbuf_new failed\n");
71 | return NULL;
72 | }
73 | while((ret = read(fd, buf, FJSON_FILE_BUF_SIZE)) > 0) {
74 | printbuf_memappend(pb, buf, ret);
75 | }
76 | if(ret < 0) {
77 | MC_ERROR("fjson_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno));
78 | printbuf_free(pb);
79 | return NULL;
80 | }
81 | obj = fjson_tokener_parse(pb->buf);
82 | printbuf_free(pb);
83 | return obj;
84 | }
85 |
86 | struct fjson_object* fjson_object_from_file(const char *filename)
87 | {
88 | struct fjson_object *obj;
89 | int fd;
90 |
91 | if((fd = open(filename, O_RDONLY)) < 0) {
92 | MC_ERROR("fjson_object_from_file: error opening file %s: %s\n",
93 | filename, strerror(errno));
94 | return NULL;
95 | }
96 | obj = fjson_object_from_fd(fd);
97 | close(fd);
98 | return obj;
99 | }
100 |
101 | /* extended "format and write to file" function */
102 |
103 | int fjson_object_to_file_ext(const char *filename, struct fjson_object *obj, int flags)
104 | {
105 | const char *fjson_str;
106 | int fd, ret;
107 | unsigned int wpos, wsize;
108 |
109 | if(!obj) {
110 | MC_ERROR("fjson_object_to_file: object is null\n");
111 | return -1;
112 | }
113 |
114 | if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
115 | MC_ERROR("fjson_object_to_file: error opening file %s: %s\n",
116 | filename, strerror(errno));
117 | return -1;
118 | }
119 |
120 | if(!(fjson_str = fjson_object_to_json_string_ext(obj,flags))) {
121 | close(fd);
122 | return -1;
123 | }
124 |
125 | wsize = (unsigned int)(strlen(fjson_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
126 | wpos = 0;
127 | while(wpos < wsize) {
128 | if((ret = write(fd, fjson_str + wpos, wsize-wpos)) < 0) {
129 | close(fd);
130 | MC_ERROR("fjson_object_to_file: error writing file %s: %s\n",
131 | filename, strerror(errno));
132 | return -1;
133 | }
134 |
135 | /* because of the above check for ret < 0, we can safely cast and add */
136 | wpos += (unsigned int)ret;
137 | }
138 |
139 | close(fd);
140 | return 0;
141 | }
142 |
143 | // backwards compatible "format and write to file" function
144 |
145 | int fjson_object_to_file(const char *filename, struct fjson_object *obj)
146 | {
147 | return fjson_object_to_file_ext(filename, obj, FJSON_TO_STRING_PLAIN);
148 | }
149 |
150 | int fjson_parse_double(const char *buf, double *retval)
151 | {
152 | return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
153 | }
154 |
155 | /*
156 | * Not all implementations of sscanf actually work properly.
157 | * Check whether the one we're currently using does, and if
158 | * it's broken, enable the workaround code.
159 | */
160 | static void sscanf_is_broken_test(void)
161 | {
162 | int64_t num64;
163 | int ret_errno, is_int64_min, ret_errno2, is_int64_max;
164 |
165 | (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64);
166 | ret_errno = errno;
167 | is_int64_min = (num64 == INT64_MIN);
168 |
169 | (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64);
170 | ret_errno2 = errno;
171 | is_int64_max = (num64 == INT64_MAX);
172 |
173 | if (ret_errno != ERANGE || !is_int64_min ||
174 | ret_errno2 != ERANGE || !is_int64_max)
175 | {
176 | MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n");
177 | sscanf_is_broken = 1;
178 | }
179 | }
180 |
181 | int fjson_parse_int64(const char *buf, int64_t *retval)
182 | {
183 | int64_t num64;
184 | const char *buf_sig_digits;
185 | int orig_has_neg;
186 | int saved_errno;
187 |
188 | if (!sscanf_is_broken_testdone)
189 | {
190 | sscanf_is_broken_test();
191 | sscanf_is_broken_testdone = 1;
192 | }
193 |
194 | // Skip leading spaces
195 | while (isspace((int)*buf) && *buf)
196 | buf++;
197 |
198 | errno = 0; // sscanf won't always set errno, so initialize
199 | if (sscanf(buf, "%" SCNd64, &num64) != 1)
200 | {
201 | MC_DEBUG("Failed to parse, sscanf != 1\n");
202 | return 1;
203 | }
204 |
205 | saved_errno = errno;
206 | buf_sig_digits = buf;
207 | orig_has_neg = 0;
208 | if (*buf_sig_digits == '-')
209 | {
210 | buf_sig_digits++;
211 | orig_has_neg = 1;
212 | }
213 |
214 | // Not all sscanf implementations actually work
215 | if (sscanf_is_broken && saved_errno != ERANGE)
216 | {
217 | char buf_cmp[100];
218 | char *buf_cmp_start = buf_cmp;
219 | int recheck_has_neg = 0;
220 | int buf_cmp_len;
221 |
222 | // Skip leading zeros, but keep at least one digit
223 | while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0')
224 | buf_sig_digits++;
225 | if (num64 == 0) // assume all sscanf impl's will parse -0 to 0
226 | orig_has_neg = 0; // "-0" is the same as just plain "0"
227 |
228 | snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
229 | if (*buf_cmp_start == '-')
230 | {
231 | recheck_has_neg = 1;
232 | buf_cmp_start++;
233 | }
234 | // No need to skip leading spaces or zeros here.
235 |
236 | buf_cmp_len = strlen(buf_cmp_start);
237 | /**
238 | * If the sign is different, or
239 | * some of the digits are different, or
240 | * there is another digit present in the original string
241 | * then we have NOT successfully parsed the value.
242 | */
243 | if (orig_has_neg != recheck_has_neg ||
244 | strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
245 | ((int)strlen(buf_sig_digits) != buf_cmp_len &&
246 | isdigit((int)buf_sig_digits[buf_cmp_len])
247 | )
248 | )
249 | {
250 | saved_errno = ERANGE;
251 | }
252 | }
253 |
254 | // Not all sscanf impl's set the value properly when out of range.
255 | // Always do this, even for properly functioning implementations,
256 | // since it shouldn't slow things down much.
257 | if (saved_errno == ERANGE)
258 | {
259 | if (orig_has_neg)
260 | num64 = INT64_MIN;
261 | else
262 | num64 = INT64_MAX;
263 | }
264 | *retval = num64;
265 | return 0;
266 | }
267 |
268 | #define NELEM(a) (sizeof(a) / sizeof(a[0]))
269 | static const char* fjson_type_name[] = {
270 | /* If you change this, be sure to update the enum fjson_type definition too */
271 | "null",
272 | "boolean",
273 | "double",
274 | "int",
275 | "object",
276 | "array",
277 | "string",
278 | };
279 |
280 | const char *fjson_type_to_name(enum fjson_type o_type)
281 | {
282 | int o_type_int = (int)o_type;
283 | if (o_type_int < 0 || o_type_int >= (int)NELEM(fjson_type_name))
284 | {
285 | MC_ERROR("fjson_type_to_name: type %d is out of range [0,%zu]\n", o_type, NELEM(fjson_type_name));
286 | return NULL;
287 | }
288 | return fjson_type_name[o_type];
289 | }
290 |
291 |
--------------------------------------------------------------------------------
/atomic.h:
--------------------------------------------------------------------------------
1 | /* This header supplies atomic operations. So far, we rely on GCC's
2 | * atomic builtins. During configure, we check if atomic operatons are
3 | * available. If they are not, I am making the necessary provisioning to live without them if
4 | * they are not available. Please note that you should only use the macros
5 | * here if you think you can actually live WITHOUT an explicit atomic operation,
6 | * because in the non-presence of them, we simply do it without atomicitiy.
7 | * Which, for word-aligned data types, usually (but only usually!) should work.
8 | *
9 | * We are using the functions described in
10 | * http:/gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html
11 | *
12 | * THESE MACROS MUST ONLY BE USED WITH WORD-SIZED DATA TYPES!
13 | *
14 | * Note: this file was obtained at 2015-12-16 from the rsyslog project.
15 | *
16 | * Copyright 2008-2015 Rainer Gerhards and Adiscon GmbH.
17 | *
18 | * This file is part of the rsyslog runtime library.
19 | *
20 | * Licensed under the Apache License, Version 2.0 (the "License");
21 | * you may not use this file except in compliance with the License.
22 | * You may obtain a copy of the License at
23 | *
24 | * http://www.apache.org/licenses/LICENSE-2.0
25 | * -or-
26 | * see COPYING.ASL20 in the source distribution
27 | *
28 | * Unless required by applicable law or agreed to in writing, software
29 | * distributed under the License is distributed on an "AS IS" BASIS,
30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 | * See the License for the specific language governing permissions and
32 | * limitations under the License.
33 | */
34 | #ifndef FJ_INCLUDED_ATOMIC_H
35 | #define FJ_INCLUDED_ATOMIC_H
36 |
37 | #ifdef HAVE_ATOMIC_BUILTINS
38 | # define ATOMIC_SUB(data, val, phlpmut) __sync_fetch_and_sub(data, val)
39 | # define ATOMIC_ADD(data, val) __sync_fetch_and_add(&(data), val)
40 | # define ATOMIC_INC(data, phlpmut) ((void) __sync_fetch_and_add(data, 1))
41 | # define ATOMIC_INC_AND_FETCH_int(data, phlpmut) __sync_fetch_and_add(data, 1)
42 | # define ATOMIC_INC_AND_FETCH_unsigned(data, phlpmut) __sync_fetch_and_add(data, 1)
43 | # define ATOMIC_DEC(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1))
44 | # define ATOMIC_DEC_AND_FETCH(data, phlpmut) __sync_sub_and_fetch(data, 1)
45 | # define ATOMIC_FETCH_32BIT(data, phlpmut) ((unsigned) __sync_fetch_and_and(data, 0xffffffff))
46 | # define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1)
47 | # define ATOMIC_STORE_0_TO_INT(data, phlpmut) __sync_fetch_and_and(data, 0)
48 | # define ATOMIC_STORE_1_TO_INT(data, phlpmut) __sync_fetch_and_or(data, 1)
49 | # define ATOMIC_STORE_INT_TO_INT(data, val) __sync_fetch_and_or(&(data), (val))
50 | # define ATOMIC_CAS(data, oldVal, newVal, phlpmut) __sync_bool_compare_and_swap(data, (oldVal), (newVal))
51 | # define ATOMIC_CAS_time_t(data, oldVal, newVal, phlpmut) __sync_bool_compare_and_swap(data, (oldVal), (newVal))
52 | # define ATOMIC_CAS_VAL(data, oldVal, newVal, phlpmut) __sync_val_compare_and_swap(data, (oldVal), (newVal));
53 |
54 | /* functions below are not needed if we have atomics */
55 | # define DEF_ATOMIC_HELPER_MUT(x)
56 | # define INIT_ATOMIC_HELPER_MUT(x)
57 | # define DESTROY_ATOMIC_HELPER_MUT(x)
58 |
59 | /* the following operations should preferrably be done atomic, but it is
60 | * not fatal if not -- that means we can live with some missed updates. So be
61 | * sure to use these macros only if that really does not matter!
62 | */
63 | # define PREFER_ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
64 | #else
65 | /* note that we gained parctical proof that theoretical problems DO occur
66 | * if we do not properly address them. See this blog post for details:
67 | * http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html
68 | * The bottom line is that if there are no atomics available, we should NOT
69 | * simply go ahead and do without them - use mutexes or other things.
70 | * rgerhards, 2009-01-30
71 | */
72 | #include
73 | # define ATOMIC_INC(data, phlpmut) { \
74 | pthread_mutex_lock(phlpmut); \
75 | ++(*(data)); \
76 | pthread_mutex_unlock(phlpmut); \
77 | }
78 |
79 | # define ATOMIC_STORE_0_TO_INT(data, hlpmut) { \
80 | pthread_mutex_lock(hlpmut); \
81 | *(data) = 0; \
82 | pthread_mutex_unlock(hlpmut); \
83 | }
84 |
85 | # define ATOMIC_STORE_1_TO_INT(data, hlpmut) { \
86 | pthread_mutex_lock(hlpmut); \
87 | *(data) = 1; \
88 | pthread_mutex_unlock(hlpmut); \
89 | }
90 |
91 | static inline int
92 | ATOMIC_CAS(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) {
93 | int bSuccess;
94 | pthread_mutex_lock(phlpmut);
95 | if(*data == oldVal) {
96 | *data = newVal;
97 | bSuccess = 1;
98 | } else {
99 | bSuccess = 0;
100 | }
101 | pthread_mutex_unlock(phlpmut);
102 | return(bSuccess);
103 | }
104 |
105 | static inline int
106 | ATOMIC_CAS_time_t(time_t *data, time_t oldVal, time_t newVal, pthread_mutex_t *phlpmut) {
107 | int bSuccess;
108 | pthread_mutex_lock(phlpmut);
109 | if(*data == oldVal) {
110 | *data = newVal;
111 | bSuccess = 1;
112 | } else {
113 | bSuccess = 0;
114 | }
115 | pthread_mutex_unlock(phlpmut);
116 | return(bSuccess);
117 | }
118 |
119 |
120 | static inline int
121 | ATOMIC_CAS_VAL(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) {
122 | int val;
123 | pthread_mutex_lock(phlpmut);
124 | if(*data == oldVal) {
125 | *data = newVal;
126 | }
127 | val = *data;
128 | pthread_mutex_unlock(phlpmut);
129 | return(val);
130 | }
131 |
132 | # define ATOMIC_DEC(data, phlpmut) { \
133 | pthread_mutex_lock(phlpmut); \
134 | --(*(data)); \
135 | pthread_mutex_unlock(phlpmut); \
136 | }
137 |
138 | static inline int
139 | ATOMIC_INC_AND_FETCH_int(int *data, pthread_mutex_t *phlpmut) {
140 | int val;
141 | pthread_mutex_lock(phlpmut);
142 | val = ++(*data);
143 | pthread_mutex_unlock(phlpmut);
144 | return(val);
145 | }
146 |
147 | static inline unsigned
148 | ATOMIC_INC_AND_FETCH_unsigned(unsigned *data, pthread_mutex_t *phlpmut) {
149 | unsigned val;
150 | pthread_mutex_lock(phlpmut);
151 | val = ++(*data);
152 | pthread_mutex_unlock(phlpmut);
153 | return(val);
154 | }
155 |
156 | static inline int
157 | ATOMIC_DEC_AND_FETCH(int *data, pthread_mutex_t *phlpmut) {
158 | int val;
159 | pthread_mutex_lock(phlpmut);
160 | val = --(*data);
161 | pthread_mutex_unlock(phlpmut);
162 | return(val);
163 | }
164 |
165 | static inline int
166 | ATOMIC_FETCH_32BIT(int *data, pthread_mutex_t *phlpmut) {
167 | int val;
168 | pthread_mutex_lock(phlpmut);
169 | val = (*data);
170 | pthread_mutex_unlock(phlpmut);
171 | return(val);
172 | }
173 |
174 | static inline void
175 | ATOMIC_SUB(int *data, int val, pthread_mutex_t *phlpmut) {
176 | pthread_mutex_lock(phlpmut);
177 | (*data) -= val;
178 | pthread_mutex_unlock(phlpmut);
179 | }
180 | # define DEF_ATOMIC_HELPER_MUT(x) pthread_mutex_t x;
181 | # define INIT_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL);
182 | # define DESTROY_ATOMIC_HELPER_MUT(x) pthread_mutex_destroy(&(x));
183 |
184 | # define PREFER_ATOMIC_INC(data) ((void) ++data)
185 |
186 | #endif
187 |
188 | /* we need to handle 64bit atomics seperately as some platforms have
189 | * 32 bit atomics, but not 64 bit ones... -- rgerhards, 2010-12-01
190 | */
191 | #if 0 /* currently disabled, we don't need it now and dont' have the data types present */
192 | #ifdef HAVE_ATOMIC_BUILTINS64
193 | # define ATOMIC_INC_uint64(data, phlpmut) ((void) __sync_fetch_and_add(data, 1))
194 | # define ATOMIC_DEC_unit64(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1))
195 | # define ATOMIC_INC_AND_FETCH_uint64(data, phlpmut) __sync_fetch_and_add(data, 1)
196 |
197 | # define DEF_ATOMIC_HELPER_MUT64(x)
198 | # define INIT_ATOMIC_HELPER_MUT64(x)
199 | # define DESTROY_ATOMIC_HELPER_MUT64(x)
200 | #else
201 | # define ATOMIC_INC_uint64(data, phlpmut) { \
202 | pthread_mutex_lock(phlpmut); \
203 | ++(*(data)); \
204 | pthread_mutex_unlock(phlpmut); \
205 | }
206 | # define ATOMIC_DEC_uint64(data, phlpmut) { \
207 | pthread_mutex_lock(phlpmut); \
208 | --(*(data)); \
209 | pthread_mutex_unlock(phlpmut); \
210 | }
211 |
212 | static inline unsigned
213 | ATOMIC_INC_AND_FETCH_uint64(uint64 *data, pthread_mutex_t *phlpmut) {
214 | uint64 val;
215 | pthread_mutex_lock(phlpmut);
216 | val = ++(*data);
217 | pthread_mutex_unlock(phlpmut);
218 | return(val);
219 | }
220 |
221 | # define DEF_ATOMIC_HELPER_MUT64(x) pthread_mutex_t x;
222 | # define INIT_ATOMIC_HELPER_MUT64(x) pthread_mutex_init(&(x), NULL)
223 | # define DESTROY_ATOMIC_HELPER_MUT64(x) pthread_mutex_destroy(&(x))
224 | #endif /* #ifdef HAVE_ATOMIC_BUILTINS64 */
225 | #endif
226 |
227 | #endif /* #ifndef INCLUDED_ATOMIC_H */
228 |
--------------------------------------------------------------------------------
/json_object_iterator.h:
--------------------------------------------------------------------------------
1 | /**
2 | *******************************************************************************
3 | * @file fjson_object_iterator.h
4 | *
5 | * Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
6 | *
7 | * This library is free software; you can redistribute it and/or modify
8 | * it under the terms of the MIT license. See COPYING for details.
9 | *
10 | * @brief json-c forces clients to use its private data
11 | * structures for JSON Object iteration. This API
12 | * corrects that by abstracting the private json-c
13 | * details.
14 | *
15 | * API attributes:
16 | * * Thread-safe: NO
17 | * * Reentrant: NO
18 | *
19 | *******************************************************************************
20 | */
21 |
22 |
23 | #ifndef FJ_JSON_OBJECT_ITERATOR_H
24 | #define FJ_JSON_OBJECT_ITERATOR_H
25 |
26 | #include
27 |
28 | #ifdef __cplusplus
29 | extern "C" {
30 | #endif
31 |
32 | /**
33 | * Forward declaration for the opaque iterator information.
34 | */
35 | struct fjson_object_iter_info_;
36 |
37 | /**
38 | * The opaque iterator that references a name/value pair within
39 | * a JSON Object instance or the "end" iterator value.
40 | */
41 | struct fjson_object_iterator {
42 | int objs_remain;
43 | int curr_idx;
44 | const struct _fjson_child_pg *pg;
45 | };
46 |
47 |
48 | /**
49 | * forward declaration of json-c's JSON value instance structure
50 | */
51 | struct fjson_object;
52 |
53 |
54 | /**
55 | * Initializes an iterator structure to a "default" value that
56 | * is convenient for initializing an iterator variable to a
57 | * default state (e.g., initialization list in a class'
58 | * constructor).
59 | *
60 | * @code
61 | * struct fjson_object_iterator iter = fjson_object_iter_init_default();
62 | * MyClass() : iter_(fjson_object_iter_init_default())
63 | * @endcode
64 | *
65 | * @note The initialized value doesn't reference any specific
66 | * pair, is considered an invalid iterator, and MUST NOT
67 | * be passed to any json-c API that expects a valid
68 | * iterator.
69 | *
70 | * @note User and internal code MUST NOT make any assumptions
71 | * about and dependencies on the value of the "default"
72 | * iterator value.
73 | *
74 | * @return fjson_object_iterator
75 | */
76 | struct fjson_object_iterator
77 | fjson_object_iter_init_default(void);
78 |
79 | /** Retrieves an iterator to the first pair of the JSON Object.
80 | *
81 | * @warning Any modification of the underlying pair invalidates all
82 | * iterators to that pair.
83 | *
84 | * @param obj JSON Object instance (MUST be of type fjson_object)
85 | *
86 | * @return fjson_object_iterator If the JSON Object has at
87 | * least one pair, on return, the iterator refers
88 | * to the first pair. If the JSON Object doesn't
89 | * have any pairs, the returned iterator is
90 | * equivalent to the "end" iterator for the same
91 | * JSON Object instance.
92 | *
93 | * @code
94 | * struct fjson_object_iterator it;
95 | * struct fjson_object_iterator itEnd;
96 | * struct fjson_object* obj;
97 | *
98 | * obj = fjson_tokener_parse("{'first':'george', 'age':100}");
99 | * it = fjson_object_iter_begin(obj);
100 | * itEnd = fjson_object_iter_end(obj);
101 | *
102 | * while (!fjson_object_iter_equal(&it, &itEnd)) {
103 | * printf("%s\n",
104 | * fjson_object_iter_peek_name(&it));
105 | * fjson_object_iter_next(&it);
106 | * }
107 | *
108 | * @endcode
109 | */
110 | struct fjson_object_iterator
111 | fjson_object_iter_begin(struct fjson_object* obj);
112 |
113 | /** Retrieves the iterator that represents the position beyond the
114 | * last pair of the given JSON Object instance.
115 | *
116 | * @warning Do NOT write code that assumes that the "end"
117 | * iterator value is NULL, even if it is so in a
118 | * particular instance of the implementation.
119 | *
120 | * @note The reason we do not (and MUST NOT) provide
121 | * "fjson_object_iter_is_end(fjson_object_iterator* iter)"
122 | * type of API is because it would limit the underlying
123 | * representation of name/value containment (or force us
124 | * to add additional, otherwise unnecessary, fields to
125 | * the iterator structure). The "end" iterator and the
126 | * equality test method, on the other hand, permit us to
127 | * cleanly abstract pretty much any reasonable underlying
128 | * representation without burdening the iterator
129 | * structure with unnecessary data.
130 | *
131 | * @note For performance reasons, memorize the "end" iterator prior
132 | * to any loop.
133 | *
134 | * @param obj JSON Object instance (MUST be of type fjson_object)
135 | *
136 | * @return fjson_object_iterator On return, the iterator refers
137 | * to the "end" of the Object instance's pairs
138 | * (i.e., NOT the last pair, but "beyond the last
139 | * pair" value)
140 | */
141 | struct fjson_object_iterator
142 | fjson_object_iter_end(const struct fjson_object* obj);
143 |
144 | /** Returns an iterator to the next pair, if any
145 | *
146 | * @warning Any modification of the underlying pair
147 | * invalidates all iterators to that pair.
148 | *
149 | * @param iter [IN/OUT] Pointer to iterator that references a
150 | * name/value pair; MUST be a valid, non-end iterator.
151 | * WARNING: bad things will happen if invalid or "end"
152 | * iterator is passed. Upon return will contain the
153 | * reference to the next pair if there is one; if there
154 | * are no more pairs, will contain the "end" iterator
155 | * value, which may be compared against the return value
156 | * of fjson_object_iter_end() for the same JSON Object
157 | * instance.
158 | */
159 | void
160 | fjson_object_iter_next(struct fjson_object_iterator* iter);
161 |
162 |
163 | /** Returns a const pointer to the name of the pair referenced
164 | * by the given iterator.
165 | *
166 | * @param iter pointer to iterator that references a name/value
167 | * pair; MUST be a valid, non-end iterator.
168 | *
169 | * @warning bad things will happen if an invalid or
170 | * "end" iterator is passed.
171 | *
172 | * @return const char* Pointer to the name of the referenced
173 | * name/value pair. The name memory belongs to the
174 | * name/value pair, will be freed when the pair is
175 | * deleted or modified, and MUST NOT be modified or
176 | * freed by the user.
177 | */
178 | const char*
179 | fjson_object_iter_peek_name(const struct fjson_object_iterator* iter);
180 |
181 |
182 | /** Returns a pointer to the json-c instance representing the
183 | * value of the referenced name/value pair, without altering
184 | * the instance's reference count.
185 | *
186 | * @param iter pointer to iterator that references a name/value
187 | * pair; MUST be a valid, non-end iterator.
188 | *
189 | * @warning bad things will happen if invalid or
190 | * "end" iterator is passed.
191 | *
192 | * @return struct fjson_object* Pointer to the json-c value
193 | * instance of the referenced name/value pair; the
194 | * value's reference count is not changed by this
195 | * function: if you plan to hold on to this json-c node,
196 | * take a look at fjson_object_get() and
197 | * fjson_object_put(). IMPORTANT: json-c API represents
198 | * the JSON Null value as a NULL fjson_object instance
199 | * pointer.
200 | */
201 | struct fjson_object*
202 | fjson_object_iter_peek_value(const struct fjson_object_iterator* iter);
203 |
204 |
205 | /** Tests two iterators for equality. Typically used to test
206 | * for end of iteration by comparing an iterator to the
207 | * corresponding "end" iterator (that was derived from the same
208 | * JSON Object instance).
209 | *
210 | * @note The reason we do not (and MUST NOT) provide
211 | * "fjson_object_iter_is_end(fjson_object_iterator* iter)"
212 | * type of API is because it would limit the underlying
213 | * representation of name/value containment (or force us
214 | * to add additional, otherwise unnecessary, fields to
215 | * the iterator structure). The equality test method, on
216 | * the other hand, permits us to cleanly abstract pretty
217 | * much any reasonable underlying representation.
218 | *
219 | * @param iter1 Pointer to first valid, non-NULL iterator
220 | * @param iter2 POinter to second valid, non-NULL iterator
221 | *
222 | * @warning if a NULL iterator pointer or an uninitialized
223 | * or invalid iterator, or iterators derived from
224 | * different JSON Object instances are passed, bad things
225 | * will happen!
226 | *
227 | * @return fjson_bool non-zero if iterators are equal (i.e., both
228 | * reference the same name/value pair or are both at
229 | * "end"); zero if they are not equal.
230 | */
231 | fjson_bool
232 | fjson_object_iter_equal(const struct fjson_object_iterator* iter1,
233 | const struct fjson_object_iterator* iter2);
234 |
235 | /* some private functions -- TODO: move to their own header */
236 | struct _fjson_child*
237 | _fjson_object_iter_peek_child(const struct fjson_object_iterator *const __restrict__ iter);
238 |
239 |
240 | #ifndef FJSON_NATIVE_API_ONLY
241 | #define json_object_iter_info_ fjson_object_iter_info_
242 | #define json_object_iterator fjson_object_iterator
243 | #define json_object_iter_init_default fjson_object_iter_init_default
244 | #define json_object_iter_begin fjson_object_iter_begin
245 | #define json_object_iter_end fjson_object_iter_end
246 | #define json_object_iter_next fjson_object_iter_next
247 | #define json_object_iter_peek_name fjson_object_iter_peek_name
248 | #define json_object_iter_peek_value fjson_object_iter_peek_value
249 | #define json_object_iter_equal fjson_object_iter_equal
250 | #endif
251 |
252 | #ifdef __cplusplus
253 | }
254 | #endif
255 |
256 |
257 | #endif /* FJSON_OBJECT_ITERATOR_H */
258 |
--------------------------------------------------------------------------------
/tests/test_many_subobj.expected:
--------------------------------------------------------------------------------
1 | STEP1: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "key-50": 50, "key-51": 51, "key-52": 52, "key-53": 53, "key-54": 54, "key-55": 55, "key-56": 56, "key-57": 57, "key-58": 58, "key-59": 59, "key-60": 60, "key-61": 61, "key-62": 62, "key-63": 63, "key-64": 64, "key-65": 65, "key-66": 66, "key-67": 67, "key-68": 68, "key-69": 69, "key-70": 70, "key-71": 71, "key-72": 72, "key-73": 73, "key-74": 74, "key-75": 75, "key-76": 76, "key-77": 77, "key-78": 78, "key-79": 79, "key-80": 80, "key-81": 81, "key-82": 82, "key-83": 83, "key-84": 84, "key-85": 85, "key-86": 86, "key-87": 87, "key-88": 88, "key-89": 89, "key-90": 90, "key-91": 91, "key-92": 92, "key-93": 93, "key-94": 94, "key-95": 95, "key-96": 96, "key-97": 97, "key-98": 98, "key-99": 99, "key-100": 100, "key-101": 101, "key-102": 102, "key-103": 103, "key-104": 104, "key-105": 105, "key-106": 106, "key-107": 107, "key-108": 108, "key-109": 109, "key-110": 110, "key-111": 111, "key-112": 112, "key-113": 113, "key-114": 114, "key-115": 115, "key-116": 116, "key-117": 117, "key-118": 118, "key-119": 119, "key-120": 120, "key-121": 121, "key-122": 122, "key-123": 123, "key-124": 124, "key-125": 125, "key-126": 126, "key-127": 127, "key-128": 128, "key-129": 129, "key-130": 130, "key-131": 131, "key-132": 132, "key-133": 133, "key-134": 134, "key-135": 135, "key-136": 136, "key-137": 137, "key-138": 138, "key-139": 139, "key-140": 140, "key-141": 141, "key-142": 142, "key-143": 143, "key-144": 144, "key-145": 145, "key-146": 146, "key-147": 147, "key-148": 148, "key-149": 149, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
2 | STEP2: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
3 | STEP3: { "key-0": 0, "key-1": 1, "key-2": 2, "key-3": 3, "key-4": 4, "key-5": 5, "key-6": 6, "key-7": 7, "key-8": 8, "key-9": 9, "key-10": 10, "key-11": 11, "key-12": 12, "key-13": 13, "key-14": 14, "key-15": 15, "key-16": 16, "key-17": 17, "key-18": 18, "key-19": 19, "key-20": 20, "key-21": 21, "key-22": 22, "key-23": 23, "key-24": 24, "key-25": 25, "key-26": 26, "key-27": 27, "key-28": 28, "key-29": 29, "key-30": 30, "key-31": 31, "key-32": 32, "key-33": 33, "key-34": 34, "key-35": 35, "key-36": 36, "key-37": 37, "key-38": 38, "key-39": 39, "key-40": 40, "key-41": 41, "key-42": 42, "key-43": 43, "key-44": 44, "key-45": 45, "key-46": 46, "key-47": 47, "key-48": 48, "key-49": 49, "KEY-149": 149, "KEY-148": 148, "KEY-147": 147, "KEY-146": 146, "KEY-145": 145, "KEY-144": 144, "KEY-143": 143, "KEY-142": 142, "KEY-141": 141, "KEY-140": 140, "KEY-139": 139, "KEY-138": 138, "KEY-137": 137, "KEY-136": 136, "KEY-135": 135, "KEY-134": 134, "KEY-133": 133, "KEY-132": 132, "KEY-131": 131, "KEY-130": 130, "KEY-129": 129, "KEY-128": 128, "KEY-127": 127, "KEY-126": 126, "KEY-125": 125, "KEY-124": 124, "KEY-123": 123, "KEY-122": 122, "KEY-121": 121, "KEY-120": 120, "KEY-119": 119, "KEY-118": 118, "KEY-117": 117, "KEY-116": 116, "KEY-115": 115, "KEY-114": 114, "KEY-113": 113, "KEY-112": 112, "KEY-111": 111, "KEY-110": 110, "KEY-109": 109, "KEY-108": 108, "KEY-107": 107, "KEY-106": 106, "KEY-105": 105, "KEY-104": 104, "KEY-103": 103, "KEY-102": 102, "KEY-101": 101, "KEY-100": 100, "KEY-99": 99, "KEY-98": 98, "KEY-97": 97, "KEY-96": 96, "KEY-95": 95, "KEY-94": 94, "KEY-93": 93, "KEY-92": 92, "KEY-91": 91, "KEY-90": 90, "KEY-89": 89, "KEY-88": 88, "KEY-87": 87, "KEY-86": 86, "KEY-85": 85, "KEY-84": 84, "KEY-83": 83, "KEY-82": 82, "KEY-81": 81, "KEY-80": 80, "KEY-79": 79, "KEY-78": 78, "KEY-77": 77, "KEY-76": 76, "KEY-75": 75, "KEY-74": 74, "KEY-73": 73, "KEY-72": 72, "KEY-71": 71, "KEY-70": 70, "KEY-69": 69, "KEY-68": 68, "KEY-67": 67, "KEY-66": 66, "KEY-65": 65, "KEY-64": 64, "KEY-63": 63, "KEY-62": 62, "KEY-61": 61, "KEY-60": 60, "KEY-59": 59, "KEY-58": 58, "KEY-57": 57, "KEY-56": 56, "KEY-55": 55, "KEY-54": 54, "KEY-53": 53, "KEY-52": 52, "KEY-51": 51, "KEY-50": 50, "key-150": 150, "key-151": 151, "key-152": 152, "key-153": 153, "key-154": 154, "key-155": 155, "key-156": 156, "key-157": 157, "key-158": 158, "key-159": 159, "key-160": 160, "key-161": 161, "key-162": 162, "key-163": 163, "key-164": 164, "key-165": 165, "key-166": 166, "key-167": 167, "key-168": 168, "key-169": 169, "key-170": 170, "key-171": 171, "key-172": 172, "key-173": 173, "key-174": 174, "key-175": 175, "key-176": 176, "key-177": 177, "key-178": 178, "key-179": 179, "key-180": 180, "key-181": 181, "key-182": 182, "key-183": 183, "key-184": 184, "key-185": 185, "key-186": 186, "key-187": 187, "key-188": 188, "key-189": 189, "key-190": 190, "key-191": 191, "key-192": 192, "key-193": 193, "key-194": 194, "key-195": 195, "key-196": 196, "key-197": 197, "key-198": 198, "key-199": 199 }
4 | STEP4: { "key-0": 0, "key-1": 10, "key-2": 20, "key-3": 30, "key-4": 40, "key-5": 50, "key-6": 60, "key-7": 70, "key-8": 80, "key-9": 90, "key-10": 100, "key-11": 110, "key-12": 120, "key-13": 130, "key-14": 140, "key-15": 150, "key-16": 160, "key-17": 170, "key-18": 180, "key-19": 190, "key-20": 200, "key-21": 210, "key-22": 220, "key-23": 230, "key-24": 240, "key-25": 250, "key-26": 260, "key-27": 270, "key-28": 280, "key-29": 290, "key-30": 300, "key-31": 310, "key-32": 320, "key-33": 330, "key-34": 340, "key-35": 350, "key-36": 360, "key-37": 370, "key-38": 380, "key-39": 390, "key-40": 400, "key-41": 410, "key-42": 420, "key-43": 430, "key-44": 440, "key-45": 450, "key-46": 460, "key-47": 470, "key-48": 480, "key-49": 490, "key-50": 500, "key-51": 510, "key-52": 520, "key-53": 530, "key-54": 540, "key-55": 550, "key-56": 560, "key-57": 570, "key-58": 580, "key-59": 590, "key-60": 600, "key-61": 610, "key-62": 620, "key-63": 630, "key-64": 640, "key-65": 650, "key-66": 660, "key-67": 670, "key-68": 680, "key-69": 690, "key-70": 700, "key-71": 710, "key-72": 720, "key-73": 730, "key-74": 740, "key-75": 750, "key-76": 760, "key-77": 770, "key-78": 780, "key-79": 790, "key-80": 800, "key-81": 810, "key-82": 820, "key-83": 830, "key-84": 840, "key-85": 850, "key-86": 860, "key-87": 870, "key-88": 880, "key-89": 890, "key-90": 900, "key-91": 910, "key-92": 920, "key-93": 930, "key-94": 940, "key-95": 950, "key-96": 960, "key-97": 970, "key-98": 980, "key-99": 990, "key-100": 1000, "key-101": 1010, "key-102": 1020, "key-103": 1030, "key-104": 1040, "key-105": 1050, "key-106": 1060, "key-107": 1070, "key-108": 1080, "key-109": 1090, "key-110": 1100, "key-111": 1110, "key-112": 1120, "key-113": 1130, "key-114": 1140, "key-115": 1150, "key-116": 1160, "key-117": 1170, "key-118": 1180, "key-119": 1190, "key-120": 1200, "key-121": 1210, "key-122": 1220, "key-123": 1230, "key-124": 1240, "key-125": 1250, "key-126": 1260, "key-127": 1270, "key-128": 1280, "key-129": 1290, "key-130": 1300, "key-131": 1310, "key-132": 1320, "key-133": 1330, "key-134": 1340, "key-135": 1350, "key-136": 1360, "key-137": 1370, "key-138": 1380, "key-139": 1390, "key-140": 1400, "key-141": 1410, "key-142": 1420, "key-143": 1430, "key-144": 1440, "key-145": 1450, "key-146": 1460, "key-147": 1470, "key-148": 1480, "key-149": 1490, "key-150": 1500, "key-151": 1510, "key-152": 1520, "key-153": 1530, "key-154": 1540, "key-155": 1550, "key-156": 1560, "key-157": 1570, "key-158": 1580, "key-159": 1590, "key-160": 1600, "key-161": 1610, "key-162": 1620, "key-163": 1630, "key-164": 1640, "key-165": 1650, "key-166": 1660, "key-167": 1670, "key-168": 1680, "key-169": 1690, "key-170": 1700, "key-171": 1710, "key-172": 1720, "key-173": 1730, "key-174": 1740, "key-175": 1750, "key-176": 1760, "key-177": 1770, "key-178": 1780, "key-179": 1790, "key-180": 1800, "key-181": 1810, "key-182": 1820, "key-183": 1830, "key-184": 1840, "key-185": 1850, "key-186": 1860, "key-187": 1870, "key-188": 1880, "key-189": 1890, "key-190": 1900, "key-191": 1910, "key-192": 1920, "key-193": 1930, "key-194": 1940, "key-195": 1950, "key-196": 1960, "key-197": 1970, "key-198": 1980, "key-199": 1990 }
5 | STEP5:{ "key-0": 0, "key-1": 10, "key-2": 20, "key-3": 30, "key-4": 40, "key-5": 50, "key-6": 60, "key-7": 70, "key-8": 80, "key-9": 90, "key-10": 100, "key-11": 110, "key-12": 120, "key-13": 130, "key-14": 140, "key-15": 150, "key-16": 160, "key-17": 170, "key-18": 180, "key-19": 190, "key-20": 200, "key-21": 210, "key-22": 220, "key-23": 230, "key-24": 240, "key-25": 250, "key-26": 260, "key-27": 270, "key-28": 280, "key-29": 290, "key-30": 300, "key-31": 310, "key-32": 320, "key-33": 330, "key-34": 340, "key-35": 350, "key-36": 360, "key-37": 370, "key-38": 380, "key-39": 390, "key-40": 400, "key-41": 410, "key-42": 420, "key-43": 430, "key-44": 440, "key-45": 450, "key-46": 460, "key-47": 470, "key-48": 480, "key-49": 490, "key-50": 500, "key-51": 510, "key-52": 520, "key-53": 530, "key-54": 540, "key-55": 550, "key-56": 560, "key-57": 570, "key-58": 580, "key-59": 590, "key-60": 600, "key-61": 610, "key-62": 620, "key-63": 630, "key-64": 640, "key-65": 650, "key-66": 660, "key-67": 670, "key-68": 680, "key-69": 690, "key-70": 700, "key-71": 710, "key-72": 720, "key-73": 730, "key-74": 740, "key-75": 750, "key-76": 760, "key-77": 770, "key-78": 780, "key-79": 790, "key-80": 800, "key-81": 810, "key-82": 820, "key-83": 830, "key-84": 840, "key-85": 850, "key-86": 860, "key-87": 870, "key-88": 880, "key-89": 890, "key-90": 900, "key-91": 910, "key-92": 920, "key-93": 930, "key-94": 940, "key-95": 950, "key-96": 960, "key-97": 970, "key-98": 980, "key-99": 990, "key-100": 1000, "key-101": 1010, "key-102": 1020, "key-103": 1030, "key-104": 1040, "key-105": 1050, "key-106": 1060, "key-107": 1070, "key-108": 1080, "key-109": 1090, "key-110": 1100, "key-111": 1110, "key-112": 1120, "key-113": 1130, "key-114": 1140, "key-115": 1150, "key-116": 1160, "key-117": 1170, "key-118": 1180, "key-119": 1190, "key-120": 1200, "key-121": 1210, "key-122": 1220, "key-123": 1230, "key-124": 1240, "key-125": 1250, "key-126": 1260, "key-127": 1270, "key-128": 1280, "key-129": 1290, "key-130": 1300, "key-131": 1310, "key-132": 1320, "key-133": 1330, "key-134": 1340, "key-135": 1350, "key-136": 1360, "key-137": 1370, "key-138": 1380, "key-139": 1390, "key-140": 1400, "key-141": 1410, "key-142": 1420, "key-143": 1430, "key-144": 1440, "key-145": 1450, "key-146": 1460, "key-147": 1470, "key-148": 1480, "key-149": 1490, "key-150": 1500, "key-151": 1510, "key-152": 1520, "key-153": 1530, "key-154": 1540, "key-155": 1550, "key-156": 1560, "key-157": 1570, "key-158": 1580, "key-159": 1590, "key-160": 1600, "key-161": 1610, "key-162": 1620, "key-163": 1630, "key-164": 1640, "key-165": 1650, "key-166": 1660, "key-167": 1670, "key-168": 1680, "key-169": 1690, "key-170": 1700, "key-171": 1710, "key-172": 1720, "key-173": 1730, "key-174": 1740, "key-175": 1750, "key-176": 1760, "key-177": 1770, "key-178": 1780, "key-179": 1790, "key-180": 1800, "key-181": 1810, "key-182": 1820, "key-183": 1830, "key-184": 1840, "key-185": 1850, "key-186": 1860, "key-187": 1870, "key-188": 1880, "key-189": 1890, "key-190": 1900, "key-191": 1910, "key-192": 1920, "key-193": 1930, "key-194": 1940, "key-195": 1950, "key-196": 1960, "key-197": 1970, "key-198": 1980, "key-199": 1990, "key-200": 200 }
6 |
--------------------------------------------------------------------------------
/tests/test_parse.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../json.h"
8 | #include "../json_tokener.h"
9 | #include "../debug.h"
10 |
11 | static void test_basic_parse(void);
12 | static void test_verbose_parse(void);
13 | static void test_incremental_parse(void);
14 |
15 | #define CHK(x) if (!(x)) { \
16 | printf("%s:%d: unexpected result with '%s'\n", \
17 | __FILE__, __LINE__, #x); \
18 | exit(1); \
19 | }
20 |
21 | int main(int __attribute__((unused)) argc, char __attribute__((unused)) **argv)
22 | {
23 | MC_SET_DEBUG(1);
24 |
25 | test_basic_parse();
26 | printf("==================================\n");
27 | test_verbose_parse();
28 | printf("==================================\n");
29 | test_incremental_parse();
30 | printf("==================================\n");
31 | return 0;
32 | }
33 |
34 | static void test_basic_parse(void)
35 | {
36 | fjson_object *new_obj;
37 |
38 | new_obj = fjson_tokener_parse("\"\003\"");
39 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
40 | fjson_object_put(new_obj);
41 |
42 | new_obj = fjson_tokener_parse("/* hello */\"foo\"");
43 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
44 | fjson_object_put(new_obj);
45 |
46 | new_obj = fjson_tokener_parse("// hello\n\"foo\"");
47 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
48 | fjson_object_put(new_obj);
49 |
50 | new_obj = fjson_tokener_parse("\"\\u0041\\u0042\\u0043\"");
51 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
52 | fjson_object_put(new_obj);
53 |
54 | new_obj = fjson_tokener_parse("null");
55 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
56 | fjson_object_put(new_obj);
57 |
58 | new_obj = fjson_tokener_parse("NaN");
59 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
60 | fjson_object_put(new_obj);
61 |
62 | new_obj = fjson_tokener_parse("-NaN"); /* non-sensical, returns null */
63 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
64 | fjson_object_put(new_obj);
65 |
66 | new_obj = fjson_tokener_parse("Inf"); /* must use full string, returns null */
67 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
68 | fjson_object_put(new_obj);
69 |
70 | new_obj = fjson_tokener_parse("inf"); /* must use full string, returns null */
71 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
72 | fjson_object_put(new_obj);
73 |
74 | new_obj = fjson_tokener_parse("Infinity");
75 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
76 | fjson_object_put(new_obj);
77 |
78 | new_obj = fjson_tokener_parse("infinity");
79 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
80 | fjson_object_put(new_obj);
81 |
82 | new_obj = fjson_tokener_parse("-Infinity");
83 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
84 | fjson_object_put(new_obj);
85 |
86 | new_obj = fjson_tokener_parse("-infinity");
87 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
88 | fjson_object_put(new_obj);
89 |
90 | new_obj = fjson_tokener_parse("True");
91 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
92 | fjson_object_put(new_obj);
93 |
94 | new_obj = fjson_tokener_parse("12");
95 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
96 | fjson_object_put(new_obj);
97 |
98 | new_obj = fjson_tokener_parse("12.3");
99 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
100 | fjson_object_put(new_obj);
101 |
102 | new_obj = fjson_tokener_parse("12.3.4"); /* non-sensical, returns null */
103 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
104 | fjson_object_put(new_obj);
105 |
106 | /* was returning (int)2015 before patch, should return null */
107 | new_obj = fjson_tokener_parse("2015-01-15");
108 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
109 | fjson_object_put(new_obj);
110 |
111 | new_obj = fjson_tokener_parse("{\"FoO\" : -12.3E512}");
112 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
113 | fjson_object_put(new_obj);
114 |
115 | new_obj = fjson_tokener_parse("{\"FoO\" : -12.3E51.2}"); /* non-sensical, returns null */
116 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
117 | fjson_object_put(new_obj);
118 |
119 | new_obj = fjson_tokener_parse("[\"\\n\"]");
120 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
121 | fjson_object_put(new_obj);
122 |
123 | new_obj = fjson_tokener_parse("[\"\\nabc\\n\"]");
124 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
125 | fjson_object_put(new_obj);
126 |
127 | new_obj = fjson_tokener_parse("[null]");
128 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
129 | fjson_object_put(new_obj);
130 |
131 | new_obj = fjson_tokener_parse("[]");
132 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
133 | fjson_object_put(new_obj);
134 |
135 | new_obj = fjson_tokener_parse("[false]");
136 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
137 | fjson_object_put(new_obj);
138 |
139 | new_obj = fjson_tokener_parse("[\"abc\",null,\"def\",12]");
140 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
141 | fjson_object_put(new_obj);
142 |
143 | new_obj = fjson_tokener_parse("{}");
144 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
145 | fjson_object_put(new_obj);
146 |
147 | new_obj = fjson_tokener_parse("{ \"foo\": \"bar\" }");
148 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
149 | fjson_object_put(new_obj);
150 |
151 | new_obj = fjson_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }");
152 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
153 | fjson_object_put(new_obj);
154 |
155 | new_obj = fjson_tokener_parse("{ \"foo\": [null, \"foo\"] }");
156 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
157 | fjson_object_put(new_obj);
158 |
159 | new_obj = fjson_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }");
160 | printf("new_obj.to_string()=%s\n", fjson_object_to_json_string(new_obj));
161 | fjson_object_put(new_obj);
162 | }
163 |
164 | static void test_verbose_parse(void)
165 | {
166 | fjson_object *new_obj;
167 | enum fjson_tokener_error error = fjson_tokener_success;
168 |
169 | new_obj = fjson_tokener_parse_verbose("{ foo }", &error);
170 | CHK (error == fjson_tokener_error_parse_object_key_name);
171 | CHK (new_obj == NULL);
172 |
173 | new_obj = fjson_tokener_parse("{ foo }");
174 | CHK (new_obj == NULL);
175 |
176 | new_obj = fjson_tokener_parse("foo");
177 | CHK (new_obj == NULL);
178 | new_obj = fjson_tokener_parse_verbose("foo", &error);
179 | CHK (new_obj == NULL);
180 |
181 | /* b/c the string starts with 'f' parsing return a boolean error */
182 | CHK (error == fjson_tokener_error_parse_boolean);
183 |
184 | printf("fjson_tokener_parse_versbose() OK\n");
185 | }
186 |
187 | struct incremental_step {
188 | const char *string_to_parse;
189 | int length;
190 | int char_offset;
191 | enum fjson_tokener_error expected_error;
192 | int reset_tokener;
193 | } incremental_steps[] = {
194 |
195 | /* Check that full json messages can be parsed, both w/ and w/o a reset */
196 | { "{ \"foo\": 123 }", -1, -1, fjson_tokener_success, 0 },
197 | { "{ \"foo\": 456 }", -1, -1, fjson_tokener_success, 1 },
198 | { "{ \"foo\": 789 }", -1, -1, fjson_tokener_success, 1 },
199 |
200 | /* Check a basic incremental parse */
201 | { "{ \"foo", -1, -1, fjson_tokener_continue, 0 },
202 | { "\": {\"bar", -1, -1, fjson_tokener_continue, 0 },
203 | { "\":13}}", -1, -1, fjson_tokener_success, 1 },
204 |
205 | /* Check that fjson_tokener_reset actually resets */
206 | { "{ \"foo", -1, -1, fjson_tokener_continue, 1 },
207 | { ": \"bar\"}", -1, 0, fjson_tokener_error_parse_unexpected, 1 },
208 |
209 | /* Check incremental parsing with trailing characters */
210 | { "{ \"foo", -1, -1, fjson_tokener_continue, 0 },
211 | { "\": {\"bar", -1, -1, fjson_tokener_continue, 0 },
212 | { "\":13}}XXXX", 10, 6, fjson_tokener_success, 0 },
213 | { "XXXX", 4, 0, fjson_tokener_error_parse_unexpected, 1 },
214 |
215 | /* Check that trailing characters can change w/o a reset */
216 | { "{\"x\": 123 }\"X\"", -1, 11, fjson_tokener_success, 0 },
217 | { "\"Y\"", -1, -1, fjson_tokener_success, 1 },
218 |
219 | /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */
220 | { "1", 1, 1, fjson_tokener_continue, 0 },
221 | { "2", 2, 1, fjson_tokener_success, 0 },
222 |
223 | /* Some bad formatting. Check we get the correct error status */
224 | { "2015-01-15", 10, 4, fjson_tokener_error_parse_number, 1 },
225 |
226 | /* Strings have a well defined end point, so we can stop at the quote */
227 | { "\"blue\"", -1, -1, fjson_tokener_success, 0 },
228 |
229 | /* Check each of the escape sequences defined by the spec */
230 | { "\"\\\"\"", -1, -1, fjson_tokener_success, 0 },
231 | { "\"\\\\\"", -1, -1, fjson_tokener_success, 0 },
232 | { "\"\\b\"", -1, -1, fjson_tokener_success, 0 },
233 | { "\"\\f\"", -1, -1, fjson_tokener_success, 0 },
234 | { "\"\\n\"", -1, -1, fjson_tokener_success, 0 },
235 | { "\"\\r\"", -1, -1, fjson_tokener_success, 0 },
236 | { "\"\\t\"", -1, -1, fjson_tokener_success, 0 },
237 |
238 | { "[1,2,3]", -1, -1, fjson_tokener_success, 0 },
239 |
240 | /* This behaviour doesn't entirely follow the json spec, but until we have
241 | a way to specify how strict to be we follow Postel's Law and be liberal
242 | in what we accept (up to a point). */
243 | { "[1,2,3,]", -1, -1, fjson_tokener_success, 0 },
244 | { "[1,2,,3,]", -1, 5, fjson_tokener_error_parse_unexpected, 0 },
245 |
246 | { "[1,2,3,]", -1, 7, fjson_tokener_error_parse_unexpected, 3 },
247 | { "{\"a\":1,}", -1, 7, fjson_tokener_error_parse_unexpected, 3 },
248 |
249 | { NULL, -1, -1, fjson_tokener_success, 0 },
250 | };
251 |
252 | static void test_incremental_parse(void)
253 | {
254 | fjson_object *new_obj;
255 | enum fjson_tokener_error jerr;
256 | fjson_tokener *tok;
257 | const char *string_to_parse;
258 | int ii;
259 | int num_ok, num_error;
260 |
261 | num_ok = 0;
262 | num_error = 0;
263 |
264 | printf("Starting incremental tests.\n");
265 | printf("Note: quotes and backslashes seen in the output here are literal values passed\n");
266 | printf(" to the parse functions. e.g. this is 4 characters: \"\\f\"\n");
267 |
268 | string_to_parse = "{ \"foo"; /* } */
269 | printf("fjson_tokener_parse(%s) ... ", string_to_parse);
270 | new_obj = fjson_tokener_parse(string_to_parse);
271 | if (new_obj == NULL) printf("got error as expected\n");
272 |
273 | /* test incremental parsing in various forms */
274 | tok = fjson_tokener_new();
275 | for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++)
276 | {
277 | int this_step_ok = 0;
278 | struct incremental_step *step = &incremental_steps[ii];
279 | int length = step->length;
280 | int expected_char_offset = step->char_offset;
281 |
282 | if (step->reset_tokener & 2)
283 | fjson_tokener_set_flags(tok, FJSON_TOKENER_STRICT);
284 | else
285 | fjson_tokener_set_flags(tok, 0);
286 |
287 | if (length == -1)
288 | length = strlen(step->string_to_parse);
289 | if (expected_char_offset == -1)
290 | expected_char_offset = length;
291 |
292 | printf("fjson_tokener_parse_ex(tok, %-12s, %3d) ... ",
293 | step->string_to_parse, length);
294 | new_obj = fjson_tokener_parse_ex(tok, step->string_to_parse, length);
295 |
296 | jerr = fjson_tokener_get_error(tok);
297 | if (step->expected_error != fjson_tokener_success)
298 | {
299 | if (new_obj != NULL)
300 | printf("ERROR: invalid object returned: %s\n",
301 | fjson_object_to_json_string(new_obj));
302 | else if (jerr != step->expected_error)
303 | printf("ERROR: got wrong error: %s\n",
304 | fjson_tokener_error_desc(jerr));
305 | else if (tok->char_offset != expected_char_offset)
306 | printf("ERROR: wrong char_offset %d != expected %d\n",
307 | tok->char_offset,
308 | expected_char_offset);
309 | else
310 | {
311 | printf("OK: got correct error: %s\n", fjson_tokener_error_desc(jerr));
312 | this_step_ok = 1;
313 | }
314 | }
315 | else
316 | {
317 | if (new_obj == NULL)
318 | printf("ERROR: expected valid object, instead: %s\n",
319 | fjson_tokener_error_desc(jerr));
320 | else if (tok->char_offset != expected_char_offset)
321 | printf("ERROR: wrong char_offset %d != expected %d\n",
322 | tok->char_offset,
323 | expected_char_offset);
324 | else
325 | {
326 | printf("OK: got object of type [%s]: %s\n",
327 | fjson_type_to_name(fjson_object_get_type(new_obj)),
328 | fjson_object_to_json_string(new_obj));
329 | this_step_ok = 1;
330 | }
331 | }
332 |
333 | if (new_obj)
334 | fjson_object_put(new_obj);
335 |
336 | if (step->reset_tokener & 1)
337 | fjson_tokener_reset(tok);
338 |
339 | if (this_step_ok)
340 | num_ok++;
341 | else
342 | num_error++;
343 | }
344 |
345 | fjson_tokener_free(tok);
346 |
347 | printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error);
348 |
349 | return;
350 | }
351 |
--------------------------------------------------------------------------------