diff --git a/spa/include/spa/utils/json.h b/spa/include/spa/utils/json.h index 291b7448d..cfa7fc15f 100644 --- a/spa/include/spa/utils/json.h +++ b/spa/include/spa/utils/json.h @@ -34,6 +34,7 @@ extern "C" { #include #include #include +#include #include @@ -237,9 +238,16 @@ static inline bool spa_json_is_null(const char *val, int len) static inline int spa_json_parse_float(const char *val, int len, float *result) { char *end; - *result = strtof(val, &end); + static locale_t locale = NULL; + if (SPA_UNLIKELY(locale == NULL)) + locale = newlocale(LC_ALL_MASK, "C", NULL); + if (locale != NULL) + *result = strtof_l(val, &end, locale); + else + *result = strtof(val, &end); return len > 0 && end == val + len; } + static inline bool spa_json_is_float(const char *val, int len) { float dummy; @@ -254,6 +262,16 @@ static inline int spa_json_get_float(struct spa_json *iter, float *res) return spa_json_parse_float(value, len, res); } +static inline char *spa_json_format_double(char *str, int size, const double val) +{ + int i, l; + l = snprintf(str, size, "%f", val); + for (i = 0; i < l; i++) + if (str[i] == ',') + str[i] = '.'; + return str; +} + /* int */ static inline int spa_json_parse_int(const char *val, int len, int *result) { diff --git a/src/tools/pw-dump.c b/src/tools/pw-dump.c index 3b283cab5..659361409 100644 --- a/src/tools/pw-dump.c +++ b/src/tools/pw-dump.c @@ -278,13 +278,15 @@ static void put_int(struct data *d, const char *key, int64_t val) static void put_double(struct data *d, const char *key, double val) { - put_fmt(d, key, "%s%f%s", NUMBER, val, NORMAL); + char buf[128]; + put_fmt(d, key, "%s%s%s", NUMBER, + spa_json_format_double(buf, sizeof(buf), val), NORMAL); } static void put_value(struct data *d, const char *key, const char *val) { int64_t li; - double dv; + float fv; if (val == NULL) put_literal(d, key, "null"); @@ -292,8 +294,8 @@ static void put_value(struct data *d, const char *key, const char *val) put_literal(d, key, val); else if (spa_atoi64(val, &li, 10)) put_int(d, key, li); - else if (spa_atod(val, &dv)) - put_double(d, key, dv); + else if (spa_json_parse_float(val, strlen(val), &fv)) + put_double(d, key, fv); else put_string(d, key, val); } diff --git a/test/test-spa-json.c b/test/test-spa-json.c index 877eb78d5..1fd6a83f0 100644 --- a/test/test-spa-json.c +++ b/test/test-spa-json.c @@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include + #include "pwtest.h" #include @@ -225,8 +227,39 @@ PWTEST(json_overflow) PWTEST(json_float) { + struct { + const char *str; + double val; + } val[] = { + { "0.0", 0.0f }, + { ".0", 0.0f }, + { ".0E0", 0.0E0f }, + { "1.0", 1.0f }, + { "1.011", 1.011f }, + { "176543.123456", 176543.123456f }, + { "-176543.123456", -176543.123456f }, + { "-5678.5432E10", -5678.5432E10f }, + { "-5678.5432e10", -5678.5432e10f }, + { "-5678.5432e-10", -5678.5432e-10f }, + { "5678.5432e+10", 5678.5432e+10f }, + { "00.000100", 00.000100f }, + { "-0.000100", -0.000100f }, + }; float v; + unsigned i; + pwtest_int_eq(spa_json_parse_float("", 0, &v), 0); + + setlocale(LC_NUMERIC, "C"); + for (i = 0; i < SPA_N_ELEMENTS(val); i++) { + pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0); + pwtest_double_eq(v, val[i].val); + } + setlocale(LC_NUMERIC, "fr_FR"); + for (i = 0; i < SPA_N_ELEMENTS(val); i++) { + pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0); + pwtest_double_eq(v, val[i].val); + } return PWTEST_PASS; }