summaryrefslogtreecommitdiff
path: root/json_object.c
diff options
context:
space:
mode:
authorEric Haszlakiewicz <erh+git@nimenees.com>2017-06-18 18:04:49 +0000
committerEric Haszlakiewicz <erh+git@nimenees.com>2017-06-18 18:12:07 +0000
commit1a94c70336ac355aaf9c9f34bdc1f8fcbb64018d (patch)
tree9c6f23e311a2bb1f41fb3c8d1f67ecdb340ca397 /json_object.c
parent85818065583555df66b22428cf372f2c6ac0fde4 (diff)
downloadjson-c-1a94c70336ac355aaf9c9f34bdc1f8fcbb64018d.tar.gz
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.
Diffstat (limited to 'json_object.c')
-rw-r--r--json_object.c85
1 files changed, 76 insertions, 9 deletions
diff --git a/json_object.c b/json_object.c
index 57342b0..42bb738 100644
--- a/json_object.c
+++ b/json_object.c
@@ -692,6 +692,50 @@ int json_object_set_int64(struct json_object *jso,int64_t new_value){
/* 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,
struct printbuf *pb,
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");
else
size = snprintf(buf, sizeof(buf), "-Infinity");
- else
- size = snprintf(buf, sizeof(buf),
- format ? format :
- (modf(jso->o.c_double, &dummy) == 0) ? "%.17g.0" : "%.17g",
- jso->o.c_double);
- if(size < 0 || size >= (int)sizeof(buf))
- size = (int)sizeof(buf);
+ else
+ {
+ const char *std_format = "%.17g";
+
+#ifdef HAVE___THREAD
+ if (tls_serialization_float_format)
+ 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, ',');
if (p) {
@@ -736,8 +798,13 @@ static int json_object_double_to_json_string_format(struct json_object* jso,
*(++p) = 0;
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,