xref: /freebsd/usr.sbin/moused/moused/util.h (revision aef807876c305587c60f73e2cd914115d22a53fd)
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  * Copyright © 2013-2015 Red Hat, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #pragma once
27 
28 #include <sys/types.h>
29 #include <sys/mouse.h>
30 
31 #include <assert.h>
32 #include <ctype.h>
33 #include <math.h>
34 #include <xlocale.h>
35 
36 #define	HAVE_LOCALE_H	1
37 
38 #define MOUSED_ATTRIBUTE_PRINTF(_format, _args) \
39 	__attribute__ ((format (printf, _format, _args)))
40 
41 #define	ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
42 /**
43  * Iterate through the array _arr, assigning the variable elem to each
44  * element. elem only exists within the loop.
45  */
46 #define ARRAY_FOR_EACH(_arr, _elem) \
47 	for (__typeof__((_arr)[0]) *_elem = _arr; \
48 	     _elem < (_arr) + ARRAY_LENGTH(_arr); \
49 	     _elem++)
50 
51 #define versionsort(...) alphasort(__VA_ARGS__)
52 #define bit(x_) (1UL << (x_))
53 #define min(a, b) (((a) < (b)) ? (a) : (b))
54 
55 /* Supported device interfaces */
56 enum device_if {
57 	DEVICE_IF_UNKNOWN = -1,
58 	DEVICE_IF_EVDEV = 0,
59 	DEVICE_IF_SYSMOUSE,
60 };
61 
62 /* Recognized device types */
63 enum device_type {
64 	DEVICE_TYPE_UNKNOWN = -1,
65 	DEVICE_TYPE_MOUSE = 0,
66 	DEVICE_TYPE_POINTINGSTICK,
67 	DEVICE_TYPE_TOUCHPAD,
68 	DEVICE_TYPE_TOUCHSCREEN,
69 	DEVICE_TYPE_TABLET,
70 	DEVICE_TYPE_TABLET_PAD,
71 	DEVICE_TYPE_KEYBOARD,
72 	DEVICE_TYPE_JOYSTICK,
73 };
74 
75 struct device {
76 	char path[80];
77 	enum device_if iftype;
78 	enum device_type type;
79 	char name[80];
80 	char uniq[80];
81 	struct input_id id;
82 	mousemode_t mode;
83 };
84 
85 /**
86  * @ingroup base
87  *
88  * Log handler type for custom logging.
89  *
90  * @param priority The priority of the current message
91  * @param format Message format in printf-style
92  * @param args Message arguments
93  */
94 typedef void moused_log_handler(int priority, int errnum,
95 				const char *format, va_list args);
96 
97 /* util-mem.h */
98 
99 /**
100  * Use: _unref_(foo) struct foo *bar;
101  *
102  * This requires foo_unrefp() to be present, use DEFINE_UNREF_CLEANUP_FUNC.
103  */
104 #define _unref_(_type) __attribute__((cleanup(_type##_unrefp))) struct _type
105 
106 /**
107  * Define a cleanup function for the struct type foo with a matching
108  * foo_unref(). Use:
109  * DEFINE_UNREF_CLEANUP_FUNC(foo)
110  * _unref_(foo) struct foo *bar;
111  */
112 #define DEFINE_UNREF_CLEANUP_FUNC(_type)		\
113 	static inline void _type##_unrefp(struct _type **_p) {  \
114 		if (*_p)					\
115 			_type##_unref(*_p);			\
116 	}							\
117 	struct __useless_struct_to_allow_trailing_semicolon__
118 
119 static inline void*
_steal(void * ptr)120 _steal(void *ptr) {
121 	void **original = (void**)ptr;
122 	void *swapped = *original;
123 	*original = NULL;
124 	return swapped;
125 }
126 
127 /**
128  * Resets the pointer content and resets the data to NULL.
129  * This circumvents _cleanup_ handling for that pointer.
130  * Use:
131  *   _cleanup_free_ char *data = malloc();
132  *   return steal(&data);
133  *
134  */
135 #define steal(ptr_) \
136   (typeof(*ptr_))_steal(ptr_)
137 
138 /* ! util-mem.h */
139 
140 /* util-strings.h */
141 
142 static inline bool
streq(const char * str1,const char * str2)143 streq(const char *str1, const char *str2)
144 {
145 	/* one NULL, one not NULL is always false */
146 	if (str1 && str2)
147 		return strcmp(str1, str2) == 0;
148 	return str1 == str2;
149 }
150 
151 static inline bool
strneq(const char * str1,const char * str2,int n)152 strneq(const char *str1, const char *str2, int n)
153 {
154 	/* one NULL, one not NULL is always false */
155 	if (str1 && str2)
156 		return strncmp(str1, str2, n) == 0;
157 	return str1 == str2;
158 }
159 
160 static inline void *
zalloc(size_t size)161 zalloc(size_t size)
162 {
163 	void *p;
164 
165 	/* We never need to alloc anything more than 1,5 MB so we can assume
166 	 * if we ever get above that something's going wrong */
167 	if (size > 1536 * 1024)
168 		assert(!"bug: internal malloc size limit exceeded");
169 
170 	p = calloc(1, size);
171 	if (!p)
172 		abort();
173 
174 	return p;
175 }
176 
177 /**
178  * strdup guaranteed to succeed. If the input string is NULL, the output
179  * string is NULL. If the input string is a string pointer, we strdup or
180  * abort on failure.
181  */
182 static inline char*
safe_strdup(const char * str)183 safe_strdup(const char *str)
184 {
185 	char *s;
186 
187 	if (!str)
188 		return NULL;
189 
190 	s = strdup(str);
191 	if (!s)
192 		abort();
193 	return s;
194 }
195 
196 /**
197  * Simple wrapper for asprintf that ensures the passed in-pointer is set
198  * to NULL upon error.
199  * The standard asprintf() call does not guarantee the passed in pointer
200  * will be NULL'ed upon failure, whereas this wrapper does.
201  *
202  * @param strp pointer to set to newly allocated string.
203  * This pointer should be passed to free() to release when done.
204  * @param fmt the format string to use for printing.
205  * @return The number of bytes printed (excluding the null byte terminator)
206  * upon success or -1 upon failure. In the case of failure the pointer is set
207  * to NULL.
208  */
209 __attribute__ ((format (printf, 2, 3)))
210 static inline int
xasprintf(char ** strp,const char * fmt,...)211 xasprintf(char **strp, const char *fmt, ...)
212 {
213 	int rc = 0;
214 	va_list args;
215 
216 	va_start(args, fmt);
217 	rc = vasprintf(strp, fmt, args);
218 	va_end(args);
219 	if ((rc == -1) && strp)
220 		*strp = NULL;
221 
222 	return rc;
223 }
224 
225 static inline bool
safe_atoi_base(const char * str,int * val,int base)226 safe_atoi_base(const char *str, int *val, int base)
227 {
228 	assert(str != NULL);
229 
230 	char *endptr;
231 	long v;
232 
233 	assert(base == 10 || base == 16 || base == 8);
234 
235 	errno = 0;
236 	v = strtol(str, &endptr, base);
237 	if (errno > 0)
238 		return false;
239 	if (str == endptr)
240 		return false;
241 	if (*str != '\0' && *endptr != '\0')
242 		return false;
243 
244 	if (v > INT_MAX || v < INT_MIN)
245 		return false;
246 
247 	*val = v;
248 	return true;
249 }
250 
251 static inline bool
safe_atoi(const char * str,int * val)252 safe_atoi(const char *str, int *val)
253 {
254 	assert(str != NULL);
255 	return safe_atoi_base(str, val, 10);
256 }
257 
258 static inline bool
safe_atou_base(const char * str,unsigned int * val,int base)259 safe_atou_base(const char *str, unsigned int *val, int base)
260 {
261 	assert(str != NULL);
262 
263 	char *endptr;
264 	unsigned long v;
265 
266 	assert(base == 10 || base == 16 || base == 8);
267 
268 	errno = 0;
269 	v = strtoul(str, &endptr, base);
270 	if (errno > 0)
271 		return false;
272 	if (str == endptr)
273 		return false;
274 	if (*str != '\0' && *endptr != '\0')
275 		return false;
276 
277 	if ((long)v < 0)
278 		return false;
279 
280 	*val = v;
281 	return true;
282 }
283 
284 static inline bool
safe_atou(const char * str,unsigned int * val)285 safe_atou(const char *str, unsigned int *val)
286 {
287 	assert(str != NULL);
288 	return safe_atou_base(str, val, 10);
289 }
290 
291 static inline bool
safe_atod(const char * str,double * val)292 safe_atod(const char *str, double *val)
293 {
294 	assert(str != NULL);
295 
296 	char *endptr;
297 	double v;
298 	size_t slen = strlen(str);
299 
300 	/* We don't have a use-case where we want to accept hex for a double
301 	 * or any of the other values strtod can parse */
302 	for (size_t i = 0; i < slen; i++) {
303 		char c = str[i];
304 
305 		if (isdigit(c))
306 		       continue;
307 		switch(c) {
308 		case '+':
309 		case '-':
310 		case '.':
311 			break;
312 		default:
313 			return false;
314 		}
315 	}
316 
317 #ifdef HAVE_LOCALE_H
318 	/* Create a "C" locale to force strtod to use '.' as separator */
319 	locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
320 	if (c_locale == (locale_t)0)
321 		return false;
322 
323 	errno = 0;
324 	v = strtod_l(str, &endptr, c_locale);
325 	freelocale(c_locale);
326 #else
327 	/* No locale support in provided libc, assume it already uses '.' */
328 	errno = 0;
329 	v = strtod(str, &endptr);
330 #endif
331 	if (errno > 0)
332 		return false;
333 	if (str == endptr)
334 		return false;
335 	if (*str != '\0' && *endptr != '\0')
336 		return false;
337 	if (v != 0.0 && !isnormal(v))
338 		return false;
339 
340 	*val = v;
341 	return true;
342 }
343 
344 char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
345 
346 typedef int (*strv_foreach_callback_t)(const char *str, size_t index, void *data);
347 int strv_for_each_n(const char **strv, size_t max, strv_foreach_callback_t func, void *data);
348 
349 static inline void
strv_free(char ** strv)350 strv_free(char **strv) {
351 	char **s = strv;
352 
353 	if (!strv)
354 		return;
355 
356 	while (*s != NULL) {
357 		free(*s);
358 		*s = (char*)0x1; /* detect use-after-free */
359 		s++;
360 	}
361 
362 	free (strv);
363 }
364 
365 /**
366  * Return true if str ends in suffix, false otherwise. If the suffix is the
367  * empty string, strendswith() always returns false.
368  */
369 static inline bool
strendswith(const char * str,const char * suffix)370 strendswith(const char *str, const char *suffix)
371 {
372 	if (str == NULL)
373 		return false;
374 
375 	size_t slen = strlen(str);
376 	size_t suffixlen = strlen(suffix);
377 	size_t offset;
378 
379 	if (slen == 0 || suffixlen == 0 || suffixlen > slen)
380 		return false;
381 
382 	offset = slen - suffixlen;
383 	return strneq(&str[offset], suffix, suffixlen);
384 }
385 
386 static inline bool
strstartswith(const char * str,const char * prefix)387 strstartswith(const char *str, const char *prefix)
388 {
389 	if (str == NULL)
390 		return false;
391 
392 	size_t prefixlen = strlen(prefix);
393 
394 	return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
395 }
396 
397 /* !util-strings.h */
398 
399 /* util-prop-parsers.h */
400 
401 struct input_prop {
402 	unsigned int prop;
403 	bool enabled;
404 };
405 
406 bool parse_dimension_property(const char *prop, size_t *w, size_t *h);
407 bool parse_range_property(const char *prop, int *hi, int *lo);
408 bool parse_boolean_property(const char *prop, bool *b);
409 #define	EVENT_CODE_UNDEFINED 0xffff
410 bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
411 bool parse_input_prop_property(const char *prop, struct input_prop *props_out, size_t *nprops);
412 
413 /* !util-prop-parsers.h */
414