Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / parser / scan.c
CommitLineData
a09e091a
JB
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
90static int StringToToken(const char *, xf86ConfigSymTabRec *);
91
92static struct {
93 FILE *file;
94 char *path;
95} configFiles[CONFIG_MAX_FILES];
96static const char **builtinConfig = NULL;
97static int builtinIndex = 0;
98static int configPos = 0; /* current readers position */
99static int configLineNo = 0; /* linenumber */
100static char *configBuf, *configRBuf; /* buffer for lines */
101static char *configSection = NULL; /* name of current section being parsed */
102static int numFiles = 0; /* number of config files */
103static int curFileIndex = 0; /* index of current config file */
104static int pushToken = LOCK_TOKEN;
105static int eol_seen = 0; /* private state to handle comments */
106LexRec 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
119static char *
120xf86getNextLine(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 */
249int
250xf86getToken(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 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 val.numType = PARSE_HEX;
358 }
359 else {
360 base = 8;
361 val.numType = PARSE_OCTAL;
362 }
363 else {
364 base = 10;
365 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 val.num = strtoul(configRBuf, NULL, 0);
378 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 val.str = malloc(strlen(configRBuf) + 1);
393 strcpy(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
446int
447xf86getSubToken(char **comment)
448{
449 int token;
450
451 for (;;) {
452 token = xf86getToken(NULL);
453 if (token == COMMENT) {
454 if (comment)
455 *comment = xf86addComment(*comment, val.str);
456 }
457 else
458 return token;
459 }
460 /*NOTREACHED*/}
461
462int
463xf86getSubTokenWithTab(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, val.str);
472 }
473 else
474 return token;
475 }
476 /*NOTREACHED*/}
477
478void
479xf86unGetToken(int token)
480{
481 pushToken = token;
482}
483
484char *
485xf86tokenString(void)
486{
487 return configRBuf;
488}
489
490int
491xf86pathIsAbsolute(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. */
499int
500xf86pathIsSafe(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
583static char *
584DoSubstitution(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 */
720static char *
721OpenConfigFile(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 */
762static int
763ConfigFilter(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
779static Bool
780AddConfigDirFiles(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 */
819static char *
820OpenConfigDir(const char *path, const char *cmdline, const char *projroot,
821 const char *confname)
822{
823 char *dirpath, *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 */
867void
868xf86initConfigFiles(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
913char *
914xf86openConfigFile(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 */
941char *
942xf86openConfigDirFiles(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
954void
955xf86closeConfigFile(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
977void
978xf86setBuiltinConfig(const char *config[])
979{
980 builtinConfig = config;
981}
982
983void
984xf86parseError(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
999void
1000xf86validationError(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
1014void
1015xf86setSection(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 */
1025int
1026xf86getStringToken(xf86ConfigSymTabRec * tab)
1027{
1028 return StringToToken(val.str, tab);
1029}
1030
1031static int
1032StringToToken(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 */
1047int
1048xf86nameCompare(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
1080char *
1081xf86addComment(char *cur, char *add)
1082{
1083 char *str;
1084 int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline;
1085
1086 if (add == NULL || add[0] == '\0')
1087 return cur;
1088
1089 if (cur) {
1090 curlen = strlen(cur);
1091 if (curlen)
1092 hasnewline = cur[curlen - 1] == '\n';
1093 eol_seen = 0;
1094 }
1095 else
1096 curlen = 0;
1097
1098 str = add;
1099 iscomment = 0;
1100 while (*str) {
1101 if (*str != ' ' && *str != '\t')
1102 break;
1103 ++str;
1104 }
1105 iscomment = (*str == '#');
1106
1107 len = strlen(add);
1108 endnewline = add[len - 1] == '\n';
1109
1110 insnewline = eol_seen || (curlen && !hasnewline);
1111 if (insnewline)
1112 len++;
1113 if (!iscomment)
1114 len++;
1115 if (!endnewline)
1116 len++;
1117
1118 /* Allocate + 1 char for '\0' terminator. */
1119 str = realloc(cur, curlen + len + 1);
1120 if (!str)
1121 return cur;
1122
1123 cur = str;
1124
1125 if (insnewline)
1126 cur[curlen++] = '\n';
1127 if (!iscomment)
1128 cur[curlen++] = '#';
1129 strcpy(cur + curlen, add);
1130 if (!endnewline)
1131 strcat(cur, "\n");
1132
1133 return cur;
1134}
1135
1136Bool
1137xf86getBoolValue(Bool *val, const char *str)
1138{
1139 if (!val || !str)
1140 return FALSE;
1141 if (*str == '\0') {
1142 *val = TRUE;
1143 }
1144 else {
1145 if (xf86nameCompare(str, "1") == 0)
1146 *val = TRUE;
1147 else if (xf86nameCompare(str, "on") == 0)
1148 *val = TRUE;
1149 else if (xf86nameCompare(str, "true") == 0)
1150 *val = TRUE;
1151 else if (xf86nameCompare(str, "yes") == 0)
1152 *val = TRUE;
1153 else if (xf86nameCompare(str, "0") == 0)
1154 *val = FALSE;
1155 else if (xf86nameCompare(str, "off") == 0)
1156 *val = FALSE;
1157 else if (xf86nameCompare(str, "false") == 0)
1158 *val = FALSE;
1159 else if (xf86nameCompare(str, "no") == 0)
1160 *val = FALSE;
1161 else
1162 return FALSE;
1163 }
1164 return TRUE;
1165}