]> git.mdlowis.com Git - proto/labwc.git/commitdiff
common: validate and properly parse floats
authorAndrew J. Hesford <ajh@sideband.org>
Thu, 28 Mar 2024 02:13:50 +0000 (22:13 -0400)
committerAndrew J. Hesford <ajh@sideband.org>
Tue, 2 Apr 2024 14:37:50 +0000 (10:37 -0400)
Fixes: #1665.
include/common/parse-double.h [new file with mode: 0644]
src/common/meson.build
src/common/parse-double.c [new file with mode: 0644]
src/config/rcxml.c
src/config/tablet.c

diff --git a/include/common/parse-double.h b/include/common/parse-double.h
new file mode 100644 (file)
index 0000000..8649988
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_PARSE_DOUBLE_H
+#define LABWC_PARSE_DOUBLE_H
+#include <assert.h>
+#include <stdbool.h>
+
+/**
+ * set_double() - Parse double-precision value of string.
+ * @str: String to parse
+ * @val: Storage for parsed value
+ *
+ * Return: true if string was parsed, false if not
+ *
+ * NOTE: If this function returns false, the value at *val will be untouched.
+ */
+bool set_double(const char *str, double *val);
+
+static inline bool
+set_float(const char *str, float *val)
+{
+       assert(val);
+
+       double d;
+       if (set_double(str, &d)) {
+               *val = d;
+               return true;
+       }
+
+       return false;
+}
+
+#endif /* LABWC_PARSE_DOUBLE_H */
index 6a90f9b321df351497067052e2b751f20c213d2d..250ca34744100c9dcd1737f3333313812f97692a 100644 (file)
@@ -10,6 +10,7 @@ labwc_sources += files(
   'mem.c',
   'nodename.c',
   'parse-bool.c',
+  'parse-double.c',
   'scaled_font_buffer.c',
   'scaled_scene_buffer.c',
   'scene-helpers.c',
diff --git a/src/common/parse-double.c b/src/common/parse-double.c
new file mode 100644 (file)
index 0000000..db440d0
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wlr/util/log.h>
+#include "common/mem.h"
+#include "common/parse-double.h"
+
+struct dec_separator {
+       int index;
+       bool multiple;
+};
+
+struct converted_double {
+       double value;
+       bool valid;
+};
+
+static struct dec_separator
+find_dec_separator(const char *str)
+{
+       struct dec_separator loc = {
+               .index = -1,
+               .multiple = false
+       };
+
+       for (int i = 0; *str; i++, str++) {
+               switch (*str) {
+               case ',':
+               case '.':
+                       if (loc.index >= 0) {
+                               loc.multiple = true;
+                               return loc;
+                       } else {
+                               loc.index = i;
+                       }
+                       break;
+               }
+       }
+
+       return loc;
+}
+
+static struct converted_double
+convert_double(const char *str)
+{
+       struct converted_double result = {
+               .value = 0,
+               .valid = true,
+       };
+
+       char *eptr = NULL;
+
+       errno = 0;
+       result.value = strtod(str, &eptr);
+
+       if (errno) {
+               wlr_log(WLR_ERROR, "value '%s' is out of range", str);
+               result.valid = false;
+       }
+
+       if (*eptr) {
+               wlr_log(WLR_ERROR, "value '%s' contains trailing garbage", str);
+               result.valid = false;
+       }
+
+       return result;
+}
+
+bool
+set_double(const char *str, double *val)
+{
+       assert(str);
+       assert(val);
+
+       struct dec_separator dloc = find_dec_separator(str);
+       if (dloc.multiple) {
+               wlr_log(WLR_ERROR,
+                       "value '%s' contains multiple decimal markers", str);
+               return false;
+       }
+
+       char *lstr = NULL;
+
+       if (dloc.index >= 0) {
+               lstr = xstrdup(str);
+               struct lconv *lc = localeconv();
+               lstr[dloc.index] = *lc->decimal_point;
+               str = lstr;
+       }
+
+       struct converted_double conv = convert_double(str);
+       if (conv.valid) {
+               *val = conv.value;
+       }
+
+       free(lstr);
+       return conv.valid;
+}
index 994498c3f2d7225ae3c06a598465ac1c342419c7..62afdc6c091e33bc00dffff0650e5d6deea2b935 100644 (file)
@@ -21,6 +21,7 @@
 #include "common/mem.h"
 #include "common/nodename.h"
 #include "common/parse-bool.h"
+#include "common/parse-double.h"
 #include "common/string-helpers.h"
 #include "config/default-bindings.h"
 #include "config/keybind.h"
@@ -537,7 +538,7 @@ fill_libinput_category(char *nodename, char *content)
        } else if (!strcasecmp(nodename, "leftHanded")) {
                set_bool_as_int(content, &current_libinput_category->left_handed);
        } else if (!strcasecmp(nodename, "pointerSpeed")) {
-               current_libinput_category->pointer_speed = atof(content);
+               set_float(content, &current_libinput_category->pointer_speed);
                if (current_libinput_category->pointer_speed < -1) {
                        current_libinput_category->pointer_speed = -1;
                } else if (current_libinput_category->pointer_speed > 1) {
@@ -883,7 +884,7 @@ entry(xmlNode *node, char *nodename, char *content)
                        wlr_log(WLR_ERROR, "invalid doubleClickTime");
                }
        } else if (!strcasecmp(nodename, "scrollFactor.mouse")) {
-               rc.scroll_factor = atof(content);
+               set_double(content, &rc.scroll_factor);
        } else if (!strcasecmp(nodename, "name.context.mouse")) {
                current_mouse_context = content;
                current_mousebind = NULL;
index 95e253cf059d548a2ad95a187b115479c79c63f7..bc3527a90d106d1c0ef5f81d8560d8a0d9a4f183 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdint.h>
 #include <strings.h>
 #include <wlr/util/log.h>
+#include "common/parse-double.h"
 #include "config/tablet.h"
 #include "config/rcxml.h"
 #include "input/tablet_pad.h"
@@ -11,7 +12,8 @@
 double
 tablet_get_dbl_if_positive(const char *content, const char *name)
 {
-       double value = atof(content);
+       double value = 0;
+       set_double(content, &value);
        if (value < 0) {
                wlr_log(WLR_ERROR, "Invalid value for tablet area %s", name);
                return 0;