1 /*
2  *
3  * Copyright (c) 1997  Metro Link Incorporated
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Except as contained in this notice, the name of the Metro Link shall not be
24  * used in advertising or otherwise to promote the sale, use or other dealings
25  * in this Software without prior written authorization from Metro Link.
26  *
27  */
28 /*
29  * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
30  *
31  * Permission is hereby granted, free of charge, to any person obtaining a
32  * copy of this software and associated documentation files (the "Software"),
33  * to deal in the Software without restriction, including without limitation
34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35  * and/or sell copies of the Software, and to permit persons to whom the
36  * Software is furnished to do so, subject to the following conditions:
37  *
38  * The above copyright notice and this permission notice shall be included in
39  * all copies or substantial portions of the Software.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
45  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
46  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
47  * OTHER DEALINGS IN THE SOFTWARE.
48  *
49  * Except as contained in this notice, the name of the copyright holder(s)
50  * and author(s) shall not be used in advertising or otherwise to promote
51  * the sale, use or other dealings in this Software without prior written
52  * authorization from the copyright holder(s) and author(s).
53  */
54 
55 #ifdef HAVE_XORG_CONFIG_H
56 #include <xorg-config.h>
57 #endif
58 
59 #include "xf86Parser.h"
60 #include "xf86tokens.h"
61 #include "Configint.h"
62 #include <string.h>
63 #include "optionstr.h"
64 
65 /* Needed for auto server layout */
66 extern int xf86CheckBoolOption(void *optlist, const char *name, int deflt);
67 
68 
69 static const xf86ConfigSymTabRec LayoutTab[] = {
70     {ENDSECTION, "endsection"},
71     {SCREEN, "screen"},
72     {IDENTIFIER, "identifier"},
73     {MATCHSEAT, "matchseat"},
74     {INACTIVE, "inactive"},
75     {INPUTDEVICE, "inputdevice"},
76     {OPTION, "option"},
77     {-1, ""},
78 };
79 
80 static const xf86ConfigSymTabRec AdjTab[] = {
81     {RIGHTOF, "rightof"},
82     {LEFTOF, "leftof"},
83     {ABOVE, "above"},
84     {BELOW, "below"},
85     {RELATIVE, "relative"},
86     {ABSOLUTE, "absolute"},
87     {-1, ""},
88 };
89 
90 #define CLEANUP xf86freeLayoutList
91 
92 XF86ConfLayoutPtr
xf86parseLayoutSection(void)93 xf86parseLayoutSection(void)
94 {
95     int has_ident = FALSE;
96     int token;
97 
98     parsePrologue(XF86ConfLayoutPtr, XF86ConfLayoutRec)
99 
100         while ((token = xf86getToken(LayoutTab)) != ENDSECTION) {
101         switch (token) {
102         case COMMENT:
103             ptr->lay_comment = xf86addComment(ptr->lay_comment, xf86_lex_val.str);
104             break;
105         case IDENTIFIER:
106             if (xf86getSubToken(&(ptr->lay_comment)) != STRING)
107                 Error(QUOTE_MSG, "Identifier");
108             if (has_ident == TRUE)
109                 Error(MULTIPLE_MSG, "Identifier");
110             ptr->lay_identifier = xf86_lex_val.str;
111             has_ident = TRUE;
112             break;
113         case MATCHSEAT:
114             if (xf86getSubToken(&(ptr->lay_comment)) != STRING)
115                 Error(QUOTE_MSG, "MatchSeat");
116             ptr->match_seat = xf86_lex_val.str;
117             break;
118         case INACTIVE:
119         {
120             XF86ConfInactivePtr iptr;
121 
122             iptr = calloc(1, sizeof(XF86ConfInactiveRec));
123             iptr->list.next = NULL;
124             if (xf86getSubToken(&(ptr->lay_comment)) != STRING) {
125                 free(iptr);
126                 Error(INACTIVE_MSG);
127             }
128             iptr->inactive_device_str = xf86_lex_val.str;
129             ptr->lay_inactive_lst = (XF86ConfInactivePtr)
130                 xf86addListItem((glp) ptr->lay_inactive_lst, (glp) iptr);
131         }
132             break;
133         case SCREEN:
134         {
135             XF86ConfAdjacencyPtr aptr;
136             int absKeyword = 0;
137 
138             aptr = calloc(1, sizeof(XF86ConfAdjacencyRec));
139             aptr->list.next = NULL;
140             aptr->adj_scrnum = -1;
141             aptr->adj_where = CONF_ADJ_OBSOLETE;
142             aptr->adj_x = 0;
143             aptr->adj_y = 0;
144             aptr->adj_refscreen = NULL;
145             if ((token = xf86getSubToken(&(ptr->lay_comment))) == NUMBER)
146                 aptr->adj_scrnum = xf86_lex_val.num;
147             else
148                 xf86unGetToken(token);
149             token = xf86getSubToken(&(ptr->lay_comment));
150             if (token != STRING) {
151                 free(aptr);
152                 Error(SCREEN_MSG);
153             }
154             aptr->adj_screen_str = xf86_lex_val.str;
155 
156             token = xf86getSubTokenWithTab(&(ptr->lay_comment), AdjTab);
157             switch (token) {
158             case RIGHTOF:
159                 aptr->adj_where = CONF_ADJ_RIGHTOF;
160                 break;
161             case LEFTOF:
162                 aptr->adj_where = CONF_ADJ_LEFTOF;
163                 break;
164             case ABOVE:
165                 aptr->adj_where = CONF_ADJ_ABOVE;
166                 break;
167             case BELOW:
168                 aptr->adj_where = CONF_ADJ_BELOW;
169                 break;
170             case RELATIVE:
171                 aptr->adj_where = CONF_ADJ_RELATIVE;
172                 break;
173             case ABSOLUTE:
174                 aptr->adj_where = CONF_ADJ_ABSOLUTE;
175                 absKeyword = 1;
176                 break;
177             case EOF_TOKEN:
178                 free(aptr);
179                 Error(UNEXPECTED_EOF_MSG);
180                 break;
181             default:
182                 xf86unGetToken(token);
183                 token = xf86getSubToken(&(ptr->lay_comment));
184                 if (token == STRING)
185                     aptr->adj_where = CONF_ADJ_OBSOLETE;
186                 else
187                     aptr->adj_where = CONF_ADJ_ABSOLUTE;
188             }
189             switch (aptr->adj_where) {
190             case CONF_ADJ_ABSOLUTE:
191                 if (absKeyword)
192                     token = xf86getSubToken(&(ptr->lay_comment));
193                 if (token == NUMBER) {
194                     aptr->adj_x = xf86_lex_val.num;
195                     token = xf86getSubToken(&(ptr->lay_comment));
196                     if (token != NUMBER) {
197                         free(aptr);
198                         Error(INVALID_SCR_MSG);
199                     }
200                     aptr->adj_y = xf86_lex_val.num;
201                 }
202                 else {
203                     if (absKeyword) {
204                         free(aptr);
205                         Error(INVALID_SCR_MSG);
206                     }
207                     else
208                         xf86unGetToken(token);
209                 }
210                 break;
211             case CONF_ADJ_RIGHTOF:
212             case CONF_ADJ_LEFTOF:
213             case CONF_ADJ_ABOVE:
214             case CONF_ADJ_BELOW:
215             case CONF_ADJ_RELATIVE:
216                 token = xf86getSubToken(&(ptr->lay_comment));
217                 if (token != STRING) {
218                     free(aptr);
219                     Error(INVALID_SCR_MSG);
220                 }
221                 aptr->adj_refscreen = xf86_lex_val.str;
222                 if (aptr->adj_where == CONF_ADJ_RELATIVE) {
223                     token = xf86getSubToken(&(ptr->lay_comment));
224                     if (token != NUMBER) {
225                         free(aptr);
226                         Error(INVALID_SCR_MSG);
227                     }
228                     aptr->adj_x = xf86_lex_val.num;
229                     token = xf86getSubToken(&(ptr->lay_comment));
230                     if (token != NUMBER) {
231                         free(aptr);
232                         Error(INVALID_SCR_MSG);
233                     }
234                     aptr->adj_y = xf86_lex_val.num;
235                 }
236                 break;
237             case CONF_ADJ_OBSOLETE:
238                 /* top */
239                 aptr->adj_top_str = xf86_lex_val.str;
240 
241                 /* bottom */
242                 if (xf86getSubToken(&(ptr->lay_comment)) != STRING) {
243                     free(aptr);
244                     Error(SCREEN_MSG);
245                 }
246                 aptr->adj_bottom_str = xf86_lex_val.str;
247 
248                 /* left */
249                 if (xf86getSubToken(&(ptr->lay_comment)) != STRING) {
250                     free(aptr);
251                     Error(SCREEN_MSG);
252                 }
253                 aptr->adj_left_str = xf86_lex_val.str;
254 
255                 /* right */
256                 if (xf86getSubToken(&(ptr->lay_comment)) != STRING) {
257                     free(aptr);
258                     Error(SCREEN_MSG);
259                 }
260                 aptr->adj_right_str = xf86_lex_val.str;
261 
262             }
263             ptr->lay_adjacency_lst = (XF86ConfAdjacencyPtr)
264                 xf86addListItem((glp) ptr->lay_adjacency_lst, (glp) aptr);
265         }
266             break;
267         case INPUTDEVICE:
268         {
269             XF86ConfInputrefPtr iptr;
270 
271             iptr = calloc(1, sizeof(XF86ConfInputrefRec));
272             iptr->list.next = NULL;
273             iptr->iref_option_lst = NULL;
274             if (xf86getSubToken(&(ptr->lay_comment)) != STRING) {
275                 free(iptr);
276                 Error(INPUTDEV_MSG);
277             }
278             iptr->iref_inputdev_str = xf86_lex_val.str;
279             while ((token = xf86getSubToken(&(ptr->lay_comment))) == STRING) {
280                 iptr->iref_option_lst =
281                     xf86addNewOption(iptr->iref_option_lst, xf86_lex_val.str, NULL);
282             }
283             xf86unGetToken(token);
284             ptr->lay_input_lst = (XF86ConfInputrefPtr)
285                 xf86addListItem((glp) ptr->lay_input_lst, (glp) iptr);
286         }
287             break;
288         case OPTION:
289             ptr->lay_option_lst = xf86parseOption(ptr->lay_option_lst);
290             break;
291         case EOF_TOKEN:
292             Error(UNEXPECTED_EOF_MSG);
293             break;
294         default:
295             Error(INVALID_KEYWORD_MSG, xf86tokenString());
296             break;
297         }
298     }
299 
300     if (!has_ident)
301         Error(NO_IDENT_MSG);
302 
303 #ifdef DEBUG
304     printf("Layout section parsed\n");
305 #endif
306 
307     return ptr;
308 }
309 
310 #undef CLEANUP
311 
312 void
xf86printLayoutSection(FILE * cf,XF86ConfLayoutPtr ptr)313 xf86printLayoutSection(FILE * cf, XF86ConfLayoutPtr ptr)
314 {
315     XF86ConfAdjacencyPtr aptr;
316     XF86ConfInactivePtr iptr;
317     XF86ConfInputrefPtr inptr;
318     XF86OptionPtr optr;
319 
320     while (ptr) {
321         fprintf(cf, "Section \"ServerLayout\"\n");
322         if (ptr->lay_comment)
323             fprintf(cf, "%s", ptr->lay_comment);
324         if (ptr->lay_identifier)
325             fprintf(cf, "\tIdentifier     \"%s\"\n", ptr->lay_identifier);
326 
327         for (aptr = ptr->lay_adjacency_lst; aptr; aptr = aptr->list.next) {
328             fprintf(cf, "\tScreen     ");
329             if (aptr->adj_scrnum >= 0)
330                 fprintf(cf, "%2d", aptr->adj_scrnum);
331             else
332                 fprintf(cf, "  ");
333             fprintf(cf, "  \"%s\"", aptr->adj_screen_str);
334             switch (aptr->adj_where) {
335             case CONF_ADJ_OBSOLETE:
336                 fprintf(cf, " \"%s\"", aptr->adj_top_str);
337                 fprintf(cf, " \"%s\"", aptr->adj_bottom_str);
338                 fprintf(cf, " \"%s\"", aptr->adj_right_str);
339                 fprintf(cf, " \"%s\"\n", aptr->adj_left_str);
340                 break;
341             case CONF_ADJ_ABSOLUTE:
342                 if (aptr->adj_x != -1)
343                     fprintf(cf, " %d %d\n", aptr->adj_x, aptr->adj_y);
344                 else
345                     fprintf(cf, "\n");
346                 break;
347             case CONF_ADJ_RIGHTOF:
348                 fprintf(cf, " RightOf \"%s\"\n", aptr->adj_refscreen);
349                 break;
350             case CONF_ADJ_LEFTOF:
351                 fprintf(cf, " LeftOf \"%s\"\n", aptr->adj_refscreen);
352                 break;
353             case CONF_ADJ_ABOVE:
354                 fprintf(cf, " Above \"%s\"\n", aptr->adj_refscreen);
355                 break;
356             case CONF_ADJ_BELOW:
357                 fprintf(cf, " Below \"%s\"\n", aptr->adj_refscreen);
358                 break;
359             case CONF_ADJ_RELATIVE:
360                 fprintf(cf, " Relative \"%s\" %d %d\n", aptr->adj_refscreen,
361                         aptr->adj_x, aptr->adj_y);
362                 break;
363             }
364         }
365         for (iptr = ptr->lay_inactive_lst; iptr; iptr = iptr->list.next)
366             fprintf(cf, "\tInactive       \"%s\"\n", iptr->inactive_device_str);
367         for (inptr = ptr->lay_input_lst; inptr; inptr = inptr->list.next) {
368             fprintf(cf, "\tInputDevice    \"%s\"", inptr->iref_inputdev_str);
369             for (optr = inptr->iref_option_lst; optr; optr = optr->list.next) {
370                 fprintf(cf, " \"%s\"", optr->opt_name);
371             }
372             fprintf(cf, "\n");
373         }
374         xf86printOptionList(cf, ptr->lay_option_lst, 1);
375         fprintf(cf, "EndSection\n\n");
376         ptr = ptr->list.next;
377     }
378 }
379 
380 static void
xf86freeAdjacencyList(XF86ConfAdjacencyPtr ptr)381 xf86freeAdjacencyList(XF86ConfAdjacencyPtr ptr)
382 {
383     XF86ConfAdjacencyPtr prev;
384 
385     while (ptr) {
386         TestFree(ptr->adj_screen_str);
387         TestFree(ptr->adj_top_str);
388         TestFree(ptr->adj_bottom_str);
389         TestFree(ptr->adj_left_str);
390         TestFree(ptr->adj_right_str);
391 
392         prev = ptr;
393         ptr = ptr->list.next;
394         free(prev);
395     }
396 
397 }
398 
399 static void
xf86freeInputrefList(XF86ConfInputrefPtr ptr)400 xf86freeInputrefList(XF86ConfInputrefPtr ptr)
401 {
402     XF86ConfInputrefPtr prev;
403 
404     while (ptr) {
405         TestFree(ptr->iref_inputdev_str);
406         xf86optionListFree(ptr->iref_option_lst);
407         prev = ptr;
408         ptr = ptr->list.next;
409         free(prev);
410     }
411 
412 }
413 
414 void
xf86freeLayoutList(XF86ConfLayoutPtr ptr)415 xf86freeLayoutList(XF86ConfLayoutPtr ptr)
416 {
417     XF86ConfLayoutPtr prev;
418 
419     while (ptr) {
420         TestFree(ptr->lay_identifier);
421         TestFree(ptr->lay_comment);
422         xf86freeAdjacencyList(ptr->lay_adjacency_lst);
423         xf86freeInputrefList(ptr->lay_input_lst);
424         prev = ptr;
425         ptr = ptr->list.next;
426         free(prev);
427     }
428 }
429 
430 int
xf86layoutAddInputDevices(XF86ConfigPtr config,XF86ConfLayoutPtr layout)431 xf86layoutAddInputDevices(XF86ConfigPtr config, XF86ConfLayoutPtr layout)
432 {
433     int count = 0;
434     XF86ConfInputPtr input = config->conf_input_lst;
435     XF86ConfInputrefPtr inptr;
436 
437     /* add all AutoServerLayout devices to the server layout */
438     while (input) {
439         if (xf86CheckBoolOption
440             (input->inp_option_lst, "AutoServerLayout", FALSE)) {
441             XF86ConfInputrefPtr iref = layout->lay_input_lst;
442 
443             /* avoid duplicates if referenced but lists AutoServerLayout too */
444             while (iref) {
445                 if (strcmp(iref->iref_inputdev_str, input->inp_identifier) == 0)
446                     break;
447                 iref = iref->list.next;
448             }
449 
450             if (!iref) {
451                 XF86ConfInputrefPtr iptr;
452 
453                 iptr = calloc(1, sizeof(XF86ConfInputrefRec));
454                 iptr->iref_inputdev_str = input->inp_identifier;
455                 layout->lay_input_lst = (XF86ConfInputrefPtr)
456                     xf86addListItem((glp) layout->lay_input_lst, (glp) iptr);
457                 count++;
458             }
459         }
460         input = input->list.next;
461     }
462 
463     inptr = layout->lay_input_lst;
464     while (inptr) {
465         input = xf86findInput(inptr->iref_inputdev_str, config->conf_input_lst);
466         if (!input) {
467             xf86validationError(UNDEFINED_INPUT_MSG,
468                                 inptr->iref_inputdev_str,
469                                 layout->lay_identifier);
470             return -1;
471         }
472         else
473             inptr->iref_inputdev = input;
474         inptr = inptr->list.next;
475     }
476 
477     return count;
478 }
479 
480 int
xf86validateLayout(XF86ConfigPtr p)481 xf86validateLayout(XF86ConfigPtr p)
482 {
483     XF86ConfLayoutPtr layout = p->conf_layout_lst;
484     XF86ConfAdjacencyPtr adj;
485     XF86ConfInactivePtr iptr;
486     XF86ConfScreenPtr screen;
487     XF86ConfDevicePtr device;
488 
489     while (layout) {
490         adj = layout->lay_adjacency_lst;
491         while (adj) {
492             /* the first one can't be "" but all others can */
493             screen = xf86findScreen(adj->adj_screen_str, p->conf_screen_lst);
494             if (!screen) {
495                 xf86validationError(UNDEFINED_SCREEN_MSG,
496                                     adj->adj_screen_str,
497                                     layout->lay_identifier);
498                 return FALSE;
499             }
500             else
501                 adj->adj_screen = screen;
502 
503             adj = adj->list.next;
504         }
505         iptr = layout->lay_inactive_lst;
506         while (iptr) {
507             device = xf86findDevice(iptr->inactive_device_str,
508                                     p->conf_device_lst);
509             if (!device) {
510                 xf86validationError(UNDEFINED_DEVICE_LAY_MSG,
511                                     iptr->inactive_device_str,
512                                     layout->lay_identifier);
513                 return FALSE;
514             }
515             else
516                 iptr->inactive_device = device;
517             iptr = iptr->list.next;
518         }
519 
520         if (xf86layoutAddInputDevices(p, layout) == -1)
521             return FALSE;
522 
523         layout = layout->list.next;
524     }
525     return TRUE;
526 }
527 
528 XF86ConfLayoutPtr
xf86findLayout(const char * name,XF86ConfLayoutPtr list)529 xf86findLayout(const char *name, XF86ConfLayoutPtr list)
530 {
531     while (list) {
532         if (xf86nameCompare(list->lay_identifier, name) == 0)
533             return list;
534         list = list->list.next;
535     }
536     return NULL;
537 }
538