1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
4 */
5
6 #include "config.h"
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <strings.h>
11
12 #include "libevdev-int.h"
13 #include "libevdev-util.h"
14 #include "libevdev.h"
15
16 #include "event-names.h"
17
18 struct name_lookup {
19 const char *name;
20 size_t len;
21 };
22
cmp_entry(const void * vlookup,const void * ventry)23 static int cmp_entry(const void *vlookup, const void *ventry)
24 {
25 const struct name_lookup *lookup = vlookup;
26 const struct name_entry *entry = ventry;
27 int r;
28
29 r = strncmp(lookup->name, entry->name, lookup->len);
30 if (!r) {
31 if (entry->name[lookup->len])
32 r = -1;
33 else
34 r = 0;
35 }
36
37 return r;
38 }
39
40 static const struct name_entry*
lookup_name(const struct name_entry * array,size_t asize,struct name_lookup * lookup)41 lookup_name(const struct name_entry *array, size_t asize,
42 struct name_lookup *lookup)
43 {
44 const struct name_entry *entry;
45
46 entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
47 if (!entry)
48 return NULL;
49
50 return entry;
51 }
52
53 LIBEVDEV_EXPORT int
libevdev_event_type_from_name(const char * name)54 libevdev_event_type_from_name(const char *name)
55 {
56 return libevdev_event_type_from_name_n(name, strlen(name));
57 }
58
59 LIBEVDEV_EXPORT int
libevdev_event_type_from_name_n(const char * name,size_t len)60 libevdev_event_type_from_name_n(const char *name, size_t len)
61 {
62 struct name_lookup lookup;
63 const struct name_entry *entry;
64
65 lookup.name = name;
66 lookup.len = len;
67
68 entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
69
70 return entry ? (int)entry->value : -1;
71 }
72
type_from_prefix(const char * name,ssize_t len)73 static int type_from_prefix(const char *name, ssize_t len)
74 {
75 const char *e;
76 size_t i;
77 ssize_t l;
78
79 /* MAX_ is not allowed, even though EV_MAX exists */
80 if (startswith(name, len, "MAX_", 4))
81 return -1;
82 /* BTN_ is special as there is no EV_BTN type */
83 if (startswith(name, len, "BTN_", 4))
84 return EV_KEY;
85 /* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */
86 if (startswith(name, len, "FF_STATUS_", 10))
87 return EV_FF_STATUS;
88
89 for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
90 /* skip EV_ prefix so @e is suffix of [EV_]XYZ */
91 e = &ev_names[i].name[3];
92 l = strlen(e);
93
94 /* compare prefix and test for trailing _ */
95 if (len > l && startswith(name, len, e, l) && name[l] == '_')
96 return ev_names[i].value;
97 }
98
99 return -1;
100 }
101
102 LIBEVDEV_EXPORT int
libevdev_event_code_from_name(unsigned int type,const char * name)103 libevdev_event_code_from_name(unsigned int type, const char *name)
104 {
105 return libevdev_event_code_from_name_n(type, name, strlen(name));
106 }
107
108 LIBEVDEV_EXPORT int
libevdev_event_code_from_name_n(unsigned int type,const char * name,size_t len)109 libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len)
110 {
111 struct name_lookup lookup;
112 const struct name_entry *entry;
113 int real_type;
114
115 /* verify that @name is really of type @type */
116 real_type = type_from_prefix(name, len);
117 if (real_type < 0 || (unsigned int)real_type != type)
118 return -1;
119
120 /* now look up the name @name and return the constant */
121 lookup.name = name;
122 lookup.len = len;
123
124 entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
125
126 return entry ? (int)entry->value : -1;
127 }
128
129 LIBEVDEV_EXPORT int
libevdev_event_value_from_name(unsigned int type,unsigned int code,const char * name)130 libevdev_event_value_from_name(unsigned int type, unsigned int code, const char *name)
131 {
132 return libevdev_event_value_from_name_n(type, code, name, strlen(name));
133 }
134
135 LIBEVDEV_EXPORT int
libevdev_event_value_from_name_n(unsigned int type,unsigned int code,const char * name,size_t len)136 libevdev_event_value_from_name_n(unsigned int type, unsigned int code, const char *name, size_t len)
137 {
138 struct name_lookup lookup;
139 const struct name_entry *entry;
140
141 if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
142 return -1;
143
144 lookup.name = name;
145 lookup.len = len;
146
147 entry = lookup_name(tool_type_names, ARRAY_LENGTH(tool_type_names), &lookup);
148
149 return entry ? (int)entry->value : -1;
150 }
151
152 LIBEVDEV_EXPORT int
libevdev_property_from_name(const char * name)153 libevdev_property_from_name(const char *name)
154 {
155 return libevdev_property_from_name_n(name, strlen(name));
156 }
157
158 LIBEVDEV_EXPORT int
libevdev_property_from_name_n(const char * name,size_t len)159 libevdev_property_from_name_n(const char *name, size_t len)
160 {
161 struct name_lookup lookup;
162 const struct name_entry *entry;
163
164 lookup.name = name;
165 lookup.len = len;
166
167 entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup);
168
169 return entry ? (int)entry->value : -1;
170 }
171
172 LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name(const char * name)173 libevdev_event_code_from_code_name(const char *name)
174 {
175 return libevdev_event_code_from_code_name_n(name, strlen(name));
176 }
177
178 LIBEVDEV_EXPORT int
libevdev_event_code_from_code_name_n(const char * name,size_t len)179 libevdev_event_code_from_code_name_n(const char *name, size_t len)
180 {
181 const struct name_entry *entry;
182 struct name_lookup lookup;
183
184 /* now look up the name @name and return the constant */
185 lookup.name = name;
186 lookup.len = len;
187
188 entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
189
190 return entry ? (int)entry->value : -1;
191 }
192
193 LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name(const char * name)194 libevdev_event_type_from_code_name(const char *name)
195 {
196 return libevdev_event_type_from_code_name_n(name, strlen(name));
197 }
198
199 LIBEVDEV_EXPORT int
libevdev_event_type_from_code_name_n(const char * name,size_t len)200 libevdev_event_type_from_code_name_n(const char *name, size_t len)
201 {
202 const struct name_entry *entry;
203 struct name_lookup lookup;
204
205 /* First look up if the name exists, we dont' want to return a valid
206 * type for an invalid code name */
207 lookup.name = name;
208 lookup.len = len;
209
210 entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
211
212 return entry ? type_from_prefix(name, len) : -1;
213 }
214