2 * Copyright (c) 1997 Metro Link Incorporated
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
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.
28 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
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:
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
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.
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).
54 #ifdef HAVE_XORG_CONFIG_H
55 #include <xorg-config.h>
62 #include <sys/types.h>
66 #include <X11/Xdefs.h>
67 #include <X11/Xfuncproto.h>
69 #if defined(_POSIX_SOURCE)
75 #endif /* _POSIX_SOURCE */
77 #if !defined(MAXHOSTNAMELEN)
78 #define MAXHOSTNAMELEN 32
79 #endif /* !MAXHOSTNAMELEN */
84 #include "Configint.h"
85 #include "xf86tokens.h"
87 #define CONFIG_BUF_LEN 1024
88 #define CONFIG_MAX_FILES 64
90 static int StringToToken(const char *, xf86ConfigSymTabRec *);
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 */
111 * read from the configFiles FILE stream until we encounter a new
112 * line; this is effectively just a big wrapper for fgets(3).
114 * xf86getToken() assumes that we will read up to the next
115 * newline; we need to grow configBuf and configRBuf as needed to
120 xf86getNextLine(void)
122 static int configBufLen = CONFIG_BUF_LEN;
123 char *tmpConfigBuf, *tmpConfigRBuf;
124 int c, i, pos = 0, eolFound = 0;
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
134 if (configBufLen != CONFIG_BUF_LEN) {
136 tmpConfigBuf = malloc(CONFIG_BUF_LEN);
137 tmpConfigRBuf = malloc(CONFIG_BUF_LEN);
139 if (!tmpConfigBuf || !tmpConfigRBuf) {
142 * at least one of the mallocs failed; keep the old buffers
143 * and free any partial allocations
153 * malloc succeeded; free the old buffers and use the new
157 configBufLen = CONFIG_BUF_LEN;
162 configBuf = tmpConfigBuf;
163 configRBuf = tmpConfigRBuf;
167 /* read in another block of chars */
170 ret = fgets(configBuf + pos, configBufLen - pos - 1,
171 configFiles[curFileIndex].file);
175 * if the file doesn't end in a newline, add one
176 * and trigger another read
179 strcpy(&configBuf[pos], "\n");
186 /* search for EOL in the new block of chars */
188 for (i = pos; i < (configBufLen - 1); i++) {
194 if ((c == '\n') || (c == '\r')) {
201 * if we didn't find EOL, then grow the string and
207 tmpConfigBuf = realloc(configBuf, configBufLen + CONFIG_BUF_LEN);
208 tmpConfigRBuf = realloc(configRBuf, configBufLen + CONFIG_BUF_LEN);
210 if (!tmpConfigBuf || !tmpConfigRBuf) {
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
221 configBuf = tmpConfigBuf;
223 configRBuf = tmpConfigRBuf;
230 /* reallocation succeeded */
232 configBuf = tmpConfigBuf;
233 configRBuf = tmpConfigRBuf;
235 configBufLen += CONFIG_BUF_LEN;
246 * Read next Token from the config file. Handle the global variable
250 xf86getToken(xf86ConfigSymTabRec * tab)
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.
259 if (pushToken == EOF_TOKEN)
261 else if (pushToken == LOCK_TOKEN) {
263 * eol_seen is only set for the first token after a newline.
267 c = configBuf[configPos];
270 * Get start of next Token. EOF is handled,
271 * whitespaces are skipped.
279 ret = xf86getNextLine();
281 if (builtinConfig[builtinIndex] == NULL)
285 builtinConfig[builtinIndex], CONFIG_BUF_LEN);
292 * if necessary, move to the next file and
293 * read the first line
295 if (curFileIndex + 1 < numFiles) {
301 return pushToken = EOF_TOKEN;
310 c = configBuf[configPos++];
328 configRBuf[i++] = (c = configBuf[configPos++]);
330 while ((c != '\n') && (c != '\r') && (c != '\0'));
331 configRBuf[i] = '\0';
332 /* XXX no private copy.
333 * Use xf86addComment when setting a comment.
335 xf86_lex_val.str = configRBuf;
339 /* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */
340 else if ((c == ',') && !isalpha(configBuf[configPos])) {
343 else if ((c == '-') && !isalpha(configBuf[configPos])) {
348 * Numbers are returned immediately ...
354 if ((configBuf[configPos] == 'x') ||
355 (configBuf[configPos] == 'X')) {
357 xf86_lex_val.numType = PARSE_HEX;
361 xf86_lex_val.numType = PARSE_OCTAL;
365 xf86_lex_val.numType = PARSE_DECIMAL;
370 while (isdigit(c = configBuf[configPos++]) ||
371 (c == '.') || (c == 'x') || (c == 'X') ||
372 ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
373 ((c >= 'A') && (c <= 'F')))))
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);
383 * All Strings START with a \" ...
385 else if (c == '\"') {
388 configRBuf[++i] = (c = configBuf[configPos++]);
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 ! */
398 * ... and now we MUST have a valid token. The search is
399 * handled later along with the pushed tokens.
405 configRBuf[++i] = (c = configBuf[configPos++]);
407 while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') &&
408 (c != '\0') && (c != '#'));
410 configRBuf[i] = '\0';
418 * Here we deal with pushed tokens. Reinitialize pushToken again. If
419 * the pushed token was NUMBER || STRING return them again ...
421 int temp = pushToken;
423 pushToken = LOCK_TOKEN;
425 if (temp == COMMA || temp == DASH)
427 if (temp == NUMBER || temp == STRING)
432 * Joop, at last we have to lookup the token ...
436 while (tab[i].token != -1)
437 if (xf86nameCompare(configRBuf, tab[i].name) == 0)
443 return ERROR_TOKEN; /* Error catcher */
447 xf86getSubToken(char **comment)
452 token = xf86getToken(NULL);
453 if (token == COMMENT) {
455 *comment = xf86addComment(*comment, xf86_lex_val.str);
463 xf86getSubTokenWithTab(char **comment, xf86ConfigSymTabRec * tab)
468 token = xf86getToken(tab);
469 if (token == COMMENT) {
471 *comment = xf86addComment(*comment, xf86_lex_val.str);
479 xf86unGetToken(int token)
485 xf86tokenString(void)
491 xf86pathIsAbsolute(const char *path)
493 if (path && path[0] == '/')
498 /* A path is "safe" if it is relative and if it contains no ".." elements. */
500 xf86pathIsSafe(const char *path)
502 if (xf86pathIsAbsolute(path))
505 /* Compare with ".." */
506 if (!strcmp(path, ".."))
509 /* Look for leading "../" */
510 if (!strncmp(path, "../", 3))
513 /* Look for trailing "/.." */
514 if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
517 /* Look for "/../" */
518 if (strstr(path, "/../"))
525 * This function substitutes the following escape sequences:
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")
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
542 #define XCONFIGFILE "xorg.conf"
545 #define XCONFIGDIR "xorg.conf.d"
547 #ifndef XCONFIGSUFFIX
548 #define XCONFIGSUFFIX ".conf"
551 #define PROJECTROOT "/usr/X11R6"
554 #define SYSCONFDIR PROJECTROOT "/etc"
557 #define DATADIR PROJECTROOT "/share"
560 #define XCONFENV "XORGCONFIG"
563 #define BAIL_OUT do { \
568 #define CHECK_LENGTH do { \
569 if (l > PATH_MAX) { \
574 #define APPEND_STR(s) do { \
575 if (strlen(s) + l > PATH_MAX) { \
578 strcpy(result + l, s); \
584 DoSubstitution(const char *template, const char *cmdline, const char *projroot,
585 int *cmdlineUsed, int *envUsed, const char *XConfigFile)
589 static const char *env = NULL;
590 static char *hostname = NULL;
600 result = malloc(PATH_MAX + 1);
602 for (i = 0; template[i]; i++) {
603 if (template[i] != '%') {
604 result[l++] = template[i];
608 switch (template[++i]) {
610 if (cmdline && xf86pathIsAbsolute(cmdline)) {
619 if (cmdline && !xf86pathIsAbsolute(cmdline)) {
628 if (cmdline && xf86pathIsSafe(cmdline)) {
637 APPEND_STR(XConfigFile);
641 if ((hostname = malloc(MAXHOSTNAMELEN + 1))) {
642 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
643 hostname[MAXHOSTNAMELEN] = '\0';
652 APPEND_STR(hostname);
656 env = getenv(XCONFENV);
657 if (env && xf86pathIsAbsolute(env)) {
667 env = getenv(XCONFENV);
668 if (env && !xf86pathIsAbsolute(env)) {
678 env = getenv(XCONFENV);
679 if (env && xf86pathIsSafe(env)) {
688 if (projroot && xf86pathIsAbsolute(projroot))
689 APPEND_STR(projroot);
694 APPEND_STR(SYSCONFDIR);
704 fprintf(stderr, "invalid escape %%%c found in path template\n",
712 fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
718 * Given some searching parameters, locate and open the xorg config file.
721 OpenConfigFile(const char *path, const char *cmdline, const char *projroot,
722 const char *confname)
724 char *filepath = NULL;
726 const char *template;
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);
737 if (cmdline && !cmdlineUsed) {
742 file = fopen(filepath, "r");
751 configFiles[numFiles].file = file;
752 configFiles[numFiles].path = strdup(filepath);
759 * Match non-hidden files in the xorg config directory with a .conf
760 * suffix. This filter is passed to scandir(3).
763 ConfigFilter(const struct dirent *de)
765 const char *name = de->d_name;
767 size_t suflen = strlen(XCONFIGSUFFIX);
769 if (!name || name[0] == '.')
774 if (strcmp(&name[len - suflen], XCONFIGSUFFIX) != 0)
780 AddConfigDirFiles(const char *dirpath, struct dirent **list, int num)
783 Bool openedFile = FALSE;
784 Bool warnOnce = FALSE;
786 for (i = 0; i < num; i++) {
790 if (numFiles >= CONFIG_MAX_FILES) {
792 ErrorF("Maximum number of configuration " "files opened\n");
798 path = malloc(PATH_MAX + 1);
799 snprintf(path, PATH_MAX + 1, "%s/%s", dirpath, list[i]->d_name);
800 file = fopen(path, "r");
807 configFiles[numFiles].file = file;
808 configFiles[numFiles].path = path;
816 * Given some searching parameters, locate and open the xorg config
817 * directory. The directory does not need to contain config files.
820 OpenConfigDir(const char *path, const char *cmdline, const char *projroot,
821 const char *confname)
823 char *dirpath = NULL, *pathcopy;
824 const char *template;
828 pathcopy = strdup(path);
829 for (template = strtok(pathcopy, ","); template && !found;
830 template = strtok(NULL, ",")) {
831 struct dirent **list = NULL;
834 dirpath = DoSubstitution(template, cmdline, projroot,
835 &cmdlineUsed, NULL, confname);
838 if (cmdline && !cmdlineUsed) {
844 /* match files named *.conf */
845 num = scandir(dirpath, &list, ConfigFilter, alphasort);
850 found = AddConfigDirFiles(dirpath, list, num);
865 * xf86initConfigFiles -- Setup global variables and buffers.
868 xf86initConfigFiles(void)
873 pushToken = LOCK_TOKEN;
875 configBuf = malloc(CONFIG_BUF_LEN);
876 configRBuf = malloc(CONFIG_BUF_LEN);
877 configBuf[0] = '\0'; /* sanity ... */
881 * xf86openConfigFile --
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.
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.
893 * The escape sequences allowed in the search path are defined above.
897 #ifndef DEFAULT_CONF_PATH
898 #define DEFAULT_CONF_PATH "/etc/X11/%S," \
905 "%P/etc/X11/%X.%H," \
906 "%P/etc/X11/%X-%M," \
908 "%P/lib/X11/%X.%H," \
909 "%P/lib/X11/%X-%M," \
914 xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
916 if (!path || !path[0])
917 path = DEFAULT_CONF_PATH;
918 if (!projroot || !projroot[0])
919 projroot = PROJECTROOT;
921 /* Search for a config file */
922 return OpenConfigFile(path, cmdline, projroot, XCONFIGFILE);
926 * xf86openConfigDirFiles --
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.
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.
938 * The escape sequences allowed in the search path are defined above.
942 xf86openConfigDirFiles(const char *path, const char *cmdline,
943 const char *projroot)
945 if (!path || !path[0])
946 path = DEFAULT_CONF_PATH;
947 if (!projroot || !projroot[0])
948 projroot = PROJECTROOT;
950 /* Search for the multiconf directory */
951 return OpenConfigDir(path, cmdline, projroot, XCONFIGDIR);
955 xf86closeConfigFile(void)
965 builtinConfig = NULL;
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;
978 xf86setBuiltinConfig(const char *config[])
980 builtinConfig = config;
984 xf86parseError(const char *format, ...)
987 const char *filename = numFiles ? configFiles[curFileIndex].path
988 : "<builtin configuration>";
990 ErrorF("Parse error on line %d of section %s in file %s\n\t",
991 configLineNo, configSection, filename);
992 va_start(ap, format);
1000 xf86validationError(const char *format, ...)
1003 const char *filename = numFiles ? configFiles[curFileIndex].path
1004 : "<builtin configuration>";
1006 ErrorF("Data incomplete in file %s\n\t", filename);
1007 va_start(ap, format);
1008 VErrorF(format, ap);
1015 xf86setSection(const char *section)
1017 free(configSection);
1018 configSection = strdup(section);
1023 * Lookup a string if it is actually a token in disguise.
1026 xf86getStringToken(xf86ConfigSymTabRec * tab)
1028 return StringToToken(xf86_lex_val.str, tab);
1032 StringToToken(const char *str, xf86ConfigSymTabRec * tab)
1036 for (i = 0; tab[i].token != -1; i++) {
1037 if (!xf86nameCompare(tab[i].name, str))
1038 return tab[i].token;
1044 * Compare two names. The characters '_', ' ', and '\t' are ignored
1045 * in the comparison.
1048 xf86nameCompare(const char *s1, const char *s2)
1052 if (!s1 || *s1 == 0) {
1053 if (!s2 || *s2 == 0)
1059 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1061 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1063 c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1064 c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1070 while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1072 while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1074 c1 = (isupper(*s1) ? tolower(*s1) : *s1);
1075 c2 = (isupper(*s2) ? tolower(*s2) : *s2);
1081 xf86addComment(char *cur, const char *add)
1085 int len, curlen, iscomment, hasnewline = 0, insnewline, endnewline;
1087 if (add == NULL || add[0] == '\0')
1091 curlen = strlen(cur);
1093 hasnewline = cur[curlen - 1] == '\n';
1102 if (*cstr != ' ' && *cstr != '\t')
1106 iscomment = (*cstr == '#');
1109 endnewline = add[len - 1] == '\n';
1111 insnewline = eol_seen || (curlen && !hasnewline);
1119 /* Allocate + 1 char for '\0' terminator. */
1120 str = realloc(cur, curlen + len + 1);
1127 cur[curlen++] = '\n';
1129 cur[curlen++] = '#';
1130 strcpy(cur + curlen, add);
1138 xf86getBoolValue(Bool *val, const char *str)
1146 if (xf86nameCompare(str, "1") == 0)
1148 else if (xf86nameCompare(str, "on") == 0)
1150 else if (xf86nameCompare(str, "true") == 0)
1152 else if (xf86nameCompare(str, "yes") == 0)
1154 else if (xf86nameCompare(str, "0") == 0)
1156 else if (xf86nameCompare(str, "off") == 0)
1158 else if (xf86nameCompare(str, "false") == 0)
1160 else if (xf86nameCompare(str, "no") == 0)