1
/* $XFree86: xc/programs/Xserver/hw/xfree86/parser/scan.c,v 1.30 2003/11/03 05:11:52 tsi Exp $ */
4
* Copyright (c) 1997 Metro Link Incorporated
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the "Software"),
8
* to deal in the Software without restriction, including without limitation
9
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
* and/or sell copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following conditions:
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
21
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
* Except as contained in this notice, the name of the Metro Link shall not be
25
* used in advertising or otherwise to promote the sale, use or other dealings
26
* in this Software without prior written authorization from Metro Link.
30
* Copyright (c) 1997-2003 by The XFree86 Project, Inc.
32
* Permission is hereby granted, free of charge, to any person obtaining a
33
* copy of this software and associated documentation files (the "Software"),
34
* to deal in the Software without restriction, including without limitation
35
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
36
* and/or sell copies of the Software, and to permit persons to whom the
37
* Software is furnished to do so, subject to the following conditions:
39
* The above copyright notice and this permission notice shall be included in
40
* all copies or substantial portions of the Software.
42
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
45
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
46
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
47
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
48
* OTHER DEALINGS IN THE SOFTWARE.
50
* Except as contained in this notice, the name of the copyright holder(s)
51
* and author(s) shall not be used in advertising or otherwise to promote
52
* the sale, use or other dealings in this Software without prior written
53
* authorization from the copyright holder(s) and author(s).
57
/* View/edit this file with tab stops set to 4 */
59
#ifdef HAVE_XORG_CONFIG_H
60
#include <xorg-config.h>
70
#if !defined(X_NOT_POSIX)
71
#if defined(_POSIX_SOURCE)
77
#endif /* _POSIX_SOURCE */
78
#endif /* !X_NOT_POSIX */
79
#if !defined(PATH_MAX)
80
#if defined(MAXPATHLEN)
81
#define PATH_MAX MAXPATHLEN
84
#endif /* MAXPATHLEN */
85
#endif /* !PATH_MAX */
87
#if !defined(MAXHOSTNAMELEN)
88
#define MAXHOSTNAMELEN 32
89
#endif /* !MAXHOSTNAMELEN */
91
#include "Configint.h"
92
#include "xf86tokens.h"
94
#define CONFIG_BUF_LEN 1024
96
static int StringToToken (char *, xf86ConfigSymTabRec *);
98
static FILE *configFile = NULL;
99
static const char **builtinConfig = NULL;
100
static int builtinIndex = 0;
101
static int configPos = 0; /* current readers position */
102
static int configLineNo = 0; /* linenumber */
103
static char *configBuf, *configRBuf; /* buffer for lines */
104
static char *configPath; /* path to config file */
105
static char *configSection = NULL; /* name of current section being parsed */
106
static int pushToken = LOCK_TOKEN;
107
static int eol_seen = 0; /* private state to handle comments */
111
extern char *__XOS2RedirRoot(char *path);
117
* A portable, but restricted, version of strtoul(). It only understands
118
* hex, octal, and decimal. But it's good enough for our needs.
121
xf86strToUL (char *str)
125
unsigned int tot = 0;
130
if ((*p == 'x') || (*p == 'X'))
140
if ((*p >= '0') && (*p <= ((base == 8) ? '7' : '9')))
142
tot = tot * base + (*p - '0');
144
else if ((base == 16) && (*p >= 'a') && (*p <= 'f'))
146
tot = tot * base + 10 + (*p - 'a');
148
else if ((base == 16) && (*p >= 'A') && (*p <= 'F'))
150
tot = tot * base + 10 + (*p - 'A');
163
* Read next Token form the config file. Handle the global variable
167
xf86getToken (xf86ConfigSymTabRec * tab)
172
* First check whether pushToken has a different value than LOCK_TOKEN.
173
* In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
174
* oth * case the next token must be read from the input.
176
if (pushToken == EOF_TOKEN)
178
else if (pushToken == LOCK_TOKEN)
181
* eol_seen is only set for the first token after a newline.
185
c = configBuf[configPos];
188
* Get start of next Token. EOF is handled,
189
* whitespaces are skipped.
197
ret = fgets (configBuf, CONFIG_BUF_LEN - 1, configFile);
199
if (builtinConfig[builtinIndex] == NULL)
202
ret = strncpy(configBuf, builtinConfig[builtinIndex],
209
return (pushToken = EOF_TOKEN);
218
c = configBuf[configPos++];
238
configRBuf[i++] = (c = configBuf[configPos++]);
240
while ((c != '\n') && (c != '\r') && (c != '\0'));
241
configRBuf[i] = '\0';
242
/* XXX no private copy.
243
* Use xf86addComment when setting a comment.
245
val.str = configRBuf;
249
/* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */
250
else if ((c == ',') && !isalpha (configBuf[configPos]))
254
else if ((c == '-') && !isalpha (configBuf[configPos]))
260
* Numbers are returned immediately ...
267
if ((configBuf[configPos] == 'x') ||
268
(configBuf[configPos] == 'X'))
277
while (isdigit (c = configBuf[configPos++]) ||
278
(c == '.') || (c == 'x') || (c == 'X') ||
279
((base == 16) && (((c >= 'a') && (c <= 'f')) ||
280
((c >= 'A') && (c <= 'F')))))
282
configPos--; /* GJA -- one too far */
283
configRBuf[i] = '\0';
284
val.num = xf86strToUL (configRBuf);
285
val.realnum = atof (configRBuf);
290
* All Strings START with a \" ...
297
configRBuf[++i] = (c = configBuf[configPos++]);
299
while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
300
configRBuf[i] = '\0';
301
val.str = xf86confmalloc (strlen (configRBuf) + 1);
302
strcpy (val.str, configRBuf); /* private copy ! */
307
* ... and now we MUST have a valid token. The search is
308
* handled later along with the pushed tokens.
316
configRBuf[++i] = (c = configBuf[configPos++]);;
318
while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0') && (c != '#'));
320
configRBuf[i] = '\0';
329
* Here we deal with pushed tokens. Reinitialize pushToken again. If
330
* the pushed token was NUMBER || STRING return them again ...
332
int temp = pushToken;
333
pushToken = LOCK_TOKEN;
335
if (temp == COMMA || temp == DASH)
337
if (temp == NUMBER || temp == STRING)
342
* Joop, at last we have to lookup the token ...
347
while (tab[i].token != -1)
348
if (xf86nameCompare (configRBuf, tab[i].name) == 0)
349
return (tab[i].token);
354
return (ERROR_TOKEN); /* Error catcher */
358
xf86getSubToken (char **comment)
363
token = xf86getToken(NULL);
364
if (token == COMMENT) {
366
*comment = xf86addComment(*comment, val.str);
375
xf86getSubTokenWithTab (char **comment, xf86ConfigSymTabRec *tab)
380
token = xf86getToken(tab);
381
if (token == COMMENT) {
383
*comment = xf86addComment(*comment, val.str);
392
xf86unGetToken (int token)
398
xf86tokenString (void)
404
xf86pathIsAbsolute(const char *path)
406
if (path && path[0] == '/')
409
if (path && (path[0] == '\\' || (path[1] == ':')))
415
/* A path is "safe" if it is relative and if it contains no ".." elements. */
417
xf86pathIsSafe(const char *path)
419
if (xf86pathIsAbsolute(path))
422
/* Compare with ".." */
423
if (!strcmp(path, ".."))
426
/* Look for leading "../" */
427
if (!strncmp(path, "../", 3))
430
/* Look for trailing "/.." */
431
if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
434
/* Look for "/../" */
435
if (strstr(path, "/../"))
442
* This function substitutes the following escape sequences:
444
* %A cmdline argument as an absolute path (must be absolute to match)
445
* %R cmdline argument as a relative path
446
* %S cmdline argument as a "safe" path (relative, and no ".." elements)
447
* %X default config file name ("xorg.conf")
449
* %E config file environment ($XORGCONFIG) as an absolute path
450
* %F config file environment ($XORGCONFIG) as a relative path
451
* %G config file environment ($XORGCONFIG) as a safe path
454
* %M major version number
456
* %& UNIXOS2 only: prepend X11ROOT env var
460
#define XCONFIGFILE "xorg.conf"
463
#define PROJECTROOT "/usr/X11R6"
466
#define XCONFENV "XORGCONFIG"
468
#define XFREE86CFGFILE "XF86Config"
469
#ifndef XF86_VERSION_MAJOR
471
#if XVERSION > 40000000
472
#define XF86_VERSION_MAJOR (XVERSION / 10000000)
474
#define XF86_VERSION_MAJOR (XVERSION / 1000)
477
#define XF86_VERSION_MAJOR 4
481
#define BAIL_OUT do { \
482
xf86conffree(result); \
486
#define CHECK_LENGTH do { \
487
if (l > PATH_MAX) { \
492
#define APPEND_STR(s) do { \
493
if (strlen(s) + l > PATH_MAX) { \
496
strcpy(result + l, s); \
502
DoSubstitution(const char *template, const char *cmdline, const char *projroot,
503
int *cmdlineUsed, int *envUsed, char *XConfigFile)
507
static const char *env = NULL, *home = NULL;
508
static char *hostname = NULL;
509
static char majorvers[3] = "";
511
static char *x11root = NULL;
522
result = xf86confmalloc(PATH_MAX + 1);
524
for (i = 0; template[i]; i++) {
525
if (template[i] != '%') {
526
result[l++] = template[i];
529
switch (template[++i]) {
531
if (cmdline && xf86pathIsAbsolute(cmdline)) {
539
if (cmdline && !xf86pathIsAbsolute(cmdline)) {
547
if (cmdline && xf86pathIsSafe(cmdline)) {
555
APPEND_STR(XConfigFile);
559
if ((hostname = xf86confmalloc(MAXHOSTNAMELEN + 1))) {
560
if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
561
hostname[MAXHOSTNAMELEN] = '\0';
563
xf86conffree(hostname);
569
APPEND_STR(hostname);
573
env = getenv(XCONFENV);
574
if (env && xf86pathIsAbsolute(env)) {
583
env = getenv(XCONFENV);
584
if (env && !xf86pathIsAbsolute(env)) {
593
env = getenv(XCONFENV);
594
if (env && xf86pathIsSafe(env)) {
603
home = getenv("HOME");
604
if (home && xf86pathIsAbsolute(home))
610
if (projroot && xf86pathIsAbsolute(projroot))
611
APPEND_STR(projroot);
617
if (XF86_VERSION_MAJOR < 0 || XF86_VERSION_MAJOR > 99) {
618
fprintf(stderr, "XF86_VERSION_MAJOR is out of range\n");
621
sprintf(majorvers, "%d", XF86_VERSION_MAJOR);
623
APPEND_STR(majorvers);
632
x11root = getenv("X11ROOT");
640
fprintf(stderr, "invalid escape %%%c found in path template\n",
648
fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
654
* xf86openConfigFile --
656
* This function take a config file search path (optional), a command-line
657
* specified file name (optional) and the ProjectRoot path (optional) and
658
* locates and opens a config file based on that information. If a
659
* command-line file name is specified, then this function fails if none
660
* of the located files.
662
* The return value is a pointer to the actual name of the file that was
663
* opened. When no file is found, the return value is NULL.
665
* The escape sequences allowed in the search path are defined above.
669
#ifndef DEFAULT_CONF_PATH
670
#define DEFAULT_CONF_PATH "/etc/X11/%S," \
677
"%P/etc/X11/%X.%H," \
678
"%P/etc/X11/%X-%M," \
680
"%P/lib/X11/%X.%H," \
681
"%P/lib/X11/%X-%M," \
686
xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
689
const char *template;
693
configPos = 0; /* current readers position */
694
configLineNo = 0; /* linenumber */
695
pushToken = LOCK_TOKEN;
697
if (!path || !path[0])
698
path = DEFAULT_CONF_PATH;
699
pathcopy = xf86confmalloc(strlen(path) + 1);
700
strcpy(pathcopy, path);
701
if (!projroot || !projroot[0])
702
projroot = PROJECTROOT;
704
template = strtok(pathcopy, ",");
706
/* First, search for a config file. */
707
while (template && !configFile) {
708
if ((configPath = DoSubstitution(template, cmdline, projroot,
711
if ((configFile = fopen(configPath, "r")) != 0) {
712
if (cmdline && !cmdlineUsed) {
718
if (configPath && !configFile) {
719
xf86conffree(configPath);
722
template = strtok(NULL, ",");
725
/* Then search for fallback */
727
strcpy(pathcopy, path);
728
template = strtok(pathcopy, ",");
730
while (template && !configFile) {
731
if ((configPath = DoSubstitution(template, cmdline, projroot,
734
if ((configFile = fopen(configPath, "r")) != 0) {
735
if (cmdline && !cmdlineUsed) {
741
if (configPath && !configFile) {
742
xf86conffree(configPath);
745
template = strtok(NULL, ",");
749
xf86conffree(pathcopy);
755
configBuf = xf86confmalloc (CONFIG_BUF_LEN);
756
configRBuf = xf86confmalloc (CONFIG_BUF_LEN);
757
configBuf[0] = '\0'; /* sanity ... */
763
xf86closeConfigFile (void)
765
xf86conffree (configPath);
767
xf86conffree (configRBuf);
769
xf86conffree (configBuf);
776
builtinConfig = NULL;
782
xf86setBuiltinConfig(const char *config[])
784
builtinConfig = config;
785
configPath = xf86configStrdup("<builtin configuration>");
786
configBuf = xf86confmalloc (CONFIG_BUF_LEN);
787
configRBuf = xf86confmalloc (CONFIG_BUF_LEN);
788
configBuf[0] = '\0'; /* sanity ... */
793
xf86parseError (char *format,...)
797
ErrorF ("Parse error on line %d of section %s in file %s\n\t",
798
configLineNo, configSection, configPath);
799
va_start (ap, format);
800
VErrorF (format, ap);
807
xf86parseWarning (char *format,...)
811
ErrorF ("Parse warning on line %d of section %s in file %s\n\t",
812
configLineNo, configSection, configPath);
813
va_start (ap, format);
814
VErrorF (format, ap);
821
xf86validationError (char *format,...)
825
ErrorF ("Data incomplete in file %s\n\t", configPath);
826
va_start (ap, format);
827
VErrorF (format, ap);
834
xf86setSection (char *section)
837
xf86conffree(configSection);
838
configSection = xf86confmalloc(strlen (section) + 1);
839
strcpy (configSection, section);
844
* Lookup a string if it is actually a token in disguise.
847
xf86getStringToken (xf86ConfigSymTabRec * tab)
849
return StringToToken (val.str, tab);
853
StringToToken (char *str, xf86ConfigSymTabRec * tab)
857
for (i = 0; tab[i].token != -1; i++)
859
if (!xf86nameCompare (tab[i].name, str))
862
return (ERROR_TOKEN);
867
* Compare two names. The characters '_', ' ', and '\t' are ignored
871
xf86nameCompare (const char *s1, const char *s2)
875
if (!s1 || *s1 == 0) {
882
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
884
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
886
c1 = (isupper (*s1) ? tolower (*s1) : *s1);
887
c2 = (isupper (*s2) ? tolower (*s2) : *s2);
894
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
896
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
898
c1 = (isupper (*s1) ? tolower (*s1) : *s1);
899
c2 = (isupper (*s2) ? tolower (*s2) : *s2);
905
xf86addComment(char *cur, char *add)
908
int len, curlen, iscomment, hasnewline = 0, endnewline;
910
if (add == NULL || add[0] == '\0')
914
curlen = strlen(cur);
916
hasnewline = cur[curlen - 1] == '\n';
925
if (*str != ' ' && *str != '\t')
929
iscomment = (*str == '#');
932
endnewline = add[len - 1] == '\n';
933
len += 1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen;
935
if ((str = xf86confrealloc(cur, len + curlen)) == NULL)
940
if (eol_seen || (curlen && !hasnewline))
941
cur[curlen++] = '\n';
944
strcpy(cur + curlen, add);