1074 lines
24 KiB
C
1074 lines
24 KiB
C
/* $XFree86: xc/programs/Xserver/hw/xfree86/parser/scan.c,v 1.24 2003/01/04 20:20:23 paulo Exp $ */
|
|
/*
|
|
*
|
|
* Copyright (c) 1997 Metro Link Incorporated
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the Metro Link shall not be
|
|
* used in advertising or otherwise to promote the sale, use or other dealings
|
|
* in this Software without prior written authorization from Metro Link.
|
|
*
|
|
*/
|
|
|
|
/* View/edit this file with tab stops set to 4 */
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
|
|
#if !defined(X_NOT_POSIX)
|
|
#if defined(_POSIX_SOURCE)
|
|
#include <limits.h>
|
|
#else
|
|
#define _POSIX_SOURCE
|
|
#include <limits.h>
|
|
#undef _POSIX_SOURCE
|
|
#endif /* _POSIX_SOURCE */
|
|
#endif /* !X_NOT_POSIX */
|
|
#if !defined(PATH_MAX)
|
|
#if defined(MAXPATHLEN)
|
|
#define PATH_MAX MAXPATHLEN
|
|
#else
|
|
#define PATH_MAX 1024
|
|
#endif /* MAXPATHLEN */
|
|
#endif /* !PATH_MAX */
|
|
|
|
#if !defined(MAXHOSTNAMELEN)
|
|
#define MAXHOSTNAMELEN 32
|
|
#endif /* !MAXHOSTNAMELEN */
|
|
|
|
#include "Configint.h"
|
|
#include "xf86tokens.h"
|
|
|
|
#define CONFIG_BUF_LEN 1024
|
|
|
|
static int StringToToken (char *, xf86ConfigSymTabRec *);
|
|
|
|
static FILE *configFile = NULL;
|
|
static int configStart = 0; /* start of the current token */
|
|
static int configPos = 0; /* current readers position */
|
|
static int configLineNo = 0; /* linenumber */
|
|
static char *configBuf, *configRBuf; /* buffer for lines */
|
|
static char *configPath; /* path to config file */
|
|
static char *configSection = NULL; /* name of current section being parsed */
|
|
static int pushToken = LOCK_TOKEN;
|
|
static int eol_seen = 0; /* private state to handle comments */
|
|
LexRec val;
|
|
|
|
#ifdef __UNIXOS2__
|
|
extern char *__XOS2RedirRoot(char *path);
|
|
#endif
|
|
|
|
/*
|
|
* xf86strToUL --
|
|
*
|
|
* A portable, but restricted, version of strtoul(). It only understands
|
|
* hex, octal, and decimal. But it's good enough for our needs.
|
|
*/
|
|
unsigned int
|
|
xf86strToUL (char *str)
|
|
{
|
|
int base = 10;
|
|
char *p = str;
|
|
unsigned int tot = 0;
|
|
|
|
if (*p == '0')
|
|
{
|
|
p++;
|
|
if ((*p == 'x') || (*p == 'X'))
|
|
{
|
|
p++;
|
|
base = 16;
|
|
}
|
|
else
|
|
base = 8;
|
|
}
|
|
while (*p)
|
|
{
|
|
if ((*p >= '0') && (*p <= ((base == 8) ? '7' : '9')))
|
|
{
|
|
tot = tot * base + (*p - '0');
|
|
}
|
|
else if ((base == 16) && (*p >= 'a') && (*p <= 'f'))
|
|
{
|
|
tot = tot * base + 10 + (*p - 'a');
|
|
}
|
|
else if ((base == 16) && (*p >= 'A') && (*p <= 'F'))
|
|
{
|
|
tot = tot * base + 10 + (*p - 'A');
|
|
}
|
|
else
|
|
{
|
|
return (tot);
|
|
}
|
|
p++;
|
|
}
|
|
return (tot);
|
|
}
|
|
|
|
/*
|
|
* xf86getToken --
|
|
* Read next Token form the config file. Handle the global variable
|
|
* pushToken.
|
|
*/
|
|
int
|
|
xf86getToken (xf86ConfigSymTabRec * tab)
|
|
{
|
|
int c, i;
|
|
|
|
/*
|
|
* First check whether pushToken has a different value than LOCK_TOKEN.
|
|
* In this case rBuf[] contains a valid STRING/TOKEN/NUMBER. But in the
|
|
* oth * case the next token must be read from the input.
|
|
*/
|
|
if (pushToken == EOF_TOKEN)
|
|
return (EOF_TOKEN);
|
|
else if (pushToken == LOCK_TOKEN)
|
|
{
|
|
/*
|
|
* eol_seen is only set for the first token after a newline.
|
|
*/
|
|
eol_seen = 0;
|
|
|
|
c = configBuf[configPos];
|
|
|
|
/*
|
|
* Get start of next Token. EOF is handled,
|
|
* whitespaces are skipped.
|
|
*/
|
|
|
|
again:
|
|
if (!c)
|
|
{
|
|
if (fgets (configBuf, CONFIG_BUF_LEN - 1, configFile) == NULL)
|
|
{
|
|
return (pushToken = EOF_TOKEN);
|
|
}
|
|
configLineNo++;
|
|
configStart = configPos = 0;
|
|
eol_seen = 1;
|
|
}
|
|
|
|
i = 0;
|
|
for (;;) {
|
|
c = configBuf[configPos++];
|
|
configRBuf[i++] = c;
|
|
switch (c) {
|
|
case ' ':
|
|
case '\t':
|
|
case '\r':
|
|
continue;
|
|
case '\n':
|
|
i = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (c == '\0')
|
|
goto again;
|
|
|
|
if (c == '#')
|
|
{
|
|
do
|
|
{
|
|
configRBuf[i++] = (c = configBuf[configPos++]);
|
|
}
|
|
while ((c != '\n') && (c != '\r') && (c != '\0'));
|
|
configRBuf[i] = '\0';
|
|
/* XXX no private copy.
|
|
* Use xf86addComment when setting a comment.
|
|
*/
|
|
val.str = configRBuf;
|
|
return (COMMENT);
|
|
}
|
|
|
|
/* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */
|
|
else if ((c == ',') && !isalpha (configBuf[configPos]))
|
|
{
|
|
configStart = configPos;
|
|
return COMMA;
|
|
}
|
|
else if ((c == '-') && !isalpha (configBuf[configPos]))
|
|
{
|
|
configStart = configPos;
|
|
return DASH;
|
|
}
|
|
|
|
configStart = configPos;
|
|
/*
|
|
* Numbers are returned immediately ...
|
|
*/
|
|
if (isdigit (c))
|
|
{
|
|
int base;
|
|
|
|
if (c == '0')
|
|
if ((configBuf[configPos] == 'x') ||
|
|
(configBuf[configPos] == 'X'))
|
|
base = 16;
|
|
else
|
|
base = 8;
|
|
else
|
|
base = 10;
|
|
|
|
configRBuf[0] = c;
|
|
i = 1;
|
|
while (isdigit (c = configBuf[configPos++]) ||
|
|
(c == '.') || (c == 'x') || (c == 'X') ||
|
|
((base == 16) && (((c >= 'a') && (c <= 'f')) ||
|
|
((c >= 'A') && (c <= 'F')))))
|
|
configRBuf[i++] = c;
|
|
configPos--; /* GJA -- one too far */
|
|
configRBuf[i] = '\0';
|
|
val.num = xf86strToUL (configRBuf);
|
|
val.realnum = atof (configRBuf);
|
|
return (NUMBER);
|
|
}
|
|
|
|
/*
|
|
* All Strings START with a \" ...
|
|
*/
|
|
else if (c == '\"')
|
|
{
|
|
i = -1;
|
|
do
|
|
{
|
|
configRBuf[++i] = (c = configBuf[configPos++]);
|
|
}
|
|
while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
|
|
configRBuf[i] = '\0';
|
|
val.str = xf86confmalloc (strlen (configRBuf) + 1);
|
|
strcpy (val.str, configRBuf); /* private copy ! */
|
|
return (STRING);
|
|
}
|
|
|
|
/*
|
|
* ... and now we MUST have a valid token. The search is
|
|
* handled later along with the pushed tokens.
|
|
*/
|
|
else
|
|
{
|
|
configRBuf[0] = c;
|
|
i = 0;
|
|
do
|
|
{
|
|
configRBuf[++i] = (c = configBuf[configPos++]);;
|
|
}
|
|
while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0') && (c != '#'));
|
|
--configPos;
|
|
configRBuf[i] = '\0';
|
|
i = 0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
* Here we deal with pushed tokens. Reinitialize pushToken again. If
|
|
* the pushed token was NUMBER || STRING return them again ...
|
|
*/
|
|
int temp = pushToken;
|
|
pushToken = LOCK_TOKEN;
|
|
|
|
if (temp == COMMA || temp == DASH)
|
|
return (temp);
|
|
if (temp == NUMBER || temp == STRING)
|
|
return (temp);
|
|
}
|
|
|
|
/*
|
|
* Joop, at last we have to lookup the token ...
|
|
*/
|
|
if (tab)
|
|
{
|
|
i = 0;
|
|
while (tab[i].token != -1)
|
|
if (xf86nameCompare (configRBuf, tab[i].name) == 0)
|
|
return (tab[i].token);
|
|
else
|
|
i++;
|
|
}
|
|
|
|
return (ERROR_TOKEN); /* Error catcher */
|
|
}
|
|
|
|
int
|
|
xf86getSubToken (char **comment)
|
|
{
|
|
int token;
|
|
|
|
for (;;) {
|
|
token = xf86getToken(NULL);
|
|
if (token == COMMENT) {
|
|
if (comment)
|
|
*comment = xf86addComment(*comment, val.str);
|
|
}
|
|
else
|
|
return (token);
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
int
|
|
xf86getSubTokenWithTab (char **comment, xf86ConfigSymTabRec *tab)
|
|
{
|
|
int token;
|
|
|
|
for (;;) {
|
|
token = xf86getToken(tab);
|
|
if (token == COMMENT) {
|
|
if (comment)
|
|
*comment = xf86addComment(*comment, val.str);
|
|
}
|
|
else
|
|
return (token);
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
void
|
|
xf86unGetToken (int token)
|
|
{
|
|
pushToken = token;
|
|
}
|
|
|
|
char *
|
|
xf86tokenString (void)
|
|
{
|
|
return configRBuf;
|
|
}
|
|
|
|
#if 1
|
|
int
|
|
xf86pathIsAbsolute(const char *path)
|
|
{
|
|
if (path && path[0] == '/')
|
|
return 1;
|
|
#ifdef __UNIXOS2__
|
|
if (path && (path[0] == '\\' || (path[1] == ':')))
|
|
return 0;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* A path is "safe" if it is relative and if it contains no ".." elements. */
|
|
int
|
|
xf86pathIsSafe(const char *path)
|
|
{
|
|
if (xf86pathIsAbsolute(path))
|
|
return 0;
|
|
|
|
/* Compare with ".." */
|
|
if (!strcmp(path, ".."))
|
|
return 0;
|
|
|
|
/* Look for leading "../" */
|
|
if (!strncmp(path, "../", 3))
|
|
return 0;
|
|
|
|
/* Look for trailing "/.." */
|
|
if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
|
|
return 0;
|
|
|
|
/* Look for "/../" */
|
|
if (strstr(path, "/../"))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* This function substitutes the following escape sequences:
|
|
*
|
|
* %A cmdline argument as an absolute path (must be absolute to match)
|
|
* %R cmdline argument as a relative path
|
|
* %S cmdline argument as a "safe" path (relative, and no ".." elements)
|
|
* %X default config file name ("XF86Config")
|
|
* %H hostname
|
|
* %E config file environment ($XF86CONFIG) as an absolute path
|
|
* %F config file environment ($XF86CONFIG) as a relative path
|
|
* %G config file environment ($XF86CONFIG) as a safe path
|
|
* %D $HOME
|
|
* %P projroot
|
|
* %M major version number
|
|
* %% %
|
|
* %& UNIXOS2 only: prepend X11ROOT env var
|
|
*/
|
|
|
|
#ifndef XCONFIGFILE
|
|
#define XCONFIGFILE "XF86Config"
|
|
#endif
|
|
#ifndef PROJECTROOT
|
|
#define PROJECTROOT "/usr/X11R6"
|
|
#endif
|
|
#ifndef XCONFENV
|
|
#define XCONFENV "XF86CONFIG"
|
|
#endif
|
|
#ifndef XF86_VERSION_MAJOR
|
|
#ifdef XVERSION
|
|
#if XVERSION > 40000000
|
|
#define XF86_VERSION_MAJOR (XVERSION / 10000000)
|
|
#else
|
|
#define XF86_VERSION_MAJOR (XVERSION / 1000)
|
|
#endif
|
|
#else
|
|
#define XF86_VERSION_MAJOR 4
|
|
#endif
|
|
#endif
|
|
|
|
#define BAIL_OUT do { \
|
|
xf86conffree(result); \
|
|
return NULL; \
|
|
} while (0)
|
|
|
|
#define CHECK_LENGTH do { \
|
|
if (l > PATH_MAX) { \
|
|
BAIL_OUT; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define APPEND_STR(s) do { \
|
|
if (strlen(s) + l > PATH_MAX) { \
|
|
BAIL_OUT; \
|
|
} else { \
|
|
strcpy(result + l, s); \
|
|
l += strlen(s); \
|
|
} \
|
|
} while (0)
|
|
|
|
static char *
|
|
DoSubstitution(const char *template, const char *cmdline, const char *projroot,
|
|
int *cmdlineUsed, int *envUsed)
|
|
{
|
|
char *result;
|
|
int i, l;
|
|
static const char *env = NULL, *home = NULL;
|
|
static char *hostname = NULL;
|
|
static char majorvers[3] = "";
|
|
#ifdef __UNIXOS2__
|
|
static char *x11root = NULL;
|
|
#endif
|
|
|
|
if (!template)
|
|
return NULL;
|
|
|
|
if (cmdlineUsed)
|
|
*cmdlineUsed = 0;
|
|
if (envUsed)
|
|
*envUsed = 0;
|
|
|
|
result = xf86confmalloc(PATH_MAX + 1);
|
|
l = 0;
|
|
for (i = 0; template[i]; i++) {
|
|
if (template[i] != '%') {
|
|
result[l++] = template[i];
|
|
CHECK_LENGTH;
|
|
} else {
|
|
switch (template[++i]) {
|
|
case 'A':
|
|
if (cmdline && xf86pathIsAbsolute(cmdline)) {
|
|
APPEND_STR(cmdline);
|
|
if (cmdlineUsed)
|
|
*cmdlineUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'R':
|
|
if (cmdline && !xf86pathIsAbsolute(cmdline)) {
|
|
APPEND_STR(cmdline);
|
|
if (cmdlineUsed)
|
|
*cmdlineUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'S':
|
|
if (cmdline && xf86pathIsSafe(cmdline)) {
|
|
APPEND_STR(cmdline);
|
|
if (cmdlineUsed)
|
|
*cmdlineUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'X':
|
|
APPEND_STR(XCONFIGFILE);
|
|
break;
|
|
case 'H':
|
|
if (!hostname) {
|
|
if ((hostname = xf86confmalloc(MAXHOSTNAMELEN + 1))) {
|
|
if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
|
|
hostname[MAXHOSTNAMELEN] = '\0';
|
|
} else {
|
|
xf86conffree(hostname);
|
|
hostname = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (hostname)
|
|
APPEND_STR(hostname);
|
|
break;
|
|
case 'E':
|
|
if (!env)
|
|
env = getenv(XCONFENV);
|
|
if (env && xf86pathIsAbsolute(env)) {
|
|
APPEND_STR(env);
|
|
if (envUsed)
|
|
*envUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'F':
|
|
if (!env)
|
|
env = getenv(XCONFENV);
|
|
if (env && !xf86pathIsAbsolute(env)) {
|
|
APPEND_STR(env);
|
|
if (envUsed)
|
|
*envUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'G':
|
|
if (!env)
|
|
env = getenv(XCONFENV);
|
|
if (env && xf86pathIsSafe(env)) {
|
|
APPEND_STR(env);
|
|
if (envUsed)
|
|
*envUsed = 1;
|
|
} else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'D':
|
|
if (!home)
|
|
home = getenv("HOME");
|
|
if (home && xf86pathIsAbsolute(home))
|
|
APPEND_STR(home);
|
|
else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'P':
|
|
if (projroot && xf86pathIsAbsolute(projroot))
|
|
APPEND_STR(projroot);
|
|
else
|
|
BAIL_OUT;
|
|
break;
|
|
case 'M':
|
|
if (!majorvers[0]) {
|
|
if (XF86_VERSION_MAJOR < 0 || XF86_VERSION_MAJOR > 99) {
|
|
fprintf(stderr, "XF86_VERSION_MAJOR is out of range\n");
|
|
BAIL_OUT;
|
|
} else
|
|
sprintf(majorvers, "%d", XF86_VERSION_MAJOR);
|
|
}
|
|
APPEND_STR(majorvers);
|
|
break;
|
|
case '%':
|
|
result[l++] = '%';
|
|
CHECK_LENGTH;
|
|
break;
|
|
#ifdef __UNIXOS2__
|
|
case '&':
|
|
if (!x11root)
|
|
x11root = getenv("X11ROOT");
|
|
if (x11root)
|
|
APPEND_STR(x11root);
|
|
else
|
|
BAIL_OUT;
|
|
break;
|
|
#endif
|
|
default:
|
|
fprintf(stderr, "invalid escape %%%c found in path template\n",
|
|
template[i]);
|
|
BAIL_OUT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* xf86openConfigFile --
|
|
*
|
|
* This function take a config file search path (optional), a command-line
|
|
* specified file name (optional) and the ProjectRoot path (optional) and
|
|
* locates and opens a config file based on that information. If a
|
|
* command-line file name is specified, then this function fails if none
|
|
* of the located files.
|
|
*
|
|
* The return value is a pointer to the actual name of the file that was
|
|
* opened. When no file is found, the return value is NULL.
|
|
*
|
|
* The escape sequences allowed in the search path are defined above.
|
|
*
|
|
*/
|
|
|
|
#ifndef DEFAULT_CONF_PATH
|
|
#define DEFAULT_CONF_PATH "/etc/X11/%S," \
|
|
"%P/etc/X11/%S," \
|
|
"/etc/X11/%G," \
|
|
"%P/etc/X11/%G," \
|
|
"/etc/X11/%X-%M," \
|
|
"/etc/X11/%X," \
|
|
"/etc/%X," \
|
|
"%P/etc/X11/%X.%H," \
|
|
"%P/etc/X11/%X-%M," \
|
|
"%P/etc/X11/%X," \
|
|
"%P/lib/X11/%X.%H," \
|
|
"%P/lib/X11/%X-%M," \
|
|
"%P/lib/X11/%X"
|
|
#endif
|
|
|
|
const char *
|
|
xf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
|
|
{
|
|
char *pathcopy;
|
|
const char *template;
|
|
int cmdlineUsed = 0;
|
|
|
|
configFile = NULL;
|
|
configStart = 0; /* start of the current token */
|
|
configPos = 0; /* current readers position */
|
|
configLineNo = 0; /* linenumber */
|
|
pushToken = LOCK_TOKEN;
|
|
|
|
if (!path || !path[0])
|
|
path = DEFAULT_CONF_PATH;
|
|
pathcopy = xf86confmalloc(strlen(path) + 1);
|
|
strcpy(pathcopy, path);
|
|
if (!projroot || !projroot[0])
|
|
projroot = PROJECTROOT;
|
|
|
|
template = strtok(pathcopy, ",");
|
|
|
|
/* First, search for a config file. */
|
|
while (template && !configFile) {
|
|
if ((configPath = DoSubstitution(template, cmdline, projroot,
|
|
&cmdlineUsed, NULL))) {
|
|
if ((configFile = fopen(configPath, "r")) != 0) {
|
|
if (cmdline && !cmdlineUsed) {
|
|
fclose(configFile);
|
|
configFile = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (configPath && !configFile) {
|
|
xf86conffree(configPath);
|
|
configPath = NULL;
|
|
}
|
|
template = strtok(NULL, ",");
|
|
}
|
|
xf86conffree(pathcopy);
|
|
if (!configFile) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
configBuf = xf86confmalloc (CONFIG_BUF_LEN);
|
|
configRBuf = xf86confmalloc (CONFIG_BUF_LEN);
|
|
configBuf[0] = '\0'; /* sanity ... */
|
|
|
|
return configPath;
|
|
}
|
|
#else
|
|
/*
|
|
* xf86openConfigFile --
|
|
*
|
|
* Formerly findConfigFile(). This function take a pointer to a location
|
|
* in which to place the actual name of the file that was opened.
|
|
* This function uses the global character array xf86ConfigFile
|
|
* This function returns the following results.
|
|
*
|
|
* 0 unable to open the config file
|
|
* 1 file opened and ready to read
|
|
*
|
|
*/
|
|
|
|
int
|
|
xf86openConfigFile (char *filename)
|
|
{
|
|
#define MAXPTRIES 6
|
|
char *home = NULL;
|
|
char *xconfig = NULL;
|
|
char *xwinhome = NULL;
|
|
char *configPaths[MAXPTRIES];
|
|
int pcount = 0, idx;
|
|
|
|
/*
|
|
* First open if necessary the config file.
|
|
* If the -xf86config flag was used, use the name supplied there (root only).
|
|
* If $XF86CONFIG is a pathname, use it as the name of the config file (root)
|
|
* If $XF86CONFIG is set but doesn't contain a '/', append it to 'XF86Config'
|
|
* and search the standard places (root only).
|
|
* If $XF86CONFIG is not set, just search the standard places.
|
|
*/
|
|
configFile = NULL;
|
|
configStart = 0; /* start of the current token */
|
|
configPos = 0; /* current readers position */
|
|
configLineNo = 0; /* linenumber */
|
|
pushToken = LOCK_TOKEN;
|
|
while (!configFile)
|
|
{
|
|
|
|
/*
|
|
* configPaths[0] is used as a buffer for -xf86config
|
|
* and $XF86CONFIG if it contains a path
|
|
* configPaths[1...MAXPTRIES-1] is used to store the paths of each of
|
|
* the other attempts
|
|
*/
|
|
for (pcount = idx = 0; idx < MAXPTRIES; idx++)
|
|
configPaths[idx] = NULL;
|
|
|
|
/*
|
|
* First check if the -xf86config option was used.
|
|
*/
|
|
configPaths[pcount] = xf86confmalloc (PATH_MAX);
|
|
if (xf86ConfigFile[0])
|
|
{
|
|
strcpy (configPaths[pcount], xf86ConfigFile);
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
else
|
|
return 0;
|
|
}
|
|
/*
|
|
* Check if XF86CONFIG is set.
|
|
*/
|
|
#ifndef __UNIXOS2__
|
|
if (getuid () == 0
|
|
&& (xconfig = getenv ("XF86CONFIG")) != 0
|
|
&& strchr (xconfig, '/'))
|
|
#else
|
|
/* no root available, and filenames start with drive letter */
|
|
if ((xconfig = getenv ("XF86CONFIG")) != 0
|
|
&& isalpha (xconfig[0])
|
|
&& xconfig[1] == ':')
|
|
#endif
|
|
{
|
|
strcpy (configPaths[pcount], xconfig);
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
#ifndef __UNIXOS2__
|
|
/*
|
|
* ~/XF86Config ...
|
|
*/
|
|
if (getuid () == 0 && (home = getenv ("HOME")) != NULL)
|
|
{
|
|
configPaths[++pcount] = xf86confmalloc (PATH_MAX);
|
|
strcpy (configPaths[pcount], home);
|
|
strcat (configPaths[pcount], "/" XCONFIGFILE);
|
|
if (xconfig)
|
|
strcat (configPaths[pcount], xconfig);
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* /etc/XF86Config
|
|
*/
|
|
configPaths[++pcount] = xf86confmalloc (PATH_MAX);
|
|
strcpy (configPaths[pcount], "/etc/" XCONFIGFILE);
|
|
if (xconfig)
|
|
strcat (configPaths[pcount], xconfig);
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
|
|
/*
|
|
* $(XCONFIGDIR)/XF86Config.<hostname>
|
|
*/
|
|
|
|
configPaths[++pcount] = xf86confmalloc (PATH_MAX);
|
|
if (getuid () == 0 && (xwinhome = getenv ("XWINHOME")) != NULL)
|
|
sprintf (configPaths[pcount], "%s/lib/X11/" XCONFIGFILE, xwinhome);
|
|
else
|
|
strcpy (configPaths[pcount], XCONFIGDIR "/" XCONFIGFILE);
|
|
if (getuid () == 0 && xconfig)
|
|
strcat (configPaths[pcount], xconfig);
|
|
strcat (configPaths[pcount], ".");
|
|
gethostname (configPaths[pcount] + strlen (configPaths[pcount]),
|
|
MAXHOSTNAMELEN);
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
#endif /* !__UNIXOS2__ */
|
|
|
|
/*
|
|
* $(XCONFIGDIR)/XF86Config
|
|
*/
|
|
configPaths[++pcount] = xf86confmalloc (PATH_MAX);
|
|
#ifndef __UNIXOS2__
|
|
if (getuid () == 0 && xwinhome)
|
|
sprintf (configPaths[pcount], "%s/lib/X11/" XCONFIGFILE, xwinhome);
|
|
else
|
|
strcpy (configPaths[pcount], XCONFIGDIR "/" XCONFIGFILE);
|
|
if (getuid () == 0 && xconfig)
|
|
strcat (configPaths[pcount], xconfig);
|
|
#else
|
|
/*
|
|
* we explicitly forbid numerous config files everywhere for OS/2;
|
|
* users should consider them lucky to have one in a standard place
|
|
* and another one with the -xf86config option
|
|
*/
|
|
xwinhome = getenv ("X11ROOT"); /* get drive letter */
|
|
if (!xwinhome) {
|
|
fprintf (stderr,"X11ROOT environment variable not set\n");
|
|
exit(2);
|
|
}
|
|
strcpy (configPaths[pcount], __XOS2RedirRoot ("/XFree86/lib/X11/XConfig"));
|
|
#endif
|
|
|
|
if ((configFile = fopen (configPaths[pcount], "r")) != 0)
|
|
break;
|
|
|
|
return 0;
|
|
}
|
|
configBuf = xf86confmalloc (CONFIG_BUF_LEN);
|
|
configRBuf = xf86confmalloc (CONFIG_BUF_LEN);
|
|
configPath = xf86confmalloc (PATH_MAX);
|
|
|
|
strcpy (configPath, configPaths[pcount]);
|
|
|
|
if (filename)
|
|
strcpy (filename, configPaths[pcount]);
|
|
for (idx = 0; idx <= pcount; idx++)
|
|
if (configPaths[idx] != NULL)
|
|
xf86conffree (configPaths[idx]);
|
|
|
|
configBuf[0] = '\0'; /* sanity ... */
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
xf86closeConfigFile (void)
|
|
{
|
|
xf86conffree (configPath);
|
|
configPath = NULL;
|
|
xf86conffree (configRBuf);
|
|
configRBuf = NULL;
|
|
xf86conffree (configBuf);
|
|
configBuf = NULL;
|
|
|
|
fclose (configFile);
|
|
configFile = NULL;
|
|
}
|
|
|
|
void
|
|
xf86parseError (char *format,...)
|
|
{
|
|
va_list ap;
|
|
|
|
#if 0
|
|
fprintf (stderr, "Parse error on line %d of section %s in file %s\n",
|
|
configLineNo, configSection, configPath);
|
|
fprintf (stderr, "\t");
|
|
va_start (ap, format);
|
|
vfprintf (stderr, format, ap);
|
|
va_end (ap);
|
|
|
|
fprintf (stderr, "\n");
|
|
#else
|
|
ErrorF ("Parse error on line %d of section %s in file %s\n\t",
|
|
configLineNo, configSection, configPath);
|
|
va_start (ap, format);
|
|
VErrorF (format, ap);
|
|
va_end (ap);
|
|
|
|
ErrorF ("\n");
|
|
#endif
|
|
|
|
}
|
|
|
|
void
|
|
xf86parseWarning (char *format,...)
|
|
{
|
|
va_list ap;
|
|
|
|
#if 0
|
|
fprintf (stderr, "Parse warning on line %d of section %s in file %s\n",
|
|
configLineNo, configSection, configPath);
|
|
fprintf (stderr, "\t");
|
|
va_start (ap, format);
|
|
vfprintf (stderr, format, ap);
|
|
va_end (ap);
|
|
|
|
fprintf (stderr, "\n");
|
|
#else
|
|
ErrorF ("Parse warning on line %d of section %s in file %s\n\t",
|
|
configLineNo, configSection, configPath);
|
|
va_start (ap, format);
|
|
VErrorF (format, ap);
|
|
va_end (ap);
|
|
|
|
ErrorF ("\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
xf86validationError (char *format,...)
|
|
{
|
|
va_list ap;
|
|
|
|
#if 0
|
|
fprintf (stderr, "Data incomplete in file %s\n",
|
|
configPath);
|
|
fprintf (stderr, "\t");
|
|
va_start (ap, format);
|
|
vfprintf (stderr, format, ap);
|
|
va_end (ap);
|
|
|
|
fprintf (stderr, "\n");
|
|
#else
|
|
ErrorF ("Data incomplete in file %s\n\t", configPath);
|
|
va_start (ap, format);
|
|
VErrorF (format, ap);
|
|
va_end (ap);
|
|
|
|
ErrorF ("\n");
|
|
#endif
|
|
}
|
|
|
|
void
|
|
xf86setSection (char *section)
|
|
{
|
|
if (configSection)
|
|
xf86conffree(configSection);
|
|
configSection = xf86confmalloc(strlen (section) + 1);
|
|
strcpy (configSection, section);
|
|
}
|
|
|
|
/*
|
|
* xf86getToken --
|
|
* Lookup a string if it is actually a token in disguise.
|
|
*/
|
|
int
|
|
xf86getStringToken (xf86ConfigSymTabRec * tab)
|
|
{
|
|
return StringToToken (val.str, tab);
|
|
}
|
|
|
|
static int
|
|
StringToToken (char *str, xf86ConfigSymTabRec * tab)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; tab[i].token != -1; i++)
|
|
{
|
|
if (!xf86nameCompare (tab[i].name, str))
|
|
return tab[i].token;
|
|
}
|
|
return (ERROR_TOKEN);
|
|
}
|
|
|
|
|
|
/*
|
|
* Compare two names. The characters '_', ' ', and '\t' are ignored
|
|
* in the comparison.
|
|
*/
|
|
int
|
|
xf86nameCompare (const char *s1, const char *s2)
|
|
{
|
|
char c1, c2;
|
|
|
|
if (!s1 || *s1 == 0) {
|
|
if (!s2 || *s2 == 0)
|
|
return (0);
|
|
else
|
|
return (1);
|
|
}
|
|
|
|
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
|
|
s1++;
|
|
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
|
|
s2++;
|
|
c1 = (isupper (*s1) ? tolower (*s1) : *s1);
|
|
c2 = (isupper (*s2) ? tolower (*s2) : *s2);
|
|
while (c1 == c2)
|
|
{
|
|
if (c1 == '\0')
|
|
return (0);
|
|
s1++;
|
|
s2++;
|
|
while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
|
|
s1++;
|
|
while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
|
|
s2++;
|
|
c1 = (isupper (*s1) ? tolower (*s1) : *s1);
|
|
c2 = (isupper (*s2) ? tolower (*s2) : *s2);
|
|
}
|
|
return (c1 - c2);
|
|
}
|
|
|
|
char *
|
|
xf86addComment(char *cur, char *add)
|
|
{
|
|
char *str;
|
|
int len, curlen, iscomment, hasnewline = 0, endnewline;
|
|
|
|
if (add == NULL || add[0] == '\0')
|
|
return (cur);
|
|
|
|
if (cur) {
|
|
curlen = strlen(cur);
|
|
if (curlen)
|
|
hasnewline = cur[curlen - 1] == '\n';
|
|
eol_seen = 0;
|
|
}
|
|
else
|
|
curlen = 0;
|
|
|
|
str = add;
|
|
iscomment = 0;
|
|
while (*str) {
|
|
if (*str != ' ' && *str != '\t')
|
|
break;
|
|
++str;
|
|
}
|
|
iscomment = (*str == '#');
|
|
|
|
len = strlen(add);
|
|
endnewline = add[len - 1] == '\n';
|
|
len += 1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen;
|
|
|
|
if ((str = xf86confrealloc(cur, len + curlen)) == NULL)
|
|
return (cur);
|
|
|
|
cur = str;
|
|
|
|
if (eol_seen || (curlen && !hasnewline))
|
|
cur[curlen++] = '\n';
|
|
if (!iscomment)
|
|
cur[curlen++] = '#';
|
|
strcpy(cur + curlen, add);
|
|
if (!endnewline)
|
|
strcat(cur, "\n");
|
|
|
|
return (cur);
|
|
}
|