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
37static 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
70static void
71xf86freeInputClassList(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
150enum MatchType {
151    MATCH_NORMAL,
152    MATCH_NEGATED,
153};
154
155static void
156add_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
168XF86ConfInputClassPtr
169xf86parseInputClassSection(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            free(xf86_lex_val.str);
195            xf86_lex_val.str = NULL;
196            break;
197        case IDENTIFIER:
198            if (xf86getSubToken(&(ptr->comment)) != STRING)
199                Error(QUOTE_MSG, "Identifier");
200            if (has_ident == TRUE)
201                Error(MULTIPLE_MSG, "Identifier");
202            ptr->identifier = xf86_lex_val.str;
203            has_ident = TRUE;
204            break;
205        case DRIVER:
206            if (xf86getSubToken(&(ptr->comment)) != STRING)
207                Error(QUOTE_MSG, "Driver");
208            if (strcmp(xf86_lex_val.str, "keyboard") == 0) {
209                ptr->driver = strdup("kbd");
210                free(xf86_lex_val.str);
211            }
212            else
213                ptr->driver = xf86_lex_val.str;
214            break;
215        case OPTION:
216            ptr->option_lst = xf86parseOption(ptr->option_lst);
217            break;
218        case NOMATCH_PRODUCT:
219            matchtype = MATCH_NEGATED;
220            /* fallthrough */
221        case MATCH_PRODUCT:
222            if (xf86getSubToken(&(ptr->comment)) != STRING)
223                Error(QUOTE_MSG, "MatchProduct");
224            add_group_entry(&ptr->match_product,
225                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
226                            matchtype);
227            free(xf86_lex_val.str);
228            break;
229        case NOMATCH_VENDOR:
230            matchtype = MATCH_NEGATED;
231            /* fallthrough */
232        case MATCH_VENDOR:
233            if (xf86getSubToken(&(ptr->comment)) != STRING)
234                Error(QUOTE_MSG, "MatchVendor");
235            add_group_entry(&ptr->match_vendor,
236                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
237                            matchtype);
238            free(xf86_lex_val.str);
239            break;
240        case NOMATCH_DEVICE_PATH:
241            matchtype = MATCH_NEGATED;
242            /* fallthrough */
243        case MATCH_DEVICE_PATH:
244            if (xf86getSubToken(&(ptr->comment)) != STRING)
245                Error(QUOTE_MSG, "MatchDevicePath");
246            add_group_entry(&ptr->match_device,
247                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
248                            matchtype);
249            free(xf86_lex_val.str);
250            break;
251        case NOMATCH_OS:
252            matchtype = MATCH_NEGATED;
253            /* fallthrough */
254        case MATCH_OS:
255            if (xf86getSubToken(&(ptr->comment)) != STRING)
256                Error(QUOTE_MSG, "MatchOS");
257            add_group_entry(&ptr->match_os, xstrtokenize(xf86_lex_val.str,
258                                                         TOKEN_SEP),
259                            matchtype);
260            free(xf86_lex_val.str);
261            break;
262        case NOMATCH_PNPID:
263            matchtype = MATCH_NEGATED;
264            /* fallthrough */
265        case MATCH_PNPID:
266            if (xf86getSubToken(&(ptr->comment)) != STRING)
267                Error(QUOTE_MSG, "MatchPnPID");
268            add_group_entry(&ptr->match_pnpid,
269                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
270                            matchtype);
271            free(xf86_lex_val.str);
272            break;
273        case NOMATCH_USBID:
274            matchtype = MATCH_NEGATED;
275            /* fallthrough */
276        case MATCH_USBID:
277            if (xf86getSubToken(&(ptr->comment)) != STRING)
278                Error(QUOTE_MSG, "MatchUSBID");
279            add_group_entry(&ptr->match_usbid,
280                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
281                            matchtype);
282            free(xf86_lex_val.str);
283            break;
284        case NOMATCH_DRIVER:
285            matchtype = MATCH_NEGATED;
286            /* fallthrough */
287        case MATCH_DRIVER:
288            if (xf86getSubToken(&(ptr->comment)) != STRING)
289                Error(QUOTE_MSG, "MatchDriver");
290            add_group_entry(&ptr->match_driver,
291                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
292                            matchtype);
293            free(xf86_lex_val.str);
294            break;
295        case NOMATCH_TAG:
296            matchtype = MATCH_NEGATED;
297            /* fallthrough */
298        case MATCH_TAG:
299            if (xf86getSubToken(&(ptr->comment)) != STRING)
300                Error(QUOTE_MSG, "MatchTag");
301            add_group_entry(&ptr->match_tag, xstrtokenize(xf86_lex_val.str,
302                                                          TOKEN_SEP),
303                            matchtype);
304            free(xf86_lex_val.str);
305            break;
306        case NOMATCH_LAYOUT:
307            matchtype = MATCH_NEGATED;
308            /* fallthrough */
309        case MATCH_LAYOUT:
310            if (xf86getSubToken(&(ptr->comment)) != STRING)
311                Error(QUOTE_MSG, "MatchLayout");
312            add_group_entry(&ptr->match_layout,
313                            xstrtokenize(xf86_lex_val.str, TOKEN_SEP),
314                            matchtype);
315            free(xf86_lex_val.str);
316            break;
317        case MATCH_IS_KEYBOARD:
318            if (xf86getSubToken(&(ptr->comment)) != STRING)
319                Error(QUOTE_MSG, "MatchIsKeyboard");
320            ptr->is_keyboard.set = xf86getBoolValue(&ptr->is_keyboard.val,
321                                                    xf86_lex_val.str);
322            free(xf86_lex_val.str);
323            if (!ptr->is_keyboard.set)
324                Error(BOOL_MSG, "MatchIsKeyboard");
325            break;
326        case MATCH_IS_POINTER:
327            if (xf86getSubToken(&(ptr->comment)) != STRING)
328                Error(QUOTE_MSG, "MatchIsPointer");
329            ptr->is_pointer.set = xf86getBoolValue(&ptr->is_pointer.val,
330                                                   xf86_lex_val.str);
331            free(xf86_lex_val.str);
332            if (!ptr->is_pointer.set)
333                Error(BOOL_MSG, "MatchIsPointer");
334            break;
335        case MATCH_IS_JOYSTICK:
336            if (xf86getSubToken(&(ptr->comment)) != STRING)
337                Error(QUOTE_MSG, "MatchIsJoystick");
338            ptr->is_joystick.set = xf86getBoolValue(&ptr->is_joystick.val,
339                                                    xf86_lex_val.str);
340            free(xf86_lex_val.str);
341            if (!ptr->is_joystick.set)
342                Error(BOOL_MSG, "MatchIsJoystick");
343            break;
344        case MATCH_IS_TABLET:
345            if (xf86getSubToken(&(ptr->comment)) != STRING)
346                Error(QUOTE_MSG, "MatchIsTablet");
347            ptr->is_tablet.set = xf86getBoolValue(&ptr->is_tablet.val, xf86_lex_val.str);
348            free(xf86_lex_val.str);
349            if (!ptr->is_tablet.set)
350                Error(BOOL_MSG, "MatchIsTablet");
351            break;
352        case MATCH_IS_TABLET_PAD:
353            if (xf86getSubToken(&(ptr->comment)) != STRING)
354                Error(QUOTE_MSG, "MatchIsTabletPad");
355            ptr->is_tablet_pad.set = xf86getBoolValue(&ptr->is_tablet_pad.val, xf86_lex_val.str);
356            free(xf86_lex_val.str);
357            if (!ptr->is_tablet_pad.set)
358                Error(BOOL_MSG, "MatchIsTabletPad");
359            break;
360        case MATCH_IS_TOUCHPAD:
361            if (xf86getSubToken(&(ptr->comment)) != STRING)
362                Error(QUOTE_MSG, "MatchIsTouchpad");
363            ptr->is_touchpad.set = xf86getBoolValue(&ptr->is_touchpad.val,
364                                                    xf86_lex_val.str);
365            free(xf86_lex_val.str);
366            if (!ptr->is_touchpad.set)
367                Error(BOOL_MSG, "MatchIsTouchpad");
368            break;
369        case MATCH_IS_TOUCHSCREEN:
370            if (xf86getSubToken(&(ptr->comment)) != STRING)
371                Error(QUOTE_MSG, "MatchIsTouchscreen");
372            ptr->is_touchscreen.set = xf86getBoolValue(&ptr->is_touchscreen.val,
373                                                       xf86_lex_val.str);
374            free(xf86_lex_val.str);
375            if (!ptr->is_touchscreen.set)
376                Error(BOOL_MSG, "MatchIsTouchscreen");
377            break;
378        case EOF_TOKEN:
379            Error(UNEXPECTED_EOF_MSG);
380            break;
381        default:
382            Error(INVALID_KEYWORD_MSG, xf86tokenString());
383            break;
384        }
385    }
386
387    if (!has_ident)
388        Error(NO_IDENT_MSG);
389
390#ifdef DEBUG
391    printf("InputClass section parsed\n");
392#endif
393
394    return ptr;
395}
396
397void
398xf86printInputClassSection(FILE * cf, XF86ConfInputClassPtr ptr)
399{
400    const xf86MatchGroup *group;
401    char *const *cur;
402
403    while (ptr) {
404        fprintf(cf, "Section \"InputClass\"\n");
405        if (ptr->comment)
406            fprintf(cf, "%s", ptr->comment);
407        if (ptr->identifier)
408            fprintf(cf, "\tIdentifier      \"%s\"\n", ptr->identifier);
409        if (ptr->driver)
410            fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
411
412        xorg_list_for_each_entry(group, &ptr->match_product, entry) {
413            fprintf(cf, "\tMatchProduct    \"");
414            for (cur = group->values; *cur; cur++)
415                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
416                        *cur);
417            fprintf(cf, "\"\n");
418        }
419        xorg_list_for_each_entry(group, &ptr->match_vendor, entry) {
420            fprintf(cf, "\tMatchVendor     \"");
421            for (cur = group->values; *cur; cur++)
422                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
423                        *cur);
424            fprintf(cf, "\"\n");
425        }
426        xorg_list_for_each_entry(group, &ptr->match_device, entry) {
427            fprintf(cf, "\tMatchDevicePath \"");
428            for (cur = group->values; *cur; cur++)
429                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
430                        *cur);
431            fprintf(cf, "\"\n");
432        }
433        xorg_list_for_each_entry(group, &ptr->match_os, entry) {
434            fprintf(cf, "\tMatchOS         \"");
435            for (cur = group->values; *cur; cur++)
436                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
437                        *cur);
438            fprintf(cf, "\"\n");
439        }
440        xorg_list_for_each_entry(group, &ptr->match_pnpid, entry) {
441            fprintf(cf, "\tMatchPnPID      \"");
442            for (cur = group->values; *cur; cur++)
443                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
444                        *cur);
445            fprintf(cf, "\"\n");
446        }
447        xorg_list_for_each_entry(group, &ptr->match_usbid, entry) {
448            fprintf(cf, "\tMatchUSBID      \"");
449            for (cur = group->values; *cur; cur++)
450                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
451                        *cur);
452            fprintf(cf, "\"\n");
453        }
454        xorg_list_for_each_entry(group, &ptr->match_driver, entry) {
455            fprintf(cf, "\tMatchDriver     \"");
456            for (cur = group->values; *cur; cur++)
457                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
458                        *cur);
459            fprintf(cf, "\"\n");
460        }
461        xorg_list_for_each_entry(group, &ptr->match_tag, entry) {
462            fprintf(cf, "\tMatchTag        \"");
463            for (cur = group->values; *cur; cur++)
464                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
465                        *cur);
466            fprintf(cf, "\"\n");
467        }
468        xorg_list_for_each_entry(group, &ptr->match_layout, entry) {
469            fprintf(cf, "\tMatchLayout     \"");
470            for (cur = group->values; *cur; cur++)
471                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
472                        *cur);
473            fprintf(cf, "\"\n");
474        }
475
476        if (ptr->is_keyboard.set)
477            fprintf(cf, "\tIsKeyboard      \"%s\"\n",
478                    ptr->is_keyboard.val ? "yes" : "no");
479        if (ptr->is_pointer.set)
480            fprintf(cf, "\tIsPointer       \"%s\"\n",
481                    ptr->is_pointer.val ? "yes" : "no");
482        if (ptr->is_joystick.set)
483            fprintf(cf, "\tIsJoystick      \"%s\"\n",
484                    ptr->is_joystick.val ? "yes" : "no");
485        if (ptr->is_tablet.set)
486            fprintf(cf, "\tIsTablet        \"%s\"\n",
487                    ptr->is_tablet.val ? "yes" : "no");
488        if (ptr->is_tablet_pad.set)
489            fprintf(cf, "\tIsTabletPad     \"%s\"\n",
490                    ptr->is_tablet_pad.val ? "yes" : "no");
491        if (ptr->is_touchpad.set)
492            fprintf(cf, "\tIsTouchpad      \"%s\"\n",
493                    ptr->is_touchpad.val ? "yes" : "no");
494        if (ptr->is_touchscreen.set)
495            fprintf(cf, "\tIsTouchscreen   \"%s\"\n",
496                    ptr->is_touchscreen.val ? "yes" : "no");
497        xf86printOptionList(cf, ptr->option_lst, 1);
498        fprintf(cf, "EndSection\n\n");
499        ptr = ptr->list.next;
500    }
501}
502