--- /dev/null
+/* 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 */
'mem.c',
'nodename.c',
'parse-bool.c',
+ 'parse-double.c',
'scaled_font_buffer.c',
'scaled_scene_buffer.c',
'scene-helpers.c',
--- /dev/null
+// 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;
+}
#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"
} else if (!strcasecmp(nodename, "leftHanded")) {
set_bool_as_int(content, ¤t_libinput_category->left_handed);
} else if (!strcasecmp(nodename, "pointerSpeed")) {
- current_libinput_category->pointer_speed = atof(content);
+ set_float(content, ¤t_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) {
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;
#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"
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;