From d6020d7ab28de5d5c6ad3e8db948d6366fb758b3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 24 Nov 2016 10:51:26 +1000 Subject: [PATCH] util: add safe_atod for locale-independent conversion Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/libinput-util.c | 15 ++------------ src/libinput-util.h | 29 ++++++++++++++++++++++++++ test/misc.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/libinput-util.c b/src/libinput-util.c index 6c051c38..4cf310b3 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -248,21 +248,10 @@ parse_mouse_wheel_click_angle_property(const char *prop) double parse_trackpoint_accel_property(const char *prop) { - locale_t c_locale; double accel; - char *endp; - /* Create a "C" locale to force strtod to use '.' as separator */ - c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); - if (c_locale == (locale_t)0) - return 0.0; - - accel = strtod_l(prop, &endp, c_locale); - - freelocale(c_locale); - - if (*endp != '\0') - return 0.0; + if (!safe_atod(prop, &accel)) + accel = 0.0; return accel; } diff --git a/src/libinput-util.h b/src/libinput-util.h index a42643d3..9b10e7dc 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -427,4 +428,32 @@ safe_atoi(const char *str, int *val) return true; } +static inline bool +safe_atod(const char *str, double *val) +{ + char *endptr; + double v; + locale_t c_locale; + + /* Create a "C" locale to force strtod to use '.' as separator */ + c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); + if (c_locale == (locale_t)0) + return false; + + errno = 0; + v = strtod_l(str, &endptr, c_locale); + freelocale(c_locale); + if (errno > 0) + return false; + if (str == endptr) + return false; + if (*str != '\0' && *endptr != '\0') + return false; + if (isnan(v) || isinf(v)) + return false; + + *val = v; + return true; +} + #endif /* LIBINPUT_UTIL_H */ diff --git a/test/misc.c b/test/misc.c index 95776f7b..b514f90b 100644 --- a/test/misc.c +++ b/test/misc.c @@ -902,6 +902,55 @@ START_TEST(safe_atoi_test) } END_TEST +struct atod_test { + char *str; + bool success; + double val; +}; + +START_TEST(safe_atod_test) +{ + struct atod_test tests[] = { + { "10", true, 10 }, + { "20", true, 20 }, + { "-1", true, -1 }, + { "2147483647", true, 2147483647 }, + { "-2147483648", true, -2147483648 }, + { "4294967295", true, 4294967295 }, + { "0x0", true, 0 }, + { "0x10", true, 0x10 }, + { "0xaf", true, 0xaf }, + { "x80", false, 0 }, + { "0.0", true, 0.0 }, + { "0.1", true, 0.1 }, + { "1.2", true, 1.2 }, + { "-324.9", true, -324.9 }, + { "9324.9", true, 9324.9 }, + { "NAN", false, 0 }, + { "INFINITY", false, 0 }, + { "-10x10", false, 0 }, + { "1x-99", false, 0 }, + { "", false, 0 }, + { "abd", false, 0 }, + { "xabd", false, 0 }, + { "0x0x", false, 0 }, + { NULL, false, 0 } + }; + double v; + bool success; + + for (int i = 0; tests[i].str != NULL; i++) { + v = 0xad; + success = safe_atod(tests[i].str, &v); + ck_assert(success == tests[i].success); + if (success) + ck_assert_int_eq(v, tests[i].val); + else + ck_assert_int_eq(v, 0xad); + } +} +END_TEST + static int open_restricted_leak(const char *path, int flags, void *data) { return *(int*)data; @@ -1030,6 +1079,7 @@ litest_setup_tests_misc(void) litest_add_no_device("misc:parser", trackpoint_accel_parser); litest_add_no_device("misc:parser", dimension_prop_parser); litest_add_no_device("misc:parser", safe_atoi_test); + litest_add_no_device("misc:parser", safe_atod_test); litest_add_no_device("misc:time", time_conversion); litest_add_no_device("misc:fd", fd_no_event_leak);