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).
55 /* View/edit this file with tab stops set to 4 */
57 #ifdef HAVE_XORG_CONFIG_H
58 #include <xorg-config.h>
68 #if !defined(X_NOT_POSIX)
69 #if defined(_POSIX_SOURCE)
75 #endif /* _POSIX_SOURCE */
76 #endif /* !X_NOT_POSIX */
77 #if !defined(PATH_MAX)
78 #if defined(MAXPATHLEN)
79 #define PATH_MAX MAXPATHLEN
82 #endif /* MAXPATHLEN */
83 #endif /* !PATH_MAX */
85 #if !defined(MAXHOSTNAMELEN)
86 #define MAXHOSTNAMELEN 32
87 #endif /* !MAXHOSTNAMELEN */
89 #include "Configint.h"
90 #include "xf86tokens.h"
92 #define CONFIG_BUF_LEN 1024
94 static int StringToToken (char *, xf86ConfigSymTabRec
*);
96 static FILE *configFile
= NULL
;
97 static const char **builtinConfig
= NULL
;
98 static int builtinIndex
= 0;
99 static int configPos
= 0; /* current readers position */
100 static int configLineNo
= 0; /* linenumber */
101 static char *configBuf
, *configRBuf
; /* buffer for lines */
102 static char *configPath
; /* path to config file */
103 static char *configSection
= NULL
; /* name of current section being parsed */
104 static int pushToken
= LOCK_TOKEN
;
105 static int eol_seen
= 0; /* private state to handle comments */
111 * A portable, but restricted, version of strtoul(). It only understands
112 * hex, octal, and decimal. But it's good enough for our needs.
115 xf86strToUL (char *str
)
119 unsigned int tot
= 0;
124 if ((*p
== 'x') || (*p
== 'X'))
134 if ((*p
>= '0') && (*p
<= ((base
== 8) ? '7' : '9')))
136 tot
= tot
* base
+ (*p
- '0');
138 else if ((base
== 16) && (*p
>= 'a') && (*p
<= 'f'))
140 tot
= tot
* base
+ 10 + (*p
- 'a');
142 else if ((base
== 16) && (*p
>= 'A') && (*p
<= 'F'))
144 tot
= tot
* base
+ 10 + (*p
- 'A');
158 * read from the configFile FILE stream until we encounter a new
159 * line; this is effectively just a big wrapper for fgets(3).
161 * xf86getToken() assumes that we will read up to the next
162 * newline; we need to grow configBuf and configRBuf as needed to
167 xf86getNextLine(void)
169 static int configBufLen
= CONFIG_BUF_LEN
;
170 char *tmpConfigBuf
, *tmpConfigRBuf
;
171 int c
, i
, pos
= 0, eolFound
= 0;
175 * reallocate the string if it was grown last time (i.e., is no
176 * longer CONFIG_BUF_LEN); we malloc the new strings first, so
177 * that if either of the mallocs fail, we can fall back on the
178 * existing buffer allocations
181 if (configBufLen
!= CONFIG_BUF_LEN
) {
183 tmpConfigBuf
= xf86confmalloc(CONFIG_BUF_LEN
);
184 tmpConfigRBuf
= xf86confmalloc(CONFIG_BUF_LEN
);
186 if (!tmpConfigBuf
|| !tmpConfigRBuf
) {
189 * at least one of the mallocs failed; keep the old buffers
190 * and free any partial allocations
193 xf86conffree(tmpConfigBuf
);
194 xf86conffree(tmpConfigRBuf
);
199 * malloc succeeded; free the old buffers and use the new
203 configBufLen
= CONFIG_BUF_LEN
;
205 xf86conffree(configBuf
);
206 xf86conffree(configRBuf
);
208 configBuf
= tmpConfigBuf
;
209 configRBuf
= tmpConfigRBuf
;
213 /* read in another block of chars */
216 ret
= fgets(configBuf
+ pos
, configBufLen
- pos
- 1, configFile
);
220 /* search for EOL in the new block of chars */
222 for (i
= pos
; i
< (configBufLen
- 1); i
++) {
225 if (c
== '\0') break;
227 if ((c
== '\n') || (c
== '\r')) {
234 * if we didn't find EOL, then grow the string and
240 tmpConfigBuf
= xf86confrealloc(configBuf
, configBufLen
+ CONFIG_BUF_LEN
);
241 tmpConfigRBuf
= xf86confrealloc(configRBuf
, configBufLen
+ CONFIG_BUF_LEN
);
243 if (!tmpConfigBuf
|| !tmpConfigRBuf
) {
246 * at least one of the reallocations failed; use the
247 * new allocation that succeeded, but we have to
248 * fallback to the previous configBufLen size and use
249 * the string we have, even though we don't have an
253 if (tmpConfigBuf
) configBuf
= tmpConfigBuf
;
254 if (tmpConfigRBuf
) configRBuf
= tmpConfigRBuf
;
260 /* reallocation succeeded */
262 configBuf
= tmpConfigBuf
;
263 configRBuf
= tmpConfigRBuf
;
265 configBufLen
+= CONFIG_BUF_LEN
;
276 * Read next Token from the config file. Handle the global variable
280 xf86getToken (xf86ConfigSymTabRec
* tab
)
285 * First check whether pushToken has a different value than LOCK_TOKEN.
286 * In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
287 * oth * case the next token must be read from the input.
289 if (pushToken
== EOF_TOKEN
)
291 else if (pushToken
== LOCK_TOKEN
)
294 * eol_seen is only set for the first token after a newline.
298 c
= configBuf
[configPos
];
301 * Get start of next Token. EOF is handled,
302 * whitespaces are skipped.
310 ret
= xf86getNextLine();
312 if (builtinConfig
[builtinIndex
] == NULL
)
315 ret
= strncpy(configBuf
, builtinConfig
[builtinIndex
],
322 return (pushToken
= EOF_TOKEN
);
331 c
= configBuf
[configPos
++];
351 configRBuf
[i
++] = (c
= configBuf
[configPos
++]);
353 while ((c
!= '\n') && (c
!= '\r') && (c
!= '\0'));
354 configRBuf
[i
] = '\0';
355 /* XXX no private copy.
356 * Use xf86addComment when setting a comment.
358 val
.str
= configRBuf
;
362 /* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */
363 else if ((c
== ',') && !isalpha (configBuf
[configPos
]))
367 else if ((c
== '-') && !isalpha (configBuf
[configPos
]))
373 * Numbers are returned immediately ...
380 if ((configBuf
[configPos
] == 'x') ||
381 (configBuf
[configPos
] == 'X'))
390 while (isdigit (c
= configBuf
[configPos
++]) ||
391 (c
== '.') || (c
== 'x') || (c
== 'X') ||
392 ((base
== 16) && (((c
>= 'a') && (c
<= 'f')) ||
393 ((c
>= 'A') && (c
<= 'F')))))
395 configPos
--; /* GJA -- one too far */
396 configRBuf
[i
] = '\0';
397 val
.num
= xf86strToUL (configRBuf
);
398 val
.realnum
= atof (configRBuf
);
403 * All Strings START with a \" ...
410 configRBuf
[++i
] = (c
= configBuf
[configPos
++]);
412 while ((c
!= '\"') && (c
!= '\n') && (c
!= '\r') && (c
!= '\0'));
413 configRBuf
[i
] = '\0';
414 val
.str
= xf86confmalloc (strlen (configRBuf
) + 1);
415 strcpy (val
.str
, configRBuf
); /* private copy ! */
420 * ... and now we MUST have a valid token. The search is
421 * handled later along with the pushed tokens.
429 configRBuf
[++i
] = (c
= configBuf
[configPos
++]);;
431 while ((c
!= ' ') && (c
!= '\t') && (c
!= '\n') && (c
!= '\r') && (c
!= '\0') && (c
!= '#'));
433 configRBuf
[i
] = '\0';
442 * Here we deal with pushed tokens. Reinitialize pushToken again. If
443 * the pushed token was NUMBER || STRING return them again ...
445 int temp
= pushToken
;
446 pushToken
= LOCK_TOKEN
;
448 if (temp
== COMMA
|| temp
== DASH
)
450 if (temp
== NUMBER
|| temp
== STRING
)
455 * Joop, at last we have to lookup the token ...
460 while (tab
[i
].token
!= -1)
461 if (xf86nameCompare (configRBuf
, tab
[i
].name
) == 0)
462 return (tab
[i
].token
);
467 return (ERROR_TOKEN
); /* Error catcher */
471 xf86getSubToken (char **comment
)
476 token
= xf86getToken(NULL
);
477 if (token
== COMMENT
) {
479 *comment
= xf86addComment(*comment
, val
.str
);
488 xf86getSubTokenWithTab (char **comment
, xf86ConfigSymTabRec
*tab
)
493 token
= xf86getToken(tab
);
494 if (token
== COMMENT
) {
496 *comment
= xf86addComment(*comment
, val
.str
);
505 xf86unGetToken (int token
)
511 xf86tokenString (void)
517 xf86pathIsAbsolute(const char *path
)
519 if (path
&& path
[0] == '/')
524 /* A path is "safe" if it is relative and if it contains no ".." elements. */
526 xf86pathIsSafe(const char *path
)
528 if (xf86pathIsAbsolute(path
))
531 /* Compare with ".." */
532 if (!strcmp(path
, ".."))
535 /* Look for leading "../" */
536 if (!strncmp(path
, "../", 3))
539 /* Look for trailing "/.." */
540 if ((strlen(path
) > 3) && !strcmp(path
+ strlen(path
) - 3, "/.."))
543 /* Look for "/../" */
544 if (strstr(path
, "/../"))
551 * This function substitutes the following escape sequences:
553 * %A cmdline argument as an absolute path (must be absolute to match)
554 * %R cmdline argument as a relative path
555 * %S cmdline argument as a "safe" path (relative, and no ".." elements)
556 * %X default config file name ("xorg.conf")
558 * %E config file environment ($XORGCONFIG) as an absolute path
559 * %F config file environment ($XORGCONFIG) as a relative path
560 * %G config file environment ($XORGCONFIG) as a safe path
563 * %M major version number
568 #define XCONFIGFILE "xorg.conf"
571 #define PROJECTROOT "/usr/X11R6"
574 #define XCONFENV "XORGCONFIG"
576 #define XFREE86CFGFILE "XF86Config"
577 #ifndef XF86_VERSION_MAJOR
579 #if XVERSION > 40000000
580 #define XF86_VERSION_MAJOR (XVERSION / 10000000)
582 #define XF86_VERSION_MAJOR (XVERSION / 1000)
585 #define XF86_VERSION_MAJOR 4
589 #define BAIL_OUT do { \
590 xf86conffree(result); \
594 #define CHECK_LENGTH do { \
595 if (l > PATH_MAX) { \
600 #define APPEND_STR(s) do { \
601 if (strlen(s) + l > PATH_MAX) { \
604 strcpy(result + l, s); \
610 DoSubstitution(const char *template, const char *cmdline
, const char *projroot
,
611 int *cmdlineUsed
, int *envUsed
, char *XConfigFile
)
615 static const char *env
= NULL
, *home
= NULL
;
616 static char *hostname
= NULL
;
617 static char majorvers
[3] = "";
627 result
= xf86confmalloc(PATH_MAX
+ 1);
629 for (i
= 0; template[i
]; i
++) {
630 if (template[i
] != '%') {
631 result
[l
++] = template[i
];
634 switch (template[++i
]) {
636 if (cmdline
&& xf86pathIsAbsolute(cmdline
)) {
644 if (cmdline
&& !xf86pathIsAbsolute(cmdline
)) {
652 if (cmdline
&& xf86pathIsSafe(cmdline
)) {
660 APPEND_STR(XConfigFile
);
664 if ((hostname
= xf86confmalloc(MAXHOSTNAMELEN
+ 1))) {
665 if (gethostname(hostname
, MAXHOSTNAMELEN
) == 0) {
666 hostname
[MAXHOSTNAMELEN
] = '\0';
668 xf86conffree(hostname
);
674 APPEND_STR(hostname
);
678 env
= getenv(XCONFENV
);
679 if (env
&& xf86pathIsAbsolute(env
)) {
688 env
= getenv(XCONFENV
);
689 if (env
&& !xf86pathIsAbsolute(env
)) {
698 env
= getenv(XCONFENV
);
699 if (env
&& xf86pathIsSafe(env
)) {
708 home
= getenv("HOME");
709 if (home
&& xf86pathIsAbsolute(home
))
715 if (projroot
&& xf86pathIsAbsolute(projroot
))
716 APPEND_STR(projroot
);
722 if (XF86_VERSION_MAJOR
< 0 || XF86_VERSION_MAJOR
> 99) {
723 fprintf(stderr
, "XF86_VERSION_MAJOR is out of range\n");
726 sprintf(majorvers
, "%d", XF86_VERSION_MAJOR
);
728 APPEND_STR(majorvers
);
735 fprintf(stderr
, "invalid escape %%%c found in path template\n",
743 fprintf(stderr
, "Converted `%s' to `%s'\n", template, result
);
749 * xf86openConfigFile --
751 * This function take a config file search path (optional), a command-line
752 * specified file name (optional) and the ProjectRoot path (optional) and
753 * locates and opens a config file based on that information. If a
754 * command-line file name is specified, then this function fails if none
755 * of the located files.
757 * The return value is a pointer to the actual name of the file that was
758 * opened. When no file is found, the return value is NULL.
760 * The escape sequences allowed in the search path are defined above.
764 #ifndef DEFAULT_CONF_PATH
765 #define DEFAULT_CONF_PATH "/etc/X11/%S," \
772 "%P/etc/X11/%X.%H," \
773 "%P/etc/X11/%X-%M," \
775 "%P/lib/X11/%X.%H," \
776 "%P/lib/X11/%X-%M," \
781 xf86openConfigFile(const char *path
, const char *cmdline
, const char *projroot
)
784 const char *template;
788 configPos
= 0; /* current readers position */
789 configLineNo
= 0; /* linenumber */
790 pushToken
= LOCK_TOKEN
;
792 if (!path
|| !path
[0])
793 path
= DEFAULT_CONF_PATH
;
794 pathcopy
= xf86confmalloc(strlen(path
) + 1);
795 strcpy(pathcopy
, path
);
796 if (!projroot
|| !projroot
[0])
797 projroot
= PROJECTROOT
;
799 template = strtok(pathcopy
, ",");
801 /* First, search for a config file. */
802 while (template && !configFile
) {
803 if ((configPath
= DoSubstitution(template, cmdline
, projroot
,
806 if ((configFile
= fopen(configPath
, "r")) != 0) {
807 if (cmdline
&& !cmdlineUsed
) {
813 if (configPath
&& !configFile
) {
814 xf86conffree(configPath
);
817 template = strtok(NULL
, ",");
820 /* Then search for fallback */
822 strcpy(pathcopy
, path
);
823 template = strtok(pathcopy
, ",");
825 while (template && !configFile
) {
826 if ((configPath
= DoSubstitution(template, cmdline
, projroot
,
829 if ((configFile
= fopen(configPath
, "r")) != 0) {
830 if (cmdline
&& !cmdlineUsed
) {
836 if (configPath
&& !configFile
) {
837 xf86conffree(configPath
);
840 template = strtok(NULL
, ",");
844 xf86conffree(pathcopy
);
850 configBuf
= xf86confmalloc (CONFIG_BUF_LEN
);
851 configRBuf
= xf86confmalloc (CONFIG_BUF_LEN
);
852 configBuf
[0] = '\0'; /* sanity ... */
858 xf86closeConfigFile (void)
860 xf86conffree (configPath
);
862 xf86conffree (configRBuf
);
864 xf86conffree (configBuf
);
871 builtinConfig
= NULL
;
877 xf86setBuiltinConfig(const char *config
[])
879 builtinConfig
= config
;
880 configPath
= xf86configStrdup("<builtin configuration>");
881 configBuf
= xf86confmalloc (CONFIG_BUF_LEN
);
882 configRBuf
= xf86confmalloc (CONFIG_BUF_LEN
);
883 configBuf
[0] = '\0'; /* sanity ... */
888 xf86parseError (char *format
,...)
892 ErrorF ("Parse error on line %d of section %s in file %s\n\t",
893 configLineNo
, configSection
, configPath
);
894 va_start (ap
, format
);
895 VErrorF (format
, ap
);
902 xf86validationError (char *format
,...)
906 ErrorF ("Data incomplete in file %s\n\t", configPath
);
907 va_start (ap
, format
);
908 VErrorF (format
, ap
);
915 xf86setSection (char *section
)
918 xf86conffree(configSection
);
919 configSection
= xf86confmalloc(strlen (section
) + 1);
920 strcpy (configSection
, section
);
925 * Lookup a string if it is actually a token in disguise.
928 xf86getStringToken (xf86ConfigSymTabRec
* tab
)
930 return StringToToken (val
.str
, tab
);
934 StringToToken (char *str
, xf86ConfigSymTabRec
* tab
)
938 for (i
= 0; tab
[i
].token
!= -1; i
++)
940 if (!xf86nameCompare (tab
[i
].name
, str
))
943 return (ERROR_TOKEN
);
948 * Compare two names. The characters '_', ' ', and '\t' are ignored
952 xf86nameCompare (const char *s1
, const char *s2
)
956 if (!s1
|| *s1
== 0) {
963 while (*s1
== '_' || *s1
== ' ' || *s1
== '\t')
965 while (*s2
== '_' || *s2
== ' ' || *s2
== '\t')
967 c1
= (isupper (*s1
) ? tolower (*s1
) : *s1
);
968 c2
= (isupper (*s2
) ? tolower (*s2
) : *s2
);
975 while (*s1
== '_' || *s1
== ' ' || *s1
== '\t')
977 while (*s2
== '_' || *s2
== ' ' || *s2
== '\t')
979 c1
= (isupper (*s1
) ? tolower (*s1
) : *s1
);
980 c2
= (isupper (*s2
) ? tolower (*s2
) : *s2
);
986 xf86addComment(char *cur
, char *add
)
989 int len
, curlen
, iscomment
, hasnewline
= 0, endnewline
;
991 if (add
== NULL
|| add
[0] == '\0')
995 curlen
= strlen(cur
);
997 hasnewline
= cur
[curlen
- 1] == '\n';
1006 if (*str
!= ' ' && *str
!= '\t')
1010 iscomment
= (*str
== '#');
1013 endnewline
= add
[len
- 1] == '\n';
1014 len
+= 1 + iscomment
+ (!hasnewline
) + (!endnewline
) + eol_seen
;
1016 if ((str
= xf86confrealloc(cur
, len
+ curlen
)) == NULL
)
1021 if (eol_seen
|| (curlen
&& !hasnewline
))
1022 cur
[curlen
++] = '\n';
1024 cur
[curlen
++] = '#';
1025 strcpy(cur
+ curlen
, add
);