aboutsummaryrefslogtreecommitdiff
path: root/src/strconv.c
diff options
context:
space:
mode:
authorPetri Lehtinen <petri@digip.org>2024-03-07 21:02:55 +0200
committerPetri Lehtinen <petri@digip.org>2024-03-08 21:36:21 +0200
commit2d1c13224f757e780763e205e22fdf0517db82d0 (patch)
treec663630339ba20e64c0c21b221e7ee47492cdf7e /src/strconv.c
parent9b9b5e81cf64936207c2081a123fa02dd943916f (diff)
downloadjansson-2d1c13224f757e780763e205e22fdf0517db82d0.zip
jansson-2d1c13224f757e780763e205e22fdf0517db82d0.tar.gz
jansson-2d1c13224f757e780763e205e22fdf0517db82d0.tar.bz2
Use sprintf() to determine locale's decimal point
This should fix thread safety of encoding and decoding, since localeconv() is not tread safe after all.
Diffstat (limited to 'src/strconv.c')
-rw-r--r--src/strconv.c36
1 files changed, 17 insertions, 19 deletions
diff --git a/src/strconv.c b/src/strconv.c
index c6f4fd1..7d317dd 100644
--- a/src/strconv.c
+++ b/src/strconv.c
@@ -11,57 +11,57 @@
#include <jansson_private_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.
+ get_decimal_point() 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 char get_decimal_point() {
+ char buf[3];
+ sprintf(buf, "%#.0f", 1.0); // "1." in the current locale
+ return buf[1];
+}
static void to_locale(strbuffer_t *strbuffer) {
- const char *point;
+ char point;
char *pos;
- point = localeconv()->decimal_point;
- if (*point == '.') {
+ point = get_decimal_point();
+ if (point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if (pos)
- *pos = *point;
+ *pos = point;
}
static void from_locale(char *buffer) {
- const char *point;
+ char point;
char *pos;
- point = localeconv()->decimal_point;
- if (*point == '.') {
+ point = get_decimal_point();
+ if (point == '.') {
/* No conversion needed */
return;
}
- pos = strchr(buffer, *point);
+ 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);
@@ -92,9 +92,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
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 */