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.h"
30 #include "libevdev-int.h"
31 #include "libevdev-util.h"
32 #include "event-names.h"
33
34 struct name_lookup {
35 const char *name;
36 size_t len;
37 };
38
cmp_entry(const void * vlookup,const void * ventry)39 static int cmp_entry(const void *vlookup, const void *ventry)
40 {
41 const struct name_lookup *lookup = vlookup;
42 const struct name_entry *entry = ventry;
43 int r;
44
45 r = strncmp(lookup->name, entry->name, lookup->len);
46 if (!r) {
47 if (entry->name[lookup->len])
48 r = -1;
49 else
50 r = 0;
51 }
52
53 return r;
54 }
55
56 static const struct name_entry*
lookup_name(const struct name_entry * array,size_t asize,struct name_lookup * lookup)57 lookup_name(const struct name_entry *array, size_t asize,
58 struct name_lookup *lookup)
59 {
60 const struct name_entry *entry;
61
62 entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
63 if (!entry)
64 return NULL;
65
66 return entry;
67 }
68
69 LIBEVDEV_EXPORT int
libevdev_event_type_from_name(const char * name)70 libevdev_event_type_from_name(const char *name)
71 {
72 return libevdev_event_type_from_name_n(name, strlen(name));
73 }
74
75 LIBEVDEV_EXPORT int
libevdev_event_type_from_name_n(const char * name,size_t len)76 libevdev_event_type_from_name_n(const char *name, size_t len)
77 {
78 struct name_lookup lookup;
79 const struct name_entry *entry;
80
81 lookup.name = name;
82 lookup.len = len;
83
84 entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
85
86 return entry ? (int)entry->value : -1;
87 }
88
type_from_prefix(const char * name,ssize_t len)89 static int type_from_prefix(const char *name, ssize_t len)
90 {
91 const char *e;
92 size_t i;
93 ssize_t l;
94
95 /* MAX_ is not allowed, even though EV_MAX exists */
96 if (startswith(name, len, "MAX_", 4))
97 return -1;
98 /* BTN_ is special as there is no EV_BTN type */
99 if (startswith(name, len, "BTN_", 4))
100 return EV_KEY;
101 /* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */
102 if (startswith(name, len, "FF_STATUS_", 10))
103 return EV_FF_STATUS;
104
105 for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
106 /* skip EV_ prefix so @e is suffix of [EV_]XYZ */
107 e = &ev_names[i].name[3];
108 l = strlen(e);
109
110 /* compare prefix and test for trailing _ */
111 if (len > l && startswith(name, len, e, l) && name[l] == '_')
112 return ev_names[i].value;
113 }
114
115 return -1;
116 }
117
118 LIBEVDEV_EXPORT int
libevdev_event_code_from_name(unsigned int type,const char * name)119 libevdev_event_code_from_name(unsigned int type, const char *name)
120 {
121 return libevdev_event_code_from_name_n(type, name, strlen(name));
122 }
123
124 LIBEVDEV_EXPORT int
libevdev_event_code_from_name_n(unsigned int type,const char * name,size_t len)125 libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len)
126 {
127 struct name_lookup lookup;
128 const struct name_entry *entry;
129 int real_type;
130
131 /* verify that @name is really of type @type */
132 real_type = type_from_prefix(name, len);
133 if (real_type < 0 || (unsigned int)real_type != type)
134 return -1;
135
136 /* now look up the name @name and return the constant */
137 lookup.name = name;
138 lookup.len = len;
139
140 entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
141
142 return entry ? (int)entry->value : -1;
143 }
144
145 LIBEVDEV_EXPORT int
libevdev_property_from_name(const char * name)146 libevdev_property_from_name(const char *name)
147 {
148 return libevdev_property_from_name_n(name, strlen(name));
149 }
150
151 LIBEVDEV_EXPORT int
libevdev_property_from_name_n(const char * name,size_t len)152 libevdev_property_from_name_n(const char *name, size_t len)
153 {
154 struct name_lookup lookup;
155 const struct name_entry *entry;
156
157 lookup.name = name;
158 lookup.len = len;
159
160 entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup);
161
162 return entry ? (int)entry->value : -1;
163 }
164