Browse Source

Update jansson windows sources to 2.6

There was sometimes problems with float values close to 0 (like 0.001)
master
Tanguy Pruvot 10 years ago
parent
commit
e72c6d4785
  1. 5
      ccminer.vcxproj
  2. 15
      ccminer.vcxproj.filters
  3. 4
      compat/jansson/.gitignore
  4. 32
      compat/jansson/Makefile.am
  5. 75
      compat/jansson/config.h
  6. 98
      compat/jansson/configure.ac
  7. 144
      compat/jansson/dump.c
  8. 63
      compat/jansson/error.c
  9. 163
      compat/jansson/hashtable.c
  10. 89
      compat/jansson/hashtable.h
  11. 179
      compat/jansson/jansson.h
  12. 43
      compat/jansson/jansson_config.h
  13. 55
      compat/jansson/jansson_private.h
  14. 570
      compat/jansson/load.c
  15. 56
      compat/jansson/memory.c
  16. 762
      compat/jansson/pack_unpack.c
  17. 43
      compat/jansson/strbuffer.c
  18. 10
      compat/jansson/strbuffer.h
  19. 134
      compat/jansson/strconv.c
  20. 2
      compat/jansson/utf.c
  21. 15
      compat/jansson/utf.h
  22. 328
      compat/jansson/value.c

5
ccminer.vcxproj

@ -225,9 +225,13 @@
<ClCompile Include="compat\getopt\getopt_long.c" /> <ClCompile Include="compat\getopt\getopt_long.c" />
<ClCompile Include="compat\gettimeofday.c" /> <ClCompile Include="compat\gettimeofday.c" />
<ClCompile Include="compat\jansson\dump.c" /> <ClCompile Include="compat\jansson\dump.c" />
<ClCompile Include="compat\jansson\error.c" />
<ClCompile Include="compat\jansson\hashtable.c" /> <ClCompile Include="compat\jansson\hashtable.c" />
<ClCompile Include="compat\jansson\load.c" /> <ClCompile Include="compat\jansson\load.c" />
<ClCompile Include="compat\jansson\memory.c" />
<ClCompile Include="compat\jansson\pack_unpack.c" />
<ClCompile Include="compat\jansson\strbuffer.c" /> <ClCompile Include="compat\jansson\strbuffer.c" />
<ClCompile Include="compat\jansson\strconv.c" />
<ClCompile Include="compat\jansson\utf.c" /> <ClCompile Include="compat\jansson\utf.c" />
<ClCompile Include="compat\jansson\value.c" /> <ClCompile Include="compat\jansson\value.c" />
<ClCompile Include="compat\winansi.c" /> <ClCompile Include="compat\winansi.c" />
@ -280,6 +284,7 @@
<ClInclude Include="compat.h" /> <ClInclude Include="compat.h" />
<ClInclude Include="compat\getopt\getopt.h" /> <ClInclude Include="compat\getopt\getopt.h" />
<ClInclude Include="compat\inttypes.h" /> <ClInclude Include="compat\inttypes.h" />
<ClInclude Include="compat\jansson\jansson_config.h" />
<ClInclude Include="compat\nvapi\nvapi.h" /> <ClInclude Include="compat\nvapi\nvapi.h" />
<ClInclude Include="compat\nvapi\nvapi_ccminer.h" /> <ClInclude Include="compat\nvapi\nvapi_ccminer.h" />
<ClInclude Include="compat\nvapi\nvapi_lite_common.h" /> <ClInclude Include="compat\nvapi\nvapi_lite_common.h" />

15
ccminer.vcxproj.filters

@ -201,6 +201,18 @@
<ClCompile Include="nvml.cpp"> <ClCompile Include="nvml.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="compat\jansson\memory.c">
<Filter>Source Files\jansson</Filter>
</ClCompile>
<ClCompile Include="compat\jansson\pack_unpack.c">
<Filter>Source Files\jansson</Filter>
</ClCompile>
<ClCompile Include="compat\jansson\strconv.c">
<Filter>Source Files\jansson</Filter>
</ClCompile>
<ClCompile Include="compat\jansson\error.c">
<Filter>Source Files\jansson</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="compat.h"> <ClInclude Include="compat.h">
@ -347,6 +359,9 @@
<ClInclude Include="compat\nvapi\nvapi_lite_salstart.h"> <ClInclude Include="compat\nvapi\nvapi_lite_salstart.h">
<Filter>Header Files\compat\nvapi</Filter> <Filter>Header Files\compat\nvapi</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="compat\jansson\jansson_config.h">
<Filter>Header Files\compat</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CudaCompile Include="cuda.cpp"> <CudaCompile Include="cuda.cpp">

4
compat/jansson/.gitignore vendored

@ -0,0 +1,4 @@
*.h.in
*.h.in~
libtool
libjansson.a

32
compat/jansson/Makefile.am

@ -1,18 +1,20 @@
noinst_LIBRARIES = libjansson.a noinst_LIBRARIES = libjansson.a
libjansson_a_SOURCES = \ libjansson_a_SOURCES = \
config.h \ config.h \
dump.c \ dump.c \
hashtable.c \ error.c \
hashtable.h \ hashtable.c hashtable.h \
jansson.h \ jansson.h \
jansson_private.h \ jansson_config.h \
load.c \ jansson_private.h \
strbuffer.c \ load.c \
strbuffer.h \ memory.c \
utf.c \ pack_unpack.c \
utf.h \ strbuffer.c strbuffer.h \
util.h \ strconv.c \
value.c utf.c utf.h \
util.h \
value.c

75
compat/jansson/config.h

@ -1,15 +1,54 @@
/* config.h. Generated from config.h.in by configure. */ /* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */ /* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if gcc's __atomic builtins are available */
/* #undef HAVE_ATOMIC_BUILTINS */
/* Define to 1 if you have the `close' function. */
#define HAVE_CLOSE 1
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1 /* #undef HAVE_DLFCN_H */
/* Define to 1 if you have the <endian.h> header file. */
/* #undef HAVE_ENDIAN_H */
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `getpid' function. */
#define HAVE_GETPID 1
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the <inttypes.h> header file. */ /* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1 #define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `localeconv' function. */
#define HAVE_LOCALECONV 1
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
/* Define to 1 if the system has the type `long long int'. */
#define HAVE_LONG_LONG_INT 1
/* Define to 1 if you have the <memory.h> header file. */ /* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1 #define HAVE_MEMORY_H 1
/* Define to 1 if you have the `open' function. */
#define HAVE_OPEN 1
/* Define to 1 if you have the `read' function. */
#define HAVE_READ 1
/* Define to 1 if you have the <sched.h> header file. */
#define HAVE_SCHED_H 1
/* Define to 1 if you have the `sched_yield' function. */
/* #undef HAVE_SCHED_YIELD */
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1 #define HAVE_STDINT_H 1
@ -22,9 +61,21 @@
/* Define to 1 if you have the <string.h> header file. */ /* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1 #define HAVE_STRING_H 1
/* Define to 1 if you have the `strtoll' function. */
#define HAVE_STRTOLL 1
/* Define to 1 if gcc's __sync builtins are available */
#define HAVE_SYNC_BUILTINS 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */ /* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1 #define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */ /* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_TYPES_H 1
@ -45,7 +96,7 @@
#define PACKAGE_NAME "jansson" #define PACKAGE_NAME "jansson"
/* Define to the full name and version of this package. */ /* Define to the full name and version of this package. */
#define PACKAGE_STRING "jansson 1.3" #define PACKAGE_STRING "jansson 2.6"
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "jansson" #define PACKAGE_TARNAME "jansson"
@ -54,13 +105,25 @@
#define PACKAGE_URL "" #define PACKAGE_URL ""
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "1.3" #define PACKAGE_VERSION "2.6"
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1 #define STDC_HEADERS 1
/* Define to 1 if /dev/urandom should be used for seeding the hash function */
#define USE_URANDOM 1
/* Define to 1 if CryptGenRandom should be used for seeding the hash function
*/
#define USE_WINDOWS_CRYPTOAPI 1
/* Version number of package */ /* Version number of package */
#define VERSION "1.3" #define VERSION "2.6"
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
/* #undef _UINT32_T */
/* Define to `__inline__' or `__inline' if that's what the C compiler /* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */ calls it, or to nothing if 'inline' is not supported under any name. */
@ -71,3 +134,7 @@
/* Define to the type of a signed integer type of width exactly 32 bits if /* Define to the type of a signed integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */ such a type exists and the standard includes do not define it. */
/* #undef int32_t */ /* #undef int32_t */
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint32_t */

98
compat/jansson/configure.ac

@ -0,0 +1,98 @@
AC_PREREQ([2.60])
AC_INIT([jansson], [2.6], [petri@digip.org])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.10 foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_SRCDIR([value.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
AM_CONDITIONAL([GCC], [test x$GCC = xyes])
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
AC_TYPE_UINT32_T
AC_TYPE_LONG_LONG_INT
AC_C_INLINE
case $ac_cv_c_inline in
yes) json_inline=inline;;
no) json_inline=;;
*) json_inline=$ac_cv_c_inline;;
esac
AC_SUBST([json_inline])
# Checks for library functions.
AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll])
AC_MSG_CHECKING([for gcc __sync builtins])
have_sync_builtins=no
AC_TRY_LINK(
[], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1);],
[have_sync_builtins=yes],
)
if test "x$have_sync_builtins" = "xyes"; then
AC_DEFINE([HAVE_SYNC_BUILTINS], [1],
[Define to 1 if gcc's __sync builtins are available])
fi
AC_MSG_RESULT([$have_sync_builtins])
AC_MSG_CHECKING([for gcc __atomic builtins])
have_atomic_builtins=no
AC_TRY_LINK(
[], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE);],
[have_atomic_builtins=yes],
)
if test "x$have_atomic_builtins" = "xyes"; then
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1],
[Define to 1 if gcc's __atomic builtins are available])
fi
AC_MSG_RESULT([$have_atomic_builtins])
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
yesyes) json_have_long_long=1;;
*) json_have_long_long=0;;
esac
AC_SUBST([json_have_long_long])
case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in
yesyes) json_have_localeconv=1;;
*) json_have_localeconv=0;;
esac
AC_SUBST([json_have_localeconv])
# Features
AC_ARG_ENABLE([urandom],
[AS_HELP_STRING([--disable-urandom],
[Don't use /dev/urandom to seed the hash function])],
[use_urandom=$enableval], [use_urandom=yes])
if test "x$use_urandom" = xyes; then
AC_DEFINE([USE_URANDOM], [1],
[Define to 1 if /dev/urandom should be used for seeding the hash function])
fi
AC_ARG_ENABLE([windows-cryptoapi],
[AS_HELP_STRING([--disable-windows-cryptoapi],
[Don't use CryptGenRandom to seed the hash function])],
[use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes])
if test "x$use_windows_cryptoapi" = xyes; then
AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1],
[Define to 1 if CryptGenRandom should be used for seeding the hash function])
fi
AC_CONFIG_FILES([
Makefile
])
AC_OUTPUT

144
compat/jansson/dump.c

@ -1,17 +1,20 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <jansson.h> #include "jansson.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "strbuffer.h" #include "strbuffer.h"
#include "utf.h" #include "utf.h"
@ -19,21 +22,17 @@
#define MAX_INTEGER_STR_LENGTH 100 #define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100
typedef int (*dump_func)(const char *buffer, int size, void *data); struct object_key {
size_t serial;
struct string const char *key;
{
char *buffer;
int length;
int size;
}; };
static int dump_to_strbuffer(const char *buffer, int size, void *data) static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{ {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
} }
static int dump_to_file(const char *buffer, int size, void *data) static int dump_to_file(const char *buffer, size_t size, void *data)
{ {
FILE *dest = (FILE *)data; FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1) if(fwrite(buffer, size, 1, dest) != 1)
@ -41,10 +40,10 @@ static int dump_to_file(const char *buffer, int size, void *data)
return 0; return 0;
} }
/* 256 spaces (the maximum indentation size) */ /* 32 spaces (the maximum indentation size) */
static char whitespace[] = " "; static const char whitespace[] = " ";
static int dump_indent(unsigned long flags, int depth, int space, dump_func dump, void *data) static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{ {
if(JSON_INDENT(flags) > 0) if(JSON_INDENT(flags) > 0)
{ {
@ -66,7 +65,7 @@ static int dump_indent(unsigned long flags, int depth, int space, dump_func dump
return 0; return 0;
} }
static int dump_string(const char *str, int ascii, dump_func dump, void *data) static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
{ {
const char *pos, *end; const char *pos, *end;
int32_t codepoint; int32_t codepoint;
@ -91,8 +90,12 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break; break;
/* slash */
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */ /* non-ASCII */
if(ascii && codepoint > 0x7F) if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break; break;
pos = end; pos = end;
@ -106,7 +109,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
if(end == pos) if(end == pos)
break; break;
/* handle \, ", and control codes */ /* handle \, /, ", and control codes */
length = 2; length = 2;
switch(codepoint) switch(codepoint)
{ {
@ -117,6 +120,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
case '\n': text = "\\n"; break; case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break; case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break; case '\t': text = "\\t"; break;
case '/': text = "\\/"; break;
default: default:
{ {
/* codepoint is in BMP */ /* codepoint is in BMP */
@ -155,20 +159,23 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data)
static int object_key_compare_keys(const void *key1, const void *key2) static int object_key_compare_keys(const void *key1, const void *key2)
{ {
return strcmp((*(const object_key_t **)key1)->key, return strcmp(((const struct object_key *)key1)->key,
(*(const object_key_t **)key2)->key); ((const struct object_key *)key2)->key);
} }
static int object_key_compare_serials(const void *key1, const void *key2) static int object_key_compare_serials(const void *key1, const void *key2)
{ {
return (*(const object_key_t **)key1)->serial - size_t a = ((const struct object_key *)key1)->serial;
(*(const object_key_t **)key2)->serial; size_t b = ((const struct object_key *)key2)->serial;
return a < b ? -1 : a == b ? 0 : 1;
} }
static int do_dump(const json_t *json, unsigned long flags, int depth, static int do_dump(const json_t *json, size_t flags, int depth,
dump_func dump, void *data) json_dump_callback_t dump, void *data)
{ {
int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0; if(!json)
return -1;
switch(json_typeof(json)) { switch(json_typeof(json)) {
case JSON_NULL: case JSON_NULL:
@ -185,8 +192,10 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
char buffer[MAX_INTEGER_STR_LENGTH]; char buffer[MAX_INTEGER_STR_LENGTH];
int size; int size;
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%d", json_integer_value(json)); size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
if(size >= MAX_INTEGER_STR_LENGTH) "%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1; return -1;
return dump(buffer, size, data); return dump(buffer, size, data);
@ -196,31 +205,17 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
{ {
char buffer[MAX_REAL_STR_LENGTH]; char buffer[MAX_REAL_STR_LENGTH];
int size; int size;
double value = json_real_value(json);
size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g", size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
json_real_value(json)); if(size < 0)
if(size >= MAX_REAL_STR_LENGTH)
return -1; return -1;
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(size + 2 >= MAX_REAL_STR_LENGTH) {
/* No space to append ".0" */
return -1;
}
buffer[size] = '.';
buffer[size + 1] = '0';
size += 2;
}
return dump(buffer, size, data); return dump(buffer, size, data);
} }
case JSON_STRING: case JSON_STRING:
return dump_string(json_string_value(json), ascii, dump, data); return dump_string(json_string_value(json), dump, data, flags);
case JSON_ARRAY: case JSON_ARRAY:
{ {
@ -306,20 +301,20 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
{ {
const object_key_t **keys; struct object_key *keys;
unsigned int size; size_t size, i;
unsigned int i;
int (*cmp_func)(const void *, const void *); int (*cmp_func)(const void *, const void *);
size = json_object_size(json); size = json_object_size(json);
keys = malloc(size * sizeof(object_key_t *)); keys = jsonp_malloc(size * sizeof(struct object_key));
if(!keys) if(!keys)
goto object_error; goto object_error;
i = 0; i = 0;
while(iter) while(iter)
{ {
keys[i] = jsonp_object_iter_fullkey(iter); keys[i].serial = hashtable_iter_serial(iter);
keys[i].key = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter); iter = json_object_iter_next((json_t *)json, iter);
i++; i++;
} }
@ -330,22 +325,22 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
else else
cmp_func = object_key_compare_serials; cmp_func = object_key_compare_serials;
qsort((void*)keys, size, sizeof(object_key_t *), cmp_func); qsort(keys, size, sizeof(struct object_key), cmp_func);
for(i = 0; i < size; i++) for(i = 0; i < size; i++)
{ {
const char *key; const char *key;
json_t *value; json_t *value;
key = keys[i]->key; key = keys[i].key;
value = json_object_get(json, key); value = json_object_get(json, key);
assert(value); assert(value);
dump_string(key, ascii, dump, data); dump_string(key, dump, data, flags);
if(dump(separator, separator_length, data) || if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data)) do_dump(value, flags, depth + 1, dump, data))
{ {
free((void*)keys); jsonp_free(keys);
goto object_error; goto object_error;
} }
@ -354,7 +349,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
if(dump(",", 1, data) || if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data)) dump_indent(flags, depth + 1, 1, dump, data))
{ {
free((void*)keys); jsonp_free(keys);
goto object_error; goto object_error;
} }
} }
@ -362,13 +357,13 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
{ {
if(dump_indent(flags, depth, 0, dump, data)) if(dump_indent(flags, depth, 0, dump, data))
{ {
free((void*)keys); jsonp_free(keys);
goto object_error; goto object_error;
} }
} }
} }
free((void*)keys); jsonp_free(keys);
} }
else else
{ {
@ -378,7 +373,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
{ {
void *next = json_object_iter_next((json_t *)json, iter); void *next = json_object_iter_next((json_t *)json, iter);
dump_string(json_object_iter_key(iter), ascii, dump, data); dump_string(json_object_iter_key(iter), dump, data, flags);
if(dump(separator, separator_length, data) || if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1, do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data)) dump, data))
@ -414,38 +409,29 @@ static int do_dump(const json_t *json, unsigned long flags, int depth,
} }
} }
char *json_dumps(const json_t *json, size_t flags)
char *json_dumps(const json_t *json, unsigned long flags)
{ {
strbuffer_t strbuff; strbuffer_t strbuff;
char *result; char *result;
if(!json_is_array(json) && !json_is_object(json))
return NULL;
if(strbuffer_init(&strbuff)) if(strbuffer_init(&strbuff))
return NULL; return NULL;
if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) { if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
strbuffer_close(&strbuff); result = NULL;
return NULL; else
} result = jsonp_strdup(strbuffer_value(&strbuff));
result = strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff); strbuffer_close(&strbuff);
return result; return result;
} }
int json_dumpf(const json_t *json, FILE *output, unsigned long flags) int json_dumpf(const json_t *json, FILE *output, size_t flags)
{ {
if(!json_is_array(json) && !json_is_object(json)) return json_dump_callback(json, dump_to_file, (void *)output, flags);
return -1;
return do_dump(json, flags, 0, dump_to_file, (void *)output);
} }
int json_dump_file(const json_t *json, const char *path, unsigned long flags) int json_dump_file(const json_t *json, const char *path, size_t flags)
{ {
int result; int result;
@ -458,3 +444,13 @@ int json_dump_file(const json_t *json, const char *path, unsigned long flags)
fclose(output); fclose(output);
return result; return result;
} }
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
return do_dump(json, flags, 0, callback, data);
}

63
compat/jansson/error.c

@ -0,0 +1,63 @@
#include <string.h>
#include "jansson_private.h"
void jsonp_error_init(json_error_t *error, const char *source)
{
if(error)
{
error->text[0] = '\0';
error->line = -1;
error->column = -1;
error->position = 0;
if(source)
jsonp_error_set_source(error, source);
else
error->source[0] = '\0';
}
}
void jsonp_error_set_source(json_error_t *error, const char *source)
{
size_t length;
if(!error || !source)
return;
length = strlen(source);
if(length < JSON_ERROR_SOURCE_LENGTH)
strcpy(error->source, source);
else {
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
strcpy(error->source, "...");
strcpy(error->source + 3, source + extra);
}
}
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
jsonp_error_vset(error, line, column, position, msg, ap);
va_end(ap);
}
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, const char *msg, va_list ap)
{
if(!error)
return;
if(error->text[0] != '\0') {
/* error already set */
return;
}
error->line = line;
error->column = column;
error->position = position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap);
error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
}

163
compat/jansson/hashtable.c

@ -1,35 +1,46 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#include <config.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h" #include "hashtable.h"
#ifdef WIN32
#define inline __inline
#endif
typedef struct hashtable_list list_t; typedef struct hashtable_list list_t;
typedef struct hashtable_pair pair_t; typedef struct hashtable_pair pair_t;
typedef struct hashtable_bucket bucket_t; typedef struct hashtable_bucket bucket_t;
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_))
#define list_to_pair(list_) container_of(list_, pair_t, list) #define list_to_pair(list_) container_of(list_, pair_t, list)
static inline void list_init(list_t *list) /* From http://www.cse.yorku.ca/~oz/hash.html */
static size_t hash_str(const void *ptr)
{
const char *str = (const char *)ptr;
size_t hash = 5381;
size_t c;
while((c = (size_t)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
static JSON_INLINE void list_init(list_t *list)
{ {
list->next = list; list->next = list;
list->prev = list; list->prev = list;
} }
static inline void list_insert(list_t *list, list_t *node) static JSON_INLINE void list_insert(list_t *list, list_t *node)
{ {
node->next = list; node->next = list;
node->prev = list->prev; node->prev = list->prev;
@ -37,13 +48,13 @@ static inline void list_insert(list_t *list, list_t *node)
list->prev = node; list->prev = node;
} }
static inline void list_remove(list_t *list) static JSON_INLINE void list_remove(list_t *list)
{ {
list->prev->next = list->next; list->prev->next = list->next;
list->next->prev = list->prev; list->next->prev = list->prev;
} }
static inline int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket)
{ {
return bucket->first == &hashtable->list && bucket->first == bucket->last; return bucket->first == &hashtable->list && bucket->first == bucket->last;
} }
@ -63,22 +74,21 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
} }
} }
static unsigned int primes[] = { static const size_t primes[] = {
5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741 805306457, 1610612741
}; };
static const unsigned int num_primes = sizeof(primes) / sizeof(unsigned int);
static inline unsigned int num_buckets(hashtable_t *hashtable) static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
{ {
return primes[hashtable->num_buckets]; return primes[hashtable->num_buckets];
} }
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const void *key, unsigned int hash) const char *key, size_t hash)
{ {
list_t *list; list_t *list;
pair_t *pair; pair_t *pair;
@ -90,7 +100,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
while(1) while(1)
{ {
pair = list_to_pair(list); pair = list_to_pair(list);
if(pair->hash == hash && hashtable->cmp_keys(pair->key, key)) if(pair->hash == hash && strcmp(pair->key, key) == 0)
return pair; return pair;
if(list == bucket->last) if(list == bucket->last)
@ -104,11 +114,11 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
/* returns 0 on success, -1 if key was not found */ /* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable, static int hashtable_do_del(hashtable_t *hashtable,
const void *key, unsigned int hash) const char *key, size_t hash)
{ {
pair_t *pair; pair_t *pair;
bucket_t *bucket; bucket_t *bucket;
unsigned int index; size_t index;
index = hash % num_buckets(hashtable); index = hash % num_buckets(hashtable);
bucket = &hashtable->buckets[index]; bucket = &hashtable->buckets[index];
@ -127,13 +137,9 @@ static int hashtable_do_del(hashtable_t *hashtable,
bucket->last = pair->list.prev; bucket->last = pair->list.prev;
list_remove(&pair->list); list_remove(&pair->list);
json_decref(pair->value);
if(hashtable->free_key) jsonp_free(pair);
hashtable->free_key(pair->key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
free(pair);
hashtable->size--; hashtable->size--;
return 0; return 0;
@ -148,11 +154,8 @@ static void hashtable_do_clear(hashtable_t *hashtable)
{ {
next = list->next; next = list->next;
pair = list_to_pair(list); pair = list_to_pair(list);
if(hashtable->free_key) json_decref(pair->value);
hashtable->free_key(pair->key); jsonp_free(pair);
if(hashtable->free_value)
hashtable->free_value(pair->value);
free(pair);
} }
} }
@ -160,14 +163,14 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
{ {
list_t *list, *next; list_t *list, *next;
pair_t *pair; pair_t *pair;
unsigned int i, index, new_size; size_t i, index, new_size;
free(hashtable->buckets); jsonp_free(hashtable->buckets);
hashtable->num_buckets++; hashtable->num_buckets++;
new_size = num_buckets(hashtable); new_size = num_buckets(hashtable);
hashtable->buckets = malloc(new_size * sizeof(bucket_t)); hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t));
if(!hashtable->buckets) if(!hashtable->buckets)
return -1; return -1;
@ -191,47 +194,18 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
} }
hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, int hashtable_init(hashtable_t *hashtable)
free_fn free_key, free_fn free_value)
{
hashtable_t *hashtable = malloc(sizeof(hashtable_t));
if(!hashtable)
return NULL;
if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value))
{
free(hashtable);
return NULL;
}
return hashtable;
}
void hashtable_destroy(hashtable_t *hashtable)
{
hashtable_close(hashtable);
free(hashtable);
}
int hashtable_init(hashtable_t *hashtable,
key_hash_fn hash_key, key_cmp_fn cmp_keys,
free_fn free_key, free_fn free_value)
{ {
unsigned int i; size_t i;
hashtable->size = 0; hashtable->size = 0;
hashtable->num_buckets = 0; /* index to primes[] */ hashtable->num_buckets = 0; /* index to primes[] */
hashtable->buckets = malloc(num_buckets(hashtable) * sizeof(bucket_t)); hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t));
if(!hashtable->buckets) if(!hashtable->buckets)
return -1; return -1;
list_init(&hashtable->list); list_init(&hashtable->list);
hashtable->hash_key = hash_key;
hashtable->cmp_keys = cmp_keys;
hashtable->free_key = free_key;
hashtable->free_value = free_value;
for(i = 0; i < num_buckets(hashtable); i++) for(i = 0; i < num_buckets(hashtable); i++)
{ {
hashtable->buckets[i].first = hashtable->buckets[i].last = hashtable->buckets[i].first = hashtable->buckets[i].last =
@ -244,42 +218,45 @@ int hashtable_init(hashtable_t *hashtable,
void hashtable_close(hashtable_t *hashtable) void hashtable_close(hashtable_t *hashtable)
{ {
hashtable_do_clear(hashtable); hashtable_do_clear(hashtable);
free(hashtable->buckets); jsonp_free(hashtable->buckets);
} }
int hashtable_set(hashtable_t *hashtable, void *key, void *value) int hashtable_set(hashtable_t *hashtable,
const char *key, size_t serial,
json_t *value)
{ {
pair_t *pair; pair_t *pair;
bucket_t *bucket; bucket_t *bucket;
unsigned int hash, index; size_t hash, index;
/* rehash if the load ratio exceeds 1 */ /* rehash if the load ratio exceeds 1 */
if(hashtable->size >= num_buckets(hashtable)) if(hashtable->size >= num_buckets(hashtable))
if(hashtable_do_rehash(hashtable)) if(hashtable_do_rehash(hashtable))
return -1; return -1;
hash = hashtable->hash_key(key); hash = hash_str(key);
index = hash % num_buckets(hashtable); index = hash % num_buckets(hashtable);
bucket = &hashtable->buckets[index]; bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(pair) if(pair)
{ {
if(hashtable->free_key) json_decref(pair->value);
hashtable->free_key(key);
if(hashtable->free_value)
hashtable->free_value(pair->value);
pair->value = value; pair->value = value;
} }
else else
{ {
pair = malloc(sizeof(pair_t)); /* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
if(!pair) if(!pair)
return -1; return -1;
pair->key = key;
pair->value = value;
pair->hash = hash; pair->hash = hash;
pair->serial = serial;
strcpy(pair->key, key);
pair->value = value;
list_init(&pair->list); list_init(&pair->list);
insert_to_bucket(hashtable, bucket, &pair->list); insert_to_bucket(hashtable, bucket, &pair->list);
@ -289,13 +266,13 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value)
return 0; return 0;
} }
void *hashtable_get(hashtable_t *hashtable, const void *key) void *hashtable_get(hashtable_t *hashtable, const char *key)
{ {
pair_t *pair; pair_t *pair;
unsigned int hash; size_t hash;
bucket_t *bucket; bucket_t *bucket;
hash = hashtable->hash_key(key); hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
@ -305,15 +282,15 @@ void *hashtable_get(hashtable_t *hashtable, const void *key)
return pair->value; return pair->value;
} }
int hashtable_del(hashtable_t *hashtable, const void *key) int hashtable_del(hashtable_t *hashtable, const char *key)
{ {
unsigned int hash = hashtable->hash_key(key); size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash); return hashtable_do_del(hashtable, key, hash);
} }
void hashtable_clear(hashtable_t *hashtable) void hashtable_clear(hashtable_t *hashtable)
{ {
unsigned int i; size_t i;
hashtable_do_clear(hashtable); hashtable_do_clear(hashtable);
@ -332,13 +309,13 @@ void *hashtable_iter(hashtable_t *hashtable)
return hashtable_iter_next(hashtable, &hashtable->list); return hashtable_iter_next(hashtable, &hashtable->list);
} }
void *hashtable_iter_at(hashtable_t *hashtable, const void *key) void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
{ {
pair_t *pair; pair_t *pair;
unsigned int hash; size_t hash;
bucket_t *bucket; bucket_t *bucket;
hash = hashtable->hash_key(key); hash = hash_str(key);
bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
pair = hashtable_find_pair(hashtable, bucket, key, hash); pair = hashtable_find_pair(hashtable, bucket, key, hash);
@ -362,18 +339,22 @@ void *hashtable_iter_key(void *iter)
return pair->key; return pair->key;
} }
size_t hashtable_iter_serial(void *iter)
{
pair_t *pair = list_to_pair((list_t *)iter);
return pair->serial;
}
void *hashtable_iter_value(void *iter) void *hashtable_iter_value(void *iter)
{ {
pair_t *pair = list_to_pair((list_t *)iter); pair_t *pair = list_to_pair((list_t *)iter);
return pair->value; return pair->value;
} }
void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value) void hashtable_iter_set(void *iter, json_t *value)
{ {
pair_t *pair = list_to_pair((list_t *)iter); pair_t *pair = list_to_pair((list_t *)iter);
if(hashtable->free_value) json_decref(pair->value);
hashtable->free_value(pair->value);
pair->value = value; pair->value = value;
} }

89
compat/jansson/hashtable.h

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

179
compat/jansson/jansson.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -9,23 +9,31 @@
#define JANSSON_H #define JANSSON_H
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> /* for size_t */
#include <stdarg.h>
#ifdef WIN32 #include <jansson_config.h>
#define snprintf(...) _snprintf(__VA_ARGS__)
#define strdup(x) _strdup(x)
#endif
#ifdef WIN32
#define inline __inline
#endif
#ifndef __cplusplus #ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE inline
extern "C" { extern "C" {
#endif #endif
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 5
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.5"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \
(JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
/* types */ /* types */
typedef enum { typedef enum {
@ -39,11 +47,25 @@ typedef enum {
JSON_NULL JSON_NULL
} json_type; } json_type;
typedef struct { typedef struct json_t {
json_type type; json_type type;
unsigned long refcount; size_t refcount;
} json_t; } json_t;
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _WIN32
#define JSON_INTEGER_FORMAT "I64d"
#else
#define JSON_INTEGER_FORMAT "lld"
#endif
typedef long long json_int_t;
#else
#define JSON_INTEGER_FORMAT "ld"
typedef long json_int_t;
#endif /* JSON_INTEGER_IS_LONG_LONG */
#endif
#define json_typeof(json) ((json)->type) #define json_typeof(json) ((json)->type)
#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) #define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) #define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY)
@ -62,16 +84,17 @@ json_t *json_object(void);
json_t *json_array(void); json_t *json_array(void);
json_t *json_string(const char *value); json_t *json_string(const char *value);
json_t *json_string_nocheck(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_real(double value);
json_t *json_true(void); json_t *json_true(void);
json_t *json_false(void); json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void); json_t *json_null(void);
static JSON_INLINE static JSON_INLINE
json_t *json_incref(json_t *json) json_t *json_incref(json_t *json)
{ {
if(json && json->refcount != (unsigned int)-1) if(json && json->refcount != (size_t)-1)
++json->refcount; ++json->refcount;
return json; return json;
} }
@ -82,27 +105,54 @@ void json_delete(json_t *json);
static JSON_INLINE static JSON_INLINE
void json_decref(json_t *json) 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); json_delete(json);
} }
/* error reporting */
#define JSON_ERROR_TEXT_LENGTH 160
#define JSON_ERROR_SOURCE_LENGTH 80
typedef struct {
int line;
int column;
int position;
char source[JSON_ERROR_SOURCE_LENGTH];
char text[JSON_ERROR_TEXT_LENGTH];
} json_error_t;
/* getters, setters, manipulation */ /* 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); 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(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key); int json_object_del(json_t *object, const char *key);
int json_object_clear(json_t *object); int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other); int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
void *json_object_iter(json_t *object); void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key); void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
void *json_object_iter_next(json_t *object, void *iter); void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter); const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter); json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value); int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
#define json_array_foreach(array, index, value) \
for(index = 0; \
index < json_array_size(array) && (value = json_array_get(array, index)); \
index++)
static JSON_INLINE static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value) int json_object_set(json_t *object, const char *key, json_t *value)
{ {
@ -115,25 +165,25 @@ int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
return json_object_set_new_nocheck(object, key, json_incref(value)); 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) int json_object_iter_set(json_t *object, void *iter, json_t *value)
{ {
return json_object_iter_set_new(object, iter, json_incref(value)); return json_object_iter_set_new(object, iter, json_incref(value));
} }
unsigned int json_array_size(const json_t *array); size_t json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, unsigned int index); json_t *json_array_get(const json_t *array, size_t index);
int json_array_set_new(json_t *array, unsigned int index, json_t *value); 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_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_insert_new(json_t *array, size_t index, json_t *value);
int json_array_remove(json_t *array, unsigned int index); int json_array_remove(json_t *array, size_t index);
int json_array_clear(json_t *array); int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other); int json_array_extend(json_t *array, json_t *other);
static JSON_INLINE 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 ind, json_t *value)
{ {
return json_array_set_new(array, index, json_incref(value)); return json_array_set_new(array, ind, json_incref(value));
} }
static JSON_INLINE static JSON_INLINE
@ -143,22 +193,36 @@ int json_array_append(json_t *array, json_t *value)
} }
static JSON_INLINE 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 ind, json_t *value)
{ {
return json_array_insert_new(array, index, json_incref(value)); return json_array_insert_new(array, ind, json_incref(value));
} }
const char *json_string_value(const json_t *string); 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_real_value(const json_t *real);
double json_number_value(const json_t *json); double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value); int json_string_set(json_t *string, const char *value);
int json_string_set_nocheck(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 json_real_set(json_t *real, double value);
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
int json_unpack(json_t *root, const char *fmt, ...);
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...);
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap);
/* equality */ /* equality */
int json_equal(json_t *value1, json_t *value2); int json_equal(json_t *value1, json_t *value2);
@ -167,31 +231,48 @@ int json_equal(json_t *value1, json_t *value2);
/* copying */ /* copying */
json_t *json_copy(json_t *value); json_t *json_copy(json_t *value);
json_t *json_deep_copy(json_t *value); json_t *json_deep_copy(const json_t *value);
/* loading, printing */ /* decoding */
#define JSON_ERROR_TEXT_LENGTH 160 #define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
typedef struct { typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
char text[JSON_ERROR_TEXT_LENGTH];
int line; json_t *json_loads(const char *input, size_t flags, json_error_t *error);
} json_error_t; json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
/* encoding */
#define JSON_INDENT(n) (n & 0x1F)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
json_t *json_loads(const char *input, json_error_t *error); /* custom memory allocation */
json_t *json_loadf(FILE *input, json_error_t *error);
json_t *json_load_file(const char *path, json_error_t *error);
#define JSON_INDENT(n) (n & 0xFF) typedef void *(*json_malloc_t)(size_t);
#define JSON_COMPACT 0x100 typedef void (*json_free_t)(void *);
#define JSON_ENSURE_ASCII 0x200
#define JSON_SORT_KEYS 0x400
#define JSON_PRESERVE_ORDER 0x800
char *json_dumps(const json_t *json, unsigned long flags); void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
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);
#ifdef __cplusplus #ifdef __cplusplus
} }

43
compat/jansson/jansson_config.h

@ -0,0 +1,43 @@
/*
* Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*
* This file specifies a part of the site-specific configuration for
* Jansson, namely those things that affect the public API in
* jansson.h.
*
* The configure script copies this file to jansson_config.h and
* replaces @var@ substitutions by values that fit your system. If you
* cannot run the configure script, you can do the value substitution
* by hand.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef _MSC_VER
#define inline __inline
#endif
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE inline
#endif
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 1
#endif

55
compat/jansson/jansson_private.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -8,23 +8,40 @@
#ifndef JANSSON_PRIVATE_H #ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H #define JANSSON_PRIVATE_H
#include <stddef.h>
#include "jansson.h" #include "jansson.h"
#include "hashtable.h" #include "hashtable.h"
#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \ #define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_)) ((type_ *)((char *)ptr_ - offsetof(type_, member_)))
/* On some platforms, max() may already be defined */
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
/* va_copy is a C99 feature. In C89 implementations, it's sometimes
available as __va_copy. If not, memcpy() should do the trick. */
#ifndef va_copy
#ifdef __va_copy
#define va_copy __va_copy
#else
#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list))
#endif
#endif
typedef struct { typedef struct {
json_t json; json_t json;
hashtable_t hashtable; hashtable_t hashtable;
unsigned long serial; size_t serial;
int visited; int visited;
} json_object_t; } json_object_t;
typedef struct { typedef struct {
json_t json; json_t json;
unsigned int size; size_t size;
unsigned int entries; size_t entries;
json_t **table; json_t **table;
int visited; int visited;
} json_array_t; } json_array_t;
@ -41,7 +58,7 @@ typedef struct {
typedef struct { typedef struct {
json_t json; json_t json;
int value; json_int_t value;
} json_integer_t; } json_integer_t;
#define json_to_object(json_) container_of(json_, json_object_t, json) #define json_to_object(json_) container_of(json_, json_object_t, json)
@ -50,11 +67,27 @@ typedef struct {
#define json_to_real(json_) container_of(json_, json_real_t, json) #define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json) #define json_to_integer(json_) container_of(json_, json_integer_t, json)
typedef struct { void jsonp_error_init(json_error_t *error, const char *source);
unsigned long serial; void jsonp_error_set_source(json_error_t *error, const char *source);
char key[]; void jsonp_error_set(json_error_t *error, int line, int column,
} object_key_t; size_t position, const char *msg, ...);
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, const char *msg, va_list ap);
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value);
const object_key_t *jsonp_object_iter_fullkey(void *iter); /* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
/* Windows compatibility */
#ifdef _WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#endif #endif

570
compat/jansson/load.c

@ -1,25 +1,30 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#include <ctype.h> #endif
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <jansson.h> #include "jansson.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "strbuffer.h" #include "strbuffer.h"
#include "utf.h" #include "utf.h"
#define STREAM_STATE_OK 0
#define STREAM_STATE_EOF -1
#define STREAM_STATE_ERROR -2
#define TOKEN_INVALID -1 #define TOKEN_INVALID -1
#define TOKEN_EOF 0 #define TOKEN_EOF 0
#define TOKEN_STRING 256 #define TOKEN_STRING 256
@ -29,113 +34,136 @@
#define TOKEN_FALSE 260 #define TOKEN_FALSE 260
#define TOKEN_NULL 261 #define TOKEN_NULL 261
/* read one byte from stream, return EOF on end of file */ /* Locale independent versions of isxxx() functions */
#define l_isupper(c) ('A' <= (c) && (c) <= 'Z')
#define l_islower(c) ('a' <= (c) && (c) <= 'z')
#define l_isalpha(c) (l_isupper(c) || l_islower(c))
#define l_isdigit(c) ('0' <= (c) && (c) <= '9')
#define l_isxdigit(c) \
(l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f'))
/* Read one byte from stream, convert to unsigned char, then int, and
return. return EOF on end of file. This corresponds to the
behaviour of fgetc(). */
typedef int (*get_func)(void *data); typedef int (*get_func)(void *data);
/* return non-zero if end of file has been reached */
typedef int (*eof_func)(void *data);
typedef struct { typedef struct {
get_func get; get_func get;
eof_func eof;
void *data; void *data;
int stream_pos;
char buffer[5]; char buffer[5];
int buffer_pos; size_t buffer_pos;
int state;
int line;
int column, last_column;
size_t position;
} stream_t; } stream_t;
typedef struct { typedef struct {
stream_t stream; stream_t stream;
strbuffer_t saved_text; strbuffer_t saved_text;
int token; int token;
int line, column;
union { union {
char *string; char *string;
int integer; json_int_t integer;
double real; double real;
} value; } value;
} lex_t; } lex_t;
#define stream_to_lex(stream) container_of(stream, lex_t, stream)
/*** error reporting ***/
static void error_init(json_error_t *error) /*** error reporting ***/
{
if(error)
{
error->text[0] = '\0';
error->line = -1;
}
}
static void error_set(json_error_t *error, const lex_t *lex, static void error_set(json_error_t *error, const lex_t *lex,
const char *msg, ...) const char *msg, ...)
{ {
va_list ap; va_list ap;
char text[JSON_ERROR_TEXT_LENGTH]; char msg_text[JSON_ERROR_TEXT_LENGTH];
char msg_with_context[JSON_ERROR_TEXT_LENGTH];
int line = -1, col = -1;
size_t pos = 0;
const char *result = msg_text;
if(!error || error->text[0] != '\0') { if(!error)
/* error already set */
return; return;
}
va_start(ap, msg); va_start(ap, msg);
vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap); vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap);
msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
va_end(ap); va_end(ap);
if(lex) if(lex)
{ {
const char *saved_text = strbuffer_value(&lex->saved_text); const char *saved_text = strbuffer_value(&lex->saved_text);
error->line = lex->line;
line = lex->stream.line;
col = lex->stream.column;
pos = lex->stream.position;
if(saved_text && saved_text[0]) if(saved_text && saved_text[0])
{ {
if(lex->saved_text.length <= 20) { if(lex->saved_text.length <= 20) {
snprintf(error->text, JSON_ERROR_TEXT_LENGTH, snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near '%s'", text, saved_text); "%s near '%s'", msg_text, saved_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context;
} }
else
snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text);
} }
else else
{ {
snprintf(error->text, JSON_ERROR_TEXT_LENGTH, if(lex->stream.state == STREAM_STATE_ERROR) {
"%s near end of file", text); /* No context for UTF-8 decoding errors */
result = msg_text;
}
else {
snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH,
"%s near end of file", msg_text);
msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
result = msg_with_context;
}
} }
} }
else
{ jsonp_error_set(error, line, col, pos, "%s", result);
error->line = -1;
snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text);
}
} }
/*** lexical analyzer ***/ /*** lexical analyzer ***/
static void static void
stream_init(stream_t *stream, get_func get, eof_func eof, void *data) stream_init(stream_t *stream, get_func get, void *data)
{ {
stream->get = get; stream->get = get;
stream->eof = eof;
stream->data = data; stream->data = data;
stream->stream_pos = 0;
stream->buffer[0] = '\0'; stream->buffer[0] = '\0';
stream->buffer_pos = 0; stream->buffer_pos = 0;
stream->state = STREAM_STATE_OK;
stream->line = 1;
stream->column = 0;
stream->position = 0;
} }
static char stream_get(stream_t *stream, json_error_t *error) static int stream_get(stream_t *stream, json_error_t *error)
{ {
char c; int c;
if(stream->state != STREAM_STATE_OK)
return stream->state;
if(!stream->buffer[stream->buffer_pos]) if(!stream->buffer[stream->buffer_pos])
{ {
stream->buffer[0] = stream->get(stream->data); c = stream->get(stream->data);
stream->buffer_pos = 0; if(c == EOF) {
stream->state = STREAM_STATE_EOF;
return STREAM_STATE_EOF;
}
c = stream->buffer[0]; stream->buffer[0] = c;
stream->buffer_pos = 0;
if((unsigned char)c >= 0x80 && c != (char)EOF) if(0x80 <= c && c <= 0xFF)
{ {
/* multi-byte UTF-8 sequence */ /* multi-byte UTF-8 sequence */
int i, count; int i, count;
@ -152,30 +180,47 @@ static char stream_get(stream_t *stream, json_error_t *error)
if(!utf8_check_full(stream->buffer, count, NULL)) if(!utf8_check_full(stream->buffer, count, NULL))
goto out; goto out;
stream->stream_pos += count;
stream->buffer[count] = '\0'; stream->buffer[count] = '\0';
} }
else { else
stream->buffer[1] = '\0'; stream->buffer[1] = '\0';
stream->stream_pos++;
}
} }
return stream->buffer[stream->buffer_pos++]; c = stream->buffer[stream->buffer_pos++];
out: stream->position++;
error_set(error, NULL, "unable to decode byte 0x%x at position %d", if(c == '\n') {
(unsigned char)c, stream->stream_pos); stream->line++;
stream->last_column = stream->column;
stream->column = 0;
}
else if(utf8_check_first(c)) {
/* track the Unicode character column, so increment only if
this is the first character of a UTF-8 sequence */
stream->column++;
}
stream->buffer[0] = EOF; return c;
stream->buffer[1] = '\0';
stream->buffer_pos = 1;
return EOF; out:
stream->state = STREAM_STATE_ERROR;
error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c);
return STREAM_STATE_ERROR;
} }
static void stream_unget(stream_t *stream, char c) static void stream_unget(stream_t *stream, int c)
{ {
if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR)
return;
stream->position--;
if(c == '\n') {
stream->line--;
stream->column = stream->last_column;
}
else if(utf8_check_first(c))
stream->column--;
assert(stream->buffer_pos > 0); assert(stream->buffer_pos > 0);
stream->buffer_pos--; stream->buffer_pos--;
assert(stream->buffer[stream->buffer_pos] == c); assert(stream->buffer[stream->buffer_pos] == c);
@ -187,29 +232,41 @@ static int lex_get(lex_t *lex, json_error_t *error)
return stream_get(&lex->stream, error); return stream_get(&lex->stream, error);
} }
static int lex_eof(lex_t *lex) static void lex_save(lex_t *lex, int c)
{
return lex->stream.eof(lex->stream.data);
}
static void lex_save(lex_t *lex, char c)
{ {
strbuffer_append_byte(&lex->saved_text, c); strbuffer_append_byte(&lex->saved_text, c);
} }
static int lex_get_save(lex_t *lex, json_error_t *error) static int lex_get_save(lex_t *lex, json_error_t *error)
{ {
char c = stream_get(&lex->stream, error); int c = stream_get(&lex->stream, error);
lex_save(lex, c); if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR)
lex_save(lex, c);
return c; return c;
} }
static void lex_unget_unsave(lex_t *lex, char c) static void lex_unget(lex_t *lex, int c)
{ {
char d;
stream_unget(&lex->stream, c); stream_unget(&lex->stream, c);
d = strbuffer_pop(&lex->saved_text); }
assert(c == d);
static void lex_unget_unsave(lex_t *lex, int c)
{
if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {
/* Since we treat warnings as errors, when assertions are turned
* off the "d" variable would be set but never used. Which is
* treated as an error by GCC.
*/
#ifndef NDEBUG
char d;
#endif
stream_unget(&lex->stream, c);
#ifndef NDEBUG
d =
#endif
strbuffer_pop(&lex->saved_text);
assert(c == d);
}
} }
static void lex_save_cached(lex_t *lex) static void lex_save_cached(lex_t *lex)
@ -218,6 +275,7 @@ static void lex_save_cached(lex_t *lex)
{ {
lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]);
lex->stream.buffer_pos++; lex->stream.buffer_pos++;
lex->stream.position++;
} }
} }
@ -232,11 +290,11 @@ static int32_t decode_unicode_escape(const char *str)
for(i = 1; i <= 4; i++) { for(i = 1; i <= 4; i++) {
char c = str[i]; char c = str[i];
value <<= 4; value <<= 4;
if(isdigit(c)) if(l_isdigit(c))
value += c - '0'; value += c - '0';
else if(islower(c)) else if(l_islower(c))
value += c - 'a' + 10; value += c - 'a' + 10;
else if(isupper(c)) else if(l_isupper(c))
value += c - 'A' + 10; value += c - 'A' + 10;
else else
assert(0); assert(0);
@ -247,7 +305,7 @@ static int32_t decode_unicode_escape(const char *str)
static void lex_scan_string(lex_t *lex, json_error_t *error) static void lex_scan_string(lex_t *lex, json_error_t *error)
{ {
char c; int c;
const char *p; const char *p;
char *t; char *t;
int i; int i;
@ -258,14 +316,15 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(c != '"') { while(c != '"') {
if(c == (char)EOF) { if(c == STREAM_STATE_ERROR)
lex_unget_unsave(lex, c); goto out;
if(lex_eof(lex))
error_set(error, lex, "premature end of input"); else if(c == STREAM_STATE_EOF) {
error_set(error, lex, "premature end of input");
goto out; goto out;
} }
else if((unsigned char)c <= 0x1F) { else if(0 <= c && c <= 0x1F) {
/* control character */ /* control character */
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
if(c == '\n') if(c == '\n')
@ -280,8 +339,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(c == 'u') { if(c == 'u') {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
if(!isxdigit(c)) { if(!l_isxdigit(c)) {
lex_unget_unsave(lex, c);
error_set(error, lex, "invalid escape"); error_set(error, lex, "invalid escape");
goto out; goto out;
} }
@ -292,7 +350,6 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
c == 'f' || c == 'n' || c == 'r' || c == 't') c == 'f' || c == 'n' || c == 'r' || c == 't')
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
else { else {
lex_unget_unsave(lex, c);
error_set(error, lex, "invalid escape"); error_set(error, lex, "invalid escape");
goto out; goto out;
} }
@ -308,7 +365,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
- two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
are converted to 4 bytes are converted to 4 bytes
*/ */
lex->value.string = malloc(lex->saved_text.length + 1); lex->value.string = jsonp_malloc(lex->saved_text.length + 1);
if(!lex->value.string) { if(!lex->value.string) {
/* this is not very nice, since TOKEN_INVALID is returned */ /* this is not very nice, since TOKEN_INVALID is returned */
goto out; goto out;
@ -398,10 +455,22 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
return; return;
out: out:
free(lex->value.string); jsonp_free(lex->value.string);
} }
static int lex_scan_number(lex_t *lex, char c, json_error_t *error) #ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _MSC_VER /* Microsoft Visual Studio */
#define json_strtoint _strtoi64
#else
#define json_strtoint strtoll
#endif
#else
#define json_strtoint strtol
#endif
#endif
static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
{ {
const char *saved_text; const char *saved_text;
char *end; char *end;
@ -414,52 +483,55 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
if(c == '0') { if(c == '0') {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
if(isdigit(c)) { if(l_isdigit(c)) {
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
goto out; goto out;
} }
} }
else if(isdigit(c)) { else if(l_isdigit(c)) {
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
else { else {
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
goto out; goto out;
} }
if(c != '.' && c != 'E' && c != 'e') { if(c != '.' && c != 'E' && c != 'e') {
long value; json_int_t value;
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text); saved_text = strbuffer_value(&lex->saved_text);
value = strtol(saved_text, &end, 10);
assert(end == saved_text + lex->saved_text.length);
if((value == LONG_MAX && errno == ERANGE) || value > INT_MAX) { errno = 0;
error_set(error, lex, "too big integer"); value = json_strtoint(saved_text, &end, 10);
goto out; if(errno == ERANGE) {
} if(value < 0)
else if((value == LONG_MIN && errno == ERANGE) || value < INT_MIN) { error_set(error, lex, "too big negative integer");
error_set(error, lex, "too big negative integer"); else
error_set(error, lex, "too big integer");
goto out; goto out;
} }
assert(end == saved_text + lex->saved_text.length);
lex->token = TOKEN_INTEGER; lex->token = TOKEN_INTEGER;
lex->value.integer = (int)value; lex->value.integer = value;
return 0; return 0;
} }
if(c == '.') { if(c == '.') {
c = lex_get(lex, error); c = lex_get(lex, error);
if(!isdigit(c)) if(!l_isdigit(c)) {
lex_unget(lex, c);
goto out; goto out;
}
lex_save(lex, c); lex_save(lex, c);
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
@ -468,23 +540,19 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
if(c == '+' || c == '-') if(c == '+' || c == '-')
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
if(!isdigit(c)) { if(!l_isdigit(c)) {
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
goto out; goto out;
} }
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isdigit(c)) while(l_isdigit(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
} }
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
saved_text = strbuffer_value(&lex->saved_text); if(jsonp_strtod(&lex->saved_text, &value)) {
value = strtod(saved_text, &end);
assert(end == saved_text + lex->saved_text.length);
if(errno == ERANGE && value != 0) {
error_set(error, lex, "real number overflow"); error_set(error, lex, "real number overflow");
goto out; goto out;
} }
@ -499,29 +567,26 @@ out:
static int lex_scan(lex_t *lex, json_error_t *error) static int lex_scan(lex_t *lex, json_error_t *error)
{ {
char c; int c;
strbuffer_clear(&lex->saved_text); strbuffer_clear(&lex->saved_text);
if(lex->token == TOKEN_STRING) { if(lex->token == TOKEN_STRING) {
free(lex->value.string); jsonp_free(lex->value.string);
lex->value.string = NULL; lex->value.string = NULL;
} }
c = lex_get(lex, error); c = lex_get(lex, error);
while(c == ' ' || c == '\t' || c == '\n' || c == '\r') while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
{
if(c == '\n')
lex->line++;
c = lex_get(lex, error); c = lex_get(lex, error);
if(c == STREAM_STATE_EOF) {
lex->token = TOKEN_EOF;
goto out;
} }
if(c == (char)EOF) { if(c == STREAM_STATE_ERROR) {
if(lex_eof(lex)) lex->token = TOKEN_INVALID;
lex->token = TOKEN_EOF;
else
lex->token = TOKEN_INVALID;
goto out; goto out;
} }
@ -533,17 +598,17 @@ static int lex_scan(lex_t *lex, json_error_t *error)
else if(c == '"') else if(c == '"')
lex_scan_string(lex, error); lex_scan_string(lex, error);
else if(isdigit(c) || c == '-') { else if(l_isdigit(c) || c == '-') {
if(lex_scan_number(lex, c, error)) if(lex_scan_number(lex, c, error))
goto out; goto out;
} }
else if(isupper(c) || islower(c)) { else if(l_isalpha(c)) {
/* eat up the whole identifier for clearer error messages */ /* eat up the whole identifier for clearer error messages */
const char *saved_text; const char *saved_text;
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
while(isupper(c) || islower(c)) while(l_isalpha(c))
c = lex_get_save(lex, error); c = lex_get_save(lex, error);
lex_unget_unsave(lex, c); lex_unget_unsave(lex, c);
@ -581,31 +646,29 @@ static char *lex_steal_string(lex_t *lex)
return result; return result;
} }
static int lex_init(lex_t *lex, get_func get, eof_func eof, void *data) static int lex_init(lex_t *lex, get_func get, void *data)
{ {
stream_init(&lex->stream, get, eof, data); stream_init(&lex->stream, get, data);
if(strbuffer_init(&lex->saved_text)) if(strbuffer_init(&lex->saved_text))
return -1; return -1;
lex->token = TOKEN_INVALID; lex->token = TOKEN_INVALID;
lex->line = 1;
return 0; return 0;
} }
static void lex_close(lex_t *lex) static void lex_close(lex_t *lex)
{ {
if(lex->token == TOKEN_STRING) if(lex->token == TOKEN_STRING)
free(lex->value.string); jsonp_free(lex->value.string);
strbuffer_close(&lex->saved_text); strbuffer_close(&lex->saved_text);
} }
/*** parser ***/ /*** parser ***/
static json_t *parse_value(lex_t *lex, json_error_t *error); static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error);
static json_t *parse_object(lex_t *lex, json_error_t *error) static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
{ {
json_t *object = json_object(); json_t *object = json_object();
if(!object) if(!object)
@ -628,28 +691,36 @@ static json_t *parse_object(lex_t *lex, json_error_t *error)
if(!key) if(!key)
return NULL; return NULL;
if(flags & JSON_REJECT_DUPLICATES) {
if(json_object_get(object, key)) {
jsonp_free(key);
error_set(error, lex, "duplicate object key");
goto error;
}
}
lex_scan(lex, error); lex_scan(lex, error);
if(lex->token != ':') { if(lex->token != ':') {
free(key); jsonp_free(key);
error_set(error, lex, "':' expected"); error_set(error, lex, "':' expected");
goto error; goto error;
} }
lex_scan(lex, error); lex_scan(lex, error);
value = parse_value(lex, error); value = parse_value(lex, flags, error);
if(!value) { if(!value) {
free(key); jsonp_free(key);
goto error; goto error;
} }
if(json_object_set_nocheck(object, key, value)) { if(json_object_set_nocheck(object, key, value)) {
free(key); jsonp_free(key);
json_decref(value); json_decref(value);
goto error; goto error;
} }
json_decref(value); json_decref(value);
free(key); jsonp_free(key);
lex_scan(lex, error); lex_scan(lex, error);
if(lex->token != ',') if(lex->token != ',')
@ -670,7 +741,7 @@ error:
return NULL; return NULL;
} }
static json_t *parse_array(lex_t *lex, json_error_t *error) static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error)
{ {
json_t *array = json_array(); json_t *array = json_array();
if(!array) if(!array)
@ -681,7 +752,7 @@ static json_t *parse_array(lex_t *lex, json_error_t *error)
return array; return array;
while(lex->token) { while(lex->token) {
json_t *elem = parse_value(lex, error); json_t *elem = parse_value(lex, flags, error);
if(!elem) if(!elem)
goto error; goto error;
@ -710,9 +781,10 @@ error:
return NULL; return NULL;
} }
static json_t *parse_value(lex_t *lex, json_error_t *error) static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
{ {
json_t *json; json_t *json;
double value;
switch(lex->token) { switch(lex->token) {
case TOKEN_STRING: { case TOKEN_STRING: {
@ -721,7 +793,15 @@ static json_t *parse_value(lex_t *lex, json_error_t *error)
} }
case TOKEN_INTEGER: { case TOKEN_INTEGER: {
json = json_integer(lex->value.integer); if (flags & JSON_DECODE_INT_AS_REAL) {
if(jsonp_strtod(&lex->saved_text, &value)) {
error_set(error, lex, "real number overflow");
return NULL;
}
json = json_real(value);
} else {
json = json_integer(lex->value.integer);
}
break; break;
} }
@ -743,11 +823,11 @@ static json_t *parse_value(lex_t *lex, json_error_t *error)
break; break;
case '{': case '{':
json = parse_object(lex, error); json = parse_object(lex, flags, error);
break; break;
case '[': case '[':
json = parse_array(lex, error); json = parse_array(lex, flags, error);
break; break;
case TOKEN_INVALID: case TOKEN_INVALID:
@ -765,17 +845,37 @@ static json_t *parse_value(lex_t *lex, json_error_t *error)
return json; return json;
} }
static json_t *parse_json(lex_t *lex, json_error_t *error) static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
{ {
error_init(error); json_t *result;
lex_scan(lex, error); lex_scan(lex, error);
if(lex->token != '[' && lex->token != '{') { if(!(flags & JSON_DECODE_ANY)) {
error_set(error, lex, "'[' or '{' expected"); if(lex->token != '[' && lex->token != '{') {
error_set(error, lex, "'[' or '{' expected");
return NULL;
}
}
result = parse_value(lex, flags, error);
if(!result)
return NULL; return NULL;
if(!(flags & JSON_DISABLE_EOF_CHECK)) {
lex_scan(lex, error);
if(lex->token != TOKEN_EOF) {
error_set(error, lex, "end of file expected");
json_decref(result);
return NULL;
}
}
if(error) {
/* Save the position even though there was no error */
error->position = lex->stream.position;
} }
return parse_value(lex, error); return result;
} }
typedef struct typedef struct
@ -794,77 +894,120 @@ static int string_get(void *data)
else else
{ {
stream->pos++; stream->pos++;
return c; return (unsigned char)c;
} }
} }
static int string_eof(void *data) json_t *json_loads(const char *string, size_t flags, json_error_t *error)
{ {
string_data_t *stream = (string_data_t *)data; lex_t lex;
return (stream->data[stream->pos] == '\0'); json_t *result;
string_data_t stream_data;
jsonp_error_init(error, "<string>");
if (string == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
stream_data.data = string;
stream_data.pos = 0;
if(lex_init(&lex, string_get, (void *)&stream_data))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}
typedef struct
{
const char *data;
size_t len;
size_t pos;
} buffer_data_t;
static int buffer_get(void *data)
{
char c;
buffer_data_t *stream = data;
if(stream->pos >= stream->len)
return EOF;
c = stream->data[stream->pos];
stream->pos++;
return (unsigned char)c;
} }
json_t *json_loads(const char *string, json_error_t *error) json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
{ {
lex_t lex; lex_t lex;
json_t *result; json_t *result;
buffer_data_t stream_data;
string_data_t stream_data = { jsonp_error_init(error, "<buffer>");
string,
0
};
if(lex_init(&lex, string_get, string_eof, (void *)&stream_data)) if (buffer == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL; return NULL;
}
result = parse_json(&lex, error); stream_data.data = buffer;
if(!result) stream_data.pos = 0;
goto out; stream_data.len = buflen;
lex_scan(&lex, error); if(lex_init(&lex, buffer_get, (void *)&stream_data))
if(lex.token != TOKEN_EOF) { return NULL;
error_set(error, &lex, "end of file expected");
json_decref(result); result = parse_json(&lex, flags, error);
result = NULL;
}
out:
lex_close(&lex); lex_close(&lex);
return result; return result;
} }
json_t *json_loadf(FILE *input, json_error_t *error) json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
{ {
lex_t lex; lex_t lex;
const char *source;
json_t *result; json_t *result;
if(lex_init(&lex, (get_func)fgetc, (eof_func)feof, input)) if(input == stdin)
return NULL; source = "<stdin>";
else
source = "<stream>";
result = parse_json(&lex, error); jsonp_error_init(error, source);
if(!result)
goto out;
lex_scan(&lex, error); if (input == NULL) {
if(lex.token != TOKEN_EOF) { error_set(error, NULL, "wrong arguments");
error_set(error, &lex, "end of file expected"); return NULL;
json_decref(result);
result = NULL;
} }
out: if(lex_init(&lex, (get_func)fgetc, input))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex); lex_close(&lex);
return result; return result;
} }
json_t *json_load_file(const char *path, json_error_t *error) json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
{ {
json_t *result; json_t *result;
FILE *fp; FILE *fp;
error_init(error); jsonp_error_init(error, path);
if (path == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
fp = fopen(path, "r"); fp = fopen(path, "rb");
if(!fp) if(!fp)
{ {
error_set(error, NULL, "unable to open %s: %s", error_set(error, NULL, "unable to open %s: %s",
@ -872,8 +1015,63 @@ json_t *json_load_file(const char *path, json_error_t *error)
return NULL; return NULL;
} }
result = json_loadf(fp, error); result = json_loadf(fp, flags, error);
fclose(fp); fclose(fp);
return result; return result;
} }
#define MAX_BUF_LEN 1024
typedef struct
{
char data[MAX_BUF_LEN];
size_t len;
size_t pos;
json_load_callback_t callback;
void *arg;
} callback_data_t;
static int callback_get(void *data)
{
char c;
callback_data_t *stream = data;
if(stream->pos >= stream->len) {
stream->pos = 0;
stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg);
if(stream->len == 0 || stream->len == (size_t)-1)
return EOF;
}
c = stream->data[stream->pos];
stream->pos++;
return (unsigned char)c;
}
json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error)
{
lex_t lex;
json_t *result;
callback_data_t stream_data;
memset(&stream_data, 0, sizeof(stream_data));
stream_data.callback = callback;
stream_data.arg = arg;
jsonp_error_init(error, "<callback>");
if (callback == NULL) {
error_set(error, NULL, "wrong arguments");
return NULL;
}
if(lex_init(&lex, (get_func)callback_get, &stream_data))
return NULL;
result = parse_json(&lex, flags, error);
lex_close(&lex);
return result;
}

56
compat/jansson/memory.c

@ -0,0 +1,56 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include "jansson.h"
#include "jansson_private.h"
/* memory function pointers */
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
void *jsonp_malloc(size_t size)
{
if(!size)
return NULL;
return (*do_malloc)(size);
}
void jsonp_free(void *ptr)
{
if(!ptr)
return;
(*do_free)(ptr);
}
char *jsonp_strdup(const char *str)
{
char *new_str;
size_t len;
len = strlen(str);
if(len == (size_t)-1)
return NULL;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
memcpy(new_str, str, len + 1);
return new_str;
}
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn)
{
do_malloc = malloc_fn;
do_free = free_fn;
}

762
compat/jansson/pack_unpack.c

@ -0,0 +1,762 @@
/*
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "jansson.h"
#include "jansson_private.h"
#include "utf.h"
typedef struct {
int line;
int column;
size_t pos;
char token;
} token_t;
typedef struct {
const char *start;
const char *fmt;
token_t prev_token;
token_t token;
token_t next_token;
json_error_t *error;
size_t flags;
int line;
int column;
size_t pos;
} scanner_t;
#define token(scanner) ((scanner)->token.token)
static const char * const type_names[] = {
"object",
"array",
"string",
"integer",
"real",
"true",
"false",
"null"
};
#define type_name(x) type_names[json_typeof(x)]
static const char unpack_value_starters[] = "{[siIbfFOon";
static void scanner_init(scanner_t *s, json_error_t *error,
size_t flags, const char *fmt)
{
s->error = error;
s->flags = flags;
s->fmt = s->start = fmt;
memset(&s->prev_token, 0, sizeof(token_t));
memset(&s->token, 0, sizeof(token_t));
memset(&s->next_token, 0, sizeof(token_t));
s->line = 1;
s->column = 0;
s->pos = 0;
}
static void next_token(scanner_t *s)
{
const char *t;
s->prev_token = s->token;
if(s->next_token.line) {
s->token = s->next_token;
s->next_token.line = 0;
return;
}
t = s->fmt;
s->column++;
s->pos++;
/* skip space and ignored chars */
while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
if(*t == '\n') {
s->line++;
s->column = 1;
}
else
s->column++;
s->pos++;
t++;
}
s->token.token = *t;
s->token.line = s->line;
s->token.column = s->column;
s->token.pos = s->pos;
t++;
s->fmt = t;
}
static void prev_token(scanner_t *s)
{
s->next_token = s->token;
s->token = s->prev_token;
}
static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos,
fmt, ap);
jsonp_error_set_source(s->error, source);
va_end(ap);
}
static json_t *pack(scanner_t *s, va_list *ap);
/* ours will be set to 1 if jsonp_free() must be called for the result
afterwards */
static char *read_string(scanner_t *s, va_list *ap,
const char *purpose, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
char *result;
next_token(s);
t = token(s);
prev_token(s);
if(t != '#' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", "NULL string argument");
return NULL;
}
if(!utf8_check_string(str, -1)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
*ours = 0;
return (char *)str;
}
strbuffer_init(&strbuff);
while(1) {
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", "NULL string argument");
strbuffer_close(&strbuff);
return NULL;
}
next_token(s);
if(token(s) == '#') {
length = va_arg(*ap, int);
}
else {
prev_token(s);
length = strlen(str);
}
if(strbuffer_append_bytes(&strbuff, str, length) == -1) {
set_error(s, "<internal>", "Out of memory");
strbuffer_close(&strbuff);
return NULL;
}
next_token(s);
if(token(s) != '+') {
prev_token(s);
break;
}
}
result = strbuffer_steal_value(&strbuff);
if(!utf8_check_string(result, -1)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
*ours = 1;
return result;
}
static json_t *pack_object(scanner_t *s, va_list *ap)
{
json_t *object = json_object();
next_token(s);
while(token(s) != '}') {
char *key;
int ours;
json_t *value;
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto error;
}
if(token(s) != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
goto error;
}
key = read_string(s, ap, "object key", &ours);
if(!key)
goto error;
next_token(s);
value = pack(s, ap);
if(!value)
goto error;
if(json_object_set_new_nocheck(object, key, value)) {
if(ours)
jsonp_free(key);
set_error(s, "<internal>", "Unable to add key \"%s\"", key);
goto error;
}
if(ours)
jsonp_free(key);
next_token(s);
}
return object;
error:
json_decref(object);
return NULL;
}
static json_t *pack_array(scanner_t *s, va_list *ap)
{
json_t *array = json_array();
next_token(s);
while(token(s) != ']') {
json_t *value;
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto error;
}
value = pack(s, ap);
if(!value)
goto error;
if(json_array_append_new(array, value)) {
set_error(s, "<internal>", "Unable to append to array");
goto error;
}
next_token(s);
}
return array;
error:
json_decref(array);
return NULL;
}
static json_t *pack(scanner_t *s, va_list *ap)
{
switch(token(s)) {
case '{':
return pack_object(s, ap);
case '[':
return pack_array(s, ap);
case 's': { /* string */
char *str;
int ours;
json_t *result;
str = read_string(s, ap, "string", &ours);
if(!str)
return NULL;
result = json_string_nocheck(str);
if(ours)
jsonp_free(str);
return result;
}
case 'n': /* null */
return json_null();
case 'b': /* boolean */
return va_arg(*ap, int) ? json_true() : json_false();
case 'i': /* integer from int */
return json_integer(va_arg(*ap, int));
case 'I': /* integer from json_int_t */
return json_integer(va_arg(*ap, json_int_t));
case 'f': /* real */
return json_real(va_arg(*ap, double));
case 'O': /* a json_t object; increments refcount */
return json_incref(va_arg(*ap, json_t *));
case 'o': /* a json_t object; doesn't increment refcount */
return va_arg(*ap, json_t *);
default:
set_error(s, "<format>", "Unexpected format character '%c'",
token(s));
return NULL;
}
}
static int unpack(scanner_t *s, json_t *root, va_list *ap);
static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
{
int ret = -1;
int strict = 0;
/* Use a set (emulated by a hashtable) to check that all object
keys are accessed. Checking that the correct number of keys
were accessed is not enough, as the same key can be unpacked
multiple times.
*/
hashtable_t key_set;
if(hashtable_init(&key_set)) {
set_error(s, "<internal>", "Out of memory");
return -1;
}
if(root && !json_is_object(root)) {
set_error(s, "<validation>", "Expected object, got %s",
type_name(root));
goto out;
}
next_token(s);
while(token(s) != '}') {
const char *key;
json_t *value;
int opt = 0;
if(strict != 0) {
set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
(strict == 1 ? '!' : '*'), token(s));
goto out;
}
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto out;
}
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(token(s) != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
goto out;
}
key = va_arg(*ap, const char *);
if(!key) {
set_error(s, "<args>", "NULL object key");
goto out;
}
next_token(s);
if(token(s) == '?') {
opt = 1;
next_token(s);
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_object_get(root, key);
if(!value && !opt) {
set_error(s, "<validation>", "Object item not found: %s", key);
goto out;
}
}
if(unpack(s, value, ap))
goto out;
hashtable_set(&key_set, key, 0, json_null());
next_token(s);
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && key_set.size != json_object_size(root)) {
long diff = (long)json_object_size(root) - (long)key_set.size;
set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
goto out;
}
ret = 0;
out:
hashtable_close(&key_set);
return ret;
}
static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
{
size_t i = 0;
int strict = 0;
if(root && !json_is_array(root)) {
set_error(s, "<validation>", "Expected array, got %s", type_name(root));
return -1;
}
next_token(s);
while(token(s) != ']') {
json_t *value;
if(strict != 0) {
set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
(strict == 1 ? '!' : '*'),
token(s));
return -1;
}
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
return -1;
}
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(!strchr(unpack_value_starters, token(s))) {
set_error(s, "<format>", "Unexpected format character '%c'",
token(s));
return -1;
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_array_get(root, i);
if(!value) {
set_error(s, "<validation>", "Array index %lu out of range",
(unsigned long)i);
return -1;
}
}
if(unpack(s, value, ap))
return -1;
next_token(s);
i++;
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && i != json_array_size(root)) {
long diff = (long)json_array_size(root) - (long)i;
set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
return -1;
}
return 0;
}
static int unpack(scanner_t *s, json_t *root, va_list *ap)
{
switch(token(s))
{
case '{':
return unpack_object(s, root, ap);
case '[':
return unpack_array(s, root, ap);
case 's':
if(root && !json_is_string(root)) {
set_error(s, "<validation>", "Expected string, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
const char **target;
target = va_arg(*ap, const char **);
if(!target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
if(root)
*target = json_string_value(root);
}
return 0;
case 'i':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = (int)json_integer_value(root);
}
return 0;
case 'I':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_int_t *target = va_arg(*ap, json_int_t*);
if(root)
*target = json_integer_value(root);
}
return 0;
case 'b':
if(root && !json_is_boolean(root)) {
set_error(s, "<validation>", "Expected true or false, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = json_is_true(root);
}
return 0;
case 'f':
if(root && !json_is_real(root)) {
set_error(s, "<validation>", "Expected real, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_real_value(root);
}
return 0;
case 'F':
if(root && !json_is_number(root)) {
set_error(s, "<validation>", "Expected real or integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_number_value(root);
}
return 0;
case 'O':
if(root && !(s->flags & JSON_VALIDATE_ONLY))
json_incref(root);
/* Fall through */
case 'o':
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_t **target = va_arg(*ap, json_t**);
if(root)
*target = root;
}
return 0;
case 'n':
/* Never assign, just validate */
if(root && !json_is_null(root)) {
set_error(s, "<validation>", "Expected null, got %s",
type_name(root));
return -1;
}
return 0;
default:
set_error(s, "<format>", "Unexpected format character '%c'",
token(s));
return -1;
}
}
json_t *json_vpack_ex(json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
json_t *value;
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
return NULL;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
value = pack(&s, &ap_copy);
va_end(ap_copy);
if(!value)
return NULL;
next_token(&s);
if(token(&s)) {
json_decref(value);
set_error(&s, "<format>", "Garbage after format string");
return NULL;
}
return value;
}
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(error, flags, fmt, ap);
va_end(ap);
return value;
}
json_t *json_pack(const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(NULL, 0, fmt, ap);
va_end(ap);
return value;
}
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
if(!root) {
jsonp_error_init(error, "<root>");
jsonp_error_set(error, -1, -1, 0, "NULL root value");
return -1;
}
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
return -1;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
if(unpack(&s, root, &ap_copy)) {
va_end(ap_copy);
return -1;
}
va_end(ap_copy);
next_token(&s);
if(token(&s)) {
set_error(&s, "<format>", "Garbage after format string");
return -1;
}
return 0;
}
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, error, flags, fmt, ap);
va_end(ap);
return ret;
}
int json_unpack(json_t *root, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
va_end(ap);
return ret;
}

43
compat/jansson/strbuffer.c

@ -1,25 +1,29 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "jansson_private.h"
#include "strbuffer.h" #include "strbuffer.h"
#include "util.h"
#define STRBUFFER_MIN_SIZE 16 #define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2 #define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff) int strbuffer_init(strbuffer_t *strbuff)
{ {
strbuff->size = STRBUFFER_MIN_SIZE; strbuff->size = STRBUFFER_MIN_SIZE;
strbuff->length = 0; strbuff->length = 0;
strbuff->value = malloc(strbuff->size); strbuff->value = jsonp_malloc(strbuff->size);
if(!strbuff->value) if(!strbuff->value)
return -1; return -1;
@ -30,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff)
void strbuffer_close(strbuffer_t *strbuff) void strbuffer_close(strbuffer_t *strbuff)
{ {
free(strbuff->value); if(strbuff->value)
jsonp_free(strbuff->value);
strbuff->size = 0; strbuff->size = 0;
strbuff->length = 0; strbuff->length = 0;
strbuff->value = NULL; strbuff->value = NULL;
@ -50,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff)
char *strbuffer_steal_value(strbuffer_t *strbuff) char *strbuffer_steal_value(strbuffer_t *strbuff)
{ {
char *result = strbuff->value; char *result = strbuff->value;
strbuffer_init(strbuff); strbuff->value = NULL;
return result; return result;
} }
@ -64,16 +70,31 @@ int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
return strbuffer_append_bytes(strbuff, &byte, 1); return strbuffer_append_bytes(strbuff, &byte, 1);
} }
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size) int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{ {
if(strbuff->length + size >= strbuff->size) if(size >= strbuff->size - strbuff->length)
{ {
strbuff->size = max(strbuff->size * STRBUFFER_FACTOR, size_t new_size;
strbuff->length + size + 1); char *new_value;
/* avoid integer overflow */
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
|| size > STRBUFFER_SIZE_MAX - 1
|| strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
return -1;
new_size = max(strbuff->size * STRBUFFER_FACTOR,
strbuff->length + size + 1);
strbuff->value = realloc(strbuff->value, strbuff->size); new_value = jsonp_malloc(new_size);
if(!strbuff->value) if(!new_value)
return -1; return -1;
memcpy(new_value, strbuff->value, strbuff->length);
jsonp_free(strbuff->value);
strbuff->value = new_value;
strbuff->size = new_size;
} }
memcpy(strbuff->value + strbuff->length, data, size); memcpy(strbuff->value + strbuff->length, data, size);

10
compat/jansson/strbuffer.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -10,8 +10,8 @@
typedef struct { typedef struct {
char *value; char *value;
int length; /* bytes used */ size_t length; /* bytes used */
int size; /* bytes allocated */ size_t size; /* bytes allocated */
} strbuffer_t; } strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff); int strbuffer_init(strbuffer_t *strbuff);
@ -20,11 +20,13 @@ void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff);
const char *strbuffer_value(const strbuffer_t *strbuff); const char *strbuffer_value(const strbuffer_t *strbuff);
/* Steal the value and close the strbuffer */
char *strbuffer_steal_value(strbuffer_t *strbuff); char *strbuffer_steal_value(strbuffer_t *strbuff);
int strbuffer_append(strbuffer_t *strbuff, const char *string); int strbuffer_append(strbuffer_t *strbuff, const char *string);
int strbuffer_append_byte(strbuffer_t *strbuff, char byte); int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size); int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff); char strbuffer_pop(strbuffer_t *strbuff);

134
compat/jansson/strconv.c

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

2
compat/jansson/utf.c

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

15
compat/jansson/utf.h

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -8,6 +8,7 @@
#ifndef UTF_H #ifndef UTF_H
#define UTF_H #define UTF_H
#ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#ifdef HAVE_INTTYPES_H #ifdef HAVE_INTTYPES_H
@ -15,7 +16,17 @@
no need to include stdint.h separately. If inttypes.h doesn't define no need to include stdint.h separately. If inttypes.h doesn't define
int32_t, it's defined in config.h. */ int32_t, it's defined in config.h. */
#include <inttypes.h> #include <inttypes.h>
#endif #endif /* HAVE_INTTYPES_H */
#else /* !HAVE_CONFIG_H */
#ifdef _WIN32
typedef int int32_t;
#else /* !_WIN32 */
/* Assume a standard environment */
#include <inttypes.h>
#endif /* _WIN32 */
#endif /* HAVE_CONFIG_H */
int utf8_encode(int codepoint, char *buffer, int *size); int utf8_encode(int codepoint, char *buffer, int *size);

328
compat/jansson/value.c

@ -1,25 +1,33 @@
/* /*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
*/ */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif
#include <config.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h>
#include <jansson.h> #include "jansson.h"
#include "hashtable.h" #include "hashtable.h"
#include "jansson_private.h" #include "jansson_private.h"
#include "utf.h" #include "utf.h"
#include "util.h"
/* Work around nonstandard isnan() and isinf() implementations */
#ifndef isnan
static JSON_INLINE int isnan(double x) { return x != x; }
#endif
#ifndef isinf
static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
static inline void json_init(json_t *json, json_type type) static JSON_INLINE void json_init(json_t *json, json_type type)
{ {
json->type = type; json->type = type;
json->refcount = 1; json->refcount = 1;
@ -28,50 +36,16 @@ static inline void json_init(json_t *json, json_type type)
/*** object ***/ /*** object ***/
/* This macro just returns a pointer that's a few bytes backwards from
string. This makes it possible to pass a pointer to object_key_t
when only the string inside it is used, without actually creating
an object_key_t instance. */
#define string_to_key(string) container_of(string, object_key_t, key)
static unsigned int hash_key(const void *ptr)
{
const char *str = ((const object_key_t *)ptr)->key;
unsigned int hash = 5381;
unsigned int c;
while((c = (unsigned int)*str))
{
hash = ((hash << 5) + hash) + c;
str++;
}
return hash;
}
static int key_equal(const void *ptr1, const void *ptr2)
{
return strcmp(((const object_key_t *)ptr1)->key,
((const object_key_t *)ptr2)->key) == 0;
}
static void value_decref(void *value)
{
json_decref((json_t *)value);
}
json_t *json_object(void) json_t *json_object(void)
{ {
json_object_t *object = malloc(sizeof(json_object_t)); json_object_t *object = jsonp_malloc(sizeof(json_object_t));
if(!object) if(!object)
return NULL; return NULL;
json_init(&object->json, JSON_OBJECT); json_init(&object->json, JSON_OBJECT);
if(hashtable_init(&object->hashtable, hash_key, key_equal, if(hashtable_init(&object->hashtable))
free, value_decref))
{ {
free(object); jsonp_free(object);
return NULL; return NULL;
} }
@ -84,15 +58,15 @@ json_t *json_object(void)
static void json_delete_object(json_object_t *object) static void json_delete_object(json_object_t *object)
{ {
hashtable_close(&object->hashtable); hashtable_close(&object->hashtable);
free(object); jsonp_free(object);
} }
unsigned int json_object_size(const json_t *json) size_t json_object_size(const json_t *json)
{ {
json_object_t *object; json_object_t *object;
if(!json_is_object(json)) if(!json_is_object(json))
return -1; return 0;
object = json_to_object(json); object = json_to_object(json);
return object->hashtable.size; return object->hashtable.size;
@ -106,32 +80,24 @@ json_t *json_object_get(const json_t *json, const char *key)
return NULL; return NULL;
object = json_to_object(json); object = json_to_object(json);
return hashtable_get(&object->hashtable, string_to_key(key)); return hashtable_get(&object->hashtable, key);
} }
int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
{ {
json_object_t *object; json_object_t *object;
object_key_t *k;
if(!key || !value) if(!value)
return -1; return -1;
if(!json_is_object(json) || json == value) if(!key || !json_is_object(json) || json == value)
{ {
json_decref(value); json_decref(value);
return -1; return -1;
} }
object = json_to_object(json); object = json_to_object(json);
k = malloc(sizeof(object_key_t) + strlen(key) + 1); if(hashtable_set(&object->hashtable, key, object->serial++, value))
if(!k)
return -1;
k->serial = object->serial++;
strcpy(k->key, key);
if(hashtable_set(&object->hashtable, k, value))
{ {
json_decref(value); json_decref(value);
return -1; return -1;
@ -159,7 +125,7 @@ int json_object_del(json_t *json, const char *key)
return -1; return -1;
object = json_to_object(json); object = json_to_object(json);
return hashtable_del(&object->hashtable, string_to_key(key)); return hashtable_del(&object->hashtable, key);
} }
int json_object_clear(json_t *json) int json_object_clear(json_t *json)
@ -170,30 +136,56 @@ int json_object_clear(json_t *json)
return -1; return -1;
object = json_to_object(json); object = json_to_object(json);
hashtable_clear(&object->hashtable); hashtable_clear(&object->hashtable);
object->serial = 0;
return 0; return 0;
} }
int json_object_update(json_t *object, json_t *other) int json_object_update(json_t *object, json_t *other)
{ {
void *iter; const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other)) if(!json_is_object(object) || !json_is_object(other))
return -1; return -1;
iter = json_object_iter(other); json_object_foreach(other, key, value) {
while(iter) {
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
if(json_object_set_nocheck(object, key, value)) if(json_object_set_nocheck(object, key, value))
return -1; return -1;
}
return 0;
}
int json_object_update_existing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
json_object_foreach(other, key, value) {
if(json_object_get(object, key))
json_object_set_nocheck(object, key, value);
}
return 0;
}
int json_object_update_missing(json_t *object, json_t *other)
{
const char *key;
json_t *value;
if(!json_is_object(object) || !json_is_object(other))
return -1;
iter = json_object_iter_next(other, iter); json_object_foreach(other, key, value) {
if(!json_object_get(object, key))
json_object_set_nocheck(object, key, value);
} }
return 0; return 0;
@ -218,7 +210,7 @@ void *json_object_iter_at(json_t *json, const char *key)
return NULL; return NULL;
object = json_to_object(json); object = json_to_object(json);
return hashtable_iter_at(&object->hashtable, string_to_key(key)); return hashtable_iter_at(&object->hashtable, key);
} }
void *json_object_iter_next(json_t *json, void *iter) void *json_object_iter_next(json_t *json, void *iter)
@ -232,20 +224,12 @@ void *json_object_iter_next(json_t *json, void *iter)
return hashtable_iter_next(&object->hashtable, iter); return hashtable_iter_next(&object->hashtable, iter);
} }
const object_key_t *jsonp_object_iter_fullkey(void *iter)
{
if(!iter)
return NULL;
return hashtable_iter_key(iter);
}
const char *json_object_iter_key(void *iter) const char *json_object_iter_key(void *iter)
{ {
if(!iter) if(!iter)
return NULL; return NULL;
return jsonp_object_iter_fullkey(iter)->key; return hashtable_iter_key(iter);
} }
json_t *json_object_iter_value(void *iter) json_t *json_object_iter_value(void *iter)
@ -258,38 +242,34 @@ json_t *json_object_iter_value(void *iter)
int json_object_iter_set_new(json_t *json, void *iter, json_t *value) int json_object_iter_set_new(json_t *json, void *iter, json_t *value)
{ {
json_object_t *object;
if(!json_is_object(json) || !iter || !value) if(!json_is_object(json) || !iter || !value)
return -1; return -1;
object = json_to_object(json); hashtable_iter_set(iter, value);
hashtable_iter_set(&object->hashtable, iter, value);
return 0; return 0;
} }
void *json_object_key_to_iter(const char *key)
{
if(!key)
return NULL;
return hashtable_key_to_iter(key);
}
static int json_object_equal(json_t *object1, json_t *object2) static int json_object_equal(json_t *object1, json_t *object2)
{ {
void *iter; const char *key;
json_t *value1, *value2;
if(json_object_size(object1) != json_object_size(object2)) if(json_object_size(object1) != json_object_size(object2))
return 0; return 0;
iter = json_object_iter(object1); json_object_foreach(object1, key, value1) {
while(iter)
{
const char *key;
json_t *value1, *value2;
key = json_object_iter_key(iter);
value1 = json_object_iter_value(iter);
value2 = json_object_get(object2, key); value2 = json_object_get(object2, key);
if(!json_equal(value1, value2)) if(!json_equal(value1, value2))
return 0; return 0;
iter = json_object_iter_next(object1, iter);
} }
return 1; return 1;
@ -298,29 +278,21 @@ static int json_object_equal(json_t *object1, json_t *object2)
static json_t *json_object_copy(json_t *object) static json_t *json_object_copy(json_t *object)
{ {
json_t *result; json_t *result;
void *iter;
const char *key;
json_t *value;
result = json_object(); result = json_object();
if(!result) if(!result)
return NULL; return NULL;
iter = json_object_iter(object); json_object_foreach(object, key, value)
while(iter)
{
const char *key;
json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_set_nocheck(result, key, value); json_object_set_nocheck(result, key, value);
iter = json_object_iter_next(object, iter);
}
return result; return result;
} }
static json_t *json_object_deep_copy(json_t *object) static json_t *json_object_deep_copy(const json_t *object)
{ {
json_t *result; json_t *result;
void *iter; void *iter;
@ -329,17 +301,17 @@ static json_t *json_object_deep_copy(json_t *object)
if(!result) if(!result)
return NULL; return NULL;
iter = json_object_iter(object); /* Cannot use json_object_foreach because object has to be cast
while(iter) non-const */
{ iter = json_object_iter((json_t *)object);
while(iter) {
const char *key; const char *key;
json_t *value; const json_t *value;
key = json_object_iter_key(iter); key = json_object_iter_key(iter);
value = json_object_iter_value(iter); value = json_object_iter_value(iter);
json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next(object, iter); json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next((json_t *)object, iter);
} }
return result; return result;
@ -350,7 +322,7 @@ static json_t *json_object_deep_copy(json_t *object)
json_t *json_array(void) json_t *json_array(void)
{ {
json_array_t *array = malloc(sizeof(json_array_t)); json_array_t *array = jsonp_malloc(sizeof(json_array_t));
if(!array) if(!array)
return NULL; return NULL;
json_init(&array->json, JSON_ARRAY); json_init(&array->json, JSON_ARRAY);
@ -358,9 +330,9 @@ json_t *json_array(void)
array->entries = 0; array->entries = 0;
array->size = 8; array->size = 8;
array->table = malloc(array->size * sizeof(json_t *)); array->table = jsonp_malloc(array->size * sizeof(json_t *));
if(!array->table) { if(!array->table) {
free(array); jsonp_free(array);
return NULL; return NULL;
} }
@ -371,16 +343,16 @@ json_t *json_array(void)
static void json_delete_array(json_array_t *array) static void json_delete_array(json_array_t *array)
{ {
unsigned int i; size_t i;
for(i = 0; i < array->entries; i++) for(i = 0; i < array->entries; i++)
json_decref(array->table[i]); json_decref(array->table[i]);
free(array->table); jsonp_free(array->table);
free(array); jsonp_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)) if(!json_is_array(json))
return 0; return 0;
@ -388,7 +360,7 @@ unsigned int json_array_size(const json_t *json)
return json_to_array(json)->entries; 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; json_array_t *array;
if(!json_is_array(json)) if(!json_is_array(json))
@ -401,7 +373,7 @@ json_t *json_array_get(const json_t *json, unsigned int index)
return array->table[index]; 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; json_array_t *array;
@ -427,24 +399,24 @@ int json_array_set_new(json_t *json, unsigned int index, json_t *value)
return 0; return 0;
} }
static void array_move(json_array_t *array, unsigned int dest, static void array_move(json_array_t *array, size_t dest,
unsigned int src, unsigned int count) size_t src, size_t count)
{ {
memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *));
} }
static void array_copy(json_t **dest, unsigned int dpos, static void array_copy(json_t **dest, size_t dpos,
json_t **src, unsigned int spos, json_t **src, size_t spos,
unsigned int count) size_t count)
{ {
memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *));
} }
static json_t **json_array_grow(json_array_t *array, static json_t **json_array_grow(json_array_t *array,
unsigned int amount, size_t amount,
int copy) int copy)
{ {
unsigned int new_size; size_t new_size;
json_t **old_table, **new_table; json_t **old_table, **new_table;
if(array->entries + amount <= array->size) if(array->entries + amount <= array->size)
@ -453,7 +425,7 @@ static json_t **json_array_grow(json_array_t *array,
old_table = array->table; old_table = array->table;
new_size = max(array->size + amount, array->size * 2); new_size = max(array->size + amount, array->size * 2);
new_table = malloc(new_size * sizeof(json_t *)); new_table = jsonp_malloc(new_size * sizeof(json_t *));
if(!new_table) if(!new_table)
return NULL; return NULL;
@ -462,7 +434,7 @@ static json_t **json_array_grow(json_array_t *array,
if(copy) { if(copy) {
array_copy(array->table, 0, old_table, 0, array->entries); array_copy(array->table, 0, old_table, 0, array->entries);
free(old_table); jsonp_free(old_table);
return array->table; return array->table;
} }
@ -494,7 +466,7 @@ int json_array_append_new(json_t *json, json_t *value)
return 0; 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_array_t *array;
json_t **old_table; json_t **old_table;
@ -523,7 +495,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value)
array_copy(array->table, 0, old_table, 0, index); array_copy(array->table, 0, old_table, 0, index);
array_copy(array->table, index + 1, old_table, index, array_copy(array->table, index + 1, old_table, index,
array->entries - index); array->entries - index);
free(old_table); jsonp_free(old_table);
} }
else else
array_move(array, index + 1, index, array->entries - index); array_move(array, index + 1, index, array->entries - index);
@ -534,7 +506,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value)
return 0; 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; json_array_t *array;
@ -547,7 +519,10 @@ int json_array_remove(json_t *json, unsigned int index)
json_decref(array->table[index]); json_decref(array->table[index]);
array_move(array, index, index + 1, array->entries - index); /* If we're removing the last element, nothing has to be moved */
if(index < array->entries - 1)
array_move(array, index, index + 1, array->entries - index - 1);
array->entries--; array->entries--;
return 0; return 0;
@ -556,7 +531,7 @@ int json_array_remove(json_t *json, unsigned int index)
int json_array_clear(json_t *json) int json_array_clear(json_t *json)
{ {
json_array_t *array; json_array_t *array;
unsigned int i; size_t i;
if(!json_is_array(json)) if(!json_is_array(json))
return -1; return -1;
@ -572,7 +547,7 @@ int json_array_clear(json_t *json)
int json_array_extend(json_t *json, json_t *other_json) int json_array_extend(json_t *json, json_t *other_json)
{ {
json_array_t *array, *other; json_array_t *array, *other;
unsigned int i; size_t i;
if(!json_is_array(json) || !json_is_array(other_json)) if(!json_is_array(json) || !json_is_array(other_json))
return -1; return -1;
@ -593,7 +568,7 @@ int json_array_extend(json_t *json, json_t *other_json)
static int json_array_equal(json_t *array1, json_t *array2) static int json_array_equal(json_t *array1, json_t *array2)
{ {
unsigned int i, size; size_t i, size;
size = json_array_size(array1); size = json_array_size(array1);
if(size != json_array_size(array2)) if(size != json_array_size(array2))
@ -616,7 +591,7 @@ static int json_array_equal(json_t *array1, json_t *array2)
static json_t *json_array_copy(json_t *array) static json_t *json_array_copy(json_t *array)
{ {
json_t *result; json_t *result;
unsigned int i; size_t i;
result = json_array(); result = json_array();
if(!result) if(!result)
@ -628,10 +603,10 @@ static json_t *json_array_copy(json_t *array)
return result; return result;
} }
static json_t *json_array_deep_copy(json_t *array) static json_t *json_array_deep_copy(const json_t *array)
{ {
json_t *result; json_t *result;
unsigned int i; size_t i;
result = json_array(); result = json_array();
if(!result) if(!result)
@ -652,14 +627,14 @@ json_t *json_string_nocheck(const char *value)
if(!value) if(!value)
return NULL; return NULL;
string = malloc(sizeof(json_string_t)); string = jsonp_malloc(sizeof(json_string_t));
if(!string) if(!string)
return NULL; return NULL;
json_init(&string->json, JSON_STRING); json_init(&string->json, JSON_STRING);
string->value = strdup(value); string->value = jsonp_strdup(value);
if(!string->value) { if(!string->value) {
free(string); jsonp_free(string);
return NULL; return NULL;
} }
@ -687,12 +662,15 @@ int json_string_set_nocheck(json_t *json, const char *value)
char *dup; char *dup;
json_string_t *string; json_string_t *string;
dup = strdup(value); if(!json_is_string(json) || !value)
return -1;
dup = jsonp_strdup(value);
if(!dup) if(!dup)
return -1; return -1;
string = json_to_string(json); string = json_to_string(json);
free(string->value); jsonp_free(string->value);
string->value = dup; string->value = dup;
return 0; return 0;
@ -708,8 +686,8 @@ int json_string_set(json_t *json, const char *value)
static void json_delete_string(json_string_t *string) static void json_delete_string(json_string_t *string)
{ {
free(string->value); jsonp_free(string->value);
free(string); jsonp_free(string);
} }
static int json_string_equal(json_t *string1, json_t *string2) static int json_string_equal(json_t *string1, json_t *string2)
@ -717,7 +695,7 @@ static int json_string_equal(json_t *string1, json_t *string2)
return strcmp(json_string_value(string1), json_string_value(string2)) == 0; return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
} }
static json_t *json_string_copy(json_t *string) static json_t *json_string_copy(const json_t *string)
{ {
return json_string_nocheck(json_string_value(string)); return json_string_nocheck(json_string_value(string));
} }
@ -725,9 +703,9 @@ static json_t *json_string_copy(json_t *string)
/*** integer ***/ /*** integer ***/
json_t *json_integer(int value) json_t *json_integer(json_int_t value)
{ {
json_integer_t *integer = malloc(sizeof(json_integer_t)); json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t));
if(!integer) if(!integer)
return NULL; return NULL;
json_init(&integer->json, JSON_INTEGER); json_init(&integer->json, JSON_INTEGER);
@ -736,7 +714,7 @@ json_t *json_integer(int value)
return &integer->json; 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)) if(!json_is_integer(json))
return 0; return 0;
@ -744,7 +722,7 @@ int json_integer_value(const json_t *json)
return json_to_integer(json)->value; 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)) if(!json_is_integer(json))
return -1; return -1;
@ -756,7 +734,7 @@ int json_integer_set(json_t *json, int value)
static void json_delete_integer(json_integer_t *integer) static void json_delete_integer(json_integer_t *integer)
{ {
free(integer); jsonp_free(integer);
} }
static int json_integer_equal(json_t *integer1, json_t *integer2) static int json_integer_equal(json_t *integer1, json_t *integer2)
@ -764,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2)
return json_integer_value(integer1) == json_integer_value(integer2); return json_integer_value(integer1) == json_integer_value(integer2);
} }
static json_t *json_integer_copy(json_t *integer) static json_t *json_integer_copy(const json_t *integer)
{ {
return json_integer(json_integer_value(integer)); return json_integer(json_integer_value(integer));
} }
@ -774,7 +752,12 @@ static json_t *json_integer_copy(json_t *integer)
json_t *json_real(double value) json_t *json_real(double value)
{ {
json_real_t *real = malloc(sizeof(json_real_t)); json_real_t *real;
if(isnan(value) || isinf(value))
return NULL;
real = jsonp_malloc(sizeof(json_real_t));
if(!real) if(!real)
return NULL; return NULL;
json_init(&real->json, JSON_REAL); json_init(&real->json, JSON_REAL);
@ -793,8 +776,8 @@ double json_real_value(const json_t *json)
int json_real_set(json_t *json, double value) int json_real_set(json_t *json, double value)
{ {
if(!json_is_real(json)) if(!json_is_real(json) || isnan(value) || isinf(value))
return 0; return -1;
json_to_real(json)->value = value; json_to_real(json)->value = value;
@ -803,7 +786,7 @@ int json_real_set(json_t *json, double value)
static void json_delete_real(json_real_t *real) static void json_delete_real(json_real_t *real)
{ {
free(real); jsonp_free(real);
} }
static int json_real_equal(json_t *real1, json_t *real2) static int json_real_equal(json_t *real1, json_t *real2)
@ -811,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2)
return json_real_value(real1) == json_real_value(real2); return json_real_value(real1) == json_real_value(real2);
} }
static json_t *json_real_copy(json_t *real) static json_t *json_real_copy(const json_t *real)
{ {
return json_real(json_real_value(real)); return json_real(json_real_value(real));
} }
@ -822,7 +805,7 @@ static json_t *json_real_copy(json_t *real)
double json_number_value(const json_t *json) double json_number_value(const json_t *json)
{ {
if(json_is_integer(json)) if(json_is_integer(json))
return json_integer_value(json); return (double)json_integer_value(json);
else if(json_is_real(json)) else if(json_is_real(json))
return json_real_value(json); return json_real_value(json);
else else
@ -834,30 +817,21 @@ double json_number_value(const json_t *json)
json_t *json_true(void) json_t *json_true(void)
{ {
static json_t the_true = { static json_t the_true = {JSON_TRUE, (size_t)-1};
JSON_TRUE,
(unsigned int)-1
};
return &the_true; return &the_true;
} }
json_t *json_false(void) json_t *json_false(void)
{ {
static json_t the_false = { static json_t the_false = {JSON_FALSE, (size_t)-1};
JSON_FALSE,
(unsigned int)-1
};
return &the_false; return &the_false;
} }
json_t *json_null(void) json_t *json_null(void)
{ {
static json_t the_null = { static json_t the_null = {JSON_NULL, (size_t)-1};
JSON_NULL,
(unsigned int)-1
};
return &the_null; return &the_null;
} }
@ -946,7 +920,7 @@ json_t *json_copy(json_t *json)
return NULL; return NULL;
} }
json_t *json_deep_copy(json_t *json) json_t *json_deep_copy(const json_t *json)
{ {
if(!json) if(!json)
return NULL; return NULL;
@ -970,7 +944,7 @@ json_t *json_deep_copy(json_t *json)
return json_real_copy(json); return json_real_copy(json);
if(json_is_true(json) || json_is_false(json) || json_is_null(json)) if(json_is_true(json) || json_is_false(json) || json_is_null(json))
return json; return (json_t *)json;
return NULL; return NULL;
} }

Loading…
Cancel
Save