From c84366e85e45a20a7d00a735aa31e7587ef5160c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 4 Sep 2019 15:11:45 +1000 Subject: [PATCH] Split utility functions into separate source files 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 --- meson.build | 42 +- src/libinput-util.h | 650 +------------------ src/util-bits.h | 101 +++ src/util-list.c | 88 +++ src/util-list.h | 66 ++ src/util-macros.h | 52 ++ src/util-matrix.h | 162 +++++ src/{libinput-util.c => util-prop-parsers.c} | 256 +------- src/util-prop-parsers.h | 56 ++ src/util-ratelimit.c | 79 +++ src/util-ratelimit.h | 45 ++ src/util-strings.c | 157 +++++ src/util-strings.h | 314 +++++++++ src/util-time.h | 83 +++ test/test-util-includes.c | 6 + test/test-utils.c | 11 +- 16 files changed, 1270 insertions(+), 898 deletions(-) create mode 100644 src/util-bits.h create mode 100644 src/util-list.c create mode 100644 src/util-list.h create mode 100644 src/util-macros.h create mode 100644 src/util-matrix.h rename src/{libinput-util.c => util-prop-parsers.c} (62%) create mode 100644 src/util-prop-parsers.h create mode 100644 src/util-ratelimit.c create mode 100644 src/util-ratelimit.h create mode 100644 src/util-strings.c create mode 100644 src/util-strings.h create mode 100644 src/util-time.h create mode 100644 test/test-util-includes.c diff --git a/meson.build b/meson.build index 5d13ca35..6dda1926 100644 --- a/meson.build +++ b/meson.build @@ -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.h b/src/libinput-util.h index 680e724a..116e3e96 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -31,29 +31,18 @@ #warning "libinput relies on assert(). #defining NDEBUG is not recommended" #endif -#include -#include -#include -#include -#ifdef HAVE_LOCALE_H -#include -#endif -#ifdef HAVE_XLOCALE_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #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 @@ -68,74 +57,6 @@ #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 index 00000000..47c40f38 --- /dev/null +++ b/src/util-bits.h @@ -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 +#include +#include + +#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 index 00000000..45fed457 --- /dev/null +++ b/src/util-list.c @@ -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 +#include +#include + +#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 index 00000000..25642319 --- /dev/null +++ b/src/util-list.h @@ -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 + +/* + * 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 index 00000000..03728ebc --- /dev/null +++ b/src/util-macros.h @@ -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 index 00000000..e5a60cb0 --- /dev/null +++ b/src/util-matrix.h @@ -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 +#include +#include + +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/libinput-util.c b/src/util-prop-parsers.c similarity index 62% rename from src/libinput-util.c rename to src/util-prop-parsers.c index dcc4a168..4a4425a4 100644 --- a/src/libinput-util.c +++ b/src/util-prop-parsers.c @@ -1,7 +1,5 @@ /* - * Copyright © 2008-2011 Kristian Høgsberg - * Copyright © 2011 Intel Corporation - * Copyright © 2013-2015 Red Hat, Inc. + * 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"), @@ -23,127 +21,13 @@ * 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 "util-prop-parsers.h" -#include -#include -#include -#include -#include -#include #include +#include -#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 - * , 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; -} +#include "util-macros.h" +#include "util-strings.h" /* Helper function to parse the mouse DPI tag from udev. * The tag is of the form: @@ -517,133 +401,3 @@ 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; -} diff --git a/src/util-prop-parsers.h b/src/util-prop-parsers.h new file mode 100644 index 00000000..6fcbb426 --- /dev/null +++ b/src/util-prop-parsers.h @@ -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 +#include +#include + +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 index 00000000..a3943b1b --- /dev/null +++ b/src/util-ratelimit.c @@ -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 + +#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 + * , 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 index 00000000..a717ae96 --- /dev/null +++ b/src/util-ratelimit.h @@ -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 + +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 index 00000000..f6dc5478 --- /dev/null +++ b/src/util-strings.c @@ -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 index 00000000..15e03cef --- /dev/null +++ b/src/util-strings.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LOCALE_H +#include +#endif +#ifdef HAVE_XLOCALE_H +#include +#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 index 00000000..71dc81fd --- /dev/null +++ b/src/util-time.h @@ -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 +#include +#include + +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 index 00000000..6cb3419a --- /dev/null +++ b/test/test-util-includes.c @@ -0,0 +1,6 @@ +/* compile test for the util files */ +#include @FILE@ + +int main(void) { + return 0; +} diff --git a/test/test-utils.c b/test/test-utils.c index 9f13f2e5..46355a59 100644 --- a/test/test-utils.c +++ b/test/test-utils.c @@ -24,11 +24,18 @@ #include #include -#include #include -#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" -- 2.34.1