AC_PREREQ([2.60])
-AC_INIT([jansson], [1.3], [petri@digip.org])
+AC_INIT([jansson], [2.0pre], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
# Checks for programs.
AC_PROG_CC
- AC_PROG_CXX
AC_PROG_LIBTOOL
+ AM_CONDITIONAL([GCC], [test x$GCC = xyes])
# Checks for libraries.
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
+AC_TYPE_LONG_LONG_INT
+case $ac_cv_type_long_long_int in
+ yes) json_have_long_long=1;;
+ *) json_have_long_long=0;;
+esac
+AC_SUBST([json_have_long_long])
+
AC_C_INLINE
case $ac_cv_c_inline in
yes) json_inline=inline;;
Makefile
doc/Makefile
src/Makefile
- src/jansson.h
+ src/jansson_config.h
test/Makefile
test/bin/Makefile
test/suites/Makefile
If a circular reference is created, the memory consumed by the values
cannot be freed by :cfunc:`json_decref()`. The reference counts never
-drops to zero because the values are keeping the circular reference to
-themselves. Moreover, trying to encode the values with any of the
-encoding functions will fail. The encoder detects circular references
-and returns an error status.
+drops to zero because the values are keeping the references to each
+other. Moreover, trying to encode the values with any of the encoding
+functions will fail. The encoder detects circular references and
+returns an error status.
True, False and Null
String
======
+ Jansson uses UTF-8 as the character encoding. All JSON strings must be
+ valid UTF-8 (or ASCII, as it's a subset of UTF-8). Normal null
+ terminated C strings are used, so JSON strings may not contain
+ embedded null characters. All other Unicode codepoints U+0001 through
+ U+10FFFF are allowed.
+
.. cfunction:: json_t *json_string(const char *value)
.. refcounting:: new
Number
======
-.. cfunction:: json_t *json_integer(int value)
+ The JSON specification only contains one numeric type, "number". The C
+ programming language has distinct types for integer and floating-point
+ numbers, so for practical reasons Jansson also has distinct types for
+ the two. They are called "integer" and "real", respectively. For more
+ information, see :ref:`rfc-conformance`.
+
+.. ctype:: json_int_t
+
+ This is the C type that is used to store JSON integer values. It
+ represents the widest integer type available on your system. In
+ practice it's just a typedef of ``long long`` if your compiler
+ supports it, otherwise ``long``.
+
+ Usually, you can safely use plain ``int`` in place of
+ ``json_int_t``, and the implicit C integer conversion handles the
+ rest. Only when you know that you need the full 64-bit range, you
+ should use ``json_int_t`` explicitly.
+
+``JSON_INTEGER_IS_LONG_LONG``
+
+ This is a preprocessor variable that holds the value 1 if
+ :ctype:`json_int_t` is ``long long``, and 0 if it's ``long``. It
+ can be used as follows::
+
+ #if JSON_INTEGER_IS_LONG_LONG
+ /* Code specific for long long */
+ #else
+ /* Code specific for long */
+ #endif
+
+``JSON_INTEGER_FORMAT``
+
+ This is a macro that expands to a :cfunc:`printf()` conversion
+ specifier that corresponds to :ctype:`json_int_t`, without the
+ leading ``%`` sign, i.e. either ``"lld"`` or ``"ld"``. This macro
+ is required because the actual type of :ctype:`json_int_t` can be
+ either ``long`` or ``long long``, and :cfunc:`printf()` reuiqres
+ different length modifiers for the two.
+
+ Example::
+
+ json_int_t x = 123123123;
+ printf("x is %" JSON_INTEGER_FORMAT "\n", x);
+
+
+.. cfunction:: json_t *json_integer(json_int_t value)
.. refcounting:: new
Returns a new JSON integer, or *NULL* on error.
-.. cfunction:: int json_integer_value(const json_t *integer)
+.. cfunction:: json_int_t json_integer_value(const json_t *integer)
Returns the associated value of *integer*, or 0 if *json* is not a
JSON integer.
-.. cfunction:: int json_integer_set(const json_t *integer, int value)
+.. cfunction:: int json_integer_set(const json_t *integer, json_int_t value)
Sets the associated value of *integer* to *value*. Returns 0 on
success and -1 if *integer* is not a JSON integer.
Returns a new JSON array, or *NULL* on error. Initially, the array
is empty.
-.. cfunction:: unsigned int json_array_size(const json_t *array)
+.. cfunction:: size_t json_array_size(const json_t *array)
Returns the number of elements in *array*, or 0 if *array* is NULL
or not a JSON array.
-.. cfunction:: json_t *json_array_get(const json_t *array, unsigned int index)
+.. cfunction:: json_t *json_array_get(const json_t *array, size_t index)
.. refcounting:: borrow
if *array* is *NULL*, or if *index* is out of range, *NULL* is
returned.
-.. cfunction:: int json_array_set(json_t *array, unsigned int index, json_t *value)
+.. cfunction:: int json_array_set(json_t *array, size_t index, json_t *value)
Replaces the element in *array* at position *index* with *value*.
The valid range for *index* is from 0 to the return value of
:cfunc:`json_array_size()` minus 1. Returns 0 on success and -1 on
error.
-.. cfunction:: int json_array_set_new(json_t *array, unsigned int index, json_t *value)
+.. cfunction:: int json_array_set_new(json_t *array, size_t index, json_t *value)
Like :cfunc:`json_array_set()` but steals the reference to *value*.
This is useful when *value* is newly created and not used after
.. versionadded:: 1.1
-.. cfunction:: int json_array_insert(json_t *array, unsigned int index, json_t *value)
+.. cfunction:: int json_array_insert(json_t *array, size_t index, json_t *value)
Inserts *value* to *array* at position *index*, shifting the
elements at *index* and after it one position towards the end of
.. versionadded:: 1.1
-.. cfunction:: int json_array_insert_new(json_t *array, unsigned int index, json_t *value)
+.. cfunction:: int json_array_insert_new(json_t *array, size_t index, json_t *value)
Like :cfunc:`json_array_insert()` but steals the reference to
*value*. This is useful when *value* is newly created and not used
.. versionadded:: 1.1
-.. cfunction:: int json_array_remove(json_t *array, unsigned int index)
+.. cfunction:: int json_array_remove(json_t *array, size_t index)
Removes the element in *array* at position *index*, shifting the
elements after *index* one position towards the start of the array.
Returns a new JSON object, or *NULL* on error. Initially, the
object is empty.
-.. cfunction:: unsigned int json_object_size(const json_t *object)
+.. cfunction:: size_t json_object_size(const json_t *object)
Returns the number of elements in *object*, or 0 if *object* is not
a JSON object.
``JSON_INDENT(n)``
Pretty-print the result, using newlines between array and object
items, and indenting with *n* spaces. The valid range for *n* is
- between 0 and 255, other values result in an undefined output. If
+ between 0 and 32, other values result in an undefined output. If
``JSON_INDENT`` is not used or *n* is 0, no newlines are inserted
between array and object items.
The following functions perform the actual JSON encoding. The result
is in UTF-8.
-.. cfunction:: char *json_dumps(const json_t *root, unsigned long flags)
+.. cfunction:: char *json_dumps(const json_t *root, size_t flags)
Returns the JSON representation of *root* as a string, or *NULL* on
error. *flags* is described above. The return value must be freed
by the caller using :cfunc:`free()`.
-.. cfunction:: int json_dumpf(const json_t *root, FILE *output, unsigned long flags)
+.. cfunction:: int json_dumpf(const json_t *root, FILE *output, size_t flags)
Write the JSON representation of *root* to the stream *output*.
*flags* is described above. Returns 0 on success and -1 on error.
*output*. In this case, the output is undefined and most likely not
valid JSON.
-.. cfunction:: int json_dump_file(const json_t *json, const char *path, unsigned long flags)
+.. cfunction:: int json_dump_file(const json_t *json, const char *path, size_t flags)
Write the JSON representation of *root* to the file *path*. If
*path* already exists, it is overwritten. *flags* is described
text to the Jansson representation of JSON data. The JSON
specification requires that a JSON text is either a serialized array
or object, and this requirement is also enforced with the following
- functions.
+ functions. In other words, the top level value in the JSON text being
+ decoded must be either array or object.
- The only supported character encoding is UTF-8 (which ASCII is a
- subset of).
+ See :ref:`rfc-conformance` for a discussion on Jansson's conformance
+ to the JSON specification. It explains many design decisions that
+ affect especially the behavior of the decoder.
.. ctype:: json_error_t
json_t *json;
json_error_t error;
- json = json_load_file("/path/to/file.json", &error);
+ json = json_load_file("/path/to/file.json", 0, &error);
if(!json) {
/* the error variable contains error information */
}
The following functions perform the actual JSON decoding.
-.. cfunction:: json_t *json_loads(const char *input, json_error_t *error)
+.. cfunction:: json_t *json_loads(const char *input, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON string *input* and returns the array or object it
contains, or *NULL* on error, in which case *error* is filled with
information about the error. See above for discussion on the
- *error* parameter.
+ *error* parameter. *flags* is currently unused, and should be set
+ to 0.
-.. cfunction:: json_t *json_loadf(FILE *input, json_error_t *error)
+.. cfunction:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON text in stream *input* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
filled with information about the error. See above for discussion
- on the *error* parameter.
+ on the *error* parameter. *flags* is currently unused, and should
+ be set to 0.
-.. cfunction:: json_t *json_load_file(const char *path, json_error_t *error)
+.. cfunction:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON text in file *path* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
filled with information about the error. See above for discussion
- on the *error* parameter.
+ on the *error* parameter. *flags* is currently unused, and should
+ be set to 0.
Equality
values are equal. An integer value is never equal to a real value,
though.
- * Two strings are equal if their contained UTF-8 strings are equal.
+ * Two strings are equal if their contained UTF-8 strings are equal,
+ byte by byte. Unicode comparison algorithms are not implemented.
* Two arrays are equal if they have the same number of elements and
each element in the first array is equal to the corresponding
+ .. _rfc-conformance:
+
***************
RFC Conformance
***************
JSON makes no distinction between real and integer numbers; Jansson
does. Real numbers are mapped to the ``double`` type and integers to
-the ``int`` type.
+the ``json_int_t`` type, which is a typedef of ``long long`` or
+``long``, depending on whether ``long long`` is supported by your
+compiler or not.
A JSON number is considered to be a real number if its lexical
representation includes one of ``e``, ``E``, or ``.``; regardless if
-------------------------------
Real numbers whose absolute values are too small to be represented in
-a C double will be silently estimated with 0.0. Thus, depending on
+a C ``double`` will be silently estimated with 0.0. Thus, depending on
platform, JSON numbers very close to zero such as 1E-999 may result in
0.0.
Real numbers whose absolute values are too large to be represented in
-a C ``double`` type will result in an overflow error (a JSON decoding
+a C ``double`` will result in an overflow error (a JSON decoding
error). Thus, depending on platform, JSON numbers like 1E+999 or
-1E+999 may result in a parsing error.
Likewise, integer numbers whose absolute values are too large to be
-represented in the ``int`` type will result in an overflow error (a
-JSON decoding error). Thus, depending on platform, JSON numbers like
-1000000000000000 may result in parsing error.
+represented in the ``json_int_t`` type (see above) will result in an
+overflow error (a JSON decoding error). Thus, depending on platform,
+JSON numbers like 1000000000000000 may result in parsing error.
Parsing JSON real numbers may result in a loss of precision. As long
as overflow does not occur (i.e. a total loss of precision), the
-----
No support is provided in Jansson for any C numeric types other than
-``int`` and ``double``. This excludes things such as unsigned types,
-``long``, ``long long``, ``long double``, etc. Obviously, shorter
-types like ``short`` and ``float`` are implicitly handled via the
-ordinary C type coercion rules (subject to overflow semantics). Also,
-no support or hooks are provided for any supplemental "bignum" type
-add-on packages.
+``json_int_t`` and ``double``. This excludes things such as unsigned
+types, ``long double``, etc. Obviously, shorter types like ``short``,
+``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float``
+are implicitly handled via the ordinary C type coercion rules (subject
+to overflow semantics). Also, no support or hooks are provided for any
+supplemental "bignum" type add-on packages.
-include_HEADERS = jansson.h
+include_HEADERS = jansson.h jansson_config.h
lib_LTLIBRARIES = libjansson.la
libjansson_la_SOURCES = \
-export-symbols-regex '^json_' \
-version-info 3:0:3
+ if GCC
+ # These flags are gcc specific
AM_CFLAGS = -Wall -Wextra -Werror
+ endif
#define JANSSON_H
#include <stdio.h>
+#include <stdlib.h> /* for size_t */
+#include <jansson_config.h>
-#ifndef __cplusplus
-#define JSON_INLINE @json_inline@
-#else
-#define JSON_INLINE inline
+#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
json_type type;
- unsigned long refcount;
+ size_t refcount;
} json_t;
+#if JSON_INTEGER_IS_LONG_LONG
+#define JSON_INTEGER_FORMAT "lld"
+typedef long long json_int_t;
+#else
+#define JSON_INTEGER_FORMAT "ld"
+typedef long json_int_t;
+#endif /* JSON_INTEGER_IS_LONG_LONG */
+
#define json_typeof(json) ((json)->type)
#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY)
json_t *json_array(void);
json_t *json_string(const char *value);
json_t *json_string_nocheck(const char *value);
-json_t *json_integer(int value);
+json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
json_t *json_false(void);
static JSON_INLINE
json_t *json_incref(json_t *json)
{
- if(json && json->refcount != (unsigned int)-1)
+ if(json && json->refcount != (size_t)-1)
++json->refcount;
return json;
}
static JSON_INLINE
void json_decref(json_t *json)
{
- if(json && json->refcount != (unsigned int)-1 && --json->refcount == 0)
+ if(json && json->refcount != (size_t)-1 && --json->refcount == 0)
json_delete(json);
}
/* getters, setters, manipulation */
-unsigned int json_object_size(const json_t *object);
+size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
return json_object_set_new_nocheck(object, key, json_incref(value));
}
- static inline
+ static JSON_INLINE
int json_object_iter_set(json_t *object, void *iter, json_t *value)
{
return json_object_iter_set_new(object, iter, json_incref(value));
}
-unsigned int json_array_size(const json_t *array);
-json_t *json_array_get(const json_t *array, unsigned int index);
-int json_array_set_new(json_t *array, unsigned int index, json_t *value);
+size_t json_array_size(const json_t *array);
+json_t *json_array_get(const json_t *array, size_t index);
+int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
-int json_array_insert_new(json_t *array, unsigned int index, json_t *value);
-int json_array_remove(json_t *array, unsigned int index);
+int json_array_insert_new(json_t *array, size_t index, json_t *value);
+int json_array_remove(json_t *array, size_t index);
int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other);
static JSON_INLINE
-int json_array_set(json_t *array, unsigned int index, json_t *value)
+int json_array_set(json_t *array, size_t index, json_t *value)
{
return json_array_set_new(array, index, json_incref(value));
}
}
static JSON_INLINE
-int json_array_insert(json_t *array, unsigned int index, json_t *value)
+int json_array_insert(json_t *array, size_t index, json_t *value)
{
return json_array_insert_new(array, index, json_incref(value));
}
const char *json_string_value(const json_t *string);
-int json_integer_value(const json_t *integer);
+json_int_t json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value);
int json_string_set_nocheck(json_t *string, const char *value);
-int json_integer_set(json_t *integer, int value);
+int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);
int line;
} json_error_t;
-json_t *json_loads(const char *input, json_error_t *error);
-json_t *json_loadf(FILE *input, json_error_t *error);
-json_t *json_load_file(const char *path, json_error_t *error);
+json_t *json_loads(const char *input, size_t flags, json_error_t *error);
+json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
+json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
-#define JSON_INDENT(n) (n & 0xFF)
-#define JSON_COMPACT 0x100
-#define JSON_ENSURE_ASCII 0x200
-#define JSON_SORT_KEYS 0x400
-#define JSON_PRESERVE_ORDER 0x800
+#define JSON_INDENT(n) (n & 0x1F)
+#define JSON_COMPACT 0x20
+#define JSON_ENSURE_ASCII 0x40
+#define JSON_SORT_KEYS 0x80
+#define JSON_PRESERVE_ORDER 0x100
-char *json_dumps(const json_t *json, unsigned long flags);
-int json_dumpf(const json_t *json, FILE *output, unsigned long flags);
-int json_dump_file(const json_t *json, const char *path, unsigned long flags);
+char *json_dumps(const json_t *json, size_t flags);
+int json_dumpf(const json_t *json, FILE *output, size_t flags);
+int json_dump_file(const json_t *json, const char *path, size_t flags);
#ifdef __cplusplus
}
#ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
+ #include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
#define container_of(ptr_, type_, member_) \
- ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_))
+ ((type_ *)((char *)ptr_ - offsetof(type_, member_)))
typedef struct {
json_t json;
hashtable_t hashtable;
- unsigned long serial;
+ size_t serial;
int visited;
} json_object_t;
typedef struct {
json_t json;
- unsigned int size;
- unsigned int entries;
+ size_t size;
+ size_t entries;
json_t **table;
int visited;
} json_array_t;
typedef struct {
json_t json;
- int value;
+ json_int_t value;
} json_integer_t;
#define json_to_object(json_) container_of(json_, json_object_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
typedef struct {
- unsigned long serial;
+ size_t serial;
- char key[];
+ char key[1];
} object_key_t;
const object_key_t *jsonp_object_iter_fullkey(void *iter);
#include <config.h>
+ #include <stddef.h>
#include <stdlib.h>
#include <string.h>
an object_key_t instance. */
#define string_to_key(string) container_of(string, object_key_t, key)
-static unsigned int hash_key(const void *ptr)
+static size_t hash_key(const void *ptr)
{
const char *str = ((const object_key_t *)ptr)->key;
- unsigned int hash = 5381;
- unsigned int c;
+ size_t hash = 5381;
+ size_t c;
- while((c = (unsigned int)*str))
+ while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
free(object);
}
-unsigned int json_object_size(const json_t *json)
+size_t json_object_size(const json_t *json)
{
json_object_t *object;
}
object = json_to_object(json);
- k = malloc(sizeof(object_key_t) + strlen(key) + 1);
- if(!k)
- return -1;
+ /* offsetof(...) returns the size of object_key_t without the
+ last, flexible member. This way, the correct amount is
+ allocated. */
+ k = malloc(offsetof(object_key_t, key) +
+ strlen(key) + 1); if(!k) return -1;
k->serial = object->serial++;
strcpy(k->key, key);
static void json_delete_array(json_array_t *array)
{
- unsigned int i;
+ size_t i;
for(i = 0; i < array->entries; i++)
json_decref(array->table[i]);
free(array);
}
-unsigned int json_array_size(const json_t *json)
+size_t json_array_size(const json_t *json)
{
if(!json_is_array(json))
return 0;
return json_to_array(json)->entries;
}
-json_t *json_array_get(const json_t *json, unsigned int index)
+json_t *json_array_get(const json_t *json, size_t index)
{
json_array_t *array;
if(!json_is_array(json))
return array->table[index];
}
-int json_array_set_new(json_t *json, unsigned int index, json_t *value)
+int json_array_set_new(json_t *json, size_t index, json_t *value)
{
json_array_t *array;
return 0;
}
-static void array_move(json_array_t *array, unsigned int dest,
- unsigned int src, unsigned int count)
+static void array_move(json_array_t *array, size_t dest,
+ size_t src, size_t count)
{
memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *));
}
-static void array_copy(json_t **dest, unsigned int dpos,
- json_t **src, unsigned int spos,
- unsigned int count)
+static void array_copy(json_t **dest, size_t dpos,
+ json_t **src, size_t spos,
+ size_t count)
{
memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *));
}
static json_t **json_array_grow(json_array_t *array,
- unsigned int amount,
+ size_t amount,
int copy)
{
- unsigned int new_size;
+ size_t new_size;
json_t **old_table, **new_table;
if(array->entries + amount <= array->size)
return 0;
}
-int json_array_insert_new(json_t *json, unsigned int index, json_t *value)
+int json_array_insert_new(json_t *json, size_t index, json_t *value)
{
json_array_t *array;
json_t **old_table;
return 0;
}
-int json_array_remove(json_t *json, unsigned int index)
+int json_array_remove(json_t *json, size_t index)
{
json_array_t *array;
int json_array_clear(json_t *json)
{
json_array_t *array;
- unsigned int i;
+ size_t i;
if(!json_is_array(json))
return -1;
int json_array_extend(json_t *json, json_t *other_json)
{
json_array_t *array, *other;
- unsigned int i;
+ size_t i;
if(!json_is_array(json) || !json_is_array(other_json))
return -1;
static int json_array_equal(json_t *array1, json_t *array2)
{
- unsigned int i, size;
+ size_t i, size;
size = json_array_size(array1);
if(size != json_array_size(array2))
static json_t *json_array_copy(json_t *array)
{
json_t *result;
- unsigned int i;
+ size_t i;
result = json_array();
if(!result)
static json_t *json_array_deep_copy(json_t *array)
{
json_t *result;
- unsigned int i;
+ size_t i;
result = json_array();
if(!result)
/*** integer ***/
-json_t *json_integer(int value)
+json_t *json_integer(json_int_t value)
{
json_integer_t *integer = malloc(sizeof(json_integer_t));
if(!integer)
return &integer->json;
}
-int json_integer_value(const json_t *json)
+json_int_t json_integer_value(const json_t *json)
{
if(!json_is_integer(json))
return 0;
return json_to_integer(json)->value;
}
-int json_integer_set(json_t *json, int value)
+int json_integer_set(json_t *json, json_int_t value)
{
if(!json_is_integer(json))
return -1;
{
static json_t the_true = {
.type = JSON_TRUE,
- .refcount = (unsigned int)-1
+ .refcount = (size_t)-1
};
return &the_true;
}
{
static json_t the_false = {
.type = JSON_FALSE,
- .refcount = (unsigned int)-1
+ .refcount = (size_t)-1
};
return &the_false;
}
{
static json_t the_null = {
.type = JSON_NULL,
- .refcount = (unsigned int)-1
+ .refcount = (size_t)-1
};
return &the_null;
}