summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2023-10-09 15:21:05 +0200
committerJo-Philipp Wich <jo@mein.io>2023-10-09 15:35:16 +0200
commit7c209d736907e18ec8d79a57328c1e3bad7b2786 (patch)
treeaaf07f36605e17d8a23f7e09806716cce90ff146
parent9f9959cb23bbec0c57e12029c2b6d10dd53b28dc (diff)
types: ensure double serializatiion with decimal places
The `%g` printf format used for serializing double values into strings will not include any decimal place if the value happens to be integral, leading to an unwanted double to integer conversion when serializing and subsequently deserializing an integral double value as JSON. Solve this issue by checking the serialized string result for a decimal point or exponential notation and appending `.0` if neither is found. Ref: #173 Suggested-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--tests/custom/99_bugs/43_types_json_double_format24
-rw-r--r--types.c17
2 files changed, 40 insertions, 1 deletions
diff --git a/tests/custom/99_bugs/43_types_json_double_format b/tests/custom/99_bugs/43_types_json_double_format
new file mode 100644
index 0000000..9b90e37
--- /dev/null
+++ b/tests/custom/99_bugs/43_types_json_double_format
@@ -0,0 +1,24 @@
+When formatting integral double values as JSON, ensure that at least one
+decimal place is retained.
+
+-- Testcase --
+printf("%.J\n", [
+ 1e100,
+ 1.23,
+ 4.00,
+ 1.0/3*3,
+]);
+-- End --
+
+-- Args --
+-R
+-- End --
+
+-- Expect stdout --
+[
+ 1e+100,
+ 1.23,
+ 4.0,
+ 1.0
+]
+-- End --
diff --git a/types.c b/types.c
index c9472f7..eeac8c7 100644
--- a/types.c
+++ b/types.c
@@ -1561,6 +1561,21 @@ ucv_to_stringbuf_add_padding(uc_stringbuf_t *pb, char pad_char, size_t pad_size)
}
}
+static void
+ucv_to_stringbuf_add_double(uc_stringbuf_t *pb, double val, bool json)
+{
+ int len = ucv_stringbuf_printf(pb, "%.14g", val);
+
+ if (!json)
+ return;
+
+ for (char *p = pb->buf + pb->bpos - len; len > 0; len--, p++)
+ if (*p == '.' || *p == 'e')
+ return;
+
+ ucv_stringbuf_append(pb, ".0");
+}
+
void
ucv_to_stringbuf_formatted(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, size_t depth, char pad_char, size_t pad_size)
{
@@ -1624,7 +1639,7 @@ ucv_to_stringbuf_formatted(uc_vm_t *vm, uc_stringbuf_t *pb, uc_value_t *uv, size
else if (d == -INFINITY)
ucv_stringbuf_append(pb, "-Infinity");
else
- ucv_stringbuf_printf(pb, "%.14g", d);
+ ucv_to_stringbuf_add_double(pb, d, json);
break;