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/* View/edit this file with tab stops set to 4 */
27
28#ifdef HAVE_XORG_CONFIG_H
29#include <xorg-config.h>
30#endif
31
32#include <string.h>
33#include "os.h"
34#include "xf86Parser.h"
35#include "xf86tokens.h"
36#include "Configint.h"
37
38extern LexRec val;
39
40static
41xf86ConfigSymTabRec InputClassTab[] =
42{
43    {ENDSECTION, "endsection"},
44    {IDENTIFIER, "identifier"},
45    {OPTION, "option"},
46    {DRIVER, "driver"},
47    {MATCH_PRODUCT, "matchproduct"},
48    {MATCH_VENDOR, "matchvendor"},
49    {MATCH_DEVICE_PATH, "matchdevicepath"},
50    {MATCH_OS, "matchos"},
51    {MATCH_PNPID, "matchpnpid"},
52    {MATCH_USBID, "matchusbid"},
53    {MATCH_DRIVER, "matchdriver"},
54    {MATCH_TAG, "matchtag"},
55    {MATCH_IS_KEYBOARD, "matchiskeyboard"},
56    {MATCH_IS_POINTER, "matchispointer"},
57    {MATCH_IS_JOYSTICK, "matchisjoystick"},
58    {MATCH_IS_TABLET, "matchistablet"},
59    {MATCH_IS_TOUCHPAD, "matchistouchpad"},
60    {MATCH_IS_TOUCHSCREEN, "matchistouchscreen"},
61    {-1, ""},
62};
63
64#define CLEANUP xf86freeInputClassList
65
66#define TOKEN_SEP "|"
67
68static void
69add_group_entry(struct list *head, char **values)
70{
71    xf86MatchGroup *group;
72
73    group = malloc(sizeof(*group));
74    if (group) {
75        group->values = values;
76        list_add(&group->entry, head);
77    }
78}
79
80XF86ConfInputClassPtr
81xf86parseInputClassSection(void)
82{
83    int has_ident = FALSE;
84    int token;
85
86    parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
87
88    /* Initialize MatchGroup lists */
89    list_init(&ptr->match_product);
90    list_init(&ptr->match_vendor);
91    list_init(&ptr->match_device);
92    list_init(&ptr->match_os);
93    list_init(&ptr->match_pnpid);
94    list_init(&ptr->match_usbid);
95    list_init(&ptr->match_driver);
96    list_init(&ptr->match_tag);
97
98    while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
99        switch (token) {
100        case COMMENT:
101            ptr->comment = xf86addComment(ptr->comment, val.str);
102            break;
103        case IDENTIFIER:
104            if (xf86getSubToken(&(ptr->comment)) != STRING)
105                Error(QUOTE_MSG, "Identifier");
106            if (has_ident == TRUE)
107                Error(MULTIPLE_MSG, "Identifier");
108            ptr->identifier = val.str;
109            has_ident = TRUE;
110            break;
111        case DRIVER:
112            if (xf86getSubToken(&(ptr->comment)) != STRING)
113                Error(QUOTE_MSG, "Driver");
114            if (strcmp(val.str, "keyboard") == 0) {
115                ptr->driver = strdup("kbd");
116                free(val.str);
117            }
118            else
119                ptr->driver = val.str;
120            break;
121        case OPTION:
122            ptr->option_lst = xf86parseOption(ptr->option_lst);
123            break;
124        case MATCH_PRODUCT:
125            if (xf86getSubToken(&(ptr->comment)) != STRING)
126                Error(QUOTE_MSG, "MatchProduct");
127            add_group_entry(&ptr->match_product,
128                            xstrtokenize(val.str, TOKEN_SEP));
129            break;
130        case MATCH_VENDOR:
131            if (xf86getSubToken(&(ptr->comment)) != STRING)
132                Error(QUOTE_MSG, "MatchVendor");
133            add_group_entry(&ptr->match_vendor,
134                            xstrtokenize(val.str, TOKEN_SEP));
135            break;
136        case MATCH_DEVICE_PATH:
137            if (xf86getSubToken(&(ptr->comment)) != STRING)
138                Error(QUOTE_MSG, "MatchDevicePath");
139            add_group_entry(&ptr->match_device,
140                            xstrtokenize(val.str, TOKEN_SEP));
141            break;
142        case MATCH_OS:
143            if (xf86getSubToken(&(ptr->comment)) != STRING)
144                Error(QUOTE_MSG, "MatchOS");
145            add_group_entry(&ptr->match_os,
146                            xstrtokenize(val.str, TOKEN_SEP));
147            break;
148        case MATCH_PNPID:
149            if (xf86getSubToken(&(ptr->comment)) != STRING)
150                Error(QUOTE_MSG, "MatchPnPID");
151            add_group_entry(&ptr->match_pnpid,
152                            xstrtokenize(val.str, TOKEN_SEP));
153            break;
154        case MATCH_USBID:
155            if (xf86getSubToken(&(ptr->comment)) != STRING)
156                Error(QUOTE_MSG, "MatchUSBID");
157            add_group_entry(&ptr->match_usbid,
158                            xstrtokenize(val.str, TOKEN_SEP));
159            break;
160        case MATCH_DRIVER:
161            if (xf86getSubToken(&(ptr->comment)) != STRING)
162                Error(QUOTE_MSG, "MatchDriver");
163            add_group_entry(&ptr->match_driver,
164                            xstrtokenize(val.str, TOKEN_SEP));
165            break;
166        case MATCH_TAG:
167            if (xf86getSubToken(&(ptr->comment)) != STRING)
168                Error(QUOTE_MSG, "MatchTag");
169            add_group_entry(&ptr->match_tag,
170                            xstrtokenize(val.str, TOKEN_SEP));
171            break;
172        case MATCH_IS_KEYBOARD:
173            if (xf86getSubToken(&(ptr->comment)) != STRING)
174                Error(QUOTE_MSG, "MatchIsKeyboard");
175            ptr->is_keyboard.set = xf86getBoolValue(&ptr->is_keyboard.val,
176                                                    val.str);
177            if (!ptr->is_keyboard.set)
178                Error(BOOL_MSG, "MatchIsKeyboard");
179            break;
180        case MATCH_IS_POINTER:
181            if (xf86getSubToken(&(ptr->comment)) != STRING)
182                Error(QUOTE_MSG, "MatchIsPointer");
183            ptr->is_pointer.set = xf86getBoolValue(&ptr->is_pointer.val,
184                                                   val.str);
185            if (!ptr->is_pointer.set)
186                Error(BOOL_MSG, "MatchIsPointer");
187            break;
188        case MATCH_IS_JOYSTICK:
189            if (xf86getSubToken(&(ptr->comment)) != STRING)
190                Error(QUOTE_MSG, "MatchIsJoystick");
191            ptr->is_joystick.set = xf86getBoolValue(&ptr->is_joystick.val,
192                                                    val.str);
193            if (!ptr->is_joystick.set)
194                Error(BOOL_MSG, "MatchIsJoystick");
195            break;
196        case MATCH_IS_TABLET:
197            if (xf86getSubToken(&(ptr->comment)) != STRING)
198                Error(QUOTE_MSG, "MatchIsTablet");
199            ptr->is_tablet.set = xf86getBoolValue(&ptr->is_tablet.val,
200                                                  val.str);
201            if (!ptr->is_tablet.set)
202                Error(BOOL_MSG, "MatchIsTablet");
203            break;
204        case MATCH_IS_TOUCHPAD:
205            if (xf86getSubToken(&(ptr->comment)) != STRING)
206                Error(QUOTE_MSG, "MatchIsTouchpad");
207            ptr->is_touchpad.set = xf86getBoolValue(&ptr->is_touchpad.val,
208                                                    val.str);
209            if (!ptr->is_touchpad.set)
210                Error(BOOL_MSG, "MatchIsTouchpad");
211            break;
212        case MATCH_IS_TOUCHSCREEN:
213            if (xf86getSubToken(&(ptr->comment)) != STRING)
214                Error(QUOTE_MSG, "MatchIsTouchscreen");
215            ptr->is_touchscreen.set = xf86getBoolValue(&ptr->is_touchscreen.val,
216                                                       val.str);
217            if (!ptr->is_touchscreen.set)
218                Error(BOOL_MSG, "MatchIsTouchscreen");
219            break;
220        case EOF_TOKEN:
221            Error(UNEXPECTED_EOF_MSG, NULL);
222            break;
223        default:
224            Error(INVALID_KEYWORD_MSG, xf86tokenString ());
225            break;
226        }
227    }
228
229    if (!has_ident)
230        Error(NO_IDENT_MSG, NULL);
231
232#ifdef DEBUG
233    printf("InputClass section parsed\n");
234#endif
235
236    return ptr;
237}
238
239void
240xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
241{
242    const xf86MatchGroup *group;
243    char * const *cur;
244
245    while (ptr) {
246        fprintf(cf, "Section \"InputClass\"\n");
247        if (ptr->comment)
248            fprintf(cf, "%s", ptr->comment);
249        if (ptr->identifier)
250            fprintf(cf, "\tIdentifier      \"%s\"\n", ptr->identifier);
251        if (ptr->driver)
252            fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
253
254        list_for_each_entry(group, &ptr->match_product, entry) {
255            fprintf(cf, "\tMatchProduct    \"");
256            for (cur = group->values; *cur; cur++)
257                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
258                        *cur);
259            fprintf(cf, "\"\n");
260        }
261        list_for_each_entry(group, &ptr->match_vendor, entry) {
262            fprintf(cf, "\tMatchVendor     \"");
263            for (cur = group->values; *cur; cur++)
264                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
265                        *cur);
266            fprintf(cf, "\"\n");
267        }
268        list_for_each_entry(group, &ptr->match_device, entry) {
269            fprintf(cf, "\tMatchDevicePath \"");
270            for (cur = group->values; *cur; cur++)
271                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
272                        *cur);
273            fprintf(cf, "\"\n");
274        }
275        list_for_each_entry(group, &ptr->match_os, entry) {
276            fprintf(cf, "\tMatchOS         \"");
277            for (cur = group->values; *cur; cur++)
278                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
279                        *cur);
280            fprintf(cf, "\"\n");
281        }
282        list_for_each_entry(group, &ptr->match_pnpid, entry) {
283            fprintf(cf, "\tMatchPnPID      \"");
284            for (cur = group->values; *cur; cur++)
285                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
286                        *cur);
287            fprintf(cf, "\"\n");
288        }
289        list_for_each_entry(group, &ptr->match_usbid, entry) {
290            fprintf(cf, "\tMatchUSBID      \"");
291            for (cur = group->values; *cur; cur++)
292                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
293                        *cur);
294            fprintf(cf, "\"\n");
295        }
296        list_for_each_entry(group, &ptr->match_driver, entry) {
297            fprintf(cf, "\tMatchDriver     \"");
298            for (cur = group->values; *cur; cur++)
299                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
300                        *cur);
301            fprintf(cf, "\"\n");
302        }
303        list_for_each_entry(group, &ptr->match_tag, entry) {
304            fprintf(cf, "\tMatchTag        \"");
305            for (cur = group->values; *cur; cur++)
306                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
307                        *cur);
308            fprintf(cf, "\"\n");
309        }
310
311        if (ptr->is_keyboard.set)
312            fprintf(cf, "\tIsKeyboard      \"%s\"\n",
313                    ptr->is_keyboard.val ? "yes" : "no");
314        if (ptr->is_pointer.set)
315            fprintf(cf, "\tIsPointer       \"%s\"\n",
316                    ptr->is_pointer.val ? "yes" : "no");
317        if (ptr->is_joystick.set)
318            fprintf(cf, "\tIsJoystick      \"%s\"\n",
319                    ptr->is_joystick.val ? "yes" : "no");
320        if (ptr->is_tablet.set)
321            fprintf(cf, "\tIsTablet        \"%s\"\n",
322                    ptr->is_tablet.val ? "yes" : "no");
323        if (ptr->is_touchpad.set)
324            fprintf(cf, "\tIsTouchpad      \"%s\"\n",
325                    ptr->is_touchpad.val ? "yes" : "no");
326        if (ptr->is_touchscreen.set)
327            fprintf(cf, "\tIsTouchscreen   \"%s\"\n",
328                    ptr->is_touchscreen.val ? "yes" : "no");
329        xf86printOptionList(cf, ptr->option_lst, 1);
330        fprintf(cf, "EndSection\n\n");
331        ptr = ptr->list.next;
332    }
333}
334
335void
336xf86freeInputClassList (XF86ConfInputClassPtr ptr)
337{
338    XF86ConfInputClassPtr prev;
339
340    while (ptr) {
341        xf86MatchGroup *group, *next;
342        char **list;
343
344        TestFree(ptr->identifier);
345        TestFree(ptr->driver);
346
347        list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
348            list_del(&group->entry);
349            for (list = group->values; *list; list++)
350                free(*list);
351            free(group);
352        }
353        list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
354            list_del(&group->entry);
355            for (list = group->values; *list; list++)
356                free(*list);
357            free(group);
358        }
359        list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
360            list_del(&group->entry);
361            for (list = group->values; *list; list++)
362                free(*list);
363            free(group);
364        }
365        list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
366            list_del(&group->entry);
367            for (list = group->values; *list; list++)
368                free(*list);
369            free(group);
370        }
371        list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
372            list_del(&group->entry);
373            for (list = group->values; *list; list++)
374                free(*list);
375            free(group);
376        }
377        list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
378            list_del(&group->entry);
379            for (list = group->values; *list; list++)
380                free(*list);
381            free(group);
382        }
383        list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
384            list_del(&group->entry);
385            for (list = group->values; *list; list++)
386                free(*list);
387            free(group);
388        }
389        list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
390            list_del(&group->entry);
391            for (list = group->values; *list; list++)
392                free(*list);
393            free(group);
394        }
395
396        TestFree(ptr->comment);
397        xf86optionListFree(ptr->option_lst);
398
399        prev = ptr;
400        ptr = ptr->list.next;
401        free(prev);
402    }
403}
404