mirror of
https://github.com/json-c/json-c.git
synced 2026-03-21 05:59:07 +08:00
Add a json_c_set_serialization_double_format() function to set the *library-wide* format for how doubles are written to a serialized JSON output.
This commit is contained in:
12
configure.ac
12
configure.ac
@@ -41,6 +41,18 @@ AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public defin
|
|||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([for __thread support], ac_cv___thread, [dnl
|
||||||
|
AC_LINK_IFELSE([dnl
|
||||||
|
AC_LANG_PROGRAM([[#undef __thread
|
||||||
|
static __thread int a; int foo (int b) { return a + b; }]],
|
||||||
|
[[exit (foo (0));]])],
|
||||||
|
ac_cv___thread=yes, ac_cv___thread=no)
|
||||||
|
])
|
||||||
|
AS_IF([test "x$ac_cv___thread" != xno],
|
||||||
|
[AC_DEFINE(HAVE___THREAD, 1, [Have __thread]),
|
||||||
|
AC_DEFINE(SPEC___THREAD, [__thread], [Specifier for __thread])]
|
||||||
|
)
|
||||||
|
|
||||||
# Checks for library functions.
|
# Checks for library functions.
|
||||||
AC_FUNC_VPRINTF
|
AC_FUNC_VPRINTF
|
||||||
AC_FUNC_MEMCMP
|
AC_FUNC_MEMCMP
|
||||||
|
|||||||
@@ -692,6 +692,50 @@ int json_object_set_int64(struct json_object *jso,int64_t new_value){
|
|||||||
|
|
||||||
/* json_object_double */
|
/* json_object_double */
|
||||||
|
|
||||||
|
#ifdef HAVE___THREAD
|
||||||
|
// i.e. __thread or __declspec(thread)
|
||||||
|
static SPEC___THREAD char *tls_serialization_float_format = NULL;
|
||||||
|
#endif
|
||||||
|
static char *global_serialization_float_format = NULL;
|
||||||
|
|
||||||
|
int json_c_set_serialization_double_format(const char *double_format, int global_or_thread)
|
||||||
|
{
|
||||||
|
if (global_or_thread == JSON_C_OPTION_GLOBAL)
|
||||||
|
{
|
||||||
|
#ifdef HAVE___THREAD
|
||||||
|
if (tls_serialization_float_format)
|
||||||
|
{
|
||||||
|
free(tls_serialization_float_format);
|
||||||
|
tls_serialization_float_format = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (global_serialization_float_format)
|
||||||
|
free(global_serialization_float_format);
|
||||||
|
global_serialization_float_format = double_format ? strdup(double_format) : NULL;
|
||||||
|
}
|
||||||
|
else if (global_or_thread == JSON_C_OPTION_THREAD)
|
||||||
|
{
|
||||||
|
#ifdef HAVE___THREAD
|
||||||
|
if (tls_serialization_float_format)
|
||||||
|
{
|
||||||
|
free(tls_serialization_float_format);
|
||||||
|
tls_serialization_float_format = NULL;
|
||||||
|
}
|
||||||
|
tls_serialization_float_format = double_format ? strdup(double_format) : NULL;
|
||||||
|
#else
|
||||||
|
_set_last_err("json_c_set_option: not compiled with __thread support\n");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_set_last_err("json_c_set_option: invalid global_or_thread value: %d\n", global_or_thread);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int json_object_double_to_json_string_format(struct json_object* jso,
|
static int json_object_double_to_json_string_format(struct json_object* jso,
|
||||||
struct printbuf *pb,
|
struct printbuf *pb,
|
||||||
int level,
|
int level,
|
||||||
@@ -712,13 +756,31 @@ static int json_object_double_to_json_string_format(struct json_object* jso,
|
|||||||
size = snprintf(buf, sizeof(buf), "Infinity");
|
size = snprintf(buf, sizeof(buf), "Infinity");
|
||||||
else
|
else
|
||||||
size = snprintf(buf, sizeof(buf), "-Infinity");
|
size = snprintf(buf, sizeof(buf), "-Infinity");
|
||||||
else
|
else
|
||||||
size = snprintf(buf, sizeof(buf),
|
{
|
||||||
format ? format :
|
const char *std_format = "%.17g";
|
||||||
(modf(jso->o.c_double, &dummy) == 0) ? "%.17g.0" : "%.17g",
|
|
||||||
jso->o.c_double);
|
#ifdef HAVE___THREAD
|
||||||
if(size < 0 || size >= (int)sizeof(buf))
|
if (tls_serialization_float_format)
|
||||||
size = (int)sizeof(buf);
|
std_format = tls_serialization_float_format;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (global_serialization_float_format)
|
||||||
|
std_format = global_serialization_float_format;
|
||||||
|
if (!format)
|
||||||
|
format = std_format;
|
||||||
|
size = snprintf(buf, sizeof(buf), format, jso->o.c_double);
|
||||||
|
if (modf(jso->o.c_double, &dummy) == 0)
|
||||||
|
{
|
||||||
|
// Ensure it looks like a float, even if snprintf didn't.
|
||||||
|
strncat(buf, ".0", sizeof(buf) - 1);
|
||||||
|
if (size >= 0)
|
||||||
|
size += 2; // yes, even if strncat ran out of room
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// although unlikely, snprintf can fail
|
||||||
|
if (size < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
p = strchr(buf, ',');
|
p = strchr(buf, ',');
|
||||||
if (p) {
|
if (p) {
|
||||||
@@ -736,8 +798,13 @@ static int json_object_double_to_json_string_format(struct json_object* jso,
|
|||||||
*(++p) = 0;
|
*(++p) = 0;
|
||||||
size = p-buf;
|
size = p-buf;
|
||||||
}
|
}
|
||||||
printbuf_memappend(pb, buf, size);
|
|
||||||
return size;
|
if (size >= (int)sizeof(buf))
|
||||||
|
// The standard formats are guaranteed not to overrun the buffer,
|
||||||
|
// but if a custom one happens to do so, just silently truncate.
|
||||||
|
size = sizeof(buf) - 1;
|
||||||
|
printbuf_memappend(pb, buf, size);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int json_object_double_to_json_string_default(struct json_object* jso,
|
static int json_object_double_to_json_string_default(struct json_object* jso,
|
||||||
|
|||||||
@@ -105,6 +105,22 @@ extern "C" {
|
|||||||
#undef TRUE
|
#undef TRUE
|
||||||
#define TRUE ((json_bool)1)
|
#define TRUE ((json_bool)1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the global value of an option, which will apply to all
|
||||||
|
* current and future threads that have not set a thread-local value.
|
||||||
|
*
|
||||||
|
* @see json_c_set_serialization_double_format
|
||||||
|
*/
|
||||||
|
#define JSON_C_OPTION_GLOBAL (0)
|
||||||
|
/**
|
||||||
|
* Set a thread-local value of an option, overriding the global value.
|
||||||
|
* This will fail if json-c is not compiled with threading enabled, and
|
||||||
|
* with the __thread specifier (or equivalent) available.
|
||||||
|
*
|
||||||
|
* @see json_c_set_serialization_double_format
|
||||||
|
*/
|
||||||
|
#define JSON_C_OPTION_THREAD (1)
|
||||||
|
|
||||||
extern const char *json_number_chars;
|
extern const char *json_number_chars;
|
||||||
extern const char *json_hex_chars;
|
extern const char *json_hex_chars;
|
||||||
|
|
||||||
@@ -748,6 +764,21 @@ extern struct json_object* json_object_new_double(double d);
|
|||||||
*/
|
*/
|
||||||
extern struct json_object* json_object_new_double_s(double d, const char *ds);
|
extern struct json_object* json_object_new_double_s(double d, const char *ds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a global or thread-local json-c option, depending on whether
|
||||||
|
* JSON_C_OPTION_GLOBAL or JSON_C_OPTION_THREAD is passed.
|
||||||
|
* Thread-local options default to undefined, and inherit from the global
|
||||||
|
* value, even if the global value is changed after the thread is created.
|
||||||
|
* Attempting to set thread-local options when threading is not compiled in
|
||||||
|
* will result in an error. Be sure to check the return value.
|
||||||
|
*
|
||||||
|
* double_format is a "%g" printf format, such as "%.20g"
|
||||||
|
*
|
||||||
|
* @return -1 on errors, 0 on success.
|
||||||
|
*/
|
||||||
|
int json_c_set_serialization_double_format(const char *double_format, int global_or_thread);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Serialize a json_object of type json_type_double to a string.
|
/** Serialize a json_object of type json_type_double to a string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,5 +27,31 @@ int main()
|
|||||||
json_object_set_serializer(obj, NULL, NULL, NULL);
|
json_object_set_serializer(obj, NULL, NULL, NULL);
|
||||||
printf("obj.to_string(reset)=%s\n", json_object_to_json_string(obj));
|
printf("obj.to_string(reset)=%s\n", json_object_to_json_string(obj));
|
||||||
|
|
||||||
|
json_object_put(obj);
|
||||||
|
obj = json_object_new_double(0.52381);
|
||||||
|
|
||||||
|
printf("obj.to_string(default format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
if (json_c_set_serialization_double_format("x%0.3fy", JSON_C_OPTION_GLOBAL) < 0)
|
||||||
|
printf("ERROR: json_c_set_serialization_double_format() failed");
|
||||||
|
printf("obj.to_string(with global format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
#ifdef HAVE___THREAD
|
||||||
|
if (json_c_set_serialization_double_format("T%0.2fX", JSON_C_OPTION_THREAD) < 0)
|
||||||
|
printf("ERROR: json_c_set_serialization_double_format() failed");
|
||||||
|
printf("obj.to_string(with thread format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
if (json_c_set_serialization_double_format("Ttttttttttttt%0.2fxxxxxxxxxxxxxxxxxxX", JSON_C_OPTION_THREAD) < 0)
|
||||||
|
printf("ERROR: json_c_set_serialization_double_format() failed");
|
||||||
|
printf("obj.to_string(long thread format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
if (json_c_set_serialization_double_format(NULL, JSON_C_OPTION_THREAD) < 0)
|
||||||
|
printf("ERROR: json_c_set_serialization_double_format() failed");
|
||||||
|
printf("obj.to_string(back to global format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
#else
|
||||||
|
// Just fake it up, so the output matches.
|
||||||
|
printf("obj.to_string(with thread format)=%s\n", "T0.52X");
|
||||||
|
printf("obj.to_string(back to global format)=%s\n", "x0.524y");
|
||||||
|
#endif
|
||||||
|
if (json_c_set_serialization_double_format(NULL, JSON_C_OPTION_GLOBAL) < 0)
|
||||||
|
printf("ERROR: json_c_set_serialization_double_format() failed");
|
||||||
|
printf("obj.to_string(back to default format)=%s\n", json_object_to_json_string(obj));
|
||||||
|
|
||||||
json_object_put(obj);
|
json_object_put(obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ Test explicit serializer with custom userdata:
|
|||||||
obj.to_string(custom)=test
|
obj.to_string(custom)=test
|
||||||
Test reset serializer:
|
Test reset serializer:
|
||||||
obj.to_string(reset)=0.5
|
obj.to_string(reset)=0.5
|
||||||
|
obj.to_string(default format)=0.52381
|
||||||
|
obj.to_string(with global format)=x0.524y
|
||||||
|
obj.to_string(with thread format)=T0.52X
|
||||||
|
|||||||
Reference in New Issue
Block a user