[PATCH libinput 5/7] util: add safe_atod for locale-independent conversion

Peter Hutterer peter.hutterer at who-t.net
Mon Nov 28 05:20:48 UTC 2016


Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 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 6c051c3..4cf310b 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 a42643d..9b10e7d 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -30,6 +30,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
+#include <locale.h>
 #include <math.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -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 95776f7..b514f90 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);
-- 
2.9.3



More information about the wayland-devel mailing list