xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/parser/scan.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 1997  Metro Link Incorporated
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  * Except as contained in this notice, the name of the Metro Link shall not be
23  * used in advertising or otherwise to promote the sale, use or other dealings
24  * in this Software without prior written authorization from Metro Link.
25  *
26  */
27 /*
28  * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
29  *
30  * Permission is hereby granted, free of charge, to any person obtaining a
31  * copy of this software and associated documentation files (the "Software"),
32  * to deal in the Software without restriction, including without limitation
33  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34  * and/or sell copies of the Software, and to permit persons to whom the
35  * Software is furnished to do so, subject to the following conditions:
36  *
37  * The above copyright notice and this permission notice shall be included in
38  * all copies or substantial portions of the Software.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
43  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
44  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
45  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
46  * OTHER DEALINGS IN THE SOFTWARE.
47  *
48  * Except as contained in this notice, the name of the copyright holder(s)
49  * and author(s) shall not be used in advertising or otherwise to promote
50  * the sale, use or other dealings in this Software without prior written
51  * authorization from the copyright holder(s) and author(s).
52  */
53 
54 #ifdef HAVE_XORG_CONFIG_H
55 #include <xorg-config.h>
56 #endif
57 
58 #include <ctype.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <sys/types.h>
63 #include <dirent.h>
64 #include <unistd.h>
65 #include <stdarg.h>
66 #include <X11/Xdefs.h>
67 #include <X11/Xfuncproto.h>
68 #include <limits.h>
69 
70 #if !defined(MAXHOSTNAMELEN)
71 #define MAXHOSTNAMELEN 32
72 #endif                          /* !MAXHOSTNAMELEN */
73 
74 /* For PATH_MAX */
75 #include "misc.h"
76 
77 #include "Configint.h"
78 #include "xf86tokens.h"
79 
80 #define CONFIG_BUF_LEN     1024
81 #define CONFIG_MAX_FILES   64
82 
83 static struct {
84     FILE *file;
85     char *path;
86 } configFiles[CONFIG_MAX_FILES];
87 static const char **builtinConfig = NULL;
88 static int builtinIndex = 0;
89 static int configPos = 0;       /* current readers position */
90 static int configLineNo = 0;    /* linenumber */
91 static char *configBuf, *configRBuf;    /* buffer for lines */
92 static char *configSection = NULL;      /* name of current section being parsed */
93 static int numFiles = 0;        /* number of config files */
94 static int curFileIndex = 0;    /* index of current config file */
95 static int pushToken = LOCK_TOKEN;
96 static int eol_seen = 0;        /* private state to handle comments */
97 LexRec xf86_lex_val;
98 
99 /*
100  * xf86getNextLine --
101  *
102  *  read from the configFiles FILE stream until we encounter a new
103  *  line; this is effectively just a big wrapper for fgets(3).
104  *
105  *  xf86getToken() assumes that we will read up to the next
106  *  newline; we need to grow configBuf and configRBuf as needed to
107  *  support that.
108  */
109 
110 static char *
xf86getNextLine(void)111 xf86getNextLine(void)
112 {
113     static int configBufLen = CONFIG_BUF_LEN;
114     char *tmpConfigBuf, *tmpConfigRBuf;
115     int c, i, pos = 0, eolFound = 0;
116     char *ret = NULL;
117 
118     /*
119      * reallocate the string if it was grown last time (i.e., is no
120      * longer CONFIG_BUF_LEN); we malloc the new strings first, so
121      * that if either of the mallocs fail, we can fall back on the
122      * existing buffer allocations
123      */
124 
125     if (configBufLen != CONFIG_BUF_LEN) {
126 
127         tmpConfigBuf = malloc(CONFIG_BUF_LEN);
128         tmpConfigRBuf = malloc(CONFIG_BUF_LEN);
129 
130         if (!tmpConfigBuf || !tmpConfigRBuf) {
131 
132             /*
133              * at least one of the mallocs failed; keep the old buffers
134              * and free any partial allocations
135              */
136 
137             free(tmpConfigBuf);
138             free(tmpConfigRBuf);
139 
140         }
141         else {
142 
143             /*
144              * malloc succeeded; free the old buffers and use the new
145              * buffers
146              */
147 
148             configBufLen = CONFIG_BUF_LEN;
149 
150             free(configBuf);
151             free(configRBuf);
152 
153             configBuf = tmpConfigBuf;
154             configRBuf = tmpConfigRBuf;
155         }
156     }
157 
158     /* read in another block of chars */
159 
160     do {
161         ret = fgets(configBuf + pos, configBufLen - pos - 1,
162                     configFiles[curFileIndex].file);
163 
164         if (!ret) {
165             /*
166              * if the file doesn't end in a newline, add one
167              * and trigger another read
168              */
169             if (pos != 0) {
170                 strcpy(&configBuf[pos], "\n");
171                 ret = configBuf;
172             }
173             else
174                 break;
175         }
176 
177         /* search for EOL in the new block of chars */
178 
179         for (i = pos; i < (configBufLen - 1); i++) {
180             c = configBuf[i];
181 
182             if (c == '\0')
183                 break;
184 
185             if ((c == '\n') || (c == '\r')) {
186                 eolFound = 1;
187                 break;
188             }
189         }
190 
191         /*
192          * if we didn't find EOL, then grow the string and
193          * read in more
194          */
195 
196         if (!eolFound) {
197 
198             tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN);
199             tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN);
200 
201             if (!tmpConfigBuf || !tmpConfigRBuf) {
202 
203                 /*
204                  * at least one of the reallocations failed; use the
205                  * new allocation that succeeded, but we have to
206                  * fallback to the previous configBufLen size and use
207                  * the string we have, even though we don't have an
208                  * EOL
209                  */
210 
211                 if (tmpConfigBuf)
212                     configBuf = tmpConfigBuf;
213                 if (tmpConfigRBuf)
214                     configRBuf = tmpConfigRBuf;
215 
216                 break;
217 
218             }
219             else {
220 
221                 /* reallocation succeeded */
222 
223                 configBuf = tmpConfigBuf;
224                 configRBuf = tmpConfigRBuf;
225                 pos = i;
226                 configBufLen += CONFIG_BUF_LEN;
227             }
228         }
229 
230     } while (!eolFound);
231 
232     return ret;
233 }
234 
235 static int
StringToToken(const char * str,const xf86ConfigSymTabRec * tab)236 StringToToken(const char *str, const xf86ConfigSymTabRec * tab)
237 {
238     int i;
239 
240     for (i = 0; tab[i].token != -1; i++) {
241         if (!xf86nameCompare(tab[i].name, str))
242             return tab[i].token;
243     }
244     return ERROR_TOKEN;
245 }
246 
247 /*
248  * xf86getToken --
249  *      Read next Token from the config file. Handle the global variable
250  *      pushToken.
251  */
252 int
xf86getToken(const xf86ConfigSymTabRec * tab)253 xf86getToken(const xf86ConfigSymTabRec * tab)
254 {
255     int c, i;
256 
257     /*
258      * First check whether pushToken has a different value than LOCK_TOKEN.
259      * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
260      * oth * case the next token must be read from the input.
261      */
262     if (pushToken == EOF_TOKEN)
263         return EOF_TOKEN;
264     else if (pushToken == LOCK_TOKEN) {
265         /*
266          * eol_seen is only set for the first token after a newline.
267          */
268         eol_seen = 0;
269 
270         c = configBuf[configPos];
271 
272         /*
273          * Get start of next Token. EOF is handled,
274          * whitespaces are skipped.
275          */
276 
277  again:
278         if (!c) {
279             char *ret;
280 
281             if (numFiles > 0)
282                 ret = xf86getNextLine();
283             else {
284                 if (builtinConfig[builtinIndex] == NULL)
285                     ret = NULL;
286                 else {
287                     strlcpy(configBuf,
288                             builtinConfig[builtinIndex], CONFIG_BUF_LEN);
289                     ret = configBuf;
290                     builtinIndex++;
291                 }
292             }
293             if (ret == NULL) {
294                 /*
295                  * if necessary, move to the next file and
296                  * read the first line
297                  */
298                 if (curFileIndex + 1 < numFiles) {
299                     curFileIndex++;
300                     configLineNo = 0;
301                     goto again;
302                 }
303                 else
304                     return pushToken = EOF_TOKEN;
305             }
306             configLineNo++;
307             configPos = 0;
308             eol_seen = 1;
309         }
310 
311         i = 0;
312         for (;;) {
313             c = configBuf[configPos++];
314             configRBuf[i++] = c;
315             switch (c) {
316             case ' ':
317             case '\t':
318             case '\r':
319                 continue;
320             case '\n':
321                 i = 0;
322                 continue;
323             }
324             break;
325         }
326         if (c == '\0')
327             goto again;
328 
329         if (c == '#') {
330             do {
331                 configRBuf[i++] = (c = configBuf[configPos++]);
332             }
333             while ((c != '\n') && (c != '\r') && (c != '\0'));
334             configRBuf[i] = '\0';
335             /* XXX no private copy.
336              * Use xf86addComment when setting a comment.
337              */
338             xf86_lex_val.str = configRBuf;
339             return COMMENT;
340         }
341 
342         /* GJA -- handle '-' and ','  * Be careful: "-hsync" is a keyword. */
343         else if ((c == ',') && !isalpha(configBuf[configPos])) {
344             return COMMA;
345         }
346         else if ((c == '-') && !isalpha(configBuf[configPos])) {
347             return DASH;
348         }
349 
350         /*
351          * Numbers are returned immediately ...
352          */
353         if (isdigit(c)) {
354             int base;
355 
356             if (c == '0')
357                 if ((configBuf[configPos] == 'x') ||
358                     (configBuf[configPos] == 'X')) {
359                     base = 16;
360                     xf86_lex_val.numType = PARSE_HEX;
361                 }
362                 else {
363                     base = 8;
364                     xf86_lex_val.numType = PARSE_OCTAL;
365                 }
366             else {
367                 base = 10;
368                 xf86_lex_val.numType = PARSE_DECIMAL;
369             }
370 
371             configRBuf[0] = c;
372             i = 1;
373             while (isdigit(c = configBuf[configPos++]) ||
374                    (c == '.') || (c == 'x') || (c == 'X') ||
375                    ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
376                                      ((c >= 'A') && (c <= 'F')))))
377                 configRBuf[i++] = c;
378             configPos--;        /* GJA -- one too far */
379             configRBuf[i] = '\0';
380             xf86_lex_val.num = strtoul(configRBuf, NULL, 0);
381             xf86_lex_val.realnum = atof(configRBuf);
382             return NUMBER;
383         }
384 
385         /*
386          * All Strings START with a \" ...
387          */
388         else if (c == '\"') {
389             i = -1;
390             do {
391                 configRBuf[++i] = (c = configBuf[configPos++]);
392             }
393             while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
394             configRBuf[i] = '\0';
395             xf86_lex_val.str = malloc(strlen(configRBuf) + 1);
396             strcpy(xf86_lex_val.str, configRBuf);        /* private copy ! */
397             return STRING;
398         }
399 
400         /*
401          * ... and now we MUST have a valid token.  The search is
402          * handled later along with the pushed tokens.
403          */
404         else {
405             configRBuf[0] = c;
406             i = 0;
407             do {
408                 configRBuf[++i] = (c = configBuf[configPos++]);
409             }
410             while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') &&
411                    (c != '\0') && (c != '#'));
412             --configPos;
413             configRBuf[i] = '\0';
414             i = 0;
415         }
416 
417     }
418     else {
419 
420         /*
421          * Here we deal with pushed tokens. Reinitialize pushToken again. If
422          * the pushed token was NUMBER || STRING return them again ...
423          */
424         int temp = pushToken;
425 
426         pushToken = LOCK_TOKEN;
427 
428         if (temp == COMMA || temp == DASH)
429             return temp;
430         if (temp == NUMBER || temp == STRING)
431             return temp;
432     }
433 
434     /*
435      * Joop, at last we have to lookup the token ...
436      */
437     if (tab)
438         return StringToToken(configRBuf, tab);
439 
440     return ERROR_TOKEN;         /* Error catcher */
441 }
442 
443 int
xf86getSubToken(char ** comment)444 xf86getSubToken(char **comment)
445 {
446     int token;
447 
448     for (;;) {
449         token = xf86getToken(NULL);
450         if (token == COMMENT) {
451             if (comment)
452                 *comment = xf86addComment(*comment, xf86_lex_val.str);
453         }
454         else
455             return token;
456     }
457  /*NOTREACHED*/}
458 
459 int
xf86getSubTokenWithTab(char ** comment,const xf86ConfigSymTabRec * tab)460 xf86getSubTokenWithTab(char **comment, const xf86ConfigSymTabRec * tab)
461 {
462     int token;
463 
464     for (;;) {
465         token = xf86getToken(tab);
466         if (token == COMMENT) {
467             if (comment)
468                 *comment = xf86addComment(*comment, xf86_lex_val.str);
469         }
470         else
471             return token;
472     }
473  /*NOTREACHED*/}
474 
475 void
xf86unGetToken(int token)476 xf86unGetToken(int token)
477 {
478     pushToken = token;
479 }
480 
481 char *
xf86tokenString(void)482 xf86tokenString(void)
483 {
484     return configRBuf;
485 }
486 
487 int
xf86pathIsAbsolute(const char * path)488 xf86pathIsAbsolute(const char *path)
489 {
490     if (path && path[0] == '/')
491         return 1;
492     return 0;
493 }
494 
495 /* A path is "safe" if it is relative and if it contains no ".." elements. */
496 int
xf86pathIsSafe(const char * path)497 xf86pathIsSafe(const char *path)
498 {
499     if (xf86pathIsAbsolute(path))
500         return 0;
501 
502     /* Compare with ".." */
503     if (!strcmp(path, ".."))
504         return 0;
505 
506     /* Look for leading "../" */
507     if (!strncmp(path, "../", 3))
508         return 0;
509 
510     /* Look for trailing "/.." */
511     if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
512         return 0;
513 
514     /* Look for "/../" */
515     if (strstr(path, "/../"))
516         return 0;
517 
518     return 1;
519 }
520 
521 /*
522  * This function substitutes the following escape sequences:
523  *
524  *    %A    cmdline argument as an absolute path (must be absolute to match)
525  *    %R    cmdline argument as a relative path
526  *    %S    cmdline argument as a "safe" path (relative, and no ".." elements)
527  *    %X    default config file name ("xorg.conf")
528  *    %H    hostname
529  *    %E    config file environment ($XORGCONFIG) as an absolute path
530  *    %F    config file environment ($XORGCONFIG) as a relative path
531  *    %G    config file environment ($XORGCONFIG) as a safe path
532  *    %P    projroot
533  *    %C    sysconfdir
534  *    %D    datadir
535  *    %%    %
536  */
537 
538 #define XCONFIGSUFFIX	".conf"
539 #define XCONFENV	"XORGCONFIG"
540 
541 #define BAIL_OUT		do {									\
542 							free(result);				\
543 							return NULL;						\
544 						} while (0)
545 
546 #define CHECK_LENGTH	do {									\
547 							if (l > PATH_MAX) {					\
548 								BAIL_OUT;						\
549 							}									\
550 						} while (0)
551 
552 #define APPEND_STR(s)	do {									\
553 							if (strlen(s) + l > PATH_MAX) {		\
554 								BAIL_OUT;						\
555 							} else {							\
556 								strcpy(result + l, s);			\
557 								l += strlen(s);					\
558 							}									\
559 						} while (0)
560 
561 static char *
DoSubstitution(const char * template,const char * cmdline,const char * projroot,int * cmdlineUsed,int * envUsed,const char * XConfigFile)562 DoSubstitution(const char *template, const char *cmdline, const char *projroot,
563                int *cmdlineUsed, int *envUsed, const char *XConfigFile)
564 {
565     char *result;
566     int i, l;
567     static const char *env = NULL;
568     static char *hostname = NULL;
569 
570     if (!template)
571         return NULL;
572 
573     if (cmdlineUsed)
574         *cmdlineUsed = 0;
575     if (envUsed)
576         *envUsed = 0;
577 
578     result = malloc(PATH_MAX + 1);
579     l = 0;
580     for (i = 0; template[i]; i++) {
581         if (template[i] != '%') {
582             result[l++] = template[i];
583             CHECK_LENGTH;
584         }
585         else {
586             switch (template[++i]) {
587             case 'A':
588                 if (cmdline && xf86pathIsAbsolute(cmdline)) {
589                     APPEND_STR(cmdline);
590                     if (cmdlineUsed)
591                         *cmdlineUsed = 1;
592                 }
593                 else
594                     BAIL_OUT;
595                 break;
596             case 'R':
597                 if (cmdline && !xf86pathIsAbsolute(cmdline)) {
598                     APPEND_STR(cmdline);
599                     if (cmdlineUsed)
600                         *cmdlineUsed = 1;
601                 }
602                 else
603                     BAIL_OUT;
604                 break;
605             case 'S':
606                 if (cmdline && xf86pathIsSafe(cmdline)) {
607                     APPEND_STR(cmdline);
608                     if (cmdlineUsed)
609                         *cmdlineUsed = 1;
610                 }
611                 else
612                     BAIL_OUT;
613                 break;
614             case 'X':
615                 APPEND_STR(XConfigFile);
616                 break;
617             case 'H':
618                 if (!hostname) {
619                     if ((hostname = malloc(MAXHOSTNAMELEN + 1))) {
620                         if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
621                             hostname[MAXHOSTNAMELEN] = '\0';
622                         }
623                         else {
624                             free(hostname);
625                             hostname = NULL;
626                         }
627                     }
628                 }
629                 if (hostname)
630                     APPEND_STR(hostname);
631                 break;
632             case 'E':
633                 if (!env)
634                     env = getenv(XCONFENV);
635                 if (env && xf86pathIsAbsolute(env)) {
636                     APPEND_STR(env);
637                     if (envUsed)
638                         *envUsed = 1;
639                 }
640                 else
641                     BAIL_OUT;
642                 break;
643             case 'F':
644                 if (!env)
645                     env = getenv(XCONFENV);
646                 if (env && !xf86pathIsAbsolute(env)) {
647                     APPEND_STR(env);
648                     if (envUsed)
649                         *envUsed = 1;
650                 }
651                 else
652                     BAIL_OUT;
653                 break;
654             case 'G':
655                 if (!env)
656                     env = getenv(XCONFENV);
657                 if (env && xf86pathIsSafe(env)) {
658                     APPEND_STR(env);
659                     if (envUsed)
660                         *envUsed = 1;
661                 }
662                 else
663                     BAIL_OUT;
664                 break;
665             case 'P':
666                 if (projroot && xf86pathIsAbsolute(projroot))
667                     APPEND_STR(projroot);
668                 else
669                     BAIL_OUT;
670                 break;
671             case 'C':
672                 APPEND_STR(SYSCONFDIR);
673                 break;
674             case 'D':
675                 APPEND_STR(DATADIR);
676                 break;
677             case '%':
678                 result[l++] = '%';
679                 CHECK_LENGTH;
680                 break;
681             default:
682                 fprintf(stderr, "invalid escape %%%c found in path template\n",
683                         template[i]);
684                 BAIL_OUT;
685                 break;
686             }
687         }
688     }
689 #ifdef DEBUG
690     fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
691 #endif
692     return result;
693 }
694 
695 /*
696  * Given some searching parameters, locate and open the xorg config file.
697  */
698 static char *
OpenConfigFile(const char * path,const char * cmdline,const char * projroot,const char * confname)699 OpenConfigFile(const char *path, const char *cmdline, const char *projroot,
700                const char *confname)
701 {
702     char *filepath = NULL;
703     char *pathcopy;
704     const char *template;
705     int cmdlineUsed = 0;
706     FILE *file = NULL;
707 
708     pathcopy = strdup(path);
709     for (template = strtok(pathcopy, ","); template && !file;
710          template = strtok(NULL, ",")) {
711         filepath = DoSubstitution(template, cmdline, projroot,
712                                   &cmdlineUsed, NULL, confname);
713         if (!filepath)
714             continue;
715         if (cmdline && !cmdlineUsed) {
716             free(filepath);
717             filepath = NULL;
718             continue;
719         }
720         file = fopen(filepath, "r");
721         if (!file) {
722             free(filepath);
723             filepath = NULL;
724         }
725     }
726 
727     free(pathcopy);
728     if (file) {
729         configFiles[numFiles].file = file;
730         configFiles[numFiles].path = strdup(filepath);
731         numFiles++;
732     }
733     return filepath;
734 }
735 
736 /*
737  * Match non-hidden files in the xorg config directory with a .conf
738  * suffix. This filter is passed to scandir(3).
739  */
740 static int
ConfigFilter(const struct dirent * de)741 ConfigFilter(const struct dirent *de)
742 {
743     const char *name = de->d_name;
744     size_t len;
745     size_t suflen = strlen(XCONFIGSUFFIX);
746 
747     if (!name || name[0] == '.')
748         return 0;
749     len = strlen(name);
750     if (len <= suflen)
751         return 0;
752     if (strcmp(&name[len - suflen], XCONFIGSUFFIX) != 0)
753         return 0;
754     return 1;
755 }
756 
757 static Bool
AddConfigDirFiles(const char * dirpath,struct dirent ** list,int num)758 AddConfigDirFiles(const char *dirpath, struct dirent **list, int num)
759 {
760     int i;
761     Bool openedFile = FALSE;
762     Bool warnOnce = FALSE;
763 
764     for (i = 0; i < num; i++) {
765         char *path;
766         FILE *file;
767 
768         if (numFiles >= CONFIG_MAX_FILES) {
769             if (!warnOnce) {
770                 ErrorF("Maximum number of configuration " "files opened\n");
771                 warnOnce = TRUE;
772             }
773             continue;
774         }
775 
776         path = malloc(PATH_MAX + 1);
777         snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name);
778         file = fopen(path, "r");
779         if (!file) {
780             free(path);
781             continue;
782         }
783         openedFile = TRUE;
784 
785         configFiles[numFiles].file = file;
786         configFiles[numFiles].path = path;
787         numFiles++;
788     }
789 
790     return openedFile;
791 }
792 
793 /*
794  * Given some searching parameters, locate and open the xorg config
795  * directory. The directory does not need to contain config files.
796  */
797 static char *
OpenConfigDir(const char * path,const char * cmdline,const char * projroot,const char * confname)798 OpenConfigDir(const char *path, const char *cmdline, const char *projroot,
799               const char *confname)
800 {
801     char *dirpath = NULL, *pathcopy;
802     const char *template;
803     Bool found = FALSE;
804     int cmdlineUsed = 0;
805 
806     pathcopy = strdup(path);
807     for (template = strtok(pathcopy, ","); template && !found;
808          template = strtok(NULL, ",")) {
809         struct dirent **list = NULL;
810         int num;
811 
812         dirpath = DoSubstitution(template, cmdline, projroot,
813                                  &cmdlineUsed, NULL, confname);
814         if (!dirpath)
815             continue;
816         if (cmdline && !cmdlineUsed) {
817             free(dirpath);
818             dirpath = NULL;
819             continue;
820         }
821 
822         /* match files named *.conf */
823         num = scandir(dirpath, &list, ConfigFilter, alphasort);
824         if (num < 0) {
825             list = NULL;
826             num = 0;
827         }
828         found = AddConfigDirFiles(dirpath, list, num);
829         if (!found) {
830             free(dirpath);
831             dirpath = NULL;
832         }
833         while (num--)
834             free(list[num]);
835         free(list);
836     }
837 
838     free(pathcopy);
839     return dirpath;
840 }
841 
842 /*
843  * xf86initConfigFiles -- Setup global variables and buffers.
844  */
845 void
xf86initConfigFiles(void)846 xf86initConfigFiles(void)
847 {
848     curFileIndex = 0;
849     configPos = 0;
850     configLineNo = 0;
851     pushToken = LOCK_TOKEN;
852 
853     configBuf = malloc(CONFIG_BUF_LEN);
854     configRBuf = malloc(CONFIG_BUF_LEN);
855     configBuf[0] = '\0';        /* sanity ... */
856 }
857 
858 /*
859  * xf86openConfigFile --
860  *
861  * This function take a config file search path (optional), a command-line
862  * specified file name (optional) and the ProjectRoot path (optional) and
863  * locates and opens a config file based on that information.  If a
864  * command-line file name is specified, then this function fails if none
865  * of the located files.
866  *
867  * The return value is a pointer to the actual name of the file that was
868  * opened.  When no file is found, the return value is NULL. The caller should
869  * free() the returned value.
870  *
871  * The escape sequences allowed in the search path are defined above.
872  *
873  */
874 
875 #ifndef DEFAULT_CONF_PATH
876 #define DEFAULT_CONF_PATH	"/etc/X11/%S," \
877 							"%P/etc/X11/%S," \
878 							"/etc/X11/%G," \
879 							"%P/etc/X11/%G," \
880 							"/etc/X11/%X-%M," \
881 							"/etc/X11/%X," \
882 							"/etc/%X," \
883 							"%P/etc/X11/%X.%H," \
884 							"%P/etc/X11/%X-%M," \
885 							"%P/etc/X11/%X," \
886 							"%P/lib/X11/%X.%H," \
887 							"%P/lib/X11/%X-%M," \
888 							"%P/lib/X11/%X"
889 #endif
890 
891 char *
xf86openConfigFile(const char * path,const char * cmdline,const char * projroot)892 xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
893 {
894     if (!path || !path[0])
895         path = DEFAULT_CONF_PATH;
896     if (!projroot || !projroot[0])
897         projroot = PROJECTROOT;
898 
899     /* Search for a config file */
900     return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
901 }
902 
903 /*
904  * xf86openConfigDirFiles --
905  *
906  * This function take a config directory search path (optional), a
907  * command-line specified directory name (optional) and the ProjectRoot path
908  * (optional) and locates and opens a config directory based on that
909  * information.  If a command-line name is specified, then this function
910  * fails if it is not found.
911  *
912  * The return value is a pointer to the actual name of the directory that was
913  * opened.  When no directory is found, the return value is NULL. The caller
914  * should free() the returned value.
915  *
916  * The escape sequences allowed in the search path are defined above.
917  *
918  */
919 char *
xf86openConfigDirFiles(const char * path,const char * cmdline,const char * projroot)920 xf86openConfigDirFiles(const char *path, const char *cmdline,
921                        const char *projroot)
922 {
923     if (!path || !path[0])
924         path = DEFAULT_CONF_PATH;
925     if (!projroot || !projroot[0])
926         projroot = PROJECTROOT;
927 
928     /* Search for the multiconf directory */
929     return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR);
930 }
931 
932 void
xf86closeConfigFile(void)933 xf86closeConfigFile(void)
934 {
935     int i;
936 
937     free(configRBuf);
938     configRBuf = NULL;
939     free(configBuf);
940     configBuf = NULL;
941 
942     if (numFiles == 0) {
943         builtinConfig = NULL;
944         builtinIndex = 0;
945     }
946     for (i = 0; i < numFiles; i++) {
947         fclose(configFiles[i].file);
948         configFiles[i].file = NULL;
949         free(configFiles[i].path);
950         configFiles[i].path = NULL;
951     }
952     numFiles = 0;
953 }
954 
955 void
xf86setBuiltinConfig(const char * config[])956 xf86setBuiltinConfig(const char *config[])
957 {
958     builtinConfig = config;
959 }
960 
961 void
xf86parseError(const char * format,...)962 xf86parseError(const char *format, ...)
963 {
964     va_list ap;
965     const char *filename = numFiles ? configFiles[curFileIndex].path
966         : "<builtin configuration>";
967 
968     ErrorF("Parse error on line %d of section %s in file %s\n\t",
969            configLineNo, configSection, filename);
970     va_start(ap, format);
971     VErrorF(format, ap);
972     va_end(ap);
973 
974     ErrorF("\n");
975 }
976 
977 void
xf86validationError(const char * format,...)978 xf86validationError(const char *format, ...)
979 {
980     va_list ap;
981     const char *filename = numFiles ? configFiles[curFileIndex].path
982         : "<builtin configuration>";
983 
984     ErrorF("Data incomplete in file %s\n\t", filename);
985     va_start(ap, format);
986     VErrorF(format, ap);
987     va_end(ap);
988 
989     ErrorF("\n");
990 }
991 
992 void
xf86setSection(const char * section)993 xf86setSection(const char *section)
994 {
995     free(configSection);
996     configSection = strdup(section);
997 }
998 
999 /*
1000  * xf86getToken --
1001  *  Lookup a string if it is actually a token in disguise.
1002  */
1003 int
xf86getStringToken(const xf86ConfigSymTabRec * tab)1004 xf86getStringToken(const xf86ConfigSymTabRec * tab)
1005 {
1006     return StringToToken(xf86_lex_val.str, tab);
1007 }
1008 
1009 /*
1010  * Compare two names.  The characters '_', ' ', and '\t' are ignored
1011  * in the comparison.
1012  */
1013 int
xf86nameCompare(const char * s1,const char * s2)1014 xf86nameCompare(const char *s1, const char *s2)
1015 {
1016     char c1, c2;
1017 
1018     if (!s1 || *s1 == 0) {
1019         if (!s2 || *s2 == 0)
1020             return 0;
1021         else
1022             return 1;
1023     } else if (!s2 || *s2 == 0) {
1024         return -1;
1025     }
1026 
1027     while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1028         s1++;
1029     while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1030         s2++;
1031     c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1032     c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1033     while (c1 == c2) {
1034         if (c1 == '\0')
1035             return 0;
1036         s1++;
1037         s2++;
1038         while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1039             s1++;
1040         while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1041             s2++;
1042         c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1043         c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1044     }
1045     return c1 - c2;
1046 }
1047 
1048 char *
xf86addComment(char * cur,const char * add)1049 xf86addComment(char *cur, const char *add)
1050 {
1051     char *str;
1052     const char *cstr;
1053     int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline;
1054 
1055     if (add == NULL || add[0] == '\0')
1056         return cur;
1057 
1058     if (cur) {
1059         curlen = strlen(cur);
1060         if (curlen)
1061             hasnewline = cur[curlen - 1] == '\n';
1062         eol_seen = 0;
1063     }
1064     else
1065         curlen = 0;
1066 
1067     cstr = add;
1068     iscomment = 0;
1069     while (*cstr) {
1070         if (*cstr != ' ' && *cstr != '\t')
1071             break;
1072         ++cstr;
1073     }
1074     iscomment = (*cstr == '#');
1075 
1076     len = strlen(add);
1077     endnewline = add[len - 1] == '\n';
1078 
1079     insnewline = eol_seen || (curlen && !hasnewline);
1080     if (insnewline)
1081         len++;
1082     if (!iscomment)
1083         len++;
1084     if (!endnewline)
1085         len++;
1086 
1087     /* Allocate + 1 char for '\0' terminator. */
1088     str = realloc(cur, curlen + len + 1);
1089     if (!str)
1090         return cur;
1091 
1092     cur = str;
1093 
1094     if (insnewline)
1095         cur[curlen++] = '\n';
1096     if (!iscomment)
1097         cur[curlen++] = '#';
1098     strcpy(cur + curlen, add);
1099     if (!endnewline)
1100         strcat(cur, "\n");
1101 
1102     return cur;
1103 }
1104 
1105 Bool
xf86getBoolValue(Bool * val,const char * str)1106 xf86getBoolValue(Bool *val, const char *str)
1107 {
1108     if (!val || !str)
1109         return FALSE;
1110     if (*str == '\0') {
1111         *val = TRUE;
1112     }
1113     else {
1114         if (xf86nameCompare(str, "1") == 0)
1115             *val = TRUE;
1116         else if (xf86nameCompare(str, "on") == 0)
1117             *val = TRUE;
1118         else if (xf86nameCompare(str, "true") == 0)
1119             *val = TRUE;
1120         else if (xf86nameCompare(str, "yes") == 0)
1121             *val = TRUE;
1122         else if (xf86nameCompare(str, "0") == 0)
1123             *val = FALSE;
1124         else if (xf86nameCompare(str, "off") == 0)
1125             *val = FALSE;
1126         else if (xf86nameCompare(str, "false") == 0)
1127             *val = FALSE;
1128         else if (xf86nameCompare(str, "no") == 0)
1129             *val = FALSE;
1130         else
1131             return FALSE;
1132     }
1133     return TRUE;
1134 }
1135