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