Change the underlying type of JSON integer from long to json_int_t
authorPetri Lehtinen <petri@digip.org>
Fri, 13 Aug 2010 19:06:01 +0000 (22:06 +0300)
committerPetri Lehtinen <petri@digip.org>
Fri, 13 Aug 2010 19:07:20 +0000 (22:07 +0300)
json_int_t is typedef'd to long long if it's supported, or long
otherwise. There's also some supporting things, like the
JSON_INTEGER_FORMAT macro that expands to the printf() conversion
specifier that corresponds to json_int_t's actual type.

This is a backwards incompatible change.

17 files changed:
configure.ac
doc/apiref.rst
doc/conformance.rst
src/dump.c
src/jansson.h
src/jansson_config.h.in
src/jansson_private.h
src/load.c
src/value.c
test/suites/invalid-strip/too-big-negative-integer/error
test/suites/invalid-strip/too-big-negative-integer/input
test/suites/invalid-strip/too-big-positive-integer/error
test/suites/invalid-strip/too-big-positive-integer/input
test/suites/invalid/too-big-negative-integer/error
test/suites/invalid/too-big-negative-integer/input
test/suites/invalid/too-big-positive-integer/error
test/suites/invalid/too-big-positive-integer/input

index 0b7e79d..54a307c 100644 (file)
@@ -18,6 +18,13 @@ AC_PROG_LIBTOOL
 # Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_INT32_T
 
+AC_TYPE_LONG_LONG_INT
+case $ac_cv_type_long_long_int in
+     yes) json_have_long_long=1;;
+     *) json_have_long_long=0;;
+esac
+AC_SUBST([json_have_long_long])
+
 AC_C_INLINE
 case $ac_cv_c_inline in
     yes) json_inline=inline;;
index de2bcfe..91de0c8 100644 (file)
@@ -210,10 +210,10 @@ the user to avoid them.
 
 If a circular reference is created, the memory consumed by the values
 cannot be freed by :cfunc:`json_decref()`. The reference counts never
-drops to zero because the values are keeping the circular reference to
-themselves. Moreover, trying to encode the values with any of the
-encoding functions will fail. The encoder detects circular references
-and returns an error status.
+drops to zero because the values are keeping the references to each
+other. Moreover, trying to encode the values with any of the encoding
+functions will fail. The encoder detects circular references and
+returns an error status.
 
 
 True, False and Null
@@ -287,18 +287,45 @@ String
 Number
 ======
 
-.. cfunction:: json_t *json_integer(long value)
+.. ctype:: json_int_t
+
+   This is the C type that is used to store JSON integer values. It
+   represents the widest integer type available on your system. In
+   practice it's just a typedef of ``long long`` if your compiler
+   supports it, otherwise ``long``.
+
+   Usually, you can safely use plain ``int`` in place of
+   ``json_int_t``, and the implicit C integer conversion handles the
+   rest. Only when you know that you need a full 64-bit range, you
+   should use ``json_int_t`` explicitly.
+
+``JSON_INTEGER_FORMAT``
+
+   This is a macro that expands to a :cfunc:`printf()` conversion
+   specifier that corresponds to :ctype:`json_int_t`, without the
+   leading ``%`` sign, i.e. either ``"lld"`` or ``"ld"``. This macro
+   is required because the actual type of :ctype:`json_int_t` can be
+   either ``long`` or ``long long``, and :cfunc:`printf()` reuiqres
+   different length modifiers for the two.
+
+   Example::
+
+       json_int_t x = 123123123;
+       printf("x is %" JSON_INTEGER_FORMAT "\n", x);
+
+
+.. cfunction:: json_t *json_integer(json_int_t value)
 
    .. refcounting:: new
 
    Returns a new JSON integer, or *NULL* on error.
 
-.. cfunction:: long json_integer_value(const json_t *integer)
+.. cfunction:: json_int_t json_integer_value(const json_t *integer)
 
    Returns the associated value of *integer*, or 0 if *json* is not a
    JSON integer.
 
-.. cfunction:: int json_integer_set(const json_t *integer, long value)
+.. cfunction:: int json_integer_set(const json_t *integer, json_int_t value)
 
    Sets the associated value of *integer* to *value*. Returns 0 on
    success and -1 if *integer* is not a JSON integer.
index e2f94b1..1cb6f44 100644 (file)
@@ -36,7 +36,9 @@ Real vs. Integer
 
 JSON makes no distinction between real and integer numbers; Jansson
 does. Real numbers are mapped to the ``double`` type and integers to
-the ``long`` type.
+the ``json_int_t`` type, which is a typedef of ``long long`` or
+``long``, depending on whether ``long long`` is supported by your
+compiler or not.
 
 A JSON number is considered to be a real number if its lexical
 representation includes one of ``e``, ``E``, or ``.``; regardless if
@@ -54,19 +56,19 @@ Overflow, Underflow & Precision
 -------------------------------
 
 Real numbers whose absolute values are too small to be represented in
-a C double will be silently estimated with 0.0. Thus, depending on
+a C ``double`` will be silently estimated with 0.0. Thus, depending on
 platform, JSON numbers very close to zero such as 1E-999 may result in
 0.0.
 
 Real numbers whose absolute values are too large to be represented in
-a C ``double`` type will result in an overflow error (a JSON decoding
+a C ``double`` will result in an overflow error (a JSON decoding
 error). Thus, depending on platform, JSON numbers like 1E+999 or
 -1E+999 may result in a parsing error.
 
 Likewise, integer numbers whose absolute values are too large to be
-represented in the ``long`` type will result in an overflow error (a
-JSON decoding error). Thus, depending on platform, JSON numbers like
-1000000000000000 may result in parsing error.
+represented in the ``json_int_t`` type (see above) will result in an
+overflow error (a JSON decoding error). Thus, depending on platform,
+JSON numbers like 1000000000000000 may result in parsing error.
 
 Parsing JSON real numbers may result in a loss of precision. As long
 as overflow does not occur (i.e. a total loss of precision), the
@@ -94,9 +96,9 @@ Types
 -----
 
 No support is provided in Jansson for any C numeric types other than
-``long`` and ``double``. This excludes things such as unsigned types,
-``long long``, ``long double``, etc. Obviously, shorter types like
-``short``, ``int`` and ``float`` are implicitly handled via the
-ordinary C type coercion rules (subject to overflow semantics). Also,
-no support or hooks are provided for any supplemental "bignum" type
-add-on packages.
+``json_int_t`` and ``double``. This excludes things such as unsigned
+types, ``long double``, etc. Obviously, shorter types like ``short``,
+``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float``
+are implicitly handled via the ordinary C type coercion rules (subject
+to overflow semantics). Also, no support or hooks are provided for any
+supplemental "bignum" type add-on packages.
index c55d332..b887515 100644 (file)
@@ -185,7 +185,9 @@ static int do_dump(const json_t *json, size_t flags, int depth,
             char buffer[MAX_INTEGER_STR_LENGTH];
             int size;
 
-            size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%li", json_integer_value(json));
+            size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
+                            "%" JSON_INTEGER_FORMAT,
+                            json_integer_value(json));
             if(size >= MAX_INTEGER_STR_LENGTH)
                 return -1;
 
index 81235ff..5324e57 100644 (file)
@@ -34,6 +34,14 @@ typedef struct {
     size_t refcount;
 } json_t;
 
+#if JSON_INTEGER_IS_LONG_LONG
+#define JSON_INTEGER_FORMAT "lld"
+typedef long long json_int_t;
+#else
+#define JSON_INTEGER_FORMAT "ld"
+typedef long json_int_t;
+#endif /* JSON_INTEGER_IS_LONG_LONG */
+
 #define json_typeof(json)      ((json)->type)
 #define json_is_object(json)   (json && json_typeof(json) == JSON_OBJECT)
 #define json_is_array(json)    (json && json_typeof(json) == JSON_ARRAY)
@@ -52,7 +60,7 @@ json_t *json_object(void);
 json_t *json_array(void);
 json_t *json_string(const char *value);
 json_t *json_string_nocheck(const char *value);
-json_t *json_integer(long value);
+json_t *json_integer(json_int_t value);
 json_t *json_real(double value);
 json_t *json_true(void);
 json_t *json_false(void);
@@ -139,13 +147,13 @@ int json_array_insert(json_t *array, size_t index, json_t *value)
 }
 
 const char *json_string_value(const json_t *string);
-long json_integer_value(const json_t *integer);
+json_int_t json_integer_value(const json_t *integer);
 double json_real_value(const json_t *real);
 double json_number_value(const json_t *json);
 
 int json_string_set(json_t *string, const char *value);
 int json_string_set_nocheck(json_t *string, const char *value);
-int json_integer_set(json_t *integer, long value);
+int json_integer_set(json_t *integer, json_int_t value);
 int json_real_set(json_t *real, double value);
 
 
index 1a9d859..d55d992 100644 (file)
@@ -3,6 +3,18 @@
  *
  * 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 copy the file and do the
+ * value substitution by hand.
+ *
+ * See below for explanations of each substitution variable.
  */
 
 #ifndef JANSSON_CONFIG_H
 #ifdef __cplusplus
 #define JSON_INLINE inline
 #else
+/* If your compiler supports the inline keyword, @json_inline@ is
+   replaced with `inline', otherwise empty. */
 #define JSON_INLINE @json_inline@
 #endif
 
+/* If your compiler supports the `long long` type,
+   @json_have_long_long@ is replaced with 1, otherwise with 0. */
+#if @json_have_long_long@
+#define JSON_INTEGER_IS_LONG_LONG 1
+#else
+#define JSON_INTEGER_IS_LONG 1
+#endif
+
 #endif
index a04b6f2..bd80346 100644 (file)
@@ -41,7 +41,7 @@ typedef struct {
 
 typedef struct {
     json_t json;
-    long value;
+    json_int_t value;
 } json_integer_t;
 
 #define json_to_object(json_)  container_of(json_, json_object_t, json)
index f86d2b5..2a360ff 100644 (file)
@@ -52,7 +52,7 @@ typedef struct {
     int line, column;
     union {
         char *string;
-        long integer;
+        json_int_t integer;
         double real;
     } value;
 } lex_t;
@@ -401,6 +401,12 @@ out:
     free(lex->value.string);
 }
 
+#ifdef JSON_INTEGER_IS_LONG_LONG
+#define json_strtoint     strtoll
+#else
+#define json_strtoint     strtol
+#endif
+
 static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
 {
     const char *saved_text;
@@ -430,23 +436,24 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error)
     }
 
     if(c != '.' && c != 'E' && c != 'e') {
-        long value;
+        json_int_t value;
 
         lex_unget_unsave(lex, c);
 
         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) {
-            error_set(error, lex, "too big integer");
-            goto out;
-        }
-        else if(value == LONG_MIN && errno == ERANGE) {
-            error_set(error, lex, "too big negative integer");
+        errno = 0;
+        value = json_strtoint(saved_text, &end, 10);
+        if(errno == ERANGE) {
+            if(value < 0)
+                error_set(error, lex, "too big negative integer");
+            else
+                error_set(error, lex, "too big integer");
             goto out;
         }
 
+        assert(end == saved_text + lex->saved_text.length);
+
         lex->token = TOKEN_INTEGER;
         lex->value.integer = value;
         return 0;
index 9310ea5..0f2ae65 100644 (file)
@@ -725,7 +725,7 @@ static json_t *json_string_copy(json_t *string)
 
 /*** integer ***/
 
-json_t *json_integer(long value)
+json_t *json_integer(json_int_t value)
 {
     json_integer_t *integer = malloc(sizeof(json_integer_t));
     if(!integer)
@@ -736,7 +736,7 @@ json_t *json_integer(long value)
     return &integer->json;
 }
 
-long json_integer_value(const json_t *json)
+json_int_t json_integer_value(const json_t *json)
 {
     if(!json_is_integer(json))
         return 0;
@@ -744,7 +744,7 @@ long json_integer_value(const json_t *json)
     return json_to_integer(json)->value;
 }
 
-int json_integer_set(json_t *json, long value)
+int json_integer_set(json_t *json, json_int_t value)
 {
     if(!json_is_integer(json))
         return -1;
index f2366dc..dfa3846 100644 (file)
@@ -1 +1 @@
-[-123123123123123]
\ No newline at end of file
+[-123123123123123123123123123123]
\ No newline at end of file
index a787c2c..3156f10 100644 (file)
@@ -1 +1 @@
-[123123123123123]
\ No newline at end of file
+[123123123123123123123123123123]
\ No newline at end of file