• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #include "config.h"
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <strings.h>
28 
29 #include "libevdev-int.h"
30 #include "libevdev-util.h"
31 #include "libevdev.h"
32 
33 #include "event-names.h"
34 
35 struct name_lookup {
36 	const char *name;
37 	size_t len;
38 };
39 
cmp_entry(const void * vlookup,const void * ventry)40 static int cmp_entry(const void *vlookup, const void *ventry)
41 {
42 	const struct name_lookup *lookup = vlookup;
43 	const struct name_entry *entry = ventry;
44 	int r;
45 
46 	r = strncmp(lookup->name, entry->name, lookup->len);
47 	if (!r) {
48 		if (entry->name[lookup->len])
49 			r = -1;
50 		else
51 			r = 0;
52 	}
53 
54 	return r;
55 }
56 
57 static const struct name_entry*
lookup_name(const struct name_entry * array,size_t asize,struct name_lookup * lookup)58 lookup_name(const struct name_entry *array, size_t asize,
59 	    struct name_lookup *lookup)
60 {
61 	const struct name_entry *entry;
62 
63 	entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
64 	if (!entry)
65 		return NULL;
66 
67 	return entry;
68 }
69 
70 LIBEVDEV_EXPORT int
libevdev_event_type_from_name(const char * name)71 libevdev_event_type_from_name(const char *name)
72 {
73 	return libevdev_event_type_from_name_n(name, strlen(name));
74 }
75 
76 LIBEVDEV_EXPORT int
libevdev_event_type_from_name_n(const char * name,size_t len)77 libevdev_event_type_from_name_n(const char *name, size_t len)
78 {
79 	struct name_lookup lookup;
80 	const struct name_entry *entry;
81 
82 	lookup.name = name;
83 	lookup.len = len;
84 
85 	entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
86 
87 	return entry ? (int)entry->value : -1;
88 }
89 
type_from_prefix(const char * name,ssize_t len)90 static int type_from_prefix(const char *name, ssize_t len)
91 {
92 	const char *e;
93 	size_t i;
94 	ssize_t l;
95 
96 	/* MAX_ is not allowed, even though EV_MAX exists */
97 	if (startswith(name, len, "MAX_", 4))
98 		return -1;
99 	/* BTN_ is special as there is no EV_BTN type */
100 	if (startswith(name, len, "BTN_", 4))
101 		return EV_KEY;
102 	/* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */
103 	if (startswith(name, len, "FF_STATUS_", 10))
104 		return EV_FF_STATUS;
105 
106 	for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
107 		/* skip EV_ prefix so @e is suffix of [EV_]XYZ */
108 		e = &ev_names[i].name[3];
109 		l = strlen(e);
110 
111 		/* compare prefix and test for trailing _ */
112 		if (len > l && startswith(name, len, e, l) && name[l] == '_')
113 			return ev_names[i].value;
114 	}
115 
116 	return -1;
117 }
118 
119 LIBEVDEV_EXPORT int
libevdev_event_code_from_name(unsigned int type,const char * name)120 libevdev_event_code_from_name(unsigned int type, const char *name)
121 {
122 	return libevdev_event_code_from_name_n(type, name, strlen(name));
123 }
124 
125 LIBEVDEV_EXPORT int
libevdev_event_code_from_name_n(unsigned int type,const char * name,size_t len)126 libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len)
127 {
128 	struct name_lookup lookup;
129 	const struct name_entry *entry;
130 	int real_type;
131 
132 	/* verify that @name is really of type @type */
133 	real_type = type_from_prefix(name, len);
134 	if (real_type < 0 || (unsigned int)real_type != type)
135 		return -1;
136 
137 	/* now look up the name @name and return the constant */
138 	lookup.name = name;
139 	lookup.len = len;
140 
141 	entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
142 
143 	return entry ? (int)entry->value : -1;
144 }
145 
146 LIBEVDEV_EXPORT int
libevdev_event_value_from_name(unsigned int type,unsigned int code,const char * name)147 libevdev_event_value_from_name(unsigned int type, unsigned int code, const char *name)
148 {
149 	return libevdev_event_value_from_name_n(type, code, name, strlen(name));
150 }
151 
152 LIBEVDEV_EXPORT int
libevdev_event_value_from_name_n(unsigned int type,unsigned int code,const char * name,size_t len)153 libevdev_event_value_from_name_n(unsigned int type, unsigned int code, const char *name, size_t len)
154 {
155 	struct name_lookup lookup;
156 	const struct name_entry *entry;
157 
158 	if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
159 		return -1;
160 
161 	lookup.name = name;
162 	lookup.len = len;
163 
164 	entry = lookup_name(tool_type_names, ARRAY_LENGTH(tool_type_names), &lookup);
165 
166 	return entry ? (int)entry->value : -1;
167 }
168 
169 LIBEVDEV_EXPORT int
libevdev_property_from_name(const char * name)170 libevdev_property_from_name(const char *name)
171 {
172 	return libevdev_property_from_name_n(name, strlen(name));
173 }
174 
175 LIBEVDEV_EXPORT int
libevdev_property_from_name_n(const char * name,size_t len)176 libevdev_property_from_name_n(const char *name, size_t len)
177 {
178 	struct name_lookup lookup;
179 	const struct name_entry *entry;
180 
181 	lookup.name = name;
182 	lookup.len = len;
183 
184 	entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup);
185 
186 	return entry ? (int)entry->value : -1;
187 }
188 
189 LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name(const char * name)190 libevdev_event_code_from_code_name(const char *name)
191 {
192 	return libevdev_event_code_from_code_name_n(name, strlen(name));
193 }
194 
195 LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name_n(const char * name,size_t len)196 libevdev_event_code_from_code_name_n(const char *name, size_t len)
197 {
198 	const struct name_entry *entry;
199 	struct name_lookup lookup;
200 
201 	/* now look up the name @name and return the constant */
202 	lookup.name = name;
203 	lookup.len = len;
204 
205 	entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
206 
207 	return entry ? (int)entry->value : -1;
208 }
209 
210 LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name(const char * name)211 libevdev_event_type_from_code_name(const char *name)
212 {
213 	return libevdev_event_type_from_code_name_n(name, strlen(name));
214 }
215 
216 LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name_n(const char * name,size_t len)217 libevdev_event_type_from_code_name_n(const char *name, size_t len)
218 {
219 	const struct name_entry *entry;
220 	struct name_lookup lookup;
221 
222 	/* First look up if the name exists, we dont' want to return a valid
223 	 * type for an invalid code name */
224 	lookup.name = name;
225 	lookup.len = len;
226 
227 	entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
228 
229 	return entry ? type_from_prefix(name, len) : -1;
230 }
231