1 /*
2  * Copyright (c) 2009 Dan Nicholson
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #ifdef HAVE_XORG_CONFIG_H
27 #include <xorg-config.h>
28 #endif
29 
30 #include <string.h>
31 #include "os.h"
32 #include "xf86Parser.h"
33 #include "xf86tokens.h"
34 #include "Configint.h"
35 
36 
37 static const xf86ConfigSymTabRec InputClassTab[] = {
38     {ENDSECTION, "endsection"},
39     {IDENTIFIER, "identifier"},
40     {OPTION, "option"},
41     {DRIVER, "driver"},
42     {MATCH_PRODUCT, "matchproduct"},
43     {MATCH_VENDOR, "matchvendor"},
44     {MATCH_DEVICE_PATH, "matchdevicepath"},
45     {MATCH_OS, "matchos"},
46     {MATCH_PNPID, "matchpnpid"},
47     {MATCH_USBID, "matchusbid"},
48     {MATCH_DRIVER, "matchdriver"},
49     {MATCH_TAG, "matchtag"},
50     {MATCH_LAYOUT, "matchlayout"},
51     {MATCH_IS_KEYBOARD, "matchiskeyboard"},
52     {MATCH_IS_POINTER, "matchispointer"},
53     {MATCH_IS_JOYSTICK, "matchisjoystick"},
54     {MATCH_IS_TABLET, "matchistablet"},
55     {MATCH_IS_TABLET_PAD, "matchistabletpad"},
56     {MATCH_IS_TOUCHPAD, "matchistouchpad"},
57     {MATCH_IS_TOUCHSCREEN, "matchistouchscreen"},
58     {NOMATCH_PRODUCT, "nomatchproduct"},
59     {NOMATCH_VENDOR, "nomatchvendor"},
60     {NOMATCH_DEVICE_PATH, "nomatchdevicepath"},
61     {NOMATCH_OS, "nomatchos"},
62     {NOMATCH_PNPID, "nomatchpnpid"},
63     {NOMATCH_USBID, "nomatchusbid"},
64     {NOMATCH_DRIVER, "nomatchdriver"},
65     {NOMATCH_TAG, "nomatchtag"},
66     {NOMATCH_LAYOUT, "nomatchlayout"},
67     {-1, ""},
68 };
69 
70 static void
xf86freeInputClassList(XF86ConfInputClassPtr ptr)71 xf86freeInputClassList(XF86ConfInputClassPtr ptr)
72 {
73     XF86ConfInputClassPtr prev;
74 
75     while (ptr) {
76         xf86MatchGroup *group, *next;
77         char **list;
78 
79         TestFree(ptr->identifier);
80         TestFree(ptr->driver);
81 
82         xorg_list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
83             xorg_list_del(&group->entry);
84             for (list = group->values; *list; list++)
85                 free(*list);
86             free(group);
87         }
88         xorg_list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
89             xorg_list_del(&group->entry);
90             for (list = group->values; *list; list++)
91                 free(*list);
92             free(group);
93         }
94         xorg_list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
95             xorg_list_del(&group->entry);
96             for (list = group->values; *list; list++)
97                 free(*list);
98             free(group);
99         }
100         xorg_list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
101             xorg_list_del(&group->entry);
102             for (list = group->values; *list; list++)
103                 free(*list);
104             free(group);
105         }
106         xorg_list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
107             xorg_list_del(&group->entry);
108             for (list = group->values; *list; list++)
109                 free(*list);
110             free(group);
111         }
112         xorg_list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
113             xorg_list_del(&group->entry);
114             for (list = group->values; *list; list++)
115                 free(*list);
116             free(group);
117         }
118         xorg_list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
119             xorg_list_del(&group->entry);
120             for (list = group->values; *list; list++)
121                 free(*list);
122             free(group);
123         }
124         xorg_list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
125             xorg_list_del(&group->entry);
126             for (list = group->values; *list; list++)
127                 free(*list);
128             free(group);
129         }
130         xorg_list_for_each_entry_safe(group, next, &ptr->match_layout, entry) {
131             xorg_list_del(&group->entry);
132             for (list = group->values; *list; list++)
133                 free(*list);
134             free(group);
135         }
136 
137         TestFree(ptr->comment);
138         xf86optionListFree(ptr->option_lst);
139 
140         prev = ptr;
141         ptr = ptr->list.next;
142         free(prev);
143     }
144 }
145 
146 #define CLEANUP xf86freeInputClassList
147 
148 #define TOKEN_SEP "|"
149 
150 enum MatchType {
151     MATCH_NORMAL,
152     MATCH_NEGATED,
153 };
154 
155 static void
add_group_entry(struct xorg_list * head,char ** values,enum MatchType type)156 add_group_entry(struct xorg_list *head, char **values, enum MatchType type)
157 {
158     xf86MatchGroup *group;
159 
160     group = malloc(sizeof(*group));
161     if (group) {
162         group->is_negated = (type == MATCH_NEGATED);
163         group->values = values;
164         xorg_list_add(&group->entry, head);
165     }
166 }
167 
168 XF86ConfInputClassPtr
xf86parseInputClassSection(void)169 xf86parseInputClassSection(void)
170 {
171     int has_ident = FALSE;
172     int token;
173     enum MatchType matchtype;
174 
175     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
176 
177     /* Initialize MatchGroup lists */
178     xorg_list_init(&ptr->match_product);
179     xorg_list_init(&ptr->match_vendor);
180     xorg_list_init(&ptr->match_device);
181     xorg_list_init(&ptr->match_os);
182     xorg_list_init(&ptr->match_pnpid);
183     xorg_list_init(&ptr->match_usbid);
184     xorg_list_init(&ptr->match_driver);
185     xorg_list_init(&ptr->match_tag);
186     xorg_list_init(&ptr->match_layout);
187 
188     while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
189         matchtype = MATCH_NORMAL;
190 
191         switch (token) {
192         case COMMENT:
193             ptr->comment = xf86addComment(ptr->comment, xf86_lex_val.str);
194             break;
195         case IDENTIFIER:
196             if (xf86getSubToken(&(ptr->comment)) != STRING)
197                 Error(QUOTE_MSG, "Identifier");
198             if (has_ident == TRUE)
199                 Error(MULTIPLE_MSG, "Identifier");
200             ptr->identifier = xf86_lex_val.str;
201             has_ident = TRUE;
202             break;
203         case DRIVER:
204             if (xf86getSubToken(&(ptr->comment)) != STRING)
205                 Error(QUOTE_MSG, "Driver");
206             if (strcmp(xf86_lex_val.str, "keyboard") == 0) {
207                 ptr->driver = strdup("kbd");
208                 free(xf86_lex_val.str);
209             }
210             else
211                 ptr->driver = xf86_lex_val.str;
212             break;
213         case OPTION:
214             ptr->option_lst = xf86parseOption(ptr->option_lst);
215             break;
216         case NOMATCH_PRODUCT:
217             matchtype = MATCH_NEGATED;
218             /* fallthrough */
219         case MATCH_PRODUCT:
220             if (xf86getSubToken(&(ptr->comment)) != STRING)
221                 Error(QUOTE_MSG, "MatchProduct");
222             add_group_entry(&ptr->match_product,
223                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
224                             matchtype);
225             free(xf86_lex_val.str);
226             break;
227         case NOMATCH_VENDOR:
228             matchtype = MATCH_NEGATED;
229             /* fallthrough */
230         case MATCH_VENDOR:
231             if (xf86getSubToken(&(ptr->comment)) != STRING)
232                 Error(QUOTE_MSG, "MatchVendor");
233             add_group_entry(&ptr->match_vendor,
234                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
235                             matchtype);
236             free(xf86_lex_val.str);
237             break;
238         case NOMATCH_DEVICE_PATH:
239             matchtype = MATCH_NEGATED;
240             /* fallthrough */
241         case MATCH_DEVICE_PATH:
242             if (xf86getSubToken(&(ptr->comment)) != STRING)
243                 Error(QUOTE_MSG, "MatchDevicePath");
244             add_group_entry(&ptr->match_device,
245                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
246                             matchtype);
247             free(xf86_lex_val.str);
248             break;
249         case NOMATCH_OS:
250             matchtype = MATCH_NEGATED;
251             /* fallthrough */
252         case MATCH_OS:
253             if (xf86getSubToken(&(ptr->comment)) != STRING)
254                 Error(QUOTE_MSG, "MatchOS");
255             add_group_entry(&ptr->match_os, xstrtokenize(xf86_lex_val.str,
256                                                          TOKEN_SEP),
257                             matchtype);
258             free(xf86_lex_val.str);
259             break;
260         case NOMATCH_PNPID:
261             matchtype = MATCH_NEGATED;
262             /* fallthrough */
263         case MATCH_PNPID:
264             if (xf86getSubToken(&(ptr->comment)) != STRING)
265                 Error(QUOTE_MSG, "MatchPnPID");
266             add_group_entry(&ptr->match_pnpid,
267                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
268                             matchtype);
269             free(xf86_lex_val.str);
270             break;
271         case NOMATCH_USBID:
272             matchtype = MATCH_NEGATED;
273             /* fallthrough */
274         case MATCH_USBID:
275             if (xf86getSubToken(&(ptr->comment)) != STRING)
276                 Error(QUOTE_MSG, "MatchUSBID");
277             add_group_entry(&ptr->match_usbid,
278                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
279                             matchtype);
280             free(xf86_lex_val.str);
281             break;
282         case NOMATCH_DRIVER:
283             matchtype = MATCH_NEGATED;
284             /* fallthrough */
285         case MATCH_DRIVER:
286             if (xf86getSubToken(&(ptr->comment)) != STRING)
287                 Error(QUOTE_MSG, "MatchDriver");
288             add_group_entry(&ptr->match_driver,
289                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
290                             matchtype);
291             free(xf86_lex_val.str);
292             break;
293         case NOMATCH_TAG:
294             matchtype = MATCH_NEGATED;
295             /* fallthrough */
296         case MATCH_TAG:
297             if (xf86getSubToken(&(ptr->comment)) != STRING)
298                 Error(QUOTE_MSG, "MatchTag");
299             add_group_entry(&ptr->match_tag, xstrtokenize(xf86_lex_val.str,
300                                                           TOKEN_SEP),
301                             matchtype);
302             free(xf86_lex_val.str);
303             break;
304         case NOMATCH_LAYOUT:
305             matchtype = MATCH_NEGATED;
306             /* fallthrough */
307         case MATCH_LAYOUT:
308             if (xf86getSubToken(&(ptr->comment)) != STRING)
309                 Error(QUOTE_MSG, "MatchLayout");
310             add_group_entry(&ptr->match_layout,
311                             xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
312                             matchtype);
313             free(xf86_lex_val.str);
314             break;
315         case MATCH_IS_KEYBOARD:
316             if (xf86getSubToken(&(ptr->comment)) != STRING)
317                 Error(QUOTE_MSG, "MatchIsKeyboard");
318             ptr->is_keyboard.set = xf86getBoolValue(&ptr->is_keyboard.val,
319                                                     xf86_lex_val.str);
320             free(xf86_lex_val.str);
321             if (!ptr->is_keyboard.set)
322                 Error(BOOL_MSG, "MatchIsKeyboard");
323             break;
324         case MATCH_IS_POINTER:
325             if (xf86getSubToken(&(ptr->comment)) != STRING)
326                 Error(QUOTE_MSG, "MatchIsPointer");
327             ptr->is_pointer.set = xf86getBoolValue(&ptr->is_pointer.val,
328                                                    xf86_lex_val.str);
329             free(xf86_lex_val.str);
330             if (!ptr->is_pointer.set)
331                 Error(BOOL_MSG, "MatchIsPointer");
332             break;
333         case MATCH_IS_JOYSTICK:
334             if (xf86getSubToken(&(ptr->comment)) != STRING)
335                 Error(QUOTE_MSG, "MatchIsJoystick");
336             ptr->is_joystick.set = xf86getBoolValue(&ptr->is_joystick.val,
337                                                     xf86_lex_val.str);
338             free(xf86_lex_val.str);
339             if (!ptr->is_joystick.set)
340                 Error(BOOL_MSG, "MatchIsJoystick");
341             break;
342         case MATCH_IS_TABLET:
343             if (xf86getSubToken(&(ptr->comment)) != STRING)
344                 Error(QUOTE_MSG, "MatchIsTablet");
345             ptr->is_tablet.set = xf86getBoolValue(&ptr->is_tablet.val, xf86_lex_val.str);
346             free(xf86_lex_val.str);
347             if (!ptr->is_tablet.set)
348                 Error(BOOL_MSG, "MatchIsTablet");
349             break;
350         case MATCH_IS_TABLET_PAD:
351             if (xf86getSubToken(&(ptr->comment)) != STRING)
352                 Error(QUOTE_MSG, "MatchIsTabletPad");
353             ptr->is_tablet_pad.set = xf86getBoolValue(&ptr->is_tablet_pad.val, xf86_lex_val.str);
354             free(xf86_lex_val.str);
355             if (!ptr->is_tablet_pad.set)
356                 Error(BOOL_MSG, "MatchIsTabletPad");
357             break;
358         case MATCH_IS_TOUCHPAD:
359             if (xf86getSubToken(&(ptr->comment)) != STRING)
360                 Error(QUOTE_MSG, "MatchIsTouchpad");
361             ptr->is_touchpad.set = xf86getBoolValue(&ptr->is_touchpad.val,
362                                                     xf86_lex_val.str);
363             free(xf86_lex_val.str);
364             if (!ptr->is_touchpad.set)
365                 Error(BOOL_MSG, "MatchIsTouchpad");
366             break;
367         case MATCH_IS_TOUCHSCREEN:
368             if (xf86getSubToken(&(ptr->comment)) != STRING)
369                 Error(QUOTE_MSG, "MatchIsTouchscreen");
370             ptr->is_touchscreen.set = xf86getBoolValue(&ptr->is_touchscreen.val,
371                                                        xf86_lex_val.str);
372             free(xf86_lex_val.str);
373             if (!ptr->is_touchscreen.set)
374                 Error(BOOL_MSG, "MatchIsTouchscreen");
375             break;
376         case EOF_TOKEN:
377             Error(UNEXPECTED_EOF_MSG);
378             break;
379         default:
380             Error(INVALID_KEYWORD_MSG, xf86tokenString());
381             break;
382         }
383     }
384 
385     if (!has_ident)
386         Error(NO_IDENT_MSG);
387 
388 #ifdef DEBUG
389     printf("InputClass section parsed\n");
390 #endif
391 
392     return ptr;
393 }
394 
395 void
xf86printInputClassSection(FILE * cf,XF86ConfInputClassPtr ptr)396 xf86printInputClassSection(FILE * cf, XF86ConfInputClassPtr ptr)
397 {
398     const xf86MatchGroup *group;
399     char *const *cur;
400 
401     while (ptr) {
402         fprintf(cf, "Section \"InputClass\"\n");
403         if (ptr->comment)
404             fprintf(cf, "%s", ptr->comment);
405         if (ptr->identifier)
406             fprintf(cf, "\tIdentifier      \"%s\"\n", ptr->identifier);
407         if (ptr->driver)
408             fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
409 
410         xorg_list_for_each_entry(group, &ptr->match_product, entry) {
411             fprintf(cf, "\tMatchProduct    \"");
412             for (cur = group->values; *cur; cur++)
413                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
414                         *cur);
415             fprintf(cf, "\"\n");
416         }
417         xorg_list_for_each_entry(group, &ptr->match_vendor, entry) {
418             fprintf(cf, "\tMatchVendor     \"");
419             for (cur = group->values; *cur; cur++)
420                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
421                         *cur);
422             fprintf(cf, "\"\n");
423         }
424         xorg_list_for_each_entry(group, &ptr->match_device, entry) {
425             fprintf(cf, "\tMatchDevicePath \"");
426             for (cur = group->values; *cur; cur++)
427                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
428                         *cur);
429             fprintf(cf, "\"\n");
430         }
431         xorg_list_for_each_entry(group, &ptr->match_os, entry) {
432             fprintf(cf, "\tMatchOS         \"");
433             for (cur = group->values; *cur; cur++)
434                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
435                         *cur);
436             fprintf(cf, "\"\n");
437         }
438         xorg_list_for_each_entry(group, &ptr->match_pnpid, entry) {
439             fprintf(cf, "\tMatchPnPID      \"");
440             for (cur = group->values; *cur; cur++)
441                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
442                         *cur);
443             fprintf(cf, "\"\n");
444         }
445         xorg_list_for_each_entry(group, &ptr->match_usbid, entry) {
446             fprintf(cf, "\tMatchUSBID      \"");
447             for (cur = group->values; *cur; cur++)
448                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
449                         *cur);
450             fprintf(cf, "\"\n");
451         }
452         xorg_list_for_each_entry(group, &ptr->match_driver, entry) {
453             fprintf(cf, "\tMatchDriver     \"");
454             for (cur = group->values; *cur; cur++)
455                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
456                         *cur);
457             fprintf(cf, "\"\n");
458         }
459         xorg_list_for_each_entry(group, &ptr->match_tag, entry) {
460             fprintf(cf, "\tMatchTag        \"");
461             for (cur = group->values; *cur; cur++)
462                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
463                         *cur);
464             fprintf(cf, "\"\n");
465         }
466         xorg_list_for_each_entry(group, &ptr->match_layout, entry) {
467             fprintf(cf, "\tMatchLayout     \"");
468             for (cur = group->values; *cur; cur++)
469                 fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
470                         *cur);
471             fprintf(cf, "\"\n");
472         }
473 
474         if (ptr->is_keyboard.set)
475             fprintf(cf, "\tIsKeyboard      \"%s\"\n",
476                     ptr->is_keyboard.val ? "yes" : "no");
477         if (ptr->is_pointer.set)
478             fprintf(cf, "\tIsPointer       \"%s\"\n",
479                     ptr->is_pointer.val ? "yes" : "no");
480         if (ptr->is_joystick.set)
481             fprintf(cf, "\tIsJoystick      \"%s\"\n",
482                     ptr->is_joystick.val ? "yes" : "no");
483         if (ptr->is_tablet.set)
484             fprintf(cf, "\tIsTablet        \"%s\"\n",
485                     ptr->is_tablet.val ? "yes" : "no");
486         if (ptr->is_tablet_pad.set)
487             fprintf(cf, "\tIsTabletPad     \"%s\"\n",
488                     ptr->is_tablet_pad.val ? "yes" : "no");
489         if (ptr->is_touchpad.set)
490             fprintf(cf, "\tIsTouchpad      \"%s\"\n",
491                     ptr->is_touchpad.val ? "yes" : "no");
492         if (ptr->is_touchscreen.set)
493             fprintf(cf, "\tIsTouchscreen   \"%s\"\n",
494                     ptr->is_touchscreen.val ? "yes" : "no");
495         xf86printOptionList(cf, ptr->option_lst, 1);
496         fprintf(cf, "EndSection\n\n");
497         ptr = ptr->list.next;
498     }
499 }
500