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,
test_utils_sources = [
'src/libinput-util.h',
- 'src/libinput-util.c',
'test/test-utils.c',
]
test_utils = executable('test-utils',
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',
+++ /dev/null
-/*
- * 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;
-}
#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 { \
#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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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))
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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];
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* compile test for the util files */
+#include @FILE@
+
+int main(void) {
+ return 0;
+}
#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"