Split utility functions into separate source files
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 4 Sep 2019 05:11:45 +0000 (15:11 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 11 Sep 2019 02:23:04 +0000 (12:23 +1000)
libinput-util.h is getting a bit of a catchall bucket and it includes things
like libinput-private.h which in turn includes libwacom. This makes
libinput-util.h less useful for bits that only need e.g. the string processing
utilities.

So let's split them all up in to separate files, to be used as-needed.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
17 files changed:
meson.build
src/libinput-util.c [deleted file]
src/libinput-util.h
src/util-bits.h [new file with mode: 0644]
src/util-list.c [new file with mode: 0644]
src/util-list.h [new file with mode: 0644]
src/util-macros.h [new file with mode: 0644]
src/util-matrix.h [new file with mode: 0644]
src/util-prop-parsers.c [new file with mode: 0644]
src/util-prop-parsers.h [new file with mode: 0644]
src/util-ratelimit.c [new file with mode: 0644]
src/util-ratelimit.h [new file with mode: 0644]
src/util-strings.c [new file with mode: 0644]
src/util-strings.h [new file with mode: 0644]
src/util-time.h [new file with mode: 0644]
test/test-util-includes.c [new file with mode: 0644]
test/test-utils.c

index 5d13ca35ad72af6f4f27e31610e1e4930e9fbe39..6dda1926bd4296d689823b68137a1241bb65b5ce 100644 (file)
@@ -218,9 +218,45 @@ else
 endif
 
 ############ libinput-util.a ############
+
+# Basic compilation test to make sure the headers include and define all the
+# necessary bits.
+util_headers = [
+               'util-bits.h',
+               'util-list.h',
+               'util-macros.h',
+               'util-matrix.h',
+               'util-prop-parsers.h',
+               'util-ratelimit.h',
+               'util-strings.h',
+               'util-time.h',
+]
+foreach h: util_headers
+       c = configuration_data()
+       c.set_quoted('FILE', h)
+       testfile = configure_file(input : 'test/test-util-includes.c',
+                                 output : 'test-util-includes-@0@.c'.format(h),
+                                 configuration : c)
+       executable('test-build-@0@'.format(h),
+                  testfile, join_paths(dir_src, h),
+                  include_directories : [includes_src, includes_include],
+                  install : false)
+endforeach
+
 src_libinput_util = [
-               'src/libinput-util.c',
-               'src/libinput-util.h'
+       'src/util-bits.h',
+       'src/util-list.c',
+       'src/util-list.h',
+       'src/util-macros.h',
+       'src/util-matrix.h',
+       'src/util-ratelimit.c',
+       'src/util-ratelimit.h',
+       'src/util-strings.h',
+       'src/util-strings.c',
+       'src/util-time.h',
+       'src/util-prop-parsers.h',
+       'src/util-prop-parsers.c',
+       'src/libinput-util.h',
 ]
 libinput_util = static_library('libinput-util',
                               src_libinput_util,
@@ -836,7 +872,6 @@ if get_option('tests')
 
        test_utils_sources = [
                'src/libinput-util.h',
-               'src/libinput-util.c',
                'test/test-utils.c',
        ]
        test_utils = executable('test-utils',
@@ -850,7 +885,6 @@ if get_option('tests')
 
        libinput_test_runner_sources = litest_sources + [
                'src/libinput-util.h',
-               'src/libinput-util.c',
                'test/test-udev.c',
                'test/test-path.c',
                'test/test-pointer.c',
diff --git a/src/libinput-util.c b/src/libinput-util.c
deleted file mode 100644 (file)
index dcc4a16..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2013-2015 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * This list data structure is verbatim copy from wayland-util.h from the
- * Wayland project; except that wl_ prefix has been removed.
- */
-
-#include "config.h"
-
-#include <ctype.h>
-#include <locale.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <libevdev/libevdev.h>
-
-#include "libinput-util.h"
-#include "libinput-private.h"
-
-void
-list_init(struct list *list)
-{
-       list->prev = list;
-       list->next = list;
-}
-
-void
-list_insert(struct list *list, struct list *elm)
-{
-       assert((list->next != NULL && list->prev != NULL) ||
-              !"list->next|prev is NULL, possibly missing list_init()");
-       assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
-              !"elm->next|prev is not NULL, list node used twice?");
-
-       elm->prev = list;
-       elm->next = list->next;
-       list->next = elm;
-       elm->next->prev = elm;
-}
-
-void
-list_append(struct list *list, struct list *elm)
-{
-       assert((list->next != NULL && list->prev != NULL) ||
-              !"list->next|prev is NULL, possibly missing list_init()");
-       assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
-              !"elm->next|prev is not NULL, list node used twice?");
-
-       elm->next = list;
-       elm->prev = list->prev;
-       list->prev = elm;
-       elm->prev->next = elm;
-}
-
-void
-list_remove(struct list *elm)
-{
-       assert((elm->next != NULL && elm->prev != NULL) ||
-              !"list->next|prev is NULL, possibly missing list_init()");
-
-       elm->prev->next = elm->next;
-       elm->next->prev = elm->prev;
-       elm->next = NULL;
-       elm->prev = NULL;
-}
-
-bool
-list_empty(const struct list *list)
-{
-       assert((list->next != NULL && list->prev != NULL) ||
-              !"list->next|prev is NULL, possibly missing list_init()");
-
-       return list->next == list;
-}
-
-void
-ratelimit_init(struct ratelimit *r, uint64_t ival_us, unsigned int burst)
-{
-       r->interval = ival_us;
-       r->begin = 0;
-       r->burst = burst;
-       r->num = 0;
-}
-
-/*
- * Perform rate-limit test. Returns RATELIMIT_PASS if the rate-limited action
- * is still allowed, RATELIMIT_THRESHOLD if the limit has been reached with
- * this call, and RATELIMIT_EXCEEDED if you're beyond the threshold.
- * It's safe to treat the return-value as boolean, if you're not interested in
- * the exact state. It evaluates to "true" if the threshold hasn't been
- * exceeded, yet.
- *
- * The ratelimit object must be initialized via ratelimit_init().
- *
- * Modelled after Linux' lib/ratelimit.c by Dave Young
- * <hidave.darkstar@gmail.com>, which is licensed GPLv2.
- */
-enum ratelimit_state
-ratelimit_test(struct ratelimit *r)
-{
-       struct timespec ts;
-       uint64_t utime;
-
-       if (r->interval <= 0 || r->burst <= 0)
-               return RATELIMIT_PASS;
-
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-       utime = s2us(ts.tv_sec) + ns2us(ts.tv_nsec);
-
-       if (r->begin <= 0 || r->begin + r->interval < utime) {
-               /* reset counter */
-               r->begin = utime;
-               r->num = 1;
-               return RATELIMIT_PASS;
-       } else if (r->num < r->burst) {
-               /* continue burst */
-               return (++r->num == r->burst) ? RATELIMIT_THRESHOLD
-                                             : RATELIMIT_PASS;
-       }
-
-       return RATELIMIT_EXCEEDED;
-}
-
-/* Helper function to parse the mouse DPI tag from udev.
- * The tag is of the form:
- * MOUSE_DPI=400 *1000 2000
- * or
- * MOUSE_DPI=400@125 *1000@125 2000@125
- * Where the * indicates the default value and @number indicates device poll
- * rate.
- * Numbers should be in ascending order, and if rates are present they should
- * be present for all entries.
- *
- * When parsing the mouse DPI property, if we find an error we just return 0
- * since it's obviously invalid, the caller will treat that as an error and
- * use a reasonable default instead. If the property contains multiple DPI
- * settings but none flagged as default, we return the last because we're
- * lazy and that's a silly way to set the property anyway.
- *
- * @param prop The value of the udev property (without the MOUSE_DPI=)
- * @return The default dpi value on success, 0 on error
- */
-int
-parse_mouse_dpi_property(const char *prop)
-{
-       bool is_default = false;
-       int nread, dpi = 0, rate;
-
-       if (!prop)
-               return 0;
-
-       while (*prop != 0) {
-               if (*prop == ' ') {
-                       prop++;
-                       continue;
-               }
-               if (*prop == '*') {
-                       prop++;
-                       is_default = true;
-                       if (!isdigit(prop[0]))
-                               return 0;
-               }
-
-               /* While we don't do anything with the rate right now we
-                * will validate that, if it's present, it is non-zero and
-                * positive
-                */
-               rate = 1;
-               nread = 0;
-               sscanf(prop, "%d@%d%n", &dpi, &rate, &nread);
-               if (!nread)
-                       sscanf(prop, "%d%n", &dpi, &nread);
-               if (!nread || dpi <= 0 || rate <= 0 || prop[nread] == '@')
-                       return 0;
-
-               if (is_default)
-                       break;
-               prop += nread;
-       }
-       return dpi;
-}
-
-/**
- * Helper function to parse the MOUSE_WHEEL_CLICK_COUNT property from udev.
- * Property is of the form:
- * MOUSE_WHEEL_CLICK_COUNT=<integer>
- * Where the number indicates the number of wheel clicks per 360 deg
- * rotation.
- *
- * @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_COUNT=)
- * @return The click count of the wheel (may be negative) or 0 on error.
- */
-int
-parse_mouse_wheel_click_count_property(const char *prop)
-{
-       int count = 0;
-
-       if (!prop)
-               return 0;
-
-       if (!safe_atoi(prop, &count) || abs(count) > 360)
-               return 0;
-
-        return count;
-}
-
-/**
- *
- * Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
- * Property is of the form:
- * MOUSE_WHEEL_CLICK_ANGLE=<integer>
- * Where the number indicates the degrees travelled for each click.
- *
- * @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_ANGLE=)
- * @return The angle of the wheel (may be negative) or 0 on error.
- */
-int
-parse_mouse_wheel_click_angle_property(const char *prop)
-{
-       int angle = 0;
-
-       if (!prop)
-               return 0;
-
-       if (!safe_atoi(prop, &angle) || abs(angle) > 360)
-               return 0;
-
-        return angle;
-}
-
-/**
- * Parses a simple dimension string in the form of "10x40". The two
- * numbers must be positive integers in decimal notation.
- * On success, the two numbers are stored in w and h. On failure, w and h
- * are unmodified.
- *
- * @param prop The value of the property
- * @param w Returns the first component of the dimension
- * @param h Returns the second component of the dimension
- * @return true on success, false otherwise
- */
-bool
-parse_dimension_property(const char *prop, size_t *w, size_t *h)
-{
-       int x, y;
-
-       if (!prop)
-               return false;
-
-       if (sscanf(prop, "%dx%d", &x, &y) != 2)
-               return false;
-
-       if (x <= 0 || y <= 0)
-               return false;
-
-       *w = (size_t)x;
-       *h = (size_t)y;
-       return true;
-}
-
-/**
- * Parses a set of 6 space-separated floats.
- *
- * @param prop The string value of the property
- * @param calibration Returns the six components
- * @return true on success, false otherwise
- */
-bool
-parse_calibration_property(const char *prop, float calibration_out[6])
-{
-       int idx;
-       char **strv;
-       float calibration[6];
-
-       if (!prop)
-               return false;
-
-       strv = strv_from_string(prop, " ");
-       if (!strv)
-               return false;
-
-       for (idx = 0; idx < 6; idx++) {
-               double v;
-               if (strv[idx] == NULL || !safe_atod(strv[idx], &v)) {
-                       strv_free(strv);
-                       return false;
-               }
-
-               calibration[idx] = v;
-       }
-
-       strv_free(strv);
-
-       memcpy(calibration_out, calibration, sizeof(calibration));
-
-       return true;
-}
-
-bool
-parse_switch_reliability_property(const char *prop,
-                                 enum switch_reliability *reliability)
-{
-       if (!prop) {
-               *reliability = RELIABILITY_UNKNOWN;
-               return true;
-       }
-
-       if (streq(prop, "reliable"))
-               *reliability = RELIABILITY_RELIABLE;
-       else if (streq(prop, "write_open"))
-               *reliability = RELIABILITY_WRITE_OPEN;
-       else
-               return false;
-
-       return true;
-}
-
-/**
- * Parses a string with the allowed values: "below"
- * The value refers to the position of the touchpad (relative to the
- * keyboard, i.e. your average laptop would be 'below')
- *
- * @param prop The value of the property
- * @param layout The layout
- * @return true on success, false otherwise
- */
-bool
-parse_tpkbcombo_layout_poperty(const char *prop,
-                              enum tpkbcombo_layout *layout)
-{
-       if (!prop)
-               return false;
-
-       if (streq(prop, "below")) {
-               *layout = TPKBCOMBO_LAYOUT_BELOW;
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * Parses a string of the format "a:b" where both a and b must be integer
- * numbers and a > b. Also allowed is the special string vaule "none" which
- * amounts to unsetting the property.
- *
- * @param prop The value of the property
- * @param hi Set to the first digit or 0 in case of 'none'
- * @param lo Set to the second digit or 0 in case of 'none'
- * @return true on success, false otherwise
- */
-bool
-parse_range_property(const char *prop, int *hi, int *lo)
-{
-       int first, second;
-
-       if (!prop)
-               return false;
-
-       if (streq(prop, "none")) {
-               *hi = 0;
-               *lo = 0;
-               return true;
-       }
-
-       if (sscanf(prop, "%d:%d", &first, &second) != 2)
-               return false;
-
-       if (second >= first)
-               return false;
-
-       *hi = first;
-       *lo = second;
-
-       return true;
-}
-
-static bool
-parse_evcode_string(const char *s, int *type_out, int *code_out)
-{
-       int type, code;
-
-       if (strneq(s, "EV_", 3)) {
-               type = libevdev_event_type_from_name(s);
-               if (type == -1)
-                       return false;
-
-               code = EVENT_CODE_UNDEFINED;
-       } else {
-               struct map {
-                       const char *str;
-                       int type;
-               } map[] = {
-                       { "KEY_", EV_KEY },
-                       { "BTN_", EV_KEY },
-                       { "ABS_", EV_ABS },
-                       { "REL_", EV_REL },
-                       { "SW_", EV_SW },
-               };
-               struct map *m;
-               bool found = false;
-
-               ARRAY_FOR_EACH(map, m) {
-                       if (!strneq(s, m->str, strlen(m->str)))
-                               continue;
-
-                       type = m->type;
-                       code = libevdev_event_code_from_name(type, s);
-                       if (code == -1)
-                               return false;
-
-                       found = true;
-                       break;
-               }
-               if (!found)
-                       return false;
-       }
-
-       *type_out = type;
-       *code_out = code;
-
-       return true;
-}
-
-/**
- * Parses a string of the format "EV_ABS;KEY_A;BTN_TOOL_DOUBLETAP;ABS_X;"
- * where each element must be a named event type OR a named event code OR a
- * tuple in the form of EV_KEY:0x123, i.e. a named event type followed by a
- * hex event code.
- *
- * events must point to an existing array of size nevents.
- * nevents specifies the size of the array in events and returns the number
- * of items, elements exceeding nevents are simply ignored, just make sure
- * events is large enough for your use-case.
- *
- * The results are returned as input events with type and code set, all
- * other fields undefined. Where only the event type is specified, the code
- * is set to EVENT_CODE_UNDEFINED.
- *
- * On success, events contains nevents events.
- */
-bool
-parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
-{
-       char **strv = NULL;
-       bool rc = false;
-       size_t ncodes = 0;
-       size_t idx;
-       /* A randomly chosen max so we avoid crazy quirks */
-       struct input_event evs[32];
-
-       memset(evs, 0, sizeof evs);
-
-       strv = strv_from_string(prop, ";");
-       if (!strv)
-               goto out;
-
-       for (idx = 0; strv[idx]; idx++)
-               ncodes++;
-
-       if (ncodes == 0 || ncodes > ARRAY_LENGTH(evs))
-               goto out;
-
-       ncodes = min(*nevents, ncodes);
-       for (idx = 0; strv[idx]; idx++) {
-               char *s = strv[idx];
-
-               int type, code;
-
-               if (strstr(s, ":") == NULL) {
-                       if (!parse_evcode_string(s, &type, &code))
-                               goto out;
-               } else {
-                       int consumed;
-                       char stype[13] = {0}; /* EV_FF_STATUS + '\0' */
-
-                       if (sscanf(s, "%12[A-Z_]:%x%n", stype, &code, &consumed) != 2 ||
-                           strlen(s) != (size_t)consumed ||
-                           (type = libevdev_event_type_from_name(stype)) == -1 ||
-                           code < 0 || code > libevdev_event_type_get_max(type))
-                           goto out;
-               }
-
-               evs[idx].type = type;
-               evs[idx].code = code;
-       }
-
-       memcpy(events, evs, ncodes * sizeof *events);
-       *nevents = ncodes;
-       rc = true;
-
-out:
-       strv_free(strv);
-       return rc;
-}
-
-/**
- * Return the next word in a string pointed to by state before the first
- * separator character. Call repeatedly to tokenize a whole string.
- *
- * @param state Current state
- * @param len String length of the word returned
- * @param separators List of separator characters
- *
- * @return The first word in *state, NOT null-terminated
- */
-static const char *
-next_word(const char **state, size_t *len, const char *separators)
-{
-       const char *next = *state;
-       size_t l;
-
-       if (!*next)
-               return NULL;
-
-       next += strspn(next, separators);
-       if (!*next) {
-               *state = next;
-               return NULL;
-       }
-
-       l = strcspn(next, separators);
-       *state = next + l;
-       *len = l;
-
-       return next;
-}
-
-/**
- * Return a null-terminated string array with the tokens in the input
- * string, e.g. "one two\tthree" with a separator list of " \t" will return
- * an array [ "one", "two", "three", NULL ].
- *
- * Use strv_free() to free the array.
- *
- * @param in Input string
- * @param separators List of separator characters
- *
- * @return A null-terminated string array or NULL on errors
- */
-char **
-strv_from_string(const char *in, const char *separators)
-{
-       const char *s, *word;
-       char **strv = NULL;
-       int nelems = 0, idx;
-       size_t l;
-
-       assert(in != NULL);
-
-       s = in;
-       while ((word = next_word(&s, &l, separators)) != NULL)
-              nelems++;
-
-       if (nelems == 0)
-               return NULL;
-
-       nelems++; /* NULL-terminated */
-       strv = zalloc(nelems * sizeof *strv);
-
-       idx = 0;
-
-       s = in;
-       while ((word = next_word(&s, &l, separators)) != NULL) {
-               char *copy = strndup(word, l);
-               if (!copy) {
-                       strv_free(strv);
-                       return NULL;
-               }
-
-               strv[idx++] = copy;
-       }
-
-       return strv;
-}
-
-/**
- * Return a newly allocated string with all elements joined by the
- * joiner, same as Python's string.join() basically.
- * A strv of ["one", "two", "three", NULL] with a joiner of ", " results
- * in "one, two, three".
- *
- * An empty strv ([NULL]) returns NULL, same for passing NULL as either
- * argument.
- *
- * @param strv Input string arrray
- * @param joiner Joiner between the elements in the final string
- *
- * @return A null-terminated string joining all elements
- */
-char *
-strv_join(char **strv, const char *joiner)
-{
-       char **s;
-       char *str;
-       size_t slen = 0;
-       size_t count = 0;
-
-       if (!strv || !joiner)
-               return NULL;
-
-       if (strv[0] == NULL)
-               return NULL;
-
-       for (s = strv, count = 0; *s; s++, count++) {
-               slen += strlen(*s);
-       }
-
-       assert(slen < 1000);
-       assert(strlen(joiner) < 1000);
-       assert(count > 0);
-       assert(count < 100);
-
-       slen += (count - 1) * strlen(joiner);
-
-       str = zalloc(slen + 1); /* trailing \0 */
-       for (s = strv; *s; s++) {
-               strcat(str, *s);
-               --count;
-               if (count > 0)
-                       strcat(str, joiner);
-       }
-
-       return str;
-}
index 680e724a635c493c8f7cc8e57ec562db6a36e202..116e3e968eb082265bedb53999d775aea1614288 100644 (file)
 #warning "libinput relies on assert(). #defining NDEBUG is not recommended"
 #endif
 
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h>
-#endif
-#include <math.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <linux/input.h>
 
 #include "libinput.h"
 
+#include "util-bits.h"
+#include "util-macros.h"
+#include "util-list.h"
+#include "util-matrix.h"
+#include "util-strings.h"
+#include "util-ratelimit.h"
+#include "util-prop-parsers.h"
+#include "util-time.h"
+
 #define VENDOR_ID_APPLE 0x5ac
 #define VENDOR_ID_CHICONY 0x4f2
 #define VENDOR_ID_LOGITECH 0x46d
 #define DEFAULT_MOUSE_DPI 1000
 #define DEFAULT_TRACKPOINT_SENSITIVITY 128
 
-#define ANSI_HIGHLIGHT         "\x1B[0;1;39m"
-#define ANSI_RED               "\x1B[0;31m"
-#define ANSI_GREEN             "\x1B[0;32m"
-#define ANSI_YELLOW            "\x1B[0;33m"
-#define ANSI_BLUE              "\x1B[0;34m"
-#define ANSI_MAGENTA           "\x1B[0;35m"
-#define ANSI_CYAN              "\x1B[0;36m"
-#define ANSI_BRIGHT_RED                "\x1B[0;31;1m"
-#define ANSI_BRIGHT_GREEN      "\x1B[0;32;1m"
-#define ANSI_BRIGHT_YELLOW     "\x1B[0;33;1m"
-#define ANSI_BRIGHT_BLUE       "\x1B[0;34;1m"
-#define ANSI_BRIGHT_MAGENTA    "\x1B[0;35;1m"
-#define ANSI_BRIGHT_CYAN       "\x1B[0;36;1m"
-#define ANSI_NORMAL            "\x1B[0m"
-
-#define CASE_RETURN_STRING(a) case a: return #a
-
-#define bit(x_) (1UL << (x_))
-/*
- * This list data structure is a verbatim copy from wayland-util.h from the
- * Wayland project; except that wl_ prefix has been removed.
- */
-
-struct list {
-       struct list *prev;
-       struct list *next;
-};
-
-void list_init(struct list *list);
-void list_insert(struct list *list, struct list *elm);
-void list_append(struct list *list, struct list *elm);
-void list_remove(struct list *elm);
-bool list_empty(const struct list *list);
-
-#define container_of(ptr, type, member)                                        \
-       (__typeof__(type) *)((char *)(ptr) -                            \
-                offsetof(__typeof__(type), member))
-
-#define list_first_entry(head, pos, member)                            \
-       container_of((head)->next, __typeof__(*pos), member)
-
-#define list_for_each(pos, head, member)                               \
-       for (pos = 0, pos = list_first_entry(head, pos, member);        \
-            &pos->member != (head);                                    \
-            pos = list_first_entry(&pos->member, pos, member))
-
-#define list_for_each_safe(pos, tmp, head, member)                     \
-       for (pos = 0, tmp = 0,                                          \
-            pos = list_first_entry(head, pos, member),                 \
-            tmp = list_first_entry(&pos->member, tmp, member);         \
-            &pos->member != (head);                                    \
-            pos = tmp,                                                 \
-            tmp = list_first_entry(&pos->member, tmp, member))
-
-#define NBITS(b) (b * 8)
-#define LONG_BITS (sizeof(long) * 8)
-#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-#define ARRAY_FOR_EACH(_arr, _elem) \
-       for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
-
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
-#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
-
-#define NCHARS(x) ((size_t)(((x) + 7) / 8))
-
 #ifdef DEBUG_TRACE
 #define debug_trace(...) \
        do { \
@@ -148,557 +69,4 @@ bool list_empty(const struct list *list);
 
 #define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
 
-static inline void *
-zalloc(size_t size)
-{
-       void *p;
-
-       /* We never need to alloc anything more than 1,5 MB so we can assume
-        * if we ever get above that something's going wrong */
-       if (size > 1536 * 1024)
-               assert(!"bug: internal malloc size limit exceeded");
-
-       p = calloc(1, size);
-       if (!p)
-               abort();
-
-       return p;
-}
-
-/**
- * strdup guaranteed to succeed. If the input string is NULL, the output
- * string is NULL. If the input string is a string pointer, we strdup or
- * abort on failure.
- */
-static inline char*
-safe_strdup(const char *str)
-{
-       char *s;
-
-       if (!str)
-               return NULL;
-
-       s = strdup(str);
-       if (!s)
-               abort();
-       return s;
-}
-
-/* This bitfield helper implementation is taken from from libevdev-util.h,
- * except that it has been modified to work with arrays of unsigned chars
- */
-
-static inline bool
-bit_is_set(const unsigned char *array, int bit)
-{
-       return !!(array[bit / 8] & (1 << (bit % 8)));
-}
-
-       static inline void
-set_bit(unsigned char *array, int bit)
-{
-       array[bit / 8] |= (1 << (bit % 8));
-}
-
-       static inline void
-clear_bit(unsigned char *array, int bit)
-{
-       array[bit / 8] &= ~(1 << (bit % 8));
-}
-
-static inline void
-msleep(unsigned int ms)
-{
-       usleep(ms * 1000);
-}
-
-static inline bool
-long_bit_is_set(const unsigned long *array, int bit)
-{
-       return !!(array[bit / LONG_BITS] & (1ULL << (bit % LONG_BITS)));
-}
-
-static inline void
-long_set_bit(unsigned long *array, int bit)
-{
-       array[bit / LONG_BITS] |= (1ULL << (bit % LONG_BITS));
-}
-
-static inline void
-long_clear_bit(unsigned long *array, int bit)
-{
-       array[bit / LONG_BITS] &= ~(1ULL << (bit % LONG_BITS));
-}
-
-static inline void
-long_set_bit_state(unsigned long *array, int bit, int state)
-{
-       if (state)
-               long_set_bit(array, bit);
-       else
-               long_clear_bit(array, bit);
-}
-
-static inline bool
-long_any_bit_set(unsigned long *array, size_t size)
-{
-       unsigned long i;
-
-       assert(size > 0);
-
-       for (i = 0; i < size; i++)
-               if (array[i] != 0)
-                       return true;
-       return false;
-}
-
-static inline double
-deg2rad(int degree)
-{
-       return M_PI * degree / 180.0;
-}
-
-struct matrix {
-       float val[3][3]; /* [row][col] */
-};
-
-static inline void
-matrix_init_identity(struct matrix *m)
-{
-       memset(m, 0, sizeof(*m));
-       m->val[0][0] = 1;
-       m->val[1][1] = 1;
-       m->val[2][2] = 1;
-}
-
-static inline void
-matrix_from_farray6(struct matrix *m, const float values[6])
-{
-       matrix_init_identity(m);
-       m->val[0][0] = values[0];
-       m->val[0][1] = values[1];
-       m->val[0][2] = values[2];
-       m->val[1][0] = values[3];
-       m->val[1][1] = values[4];
-       m->val[1][2] = values[5];
-}
-
-static inline void
-matrix_init_scale(struct matrix *m, float sx, float sy)
-{
-       matrix_init_identity(m);
-       m->val[0][0] = sx;
-       m->val[1][1] = sy;
-}
-
-static inline void
-matrix_init_translate(struct matrix *m, float x, float y)
-{
-       matrix_init_identity(m);
-       m->val[0][2] = x;
-       m->val[1][2] = y;
-}
-
-static inline void
-matrix_init_rotate(struct matrix *m, int degrees)
-{
-       double s, c;
-
-       s = sin(deg2rad(degrees));
-       c = cos(deg2rad(degrees));
-
-       matrix_init_identity(m);
-       m->val[0][0] = c;
-       m->val[0][1] = -s;
-       m->val[1][0] = s;
-       m->val[1][1] = c;
-}
-
-static inline bool
-matrix_is_identity(const struct matrix *m)
-{
-       return (m->val[0][0] == 1 &&
-               m->val[0][1] == 0 &&
-               m->val[0][2] == 0 &&
-               m->val[1][0] == 0 &&
-               m->val[1][1] == 1 &&
-               m->val[1][2] == 0 &&
-               m->val[2][0] == 0 &&
-               m->val[2][1] == 0 &&
-               m->val[2][2] == 1);
-}
-
-static inline void
-matrix_mult(struct matrix *dest,
-           const struct matrix *m1,
-           const struct matrix *m2)
-{
-       struct matrix m; /* allow for dest == m1 or dest == m2 */
-       int row, col, i;
-
-       for (row = 0; row < 3; row++) {
-               for (col = 0; col < 3; col++) {
-                       double v = 0;
-                       for (i = 0; i < 3; i++) {
-                               v += m1->val[row][i] * m2->val[i][col];
-                       }
-                       m.val[row][col] = v;
-               }
-       }
-
-       memcpy(dest, &m, sizeof(m));
-}
-
-static inline void
-matrix_mult_vec(const struct matrix *m, int *x, int *y)
-{
-       int tx, ty;
-
-       tx = *x * m->val[0][0] + *y * m->val[0][1] + m->val[0][2];
-       ty = *x * m->val[1][0] + *y * m->val[1][1] + m->val[1][2];
-
-       *x = tx;
-       *y = ty;
-}
-
-static inline void
-matrix_to_farray6(const struct matrix *m, float out[6])
-{
-       out[0] = m->val[0][0];
-       out[1] = m->val[0][1];
-       out[2] = m->val[0][2];
-       out[3] = m->val[1][0];
-       out[4] = m->val[1][1];
-       out[5] = m->val[1][2];
-}
-
-static inline void
-matrix_to_relative(struct matrix *dest, const struct matrix *src)
-{
-       matrix_init_identity(dest);
-       dest->val[0][0] = src->val[0][0];
-       dest->val[0][1] = src->val[0][1];
-       dest->val[1][0] = src->val[1][0];
-       dest->val[1][1] = src->val[1][1];
-}
-
-/**
- * Simple wrapper for asprintf that ensures the passed in-pointer is set
- * to NULL upon error.
- * The standard asprintf() call does not guarantee the passed in pointer
- * will be NULL'ed upon failure, whereas this wrapper does.
- *
- * @param strp pointer to set to newly allocated string.
- * This pointer should be passed to free() to release when done.
- * @param fmt the format string to use for printing.
- * @return The number of bytes printed (excluding the null byte terminator)
- * upon success or -1 upon failure. In the case of failure the pointer is set
- * to NULL.
- */
-LIBINPUT_ATTRIBUTE_PRINTF(2, 3)
-static inline int
-xasprintf(char **strp, const char *fmt, ...)
-{
-       int rc = 0;
-       va_list args;
-
-       va_start(args, fmt);
-       rc = vasprintf(strp, fmt, args);
-       va_end(args);
-       if ((rc == -1) && strp)
-               *strp = NULL;
-
-       return rc;
-}
-
-enum ratelimit_state {
-       RATELIMIT_EXCEEDED,
-       RATELIMIT_THRESHOLD,
-       RATELIMIT_PASS,
-};
-
-struct ratelimit {
-       uint64_t interval;
-       uint64_t begin;
-       unsigned int burst;
-       unsigned int num;
-};
-
-void ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst);
-enum ratelimit_state ratelimit_test(struct ratelimit *r);
-
-int parse_mouse_dpi_property(const char *prop);
-int parse_mouse_wheel_click_angle_property(const char *prop);
-int parse_mouse_wheel_click_count_property(const char *prop);
-bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
-bool parse_calibration_property(const char *prop, float calibration[6]);
-bool parse_range_property(const char *prop, int *hi, int *lo);
-#define EVENT_CODE_UNDEFINED 0xffff
-bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
-
-enum tpkbcombo_layout {
-       TPKBCOMBO_LAYOUT_UNKNOWN,
-       TPKBCOMBO_LAYOUT_BELOW,
-};
-bool parse_tpkbcombo_layout_poperty(const char *prop,
-                                   enum tpkbcombo_layout *layout);
-
-enum switch_reliability {
-       RELIABILITY_UNKNOWN,
-       RELIABILITY_RELIABLE,
-       RELIABILITY_WRITE_OPEN,
-};
-
-bool
-parse_switch_reliability_property(const char *prop,
-                                 enum switch_reliability *reliability);
-
-static inline uint64_t
-us(uint64_t us)
-{
-       return us;
-}
-
-static inline uint64_t
-ns2us(uint64_t ns)
-{
-       return us(ns / 1000);
-}
-
-static inline uint64_t
-ms2us(uint64_t ms)
-{
-       return us(ms * 1000);
-}
-
-static inline uint64_t
-s2us(uint64_t s)
-{
-       return ms2us(s * 1000);
-}
-
-static inline uint32_t
-us2ms(uint64_t us)
-{
-       return (uint32_t)(us / 1000);
-}
-
-static inline uint64_t
-tv2us(const struct timeval *tv)
-{
-       return s2us(tv->tv_sec) + tv->tv_usec;
-}
-
-static inline struct timeval
-us2tv(uint64_t time)
-{
-       struct timeval tv;
-
-       tv.tv_sec = time / ms2us(1000);
-       tv.tv_usec = time % ms2us(1000);
-
-       return tv;
-}
-
-static inline bool
-safe_atoi_base(const char *str, int *val, int base)
-{
-       char *endptr;
-       long v;
-
-       assert(base == 10 || base == 16 || base == 8);
-
-       errno = 0;
-       v = strtol(str, &endptr, base);
-       if (errno > 0)
-               return false;
-       if (str == endptr)
-               return false;
-       if (*str != '\0' && *endptr != '\0')
-               return false;
-
-       if (v > INT_MAX || v < INT_MIN)
-               return false;
-
-       *val = v;
-       return true;
-}
-
-static inline bool
-safe_atoi(const char *str, int *val)
-{
-       return safe_atoi_base(str, val, 10);
-}
-
-static inline bool
-safe_atou_base(const char *str, unsigned int *val, int base)
-{
-       char *endptr;
-       unsigned long v;
-
-       assert(base == 10 || base == 16 || base == 8);
-
-       errno = 0;
-       v = strtoul(str, &endptr, base);
-       if (errno > 0)
-               return false;
-       if (str == endptr)
-               return false;
-       if (*str != '\0' && *endptr != '\0')
-               return false;
-
-       if ((long)v < 0)
-               return false;
-
-       *val = v;
-       return true;
-}
-
-static inline bool
-safe_atou(const char *str, unsigned int *val)
-{
-       return safe_atou_base(str, val, 10);
-}
-
-static inline bool
-safe_atod(const char *str, double *val)
-{
-       char *endptr;
-       double v;
-#ifdef HAVE_LOCALE_H
-       locale_t c_locale;
-#endif
-       size_t slen = strlen(str);
-
-       /* We don't have a use-case where we want to accept hex for a double
-        * or any of the other values strtod can parse */
-       for (size_t i = 0; i < slen; i++) {
-               char c = str[i];
-
-               if (isdigit(c))
-                      continue;
-               switch(c) {
-               case '+':
-               case '-':
-               case '.':
-                       break;
-               default:
-                       return false;
-               }
-       }
-
-#ifdef HAVE_LOCALE_H
-       /* 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);
-#else
-       /* No locale support in provided libc, assume it already uses '.' */
-       errno = 0;
-       v = strtod(str, &endptr);
-#endif
-       if (errno > 0)
-               return false;
-       if (str == endptr)
-               return false;
-       if (*str != '\0' && *endptr != '\0')
-               return false;
-       if (v != 0.0 && !isnormal(v))
-               return false;
-
-       *val = v;
-       return true;
-}
-
-char **strv_from_string(const char *string, const char *separator);
-char *strv_join(char **strv, const char *separator);
-
-static inline void
-strv_free(char **strv) {
-       char **s = strv;
-
-       if (!strv)
-               return;
-
-       while (*s != NULL) {
-               free(*s);
-               *s = (char*)0x1; /* detect use-after-free */
-               s++;
-       }
-
-       free (strv);
-}
-
-struct key_value_str{
-       char *key;
-       char *value;
-};
-
-struct key_value_double {
-       double key;
-       double value;
-};
-
-static inline ssize_t
-kv_double_from_string(const char *string,
-                     const char *pair_separator,
-                     const char *kv_separator,
-                     struct key_value_double **result_out)
-
-{
-       char **pairs;
-       char **pair;
-       struct key_value_double *result = NULL;
-       ssize_t npairs = 0;
-       unsigned int idx = 0;
-
-       if (!pair_separator || pair_separator[0] == '\0' ||
-           !kv_separator || kv_separator[0] == '\0')
-               return -1;
-
-       pairs = strv_from_string(string, pair_separator);
-       if (!pairs)
-               return -1;
-
-       for (pair = pairs; *pair; pair++)
-               npairs++;
-
-       if (npairs == 0)
-               goto error;
-
-       result = zalloc(npairs * sizeof *result);
-
-       for (pair = pairs; *pair; pair++) {
-               char **kv = strv_from_string(*pair, kv_separator);
-               double k, v;
-
-               if (!kv || !kv[0] || !kv[1] || kv[2] ||
-                   !safe_atod(kv[0], &k) ||
-                   !safe_atod(kv[1], &v)) {
-                       strv_free(kv);
-                       goto error;
-               }
-
-               result[idx].key = k;
-               result[idx].value = v;
-               idx++;
-
-               strv_free(kv);
-       }
-
-       strv_free(pairs);
-
-       *result_out = result;
-
-       return npairs;
-
-error:
-       strv_free(pairs);
-       free(result);
-       return -1;
-}
 #endif /* LIBINPUT_UTIL_H */
diff --git a/src/util-bits.h b/src/util-bits.h
new file mode 100644 (file)
index 0000000..47c40f3
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#define bit(x_) (1UL << (x_))
+#define NBITS(b) (b * 8)
+#define LONG_BITS (sizeof(long) * 8)
+#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
+#define NCHARS(x) ((size_t)(((x) + 7) / 8))
+
+
+/* This bitfield helper implementation is taken from from libevdev-util.h,
+ * except that it has been modified to work with arrays of unsigned chars
+ */
+
+static inline bool
+bit_is_set(const unsigned char *array, int bit)
+{
+       return !!(array[bit / 8] & (1 << (bit % 8)));
+}
+
+static inline void
+set_bit(unsigned char *array, int bit)
+{
+       array[bit / 8] |= (1 << (bit % 8));
+}
+
+       static inline void
+clear_bit(unsigned char *array, int bit)
+{
+       array[bit / 8] &= ~(1 << (bit % 8));
+}
+
+static inline bool
+long_bit_is_set(const unsigned long *array, int bit)
+{
+       return !!(array[bit / LONG_BITS] & (1ULL << (bit % LONG_BITS)));
+}
+
+static inline void
+long_set_bit(unsigned long *array, int bit)
+{
+       array[bit / LONG_BITS] |= (1ULL << (bit % LONG_BITS));
+}
+
+static inline void
+long_clear_bit(unsigned long *array, int bit)
+{
+       array[bit / LONG_BITS] &= ~(1ULL << (bit % LONG_BITS));
+}
+
+static inline void
+long_set_bit_state(unsigned long *array, int bit, int state)
+{
+       if (state)
+               long_set_bit(array, bit);
+       else
+               long_clear_bit(array, bit);
+}
+
+static inline bool
+long_any_bit_set(unsigned long *array, size_t size)
+{
+       unsigned long i;
+
+       assert(size > 0);
+
+       for (i = 0; i < size; i++)
+               if (array[i] != 0)
+                       return true;
+       return false;
+}
diff --git a/src/util-list.c b/src/util-list.c
new file mode 100644 (file)
index 0000000..45fed45
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "util-list.h"
+
+void
+list_init(struct list *list)
+{
+       list->prev = list;
+       list->next = list;
+}
+
+void
+list_insert(struct list *list, struct list *elm)
+{
+       assert((list->next != NULL && list->prev != NULL) ||
+              !"list->next|prev is NULL, possibly missing list_init()");
+       assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
+              !"elm->next|prev is not NULL, list node used twice?");
+
+       elm->prev = list;
+       elm->next = list->next;
+       list->next = elm;
+       elm->next->prev = elm;
+}
+
+void
+list_append(struct list *list, struct list *elm)
+{
+       assert((list->next != NULL && list->prev != NULL) ||
+              !"list->next|prev is NULL, possibly missing list_init()");
+       assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
+              !"elm->next|prev is not NULL, list node used twice?");
+
+       elm->next = list;
+       elm->prev = list->prev;
+       list->prev = elm;
+       elm->prev->next = elm;
+}
+
+void
+list_remove(struct list *elm)
+{
+       assert((elm->next != NULL && elm->prev != NULL) ||
+              !"list->next|prev is NULL, possibly missing list_init()");
+
+       elm->prev->next = elm->next;
+       elm->next->prev = elm->prev;
+       elm->next = NULL;
+       elm->prev = NULL;
+}
+
+bool
+list_empty(const struct list *list)
+{
+       assert((list->next != NULL && list->prev != NULL) ||
+              !"list->next|prev is NULL, possibly missing list_init()");
+
+       return list->next == list;
+}
diff --git a/src/util-list.h b/src/util-list.h
new file mode 100644 (file)
index 0000000..2564231
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <stdbool.h>
+
+/*
+ * This list data structure is a verbatim copy from wayland-util.h from the
+ * Wayland project; except that wl_ prefix has been removed.
+ */
+
+struct list {
+       struct list *prev;
+       struct list *next;
+};
+
+void list_init(struct list *list);
+void list_insert(struct list *list, struct list *elm);
+void list_append(struct list *list, struct list *elm);
+void list_remove(struct list *elm);
+bool list_empty(const struct list *list);
+
+#define container_of(ptr, type, member)                                        \
+       (__typeof__(type) *)((char *)(ptr) -                            \
+                offsetof(__typeof__(type), member))
+
+#define list_first_entry(head, pos, member)                            \
+       container_of((head)->next, __typeof__(*pos), member)
+
+#define list_for_each(pos, head, member)                               \
+       for (pos = 0, pos = list_first_entry(head, pos, member);        \
+            &pos->member != (head);                                    \
+            pos = list_first_entry(&pos->member, pos, member))
+
+#define list_for_each_safe(pos, tmp, head, member)                     \
+       for (pos = 0, tmp = 0,                                          \
+            pos = list_first_entry(head, pos, member),                 \
+            tmp = list_first_entry(&pos->member, tmp, member);         \
+            &pos->member != (head);                                    \
+            pos = tmp,                                                 \
+            tmp = list_first_entry(&pos->member, tmp, member))
diff --git a/src/util-macros.h b/src/util-macros.h
new file mode 100644 (file)
index 0000000..03728eb
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+#define ARRAY_FOR_EACH(_arr, _elem) \
+       for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+
+#define ANSI_HIGHLIGHT         "\x1B[0;1;39m"
+#define ANSI_RED               "\x1B[0;31m"
+#define ANSI_GREEN             "\x1B[0;32m"
+#define ANSI_YELLOW            "\x1B[0;33m"
+#define ANSI_BLUE              "\x1B[0;34m"
+#define ANSI_MAGENTA           "\x1B[0;35m"
+#define ANSI_CYAN              "\x1B[0;36m"
+#define ANSI_BRIGHT_RED                "\x1B[0;31;1m"
+#define ANSI_BRIGHT_GREEN      "\x1B[0;32;1m"
+#define ANSI_BRIGHT_YELLOW     "\x1B[0;33;1m"
+#define ANSI_BRIGHT_BLUE       "\x1B[0;34;1m"
+#define ANSI_BRIGHT_MAGENTA    "\x1B[0;35;1m"
+#define ANSI_BRIGHT_CYAN       "\x1B[0;36;1m"
+#define ANSI_NORMAL            "\x1B[0m"
+
+#define CASE_RETURN_STRING(a) case a: return #a
diff --git a/src/util-matrix.h b/src/util-matrix.h
new file mode 100644 (file)
index 0000000..e5a60cb
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#pragma once
+
+#include "config.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <math.h>
+
+struct matrix {
+       float val[3][3]; /* [row][col] */
+};
+
+static inline double
+deg2rad(int degree)
+{
+       return M_PI * degree / 180.0;
+}
+
+static inline void
+matrix_init_identity(struct matrix *m)
+{
+       memset(m, 0, sizeof(*m));
+       m->val[0][0] = 1;
+       m->val[1][1] = 1;
+       m->val[2][2] = 1;
+}
+
+static inline void
+matrix_from_farray6(struct matrix *m, const float values[6])
+{
+       matrix_init_identity(m);
+       m->val[0][0] = values[0];
+       m->val[0][1] = values[1];
+       m->val[0][2] = values[2];
+       m->val[1][0] = values[3];
+       m->val[1][1] = values[4];
+       m->val[1][2] = values[5];
+}
+
+static inline void
+matrix_init_scale(struct matrix *m, float sx, float sy)
+{
+       matrix_init_identity(m);
+       m->val[0][0] = sx;
+       m->val[1][1] = sy;
+}
+
+static inline void
+matrix_init_translate(struct matrix *m, float x, float y)
+{
+       matrix_init_identity(m);
+       m->val[0][2] = x;
+       m->val[1][2] = y;
+}
+
+static inline void
+matrix_init_rotate(struct matrix *m, int degrees)
+{
+       double s, c;
+
+       s = sin(deg2rad(degrees));
+       c = cos(deg2rad(degrees));
+
+       matrix_init_identity(m);
+       m->val[0][0] = c;
+       m->val[0][1] = -s;
+       m->val[1][0] = s;
+       m->val[1][1] = c;
+}
+
+static inline bool
+matrix_is_identity(const struct matrix *m)
+{
+       return (m->val[0][0] == 1 &&
+               m->val[0][1] == 0 &&
+               m->val[0][2] == 0 &&
+               m->val[1][0] == 0 &&
+               m->val[1][1] == 1 &&
+               m->val[1][2] == 0 &&
+               m->val[2][0] == 0 &&
+               m->val[2][1] == 0 &&
+               m->val[2][2] == 1);
+}
+
+static inline void
+matrix_mult(struct matrix *dest,
+           const struct matrix *m1,
+           const struct matrix *m2)
+{
+       struct matrix m; /* allow for dest == m1 or dest == m2 */
+       int row, col, i;
+
+       for (row = 0; row < 3; row++) {
+               for (col = 0; col < 3; col++) {
+                       double v = 0;
+                       for (i = 0; i < 3; i++) {
+                               v += m1->val[row][i] * m2->val[i][col];
+                       }
+                       m.val[row][col] = v;
+               }
+       }
+
+       memcpy(dest, &m, sizeof(m));
+}
+
+static inline void
+matrix_mult_vec(const struct matrix *m, int *x, int *y)
+{
+       int tx, ty;
+
+       tx = *x * m->val[0][0] + *y * m->val[0][1] + m->val[0][2];
+       ty = *x * m->val[1][0] + *y * m->val[1][1] + m->val[1][2];
+
+       *x = tx;
+       *y = ty;
+}
+
+static inline void
+matrix_to_farray6(const struct matrix *m, float out[6])
+{
+       out[0] = m->val[0][0];
+       out[1] = m->val[0][1];
+       out[2] = m->val[0][2];
+       out[3] = m->val[1][0];
+       out[4] = m->val[1][1];
+       out[5] = m->val[1][2];
+}
+
+static inline void
+matrix_to_relative(struct matrix *dest, const struct matrix *src)
+{
+       matrix_init_identity(dest);
+       dest->val[0][0] = src->val[0][0];
+       dest->val[0][1] = src->val[0][1];
+       dest->val[1][0] = src->val[1][0];
+       dest->val[1][1] = src->val[1][1];
+}
diff --git a/src/util-prop-parsers.c b/src/util-prop-parsers.c
new file mode 100644 (file)
index 0000000..4a4425a
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright © 2013-2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "util-prop-parsers.h"
+
+#include <libevdev/libevdev.h>
+#include <string.h>
+
+#include "util-macros.h"
+#include "util-strings.h"
+
+/* Helper function to parse the mouse DPI tag from udev.
+ * The tag is of the form:
+ * MOUSE_DPI=400 *1000 2000
+ * or
+ * MOUSE_DPI=400@125 *1000@125 2000@125
+ * Where the * indicates the default value and @number indicates device poll
+ * rate.
+ * Numbers should be in ascending order, and if rates are present they should
+ * be present for all entries.
+ *
+ * When parsing the mouse DPI property, if we find an error we just return 0
+ * since it's obviously invalid, the caller will treat that as an error and
+ * use a reasonable default instead. If the property contains multiple DPI
+ * settings but none flagged as default, we return the last because we're
+ * lazy and that's a silly way to set the property anyway.
+ *
+ * @param prop The value of the udev property (without the MOUSE_DPI=)
+ * @return The default dpi value on success, 0 on error
+ */
+int
+parse_mouse_dpi_property(const char *prop)
+{
+       bool is_default = false;
+       int nread, dpi = 0, rate;
+
+       if (!prop)
+               return 0;
+
+       while (*prop != 0) {
+               if (*prop == ' ') {
+                       prop++;
+                       continue;
+               }
+               if (*prop == '*') {
+                       prop++;
+                       is_default = true;
+                       if (!isdigit(prop[0]))
+                               return 0;
+               }
+
+               /* While we don't do anything with the rate right now we
+                * will validate that, if it's present, it is non-zero and
+                * positive
+                */
+               rate = 1;
+               nread = 0;
+               sscanf(prop, "%d@%d%n", &dpi, &rate, &nread);
+               if (!nread)
+                       sscanf(prop, "%d%n", &dpi, &nread);
+               if (!nread || dpi <= 0 || rate <= 0 || prop[nread] == '@')
+                       return 0;
+
+               if (is_default)
+                       break;
+               prop += nread;
+       }
+       return dpi;
+}
+
+/**
+ * Helper function to parse the MOUSE_WHEEL_CLICK_COUNT property from udev.
+ * Property is of the form:
+ * MOUSE_WHEEL_CLICK_COUNT=<integer>
+ * Where the number indicates the number of wheel clicks per 360 deg
+ * rotation.
+ *
+ * @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_COUNT=)
+ * @return The click count of the wheel (may be negative) or 0 on error.
+ */
+int
+parse_mouse_wheel_click_count_property(const char *prop)
+{
+       int count = 0;
+
+       if (!prop)
+               return 0;
+
+       if (!safe_atoi(prop, &count) || abs(count) > 360)
+               return 0;
+
+        return count;
+}
+
+/**
+ *
+ * Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
+ * Property is of the form:
+ * MOUSE_WHEEL_CLICK_ANGLE=<integer>
+ * Where the number indicates the degrees travelled for each click.
+ *
+ * @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_ANGLE=)
+ * @return The angle of the wheel (may be negative) or 0 on error.
+ */
+int
+parse_mouse_wheel_click_angle_property(const char *prop)
+{
+       int angle = 0;
+
+       if (!prop)
+               return 0;
+
+       if (!safe_atoi(prop, &angle) || abs(angle) > 360)
+               return 0;
+
+        return angle;
+}
+
+/**
+ * Parses a simple dimension string in the form of "10x40". The two
+ * numbers must be positive integers in decimal notation.
+ * On success, the two numbers are stored in w and h. On failure, w and h
+ * are unmodified.
+ *
+ * @param prop The value of the property
+ * @param w Returns the first component of the dimension
+ * @param h Returns the second component of the dimension
+ * @return true on success, false otherwise
+ */
+bool
+parse_dimension_property(const char *prop, size_t *w, size_t *h)
+{
+       int x, y;
+
+       if (!prop)
+               return false;
+
+       if (sscanf(prop, "%dx%d", &x, &y) != 2)
+               return false;
+
+       if (x <= 0 || y <= 0)
+               return false;
+
+       *w = (size_t)x;
+       *h = (size_t)y;
+       return true;
+}
+
+/**
+ * Parses a set of 6 space-separated floats.
+ *
+ * @param prop The string value of the property
+ * @param calibration Returns the six components
+ * @return true on success, false otherwise
+ */
+bool
+parse_calibration_property(const char *prop, float calibration_out[6])
+{
+       int idx;
+       char **strv;
+       float calibration[6];
+
+       if (!prop)
+               return false;
+
+       strv = strv_from_string(prop, " ");
+       if (!strv)
+               return false;
+
+       for (idx = 0; idx < 6; idx++) {
+               double v;
+               if (strv[idx] == NULL || !safe_atod(strv[idx], &v)) {
+                       strv_free(strv);
+                       return false;
+               }
+
+               calibration[idx] = v;
+       }
+
+       strv_free(strv);
+
+       memcpy(calibration_out, calibration, sizeof(calibration));
+
+       return true;
+}
+
+bool
+parse_switch_reliability_property(const char *prop,
+                                 enum switch_reliability *reliability)
+{
+       if (!prop) {
+               *reliability = RELIABILITY_UNKNOWN;
+               return true;
+       }
+
+       if (streq(prop, "reliable"))
+               *reliability = RELIABILITY_RELIABLE;
+       else if (streq(prop, "write_open"))
+               *reliability = RELIABILITY_WRITE_OPEN;
+       else
+               return false;
+
+       return true;
+}
+
+/**
+ * Parses a string with the allowed values: "below"
+ * The value refers to the position of the touchpad (relative to the
+ * keyboard, i.e. your average laptop would be 'below')
+ *
+ * @param prop The value of the property
+ * @param layout The layout
+ * @return true on success, false otherwise
+ */
+bool
+parse_tpkbcombo_layout_poperty(const char *prop,
+                              enum tpkbcombo_layout *layout)
+{
+       if (!prop)
+               return false;
+
+       if (streq(prop, "below")) {
+               *layout = TPKBCOMBO_LAYOUT_BELOW;
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * Parses a string of the format "a:b" where both a and b must be integer
+ * numbers and a > b. Also allowed is the special string vaule "none" which
+ * amounts to unsetting the property.
+ *
+ * @param prop The value of the property
+ * @param hi Set to the first digit or 0 in case of 'none'
+ * @param lo Set to the second digit or 0 in case of 'none'
+ * @return true on success, false otherwise
+ */
+bool
+parse_range_property(const char *prop, int *hi, int *lo)
+{
+       int first, second;
+
+       if (!prop)
+               return false;
+
+       if (streq(prop, "none")) {
+               *hi = 0;
+               *lo = 0;
+               return true;
+       }
+
+       if (sscanf(prop, "%d:%d", &first, &second) != 2)
+               return false;
+
+       if (second >= first)
+               return false;
+
+       *hi = first;
+       *lo = second;
+
+       return true;
+}
+
+static bool
+parse_evcode_string(const char *s, int *type_out, int *code_out)
+{
+       int type, code;
+
+       if (strneq(s, "EV_", 3)) {
+               type = libevdev_event_type_from_name(s);
+               if (type == -1)
+                       return false;
+
+               code = EVENT_CODE_UNDEFINED;
+       } else {
+               struct map {
+                       const char *str;
+                       int type;
+               } map[] = {
+                       { "KEY_", EV_KEY },
+                       { "BTN_", EV_KEY },
+                       { "ABS_", EV_ABS },
+                       { "REL_", EV_REL },
+                       { "SW_", EV_SW },
+               };
+               struct map *m;
+               bool found = false;
+
+               ARRAY_FOR_EACH(map, m) {
+                       if (!strneq(s, m->str, strlen(m->str)))
+                               continue;
+
+                       type = m->type;
+                       code = libevdev_event_code_from_name(type, s);
+                       if (code == -1)
+                               return false;
+
+                       found = true;
+                       break;
+               }
+               if (!found)
+                       return false;
+       }
+
+       *type_out = type;
+       *code_out = code;
+
+       return true;
+}
+
+/**
+ * Parses a string of the format "EV_ABS;KEY_A;BTN_TOOL_DOUBLETAP;ABS_X;"
+ * where each element must be a named event type OR a named event code OR a
+ * tuple in the form of EV_KEY:0x123, i.e. a named event type followed by a
+ * hex event code.
+ *
+ * events must point to an existing array of size nevents.
+ * nevents specifies the size of the array in events and returns the number
+ * of items, elements exceeding nevents are simply ignored, just make sure
+ * events is large enough for your use-case.
+ *
+ * The results are returned as input events with type and code set, all
+ * other fields undefined. Where only the event type is specified, the code
+ * is set to EVENT_CODE_UNDEFINED.
+ *
+ * On success, events contains nevents events.
+ */
+bool
+parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
+{
+       char **strv = NULL;
+       bool rc = false;
+       size_t ncodes = 0;
+       size_t idx;
+       /* A randomly chosen max so we avoid crazy quirks */
+       struct input_event evs[32];
+
+       memset(evs, 0, sizeof evs);
+
+       strv = strv_from_string(prop, ";");
+       if (!strv)
+               goto out;
+
+       for (idx = 0; strv[idx]; idx++)
+               ncodes++;
+
+       if (ncodes == 0 || ncodes > ARRAY_LENGTH(evs))
+               goto out;
+
+       ncodes = min(*nevents, ncodes);
+       for (idx = 0; strv[idx]; idx++) {
+               char *s = strv[idx];
+
+               int type, code;
+
+               if (strstr(s, ":") == NULL) {
+                       if (!parse_evcode_string(s, &type, &code))
+                               goto out;
+               } else {
+                       int consumed;
+                       char stype[13] = {0}; /* EV_FF_STATUS + '\0' */
+
+                       if (sscanf(s, "%12[A-Z_]:%x%n", stype, &code, &consumed) != 2 ||
+                           strlen(s) != (size_t)consumed ||
+                           (type = libevdev_event_type_from_name(stype)) == -1 ||
+                           code < 0 || code > libevdev_event_type_get_max(type))
+                           goto out;
+               }
+
+               evs[idx].type = type;
+               evs[idx].code = code;
+       }
+
+       memcpy(events, evs, ncodes * sizeof *events);
+       *nevents = ncodes;
+       rc = true;
+
+out:
+       strv_free(strv);
+       return rc;
+}
diff --git a/src/util-prop-parsers.h b/src/util-prop-parsers.h
new file mode 100644 (file)
index 0000000..6fcbb42
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2013-2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+int parse_mouse_dpi_property(const char *prop);
+int parse_mouse_wheel_click_angle_property(const char *prop);
+int parse_mouse_wheel_click_count_property(const char *prop);
+bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
+bool parse_calibration_property(const char *prop, float calibration[6]);
+bool parse_range_property(const char *prop, int *hi, int *lo);
+#define EVENT_CODE_UNDEFINED 0xffff
+bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
+
+enum tpkbcombo_layout {
+       TPKBCOMBO_LAYOUT_UNKNOWN,
+       TPKBCOMBO_LAYOUT_BELOW,
+};
+bool parse_tpkbcombo_layout_poperty(const char *prop,
+                                   enum tpkbcombo_layout *layout);
+
+enum switch_reliability {
+       RELIABILITY_UNKNOWN,
+       RELIABILITY_RELIABLE,
+       RELIABILITY_WRITE_OPEN,
+};
+
+bool
+parse_switch_reliability_property(const char *prop,
+                                 enum switch_reliability *reliability);
diff --git a/src/util-ratelimit.c b/src/util-ratelimit.c
new file mode 100644 (file)
index 0000000..a3943b1
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <time.h>
+
+#include "util-ratelimit.h"
+#include "util-time.h"
+
+void
+ratelimit_init(struct ratelimit *r, uint64_t ival_us, unsigned int burst)
+{
+       r->interval = ival_us;
+       r->begin = 0;
+       r->burst = burst;
+       r->num = 0;
+}
+
+/*
+ * Perform rate-limit test. Returns RATELIMIT_PASS if the rate-limited action
+ * is still allowed, RATELIMIT_THRESHOLD if the limit has been reached with
+ * this call, and RATELIMIT_EXCEEDED if you're beyond the threshold.
+ * It's safe to treat the return-value as boolean, if you're not interested in
+ * the exact state. It evaluates to "true" if the threshold hasn't been
+ * exceeded, yet.
+ *
+ * The ratelimit object must be initialized via ratelimit_init().
+ *
+ * Modelled after Linux' lib/ratelimit.c by Dave Young
+ * <hidave.darkstar@gmail.com>, which is licensed GPLv2.
+ */
+enum ratelimit_state
+ratelimit_test(struct ratelimit *r)
+{
+       struct timespec ts;
+       uint64_t utime;
+
+       if (r->interval <= 0 || r->burst <= 0)
+               return RATELIMIT_PASS;
+
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+       utime = s2us(ts.tv_sec) + ns2us(ts.tv_nsec);
+
+       if (r->begin <= 0 || r->begin + r->interval < utime) {
+               /* reset counter */
+               r->begin = utime;
+               r->num = 1;
+               return RATELIMIT_PASS;
+       } else if (r->num < r->burst) {
+               /* continue burst */
+               return (++r->num == r->burst) ? RATELIMIT_THRESHOLD
+                                             : RATELIMIT_PASS;
+       }
+
+       return RATELIMIT_EXCEEDED;
+}
diff --git a/src/util-ratelimit.h b/src/util-ratelimit.h
new file mode 100644 (file)
index 0000000..a717ae9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <stdint.h>
+
+enum ratelimit_state {
+       RATELIMIT_EXCEEDED,
+       RATELIMIT_THRESHOLD,
+       RATELIMIT_PASS,
+};
+
+struct ratelimit {
+       uint64_t interval;
+       uint64_t begin;
+       unsigned int burst;
+       unsigned int num;
+};
+
+void ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst);
+enum ratelimit_state ratelimit_test(struct ratelimit *r);
diff --git a/src/util-strings.c b/src/util-strings.c
new file mode 100644 (file)
index 0000000..f6dc547
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "util-strings.h"
+
+/**
+ * Return the next word in a string pointed to by state before the first
+ * separator character. Call repeatedly to tokenize a whole string.
+ *
+ * @param state Current state
+ * @param len String length of the word returned
+ * @param separators List of separator characters
+ *
+ * @return The first word in *state, NOT null-terminated
+ */
+static const char *
+next_word(const char **state, size_t *len, const char *separators)
+{
+       const char *next = *state;
+       size_t l;
+
+       if (!*next)
+               return NULL;
+
+       next += strspn(next, separators);
+       if (!*next) {
+               *state = next;
+               return NULL;
+       }
+
+       l = strcspn(next, separators);
+       *state = next + l;
+       *len = l;
+
+       return next;
+}
+
+/**
+ * Return a null-terminated string array with the tokens in the input
+ * string, e.g. "one two\tthree" with a separator list of " \t" will return
+ * an array [ "one", "two", "three", NULL ].
+ *
+ * Use strv_free() to free the array.
+ *
+ * @param in Input string
+ * @param separators List of separator characters
+ *
+ * @return A null-terminated string array or NULL on errors
+ */
+char **
+strv_from_string(const char *in, const char *separators)
+{
+       const char *s, *word;
+       char **strv = NULL;
+       int nelems = 0, idx;
+       size_t l;
+
+       assert(in != NULL);
+
+       s = in;
+       while ((word = next_word(&s, &l, separators)) != NULL)
+              nelems++;
+
+       if (nelems == 0)
+               return NULL;
+
+       nelems++; /* NULL-terminated */
+       strv = zalloc(nelems * sizeof *strv);
+
+       idx = 0;
+
+       s = in;
+       while ((word = next_word(&s, &l, separators)) != NULL) {
+               char *copy = strndup(word, l);
+               if (!copy) {
+                       strv_free(strv);
+                       return NULL;
+               }
+
+               strv[idx++] = copy;
+       }
+
+       return strv;
+}
+
+/**
+ * Return a newly allocated string with all elements joined by the
+ * joiner, same as Python's string.join() basically.
+ * A strv of ["one", "two", "three", NULL] with a joiner of ", " results
+ * in "one, two, three".
+ *
+ * An empty strv ([NULL]) returns NULL, same for passing NULL as either
+ * argument.
+ *
+ * @param strv Input string arrray
+ * @param joiner Joiner between the elements in the final string
+ *
+ * @return A null-terminated string joining all elements
+ */
+char *
+strv_join(char **strv, const char *joiner)
+{
+       char **s;
+       char *str;
+       size_t slen = 0;
+       size_t count = 0;
+
+       if (!strv || !joiner)
+               return NULL;
+
+       if (strv[0] == NULL)
+               return NULL;
+
+       for (s = strv, count = 0; *s; s++, count++) {
+               slen += strlen(*s);
+       }
+
+       assert(slen < 1000);
+       assert(strlen(joiner) < 1000);
+       assert(count > 0);
+       assert(count < 100);
+
+       slen += (count - 1) * strlen(joiner);
+
+       str = zalloc(slen + 1); /* trailing \0 */
+       for (s = strv; *s; s++) {
+               strcat(str, *s);
+               --count;
+               if (count > 0)
+                       strcat(str, joiner);
+       }
+
+       return str;
+}
diff --git a/src/util-strings.h b/src/util-strings.h
new file mode 100644 (file)
index 0000000..15e03ce
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
+
+#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
+#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
+
+static inline void *
+zalloc(size_t size)
+{
+       void *p;
+
+       /* We never need to alloc anything more than 1,5 MB so we can assume
+        * if we ever get above that something's going wrong */
+       if (size > 1536 * 1024)
+               assert(!"bug: internal malloc size limit exceeded");
+
+       p = calloc(1, size);
+       if (!p)
+               abort();
+
+       return p;
+}
+
+/**
+ * strdup guaranteed to succeed. If the input string is NULL, the output
+ * string is NULL. If the input string is a string pointer, we strdup or
+ * abort on failure.
+ */
+static inline char*
+safe_strdup(const char *str)
+{
+       char *s;
+
+       if (!str)
+               return NULL;
+
+       s = strdup(str);
+       if (!s)
+               abort();
+       return s;
+}
+
+/**
+ * Simple wrapper for asprintf that ensures the passed in-pointer is set
+ * to NULL upon error.
+ * The standard asprintf() call does not guarantee the passed in pointer
+ * will be NULL'ed upon failure, whereas this wrapper does.
+ *
+ * @param strp pointer to set to newly allocated string.
+ * This pointer should be passed to free() to release when done.
+ * @param fmt the format string to use for printing.
+ * @return The number of bytes printed (excluding the null byte terminator)
+ * upon success or -1 upon failure. In the case of failure the pointer is set
+ * to NULL.
+ */
+__attribute__ ((format (printf, 2, 3)))
+static inline int
+xasprintf(char **strp, const char *fmt, ...)
+{
+       int rc = 0;
+       va_list args;
+
+       va_start(args, fmt);
+       rc = vasprintf(strp, fmt, args);
+       va_end(args);
+       if ((rc == -1) && strp)
+               *strp = NULL;
+
+       return rc;
+}
+
+static inline bool
+safe_atoi_base(const char *str, int *val, int base)
+{
+       char *endptr;
+       long v;
+
+       assert(base == 10 || base == 16 || base == 8);
+
+       errno = 0;
+       v = strtol(str, &endptr, base);
+       if (errno > 0)
+               return false;
+       if (str == endptr)
+               return false;
+       if (*str != '\0' && *endptr != '\0')
+               return false;
+
+       if (v > INT_MAX || v < INT_MIN)
+               return false;
+
+       *val = v;
+       return true;
+}
+
+static inline bool
+safe_atoi(const char *str, int *val)
+{
+       return safe_atoi_base(str, val, 10);
+}
+
+static inline bool
+safe_atou_base(const char *str, unsigned int *val, int base)
+{
+       char *endptr;
+       unsigned long v;
+
+       assert(base == 10 || base == 16 || base == 8);
+
+       errno = 0;
+       v = strtoul(str, &endptr, base);
+       if (errno > 0)
+               return false;
+       if (str == endptr)
+               return false;
+       if (*str != '\0' && *endptr != '\0')
+               return false;
+
+       if ((long)v < 0)
+               return false;
+
+       *val = v;
+       return true;
+}
+
+static inline bool
+safe_atou(const char *str, unsigned int *val)
+{
+       return safe_atou_base(str, val, 10);
+}
+
+static inline bool
+safe_atod(const char *str, double *val)
+{
+       char *endptr;
+       double v;
+#ifdef HAVE_LOCALE_H
+       locale_t c_locale;
+#endif
+       size_t slen = strlen(str);
+
+       /* We don't have a use-case where we want to accept hex for a double
+        * or any of the other values strtod can parse */
+       for (size_t i = 0; i < slen; i++) {
+               char c = str[i];
+
+               if (isdigit(c))
+                      continue;
+               switch(c) {
+               case '+':
+               case '-':
+               case '.':
+                       break;
+               default:
+                       return false;
+               }
+       }
+
+#ifdef HAVE_LOCALE_H
+       /* 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);
+#else
+       /* No locale support in provided libc, assume it already uses '.' */
+       errno = 0;
+       v = strtod(str, &endptr);
+#endif
+       if (errno > 0)
+               return false;
+       if (str == endptr)
+               return false;
+       if (*str != '\0' && *endptr != '\0')
+               return false;
+       if (v != 0.0 && !isnormal(v))
+               return false;
+
+       *val = v;
+       return true;
+}
+
+char **strv_from_string(const char *string, const char *separator);
+char *strv_join(char **strv, const char *separator);
+
+static inline void
+strv_free(char **strv) {
+       char **s = strv;
+
+       if (!strv)
+               return;
+
+       while (*s != NULL) {
+               free(*s);
+               *s = (char*)0x1; /* detect use-after-free */
+               s++;
+       }
+
+       free (strv);
+}
+
+struct key_value_str{
+       char *key;
+       char *value;
+};
+
+struct key_value_double {
+       double key;
+       double value;
+};
+
+static inline ssize_t
+kv_double_from_string(const char *string,
+                     const char *pair_separator,
+                     const char *kv_separator,
+                     struct key_value_double **result_out)
+
+{
+       char **pairs;
+       char **pair;
+       struct key_value_double *result = NULL;
+       ssize_t npairs = 0;
+       unsigned int idx = 0;
+
+       if (!pair_separator || pair_separator[0] == '\0' ||
+           !kv_separator || kv_separator[0] == '\0')
+               return -1;
+
+       pairs = strv_from_string(string, pair_separator);
+       if (!pairs)
+               return -1;
+
+       for (pair = pairs; *pair; pair++)
+               npairs++;
+
+       if (npairs == 0)
+               goto error;
+
+       result = zalloc(npairs * sizeof *result);
+
+       for (pair = pairs; *pair; pair++) {
+               char **kv = strv_from_string(*pair, kv_separator);
+               double k, v;
+
+               if (!kv || !kv[0] || !kv[1] || kv[2] ||
+                   !safe_atod(kv[0], &k) ||
+                   !safe_atod(kv[1], &v)) {
+                       strv_free(kv);
+                       goto error;
+               }
+
+               result[idx].key = k;
+               result[idx].value = v;
+               idx++;
+
+               strv_free(kv);
+       }
+
+       strv_free(pairs);
+
+       *result_out = result;
+
+       return npairs;
+
+error:
+       strv_free(pairs);
+       free(result);
+       return -1;
+}
diff --git a/src/util-time.h b/src/util-time.h
new file mode 100644 (file)
index 0000000..71dc81f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2013-2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <time.h>
+#include <stdint.h>
+#include <unistd.h>
+
+static inline void
+msleep(unsigned int ms)
+{
+       usleep(ms * 1000);
+}
+
+static inline uint64_t
+us(uint64_t us)
+{
+       return us;
+}
+
+static inline uint64_t
+ns2us(uint64_t ns)
+{
+       return us(ns / 1000);
+}
+
+static inline uint64_t
+ms2us(uint64_t ms)
+{
+       return us(ms * 1000);
+}
+
+static inline uint64_t
+s2us(uint64_t s)
+{
+       return ms2us(s * 1000);
+}
+
+static inline uint32_t
+us2ms(uint64_t us)
+{
+       return (uint32_t)(us / 1000);
+}
+
+static inline uint64_t
+tv2us(const struct timeval *tv)
+{
+       return s2us(tv->tv_sec) + tv->tv_usec;
+}
+
+static inline struct timeval
+us2tv(uint64_t time)
+{
+       struct timeval tv;
+
+       tv.tv_sec = time / ms2us(1000);
+       tv.tv_usec = time % ms2us(1000);
+
+       return tv;
+}
diff --git a/test/test-util-includes.c b/test/test-util-includes.c
new file mode 100644 (file)
index 0000000..6cb3419
--- /dev/null
@@ -0,0 +1,6 @@
+/* compile test for the util files */
+#include @FILE@
+
+int main(void) {
+       return 0;
+}
index 9f13f2e512ce42f2be8a6e9047c94f1b91bde928..46355a591c410ab03bc5679a79c2ca88693a170d 100644 (file)
 #include <config.h>
 
 #include <check.h>
-#include <libinput-util.h>
 
 #include <valgrind/valgrind.h>
 
-#include "libinput-util.h"
+#include "util-list.h"
+#include "util-strings.h"
+#include "util-time.h"
+#include "util-prop-parsers.h"
+#include "util-macros.h"
+#include "util-bits.h"
+#include "util-ratelimit.h"
+#include "util-matrix.h"
+
 #define  TEST_VERSIONSORT
 #include "libinput-versionsort.h"