1117N/A/*
1117N/A *
1117N/A * Copyright (c) 1997 Metro Link Incorporated
1117N/A *
1117N/A * Permission is hereby granted, free of charge, to any person obtaining a
1117N/A * copy of this software and associated documentation files (the "Software"),
1117N/A * to deal in the Software without restriction, including without limitation
1117N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1117N/A * and/or sell copies of the Software, and to permit persons to whom the
1117N/A * Software is furnished to do so, subject to the following conditions:
1117N/A *
1117N/A * The above copyright notice and this permission notice shall be included in
1117N/A * all copies or substantial portions of the Software.
1117N/A *
1117N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1117N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1117N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1117N/A * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1117N/A * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
1117N/A * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1117N/A * SOFTWARE.
1117N/A *
1117N/A * Except as contained in this notice, the name of the Metro Link shall not be
1117N/A * used in advertising or otherwise to promote the sale, use or other dealings
1117N/A * in this Software without prior written authorization from Metro Link.
1117N/A *
1117N/A */
1117N/A/*
1117N/A * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
1117N/A *
1117N/A * Permission is hereby granted, free of charge, to any person obtaining a
1117N/A * copy of this software and associated documentation files (the "Software"),
1117N/A * to deal in the Software without restriction, including without limitation
1117N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1117N/A * and/or sell copies of the Software, and to permit persons to whom the
1117N/A * Software is furnished to do so, subject to the following conditions:
1117N/A *
1117N/A * The above copyright notice and this permission notice shall be included in
1117N/A * all copies or substantial portions of the Software.
1117N/A *
1117N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1117N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1117N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1117N/A * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1117N/A * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1117N/A * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1117N/A * OTHER DEALINGS IN THE SOFTWARE.
1117N/A *
1117N/A * Except as contained in this notice, the name of the copyright holder(s)
1117N/A * and author(s) shall not be used in advertising or otherwise to promote
1117N/A * the sale, use or other dealings in this Software without prior written
1117N/A * authorization from the copyright holder(s) and author(s).
1117N/A */
1117N/A
1117N/A
1117N/A/* View/edit this file with tab stops set to 4 */
1117N/A
1117N/A#ifdef HAVE_XORG_CONFIG_H
1117N/A#include <xorg-config.h>
1117N/A#endif
1117N/A
1117N/A#include <ctype.h>
1117N/A#include <stdio.h>
1117N/A#include <stdlib.h>
1117N/A#include <string.h>
1117N/A#include <unistd.h>
1117N/A#include <stdarg.h>
1117N/A
1117N/A#if !defined(X_NOT_POSIX)
1117N/A#if defined(_POSIX_SOURCE)
1117N/A#include <limits.h>
1117N/A#else
1117N/A#define _POSIX_SOURCE
1117N/A#include <limits.h>
1117N/A#undef _POSIX_SOURCE
1117N/A#endif /* _POSIX_SOURCE */
1117N/A#endif /* !X_NOT_POSIX */
1117N/A#if !defined(PATH_MAX)
1117N/A#if defined(MAXPATHLEN)
1117N/A#define PATH_MAX MAXPATHLEN
1117N/A#else
1117N/A#define PATH_MAX 1024
1117N/A#endif /* MAXPATHLEN */
1117N/A#endif /* !PATH_MAX */
1117N/A
1117N/A#if !defined(MAXHOSTNAMELEN)
1117N/A#define MAXHOSTNAMELEN 32
1117N/A#endif /* !MAXHOSTNAMELEN */
1117N/A
1117N/A#include "xf86Parser.h" /* Public function, etc. declarations */
1117N/A#include "Configint.h"
1117N/A#include "configProcs.h" /* Private function, etc. declarations */
1117N/A#include "xf86tokens.h"
1117N/A
1117N/A#if defined(SMI_FBCONFIG)
1117N/A#include "fbc_error.h" /* Error reporting */
1117N/A#define xf86printErrorF fbc_errormsg /* Write prog name & variable fmt error */
1117N/A#include "fbc_line_er.h" /* External Representation of config lines */
1117N/A#endif
1117N/A
1117N/A#if !defined(xf86printErrorF) /* Could write prog name & variable fmt msg */
1117N/A#define xf86printErrorF ErrorF /* Write a variable format error message */
1117N/A#endif
1117N/A
1117N/A#define CONFIG_BUF_LEN 1024
1117N/A
1117N/Astatic int StringToToken (char *, xf86ConfigSymTabRec *);
1117N/A
1117N/Astatic FILE *configFile = NULL;
1117N/Astatic const char **builtinConfig = NULL;
1117N/Astatic int builtinIndex = 0;
1117N/Astatic int configPos = 0; /* current readers position */
1117N/Astatic int configLineNo = 0; /* linenumber */
1117N/A#if !defined(SMI_FBCONFIG)
1117N/Astatic char *configBuf = NULL; /* Config file line buffer */
1117N/Astatic int configBufLen = 0; /* Line buffer length */
1117N/A#else
1117N/A#define configBuf xf86configBuf
1117N/A#define configBufLen xf86configBufLen
1117N/Achar *xf86configBuf = NULL; /* Config file line buffer */
1117N/Aint xf86configBufLen = 0; /* Line buffer length */
1117N/A#endif
1117N/Astatic char *configRBuf = NULL; /* Token buffer */
1117N/Astatic int configRBufLen = 0; /* Token buffer length */
1117N/Astatic char *configPath; /* path to config file */
1117N/Astatic char *configSection = NULL; /* name of current section being parsed */
1117N/Astatic int pushToken = LOCK_TOKEN;
1117N/Astatic int eol_seen = 0; /* private state to handle comments */
1117N/ALexRec val;
1117N/A
1117N/A#ifdef __UNIXOS2__
1117N/Aextern char *__XOS2RedirRoot(char *path);
1117N/A#endif
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86strToUL --
1117N/A *
1117N/A * A portable, but restricted, version of strtoul(). It only understands
1117N/A * hex, octal, and decimal. But it's good enough for our needs.
1117N/A */
1117N/Aunsigned int
1117N/Axf86strToUL (char *str)
1117N/A{
1117N/A int base = 10;
1117N/A char *p = str;
1117N/A unsigned int tot = 0;
1117N/A
1117N/A if (*p == '0')
1117N/A {
1117N/A p++;
1117N/A if ((*p == 'x') || (*p == 'X'))
1117N/A {
1117N/A p++;
1117N/A base = 16;
1117N/A }
1117N/A else
1117N/A base = 8;
1117N/A }
1117N/A while (*p)
1117N/A {
1117N/A if ((*p >= '0') && (*p <= ((base == 8) ? '7' : '9')))
1117N/A {
1117N/A tot = tot * base + (*p - '0');
1117N/A }
1117N/A else if ((base == 16) && (*p >= 'a') && (*p <= 'f'))
1117N/A {
1117N/A tot = tot * base + 10 + (*p - 'a');
1117N/A }
1117N/A else if ((base == 16) && (*p >= 'A') && (*p <= 'F'))
1117N/A {
1117N/A tot = tot * base + 10 + (*p - 'A');
1117N/A }
1117N/A else
1117N/A {
1117N/A return (tot);
1117N/A }
1117N/A p++;
1117N/A }
1117N/A return (tot);
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86getNextLine()
1117N/A *
1117N/A * Read from the configFile FILE stream until we encounter a newline;
1117N/A * this is a wrapper for fgets(3) that can handle arbitrarily long
1117N/A * input lines.
1117N/A *
1117N/A * Callers, such as xf86getToken(), assume that we will read up to the
1117N/A * next newline; we need to grow configBuf as necessary to support that.
1117N/A */
1117N/A
1117N/Achar *
1117N/Axf86getNextLine(char **configBuf, int *configBufLen, FILE *configFile)
1117N/A{
1117N/A char *tmpConfigBuf;
1117N/A int c, i, pos = 0, eolFound = 0;
1117N/A char *ret = NULL;
1117N/A
1117N/A /*
1117N/A * Reallocate the buffer if it was grown last time (i.e., is no
1117N/A * longer CONFIG_BUF_LEN); we malloc the new buffer first, so
1117N/A * that if the malloc() fails, we can fall back to use the
1117N/A * existing buffer.
1117N/A *
1117N/A * [Might want to wait and shrink the buffer after reading the line.]
1117N/A */
1117N/A
1117N/A if (*configBufLen != CONFIG_BUF_LEN) {
1117N/A
1117N/A tmpConfigBuf = xf86confmalloc(CONFIG_BUF_LEN);
1117N/A if (tmpConfigBuf != NULL) {
1117N/A
1117N/A /*
1117N/A * The malloc() succeeded; free the old buffer and use
1117N/A * the new buffer.
1117N/A */
1117N/A
1117N/A xf86conffree(configBuf);
1117N/A *configBuf = tmpConfigBuf;
1117N/A *configBufLen = CONFIG_BUF_LEN;
1117N/A }
1117N/A }
1117N/A
1117N/A /* read in another block of chars */
1117N/A
1117N/A do {
1117N/A ret = fgets(*configBuf + pos, *configBufLen - pos - 1, configFile);
1117N/A if (ret == NULL) {
1117N/A (*configBuf)[pos] = '\0';
1117N/A break;
1117N/A }
1117N/A
1117N/A /* search for EOL in the new block of chars */
1117N/A
1117N/A for (i = pos; i < (*configBufLen - 1); i++) {
1117N/A c = (*configBuf)[i];
1117N/A
1117N/A if (c == '\0') break;
1117N/A
1117N/A if ((c == '\n') || (c == '\r')) {
1117N/A eolFound = 1;
1117N/A break;
1117N/A }
1117N/A }
1117N/A
1117N/A /*
1117N/A * if we didn't find EOL, then grow the buffer and
1117N/A * read in more
1117N/A */
1117N/A
1117N/A if (!eolFound) {
1117N/A
1117N/A tmpConfigBuf = xf86confrealloc(*configBuf, *configBufLen + CONFIG_BUF_LEN);
1117N/A if (tmpConfigBuf == NULL) {
1117N/A /*
1117N/A * The reallocation failed; we have to fall
1117N/A * back to the previous configBufLen size and
1117N/A * use the string we have, even though we don't
1117N/A * have an EOL.
1117N/A */
1117N/A break;
1117N/A
1117N/A } else {
1117N/A
1117N/A /* reallocation succeeded */
1117N/A
1117N/A *configBuf = tmpConfigBuf;
1117N/A pos = i;
1117N/A *configBufLen += CONFIG_BUF_LEN;
1117N/A }
1117N/A }
1117N/A
1117N/A } while (!eolFound);
1117N/A
1117N/A return (ret);
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86getToken --
1117N/A * Read next Token from the config file. Handle the global variable
1117N/A * pushToken. If a pointer to a symbol table has been provided
1117N/A * (tab != NULL), the table may be searched for a match with the
1117N/A * token. If all attempts to recognize the token fail, an
1117N/A * ERROR_TOKEN code is returned.
1117N/A */
1117N/Aint
1117N/Axf86getToken (xf86ConfigSymTabRec * tab)
1117N/A{
1117N/A int c, i;
1117N/A char *tmpConfigRBuf;
1117N/A
1117N/A /*
1117N/A * First check whether pushToken has a different value than LOCK_TOKEN.
1117N/A * In this case configRBuf[] contains a valid STRING/TOKEN/NUMBER.
1117N/A * Otherwise the next token must be read from the input.
1117N/A */
1117N/A if (pushToken == EOF_TOKEN)
1117N/A return (EOF_TOKEN);
1117N/A else if (pushToken == LOCK_TOKEN)
1117N/A {
1117N/A /*
1117N/A * eol_seen is only set for the first token after a newline.
1117N/A */
1117N/A eol_seen = 0;
1117N/A
1117N/A c = configBuf[configPos];
1117N/A
1117N/A /*
1117N/A * Get start of next Token. EOF is handled,
1117N/A * whitespaces are skipped.
1117N/A */
1117N/A
1117N/Aagain:
1117N/A if (!c)
1117N/A {
1117N/A char *ret;
1117N/A if (configFile != NULL) {
1117N/A#if defined(SMI_FBCONFIG)
1117N/A off_t line_pos; /* File position of line */
1117N/A
1117N/A line_pos = ftell(configFile);
1117N/A#endif
1117N/A ret = xf86getNextLine(&configBuf, &configBufLen, configFile);
1117N/A#if defined(SMI_FBCONFIG)
1117N/A if (ret != NULL) {
1117N/A fbc_save_line_location(configFile, line_pos);
1117N/A }
1117N/A#endif
1117N/A } else {
1117N/A if (builtinConfig[builtinIndex] == NULL)
1117N/A ret = NULL;
1117N/A else {
1117N/A ret = strncpy(configBuf, builtinConfig[builtinIndex],
1117N/A CONFIG_BUF_LEN);
1117N/A builtinIndex++;
1117N/A }
1117N/A }
1117N/A if (ret == NULL)
1117N/A {
1117N/A return (pushToken = EOF_TOKEN);
1117N/A }
1117N/A configLineNo++;
1117N/A configPos = 0;
1117N/A eol_seen = 1;
1117N/A }
1117N/A
1117N/A /*
1117N/A * Make the token buffer the same size as the input line
1117N/A * buffer. We malloc() the new token buffer first, so
1117N/A * that if the malloc() fails, we can fall back to use the
1117N/A * existing token buffer.
1117N/A */
1117N/A
1117N/A if (configRBufLen != configBufLen) {
1117N/A
1117N/A tmpConfigRBuf = xf86confmalloc(configBufLen);
1117N/A if (tmpConfigRBuf != NULL) {
1117N/A
1117N/A /*
1117N/A * The malloc() succeeded; free the old buffer
1117N/A * and use the new buffer.
1117N/A */
1117N/A
1117N/A xf86conffree(configRBuf);
1117N/A configBuf = tmpConfigRBuf;
1117N/A configRBufLen = configBufLen;
1117N/A }
1117N/A }
1117N/A
1117N/A /*
1117N/A * Start scanning the new token, which may include whitespace
1117N/A */
1117N/A
1117N/A i = 0;
1117N/A for (;;) {
1117N/A c = configBuf[configPos++];
1117N/A configRBuf[i++] = c;
1117N/A switch (c) {
1117N/A case ' ':
1117N/A case '\t':
1117N/A case '\r':
1117N/A continue;
1117N/A case '\n':
1117N/A i = 0;
1117N/A continue;
1117N/A }
1117N/A break;
1117N/A }
1117N/A if (c == '\0')
1117N/A goto again; /* [Should be a do-while loop] */
1117N/A
1117N/A if (c == '#')
1117N/A {
1117N/A do
1117N/A {
1117N/A configRBuf[i++] = (c = configBuf[configPos++]);
1117N/A }
1117N/A while ((c != '\n') && (c != '\r') && (c != '\0'));
1117N/A configRBuf[i] = '\0';
1117N/A /* XXX no private copy.
1117N/A * Use xf86addComment when setting a comment.
1117N/A */
1117N/A val.str = configRBuf;
1117N/A return (COMMENT);
1117N/A }
1117N/A
1117N/A /* GJA -- handle '-' and ',' * Be careful: "-hsync" is a keyword. */
1117N/A else if ((c == ',') && !isalpha (configBuf[configPos]))
1117N/A {
1117N/A return COMMA;
1117N/A }
1117N/A else if ((c == '-') && !isalpha (configBuf[configPos]))
1117N/A {
1117N/A return DASH;
1117N/A }
1117N/A
1117N/A /*
1117N/A * Numbers are returned immediately ...
1117N/A */
1117N/A if (isdigit (c))
1117N/A {
1117N/A int base;
1117N/A
1117N/A if (c == '0')
1117N/A if ((configBuf[configPos] == 'x') ||
1117N/A (configBuf[configPos] == 'X'))
1117N/A base = 16;
1117N/A else
1117N/A base = 8;
1117N/A else
1117N/A base = 10;
1117N/A
1117N/A configRBuf[0] = c;
1117N/A i = 1;
1117N/A while (isdigit (c = configBuf[configPos++]) ||
1117N/A (c == '.') || (c == 'x') || (c == 'X') ||
1117N/A ((base == 16) && (((c >= 'a') && (c <= 'f')) ||
1117N/A ((c >= 'A') && (c <= 'F')))))
1117N/A configRBuf[i++] = c;
1117N/A configPos--; /* GJA -- one too far */
1117N/A configRBuf[i] = '\0';
1117N/A val.num = xf86strToUL (configRBuf);
1117N/A val.realnum = atof (configRBuf);
1117N/A return (NUMBER);
1117N/A }
1117N/A
1117N/A /*
1117N/A * All Strings START with a \" ...
1117N/A */
1117N/A else if (c == '\"')
1117N/A {
1117N/A i = -1;
1117N/A do
1117N/A {
1117N/A configRBuf[++i] = (c = configBuf[configPos++]);
1117N/A }
1117N/A while ((c != '\"') && (c != '\n') && (c != '\r') && (c != '\0'));
1117N/A configRBuf[i] = '\0';
1117N/A val.str = xf86confmalloc (strlen (configRBuf) + 1);
1117N/A strcpy (val.str, configRBuf); /* private copy ! */
1117N/A return (STRING);
1117N/A }
1117N/A
1117N/A /*
1117N/A * ... and now we MUST have a valid token. The search is
1117N/A * handled later along with the pushed tokens.
1117N/A */
1117N/A else
1117N/A {
1117N/A configRBuf[0] = c;
1117N/A i = 0;
1117N/A do
1117N/A {
1117N/A configRBuf[++i] = (c = configBuf[configPos++]);;
1117N/A }
1117N/A while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0') && (c != '#'));
1117N/A --configPos;
1117N/A configRBuf[i] = '\0';
1117N/A i = 0;
1117N/A }
1117N/A
1117N/A }
1117N/A else
1117N/A {
1117N/A
1117N/A /*
1117N/A * Here we deal with pushed tokens. Reinitialize pushToken again. If
1117N/A * the pushed token was NUMBER || STRING return them again ...
1117N/A */
1117N/A int temp = pushToken;
1117N/A pushToken = LOCK_TOKEN;
1117N/A
1117N/A if (temp == COMMA || temp == DASH)
1117N/A return (temp);
1117N/A if (temp == NUMBER || temp == STRING)
1117N/A return (temp);
1117N/A }
1117N/A
1117N/A /*
1117N/A * Joop, at last we have to lookup the token ...
1117N/A */
1117N/A if (tab)
1117N/A {
1117N/A
1117N/A i = 0;
1117N/A while (tab[i].token != -1)
1117N/A if (xf86nameCompare (configRBuf, tab[i].name) == 0)
1117N/A return (tab[i].token);
1117N/A else
1117N/A i++;
1117N/A }
1117N/A
1117N/A return (ERROR_TOKEN); /* Error catcher */
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86getSubToken()
1117N/A *
1117N/A * Read tokens from the configuration file until a non-COMMENT
1117N/A * token is encountered. No symbol table is provided for token
1117N/A * lookup. Unless no comment pointer is provided by the caller,
1117N/A * append any COMMENT text to the dynamically grown string of
1117N/A * comments. Return the code for the non-COMMENT token.
1117N/A */
1117N/Aint
1117N/Axf86getSubToken (char **comment)
1117N/A{
1117N/A int token;
1117N/A
1117N/A for (;;) {
1117N/A token = xf86getToken(NULL);
1117N/A if (token == COMMENT) {
1117N/A if (comment)
1117N/A *comment = xf86addComment(*comment, val.str);
1117N/A }
1117N/A else
1117N/A return (token);
1117N/A }
1117N/A /*NOTREACHED*/
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86getSubTokenWithTab()
1117N/A *
1117N/A * Read tokens from the configuration file until a non-COMMENT
1117N/A * token is encountered. A symbol table is provided for token
1117N/A * lookup. Unless no comment pointer is provided by the caller,
1117N/A * append any COMMENT text to the dynamically grown string of
1117N/A * comments. Return the code for the non-COMMENT token.
1117N/A */
1117N/Aint
1117N/Axf86getSubTokenWithTab (char **comment, xf86ConfigSymTabRec *tab)
1117N/A{
1117N/A int token;
1117N/A
1117N/A for (;;) {
1117N/A token = xf86getToken(tab);
1117N/A if (token == COMMENT) {
1117N/A if (comment)
1117N/A *comment = xf86addComment(*comment, val.str);
1117N/A }
1117N/A else
1117N/A return (token);
1117N/A }
1117N/A /*NOTREACHED*/
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86unGetToken (int token)
1117N/A{
1117N/A pushToken = token;
1117N/A}
1117N/A
1117N/Achar *
1117N/Axf86tokenString (void)
1117N/A{
1117N/A return configRBuf;
1117N/A}
1117N/A
1117N/Aint
1117N/Axf86pathIsAbsolute(const char *path)
1117N/A{
1117N/A if (path && path[0] == '/')
1117N/A return 1;
1117N/A#ifdef __UNIXOS2__
1117N/A if (path && (path[0] == '\\' || (path[1] == ':')))
1117N/A return 1;
1117N/A#endif
1117N/A return 0;
1117N/A}
1117N/A
1117N/A/* A path is "safe" if it is relative and if it contains no ".." elements. */
1117N/Aint
1117N/Axf86pathIsSafe(const char *path)
1117N/A{
1117N/A if (xf86pathIsAbsolute(path))
1117N/A return 0;
1117N/A
1117N/A /* Compare with ".." */
1117N/A if (!strcmp(path, ".."))
1117N/A return 0;
1117N/A
1117N/A /* Look for leading "../" */
1117N/A if (!strncmp(path, "../", 3))
1117N/A return 0;
1117N/A
1117N/A /* Look for trailing "/.." */
1117N/A if ((strlen(path) > 3) && !strcmp(path + strlen(path) - 3, "/.."))
1117N/A return 0;
1117N/A
1117N/A /* Look for "/../" */
1117N/A if (strstr(path, "/../"))
1117N/A return 0;
1117N/A
1117N/A return 1;
1117N/A}
1117N/A
1117N/A/*
1117N/A * This function substitutes the following escape sequences:
1117N/A *
1117N/A * %A cmdline argument as an absolute path (must be absolute to match)
1117N/A * %R cmdline argument as a relative path
1117N/A * %S cmdline argument as a "safe" path (relative, and no ".." elements)
1117N/A * %X default config file name ("xorg.conf")
1117N/A * %H hostname
1117N/A * %E config file environment ($XORGCONFIG) as an absolute path
1117N/A * %F config file environment ($XORGCONFIG) as a relative path
1117N/A * %G config file environment ($XORGCONFIG) as a safe path
1117N/A * %D $HOME
1117N/A * %P projroot
1117N/A * %M major version number
1117N/A * %% %
1117N/A * %& UNIXOS2 only: prepend X11ROOT env var
1117N/A */
1117N/A
1117N/A#ifndef XCONFIGFILE
1117N/A#define XCONFIGFILE "xorg.conf"
1117N/A#endif
1117N/A#ifndef PROJECTROOT
1117N/A#define PROJECTROOT "/usr/X11R6"
1117N/A#endif
1117N/A#ifndef XCONFENV
1117N/A#define XCONFENV "XORGCONFIG"
1117N/A#endif
1117N/A#define XFREE86CFGFILE "XF86Config"
1117N/A#ifndef XF86_VERSION_MAJOR
1117N/A#ifdef XVERSION
1117N/A#if XVERSION > 40000000
1117N/A#define XF86_VERSION_MAJOR (XVERSION / 10000000)
1117N/A#else
1117N/A#define XF86_VERSION_MAJOR (XVERSION / 1000)
1117N/A#endif
1117N/A#else
1117N/A#define XF86_VERSION_MAJOR 4
1117N/A#endif
1117N/A#endif
1117N/A
1117N/A#define BAIL_OUT do { \
1117N/A xf86conffree(result); \
1117N/A return NULL; \
1117N/A } while (0)
1117N/A
1117N/A#define CHECK_LENGTH do { \
1117N/A if (l > PATH_MAX) { \
1117N/A BAIL_OUT; \
1117N/A } \
1117N/A } while (0)
1117N/A
1117N/A#define APPEND_STR(s) do { \
1117N/A if (strlen(s) + l > PATH_MAX) { \
1117N/A BAIL_OUT; \
1117N/A } else { \
1117N/A strcpy(result + l, s); \
1117N/A l += strlen(s); \
1117N/A } \
1117N/A } while (0)
1117N/A
1117N/Astatic char *
1117N/ADoSubstitution(const char *template, const char *cmdline, const char *projroot,
1117N/A int *cmdlineUsed, int *envUsed, const char *XConfigFile)
1117N/A{
1117N/A char *result;
1117N/A int i, l;
1117N/A static const char *env = NULL, *home = NULL;
1117N/A static char *hostname = NULL;
1117N/A static char majorvers[3] = "";
1117N/A#ifdef __UNIXOS2__
1117N/A static char *x11root = NULL;
1117N/A#endif
1117N/A
1117N/A if (!template)
1117N/A return NULL;
1117N/A
1117N/A if (cmdlineUsed)
1117N/A *cmdlineUsed = 0;
1117N/A if (envUsed)
1117N/A *envUsed = 0;
1117N/A
1117N/A result = xf86confmalloc(PATH_MAX + 1);
1117N/A l = 0;
1117N/A for (i = 0; template[i]; i++) {
1117N/A if (template[i] != '%') {
1117N/A result[l++] = template[i];
1117N/A CHECK_LENGTH;
1117N/A } else {
1117N/A switch (template[++i]) {
1117N/A case 'A':
1117N/A if (cmdline && xf86pathIsAbsolute(cmdline)) {
1117N/A APPEND_STR(cmdline);
1117N/A if (cmdlineUsed)
1117N/A *cmdlineUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'R':
1117N/A if (cmdline && !xf86pathIsAbsolute(cmdline)) {
1117N/A APPEND_STR(cmdline);
1117N/A if (cmdlineUsed)
1117N/A *cmdlineUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'S':
1117N/A if (cmdline && xf86pathIsSafe(cmdline)) {
1117N/A APPEND_STR(cmdline);
1117N/A if (cmdlineUsed)
1117N/A *cmdlineUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'X':
1117N/A APPEND_STR(XConfigFile);
1117N/A break;
1117N/A case 'H':
1117N/A if (!hostname) {
1117N/A if ((hostname = xf86confmalloc(MAXHOSTNAMELEN + 1))) {
1117N/A if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
1117N/A hostname[MAXHOSTNAMELEN] = '\0';
1117N/A } else {
1117N/A xf86conffree(hostname);
1117N/A hostname = NULL;
1117N/A }
1117N/A }
1117N/A }
1117N/A if (hostname)
1117N/A APPEND_STR(hostname);
1117N/A break;
1117N/A case 'E':
1117N/A if (!env)
1117N/A env = getenv(XCONFENV);
1117N/A if (env && xf86pathIsAbsolute(env)) {
1117N/A APPEND_STR(env);
1117N/A if (envUsed)
1117N/A *envUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'F':
1117N/A if (!env)
1117N/A env = getenv(XCONFENV);
1117N/A if (env && !xf86pathIsAbsolute(env)) {
1117N/A APPEND_STR(env);
1117N/A if (envUsed)
1117N/A *envUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'G':
1117N/A if (!env)
1117N/A env = getenv(XCONFENV);
1117N/A if (env && xf86pathIsSafe(env)) {
1117N/A APPEND_STR(env);
1117N/A if (envUsed)
1117N/A *envUsed = 1;
1117N/A } else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'D':
1117N/A if (!home)
1117N/A home = getenv("HOME");
1117N/A if (home && xf86pathIsAbsolute(home))
1117N/A APPEND_STR(home);
1117N/A else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'P':
1117N/A if (projroot && xf86pathIsAbsolute(projroot))
1117N/A APPEND_STR(projroot);
1117N/A else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A case 'M':
1117N/A if (!majorvers[0]) {
1117N/A if (XF86_VERSION_MAJOR < 0 || XF86_VERSION_MAJOR > 99) {
1117N/A fprintf(stderr, "XF86_VERSION_MAJOR is out of range\n");
1117N/A BAIL_OUT;
1117N/A } else
1117N/A sprintf(majorvers, "%d", XF86_VERSION_MAJOR);
1117N/A }
1117N/A APPEND_STR(majorvers);
1117N/A break;
1117N/A case '%':
1117N/A result[l++] = '%';
1117N/A CHECK_LENGTH;
1117N/A break;
1117N/A#ifdef __UNIXOS2__
1117N/A case '&':
1117N/A if (!x11root)
1117N/A x11root = getenv("X11ROOT");
1117N/A if (x11root)
1117N/A APPEND_STR(x11root);
1117N/A else
1117N/A BAIL_OUT;
1117N/A break;
1117N/A#endif
1117N/A default:
1117N/A fprintf(stderr, "invalid escape %%%c found in path template\n",
1117N/A template[i]);
1117N/A BAIL_OUT;
1117N/A break;
1117N/A }
1117N/A }
1117N/A }
1117N/A#ifdef DEBUG
1117N/A fprintf(stderr, "Converted `%s' to `%s'\n", template, result);
1117N/A#endif
1117N/A result[l] = '\0';
1117N/A return result;
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86openConfigFileIn()
1117N/A *
1117N/A * This function takes a config file search path (optional), a command-line
1117N/A * specified file name (optional) and the ProjectRoot path (optional) and
1117N/A * locates and opens a config file based on that information. This
1117N/A * function will fail if a command-line file name is specified and there
1117N/A * is no %A, %R, or %S escape sequence in the effective search path.
1117N/A *
1117N/A * The return value is a pointer to the actual name of the file that was
1117N/A * opened. When no file is found, the return value is NULL.
1117N/A *
1117N/A * The escape sequences allowed in the search path are defined above. The
1117N/A * default search path is defined below.
1117N/A */
1117N/A
1117N/A#ifndef DEFAULT_CONF_PATH
1117N/A#define DEFAULT_CONF_PATH "/etc/X11/%S," \
1117N/A "%P/etc/X11/%S," \
1117N/A "/etc/X11/%G," \
1117N/A "%P/etc/X11/%G," \
1117N/A "/etc/X11/%X-%M," \
1117N/A "/etc/X11/%X," \
1117N/A "/etc/%X," \
1117N/A "%P/etc/X11/%X.%H," \
1117N/A "%P/etc/X11/%X-%M," \
1117N/A "%P/etc/X11/%X," \
1117N/A "%P/lib/X11/%X.%H," \
1117N/A "%P/lib/X11/%X-%M," \
1117N/A "%P/lib/X11/%X"
1117N/A#endif
1117N/A
1117N/A#if !defined(SMI_FBCONFIG)
1117N/Astatic
1117N/A#endif
1117N/Aconst char *
1117N/Axf86openConfigFileIn(
1117N/A const char *path, /* Search path, else NULL */
1117N/A const char *cmdline, /* File path (%A,%R,%S), else NULL */
1117N/A const char *projroot) /* Project root path (%P), else NULL */
1117N/A{
1117N/A const char *const Xfile[] = {
1117N/A XCONFIGFILE,
1117N/A XFREE86CFGFILE,
1117N/A NULL
1117N/A }; /* Substitutions for %X */
1117N/A char *pathcopy;
1117N/A const char *template;
1117N/A int cmdlineUsed = 0;
1117N/A const char *const *XConfigFile; /* Ptr to current %X filename */
1117N/A
1117N/A /* Initialize global variables for the scanner */
1117N/A configPath = NULL; /* Config file pathname, else NULL */
1117N/A configFile = NULL; /* Config file descriptor, else NULL */
1117N/A configLineNo = 0; /* Config file current line number */
1117N/A configPos = 0; /* Index of current char in line buf */
1117N/A if (configBuf != NULL) {
1117N/A configBuf[0] = '\0'; /* Start with an empty line buffer */
1117N/A }
1117N/A pushToken = LOCK_TOKEN;
1117N/A
1117N/A /* Be sure there's a non-empty search path and a scratch buffer */
1117N/A if (path == NULL || path[0] == '\0') {
1117N/A path = DEFAULT_CONF_PATH;
1117N/A }
1117N/A pathcopy = xf86confmalloc(strlen(path) + 1);
1117N/A if (pathcopy == NULL) {
1117N/A return (NULL);
1117N/A }
1117N/A
1117N/A /* Be sure there's a non-empty project root to substitute for %P */
1117N/A if (projroot == NULL || projroot[0] == '\0') {
1117N/A projroot = PROJECTROOT;
1117N/A }
1117N/A
1117N/A /* Repeat for each config filename that can be substituted for %X */
1117N/A for (XConfigFile = &Xfile[0]; *XConfigFile != NULL; XConfigFile += 1) {
1117N/A
1117N/A /* Repeat for each comma-separated pathname template */
1117N/A strcpy(pathcopy, path);
1117N/A for (template = strtok(pathcopy, ",");
1117N/A template != NULL;
1117N/A template = strtok(NULL, ",")) {
1117N/A
1117N/A /* Construct a config pathname from the template */
1117N/A configPath = DoSubstitution(template, cmdline, projroot,
1117N/A &cmdlineUsed, NULL,
1117N/A *XConfigFile);
1117N/A if (configPath == NULL) {
1117N/A continue; /* No memory */
1117N/A }
1117N/A
1117N/A /* Open the path unless a provided name wasn't used */
1117N/A if (cmdline == NULL || cmdlineUsed) {
1117N/A configFile = fopen(configPath, "r");
1117N/A if (configFile != NULL) {
1117N/A break; /* Success */
1117N/A }
1117N/A }
1117N/A
1117N/A /* Discard the failed config pathname */
1117N/A xf86conffree(configPath);
1117N/A configPath = NULL;
1117N/A }
1117N/A
1117N/A if (configFile != NULL) {
1117N/A break; /* Success */
1117N/A }
1117N/A }
1117N/A
1117N/A xf86conffree(pathcopy);
1117N/A
1117N/A return (configPath);
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86openConfigFile()
1117N/A *
1117N/A * This function takes a config file search path (optional), a command-line
1117N/A * specified file name (optional) and the ProjectRoot path (optional) and
1117N/A * locates and opens a config file based on that information. This
1117N/A * function will fail if a command-line file name is specified and there
1117N/A * is no %A, %R, or %S escape sequence in the effective search path.
1117N/A *
1117N/A * The return value is a pointer to the actual name of the file that was
1117N/A * opened. When no file is found, the return value is NULL.
1117N/A *
1117N/A * The escape sequences allowed in the search path are defined above.
1117N/A */
1117N/A
1117N/Aconst char *
1117N/Axf86openConfigFile(const char *path, const char *cmdline, const char *projroot)
1117N/A{
1117N/A const char *configPath; /* Config file pathname, else NULL */
1117N/A
1117N/A configPath = xf86openConfigFileIn(path, cmdline, projroot);
1117N/A
1117N/A configBuf = xf86confmalloc(CONFIG_BUF_LEN);
1117N/A configRBuf = xf86confmalloc(CONFIG_BUF_LEN);
1117N/A if (configBuf == NULL || configRBuf == NULL) {
1117N/A return (NULL);
1117N/A }
1117N/A configBufLen = CONFIG_BUF_LEN;
1117N/A configRBufLen = CONFIG_BUF_LEN;
1117N/A configBuf[0] = '\0'; /* Start with an empty line buffer */
1117N/A
1117N/A return (configPath);
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86confScanFree()
1117N/A *
1117N/A * Release all dynamically allocated memory used to scan the
1117N/A * configuration file.
1117N/A */
1117N/Avoid
1117N/Axf86confScanFree(void)
1117N/A{
1117N/A xf86conffree (configPath);
1117N/A configPath = NULL;
1117N/A xf86conffree (configRBuf);
1117N/A configRBuf = NULL;
1117N/A xf86conffree (configBuf);
1117N/A configBuf = NULL;
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86closeConfigFile()
1117N/A *
1117N/A * Release all dynamically allocated memory used to scan the
1117N/A * configuration file. Close the input configuration file, else
1117N/A * discard the in-memory configuration text.
1117N/A */
1117N/Avoid
1117N/Axf86closeConfigFile (void)
1117N/A{
1117N/A xf86confScanFree();
1117N/A
1117N/A if (configFile != NULL) {
1117N/A fclose(configFile);
1117N/A configFile = NULL;
1117N/A } else {
1117N/A builtinConfig = NULL;
1117N/A builtinIndex = 0;
1117N/A }
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86setBuiltinConfig(const char *config[])
1117N/A{
1117N/A builtinConfig = config;
1117N/A configPath = xf86configStrdup("<builtin configuration>");
1117N/A configBuf = xf86confmalloc (CONFIG_BUF_LEN);
1117N/A configBufLen = CONFIG_BUF_LEN;
1117N/A configRBuf = xf86confmalloc (CONFIG_BUF_LEN);
1117N/A configRBufLen = CONFIG_BUF_LEN;
1117N/A configBuf[0] = '\0'; /* sanity ... */
1117N/A
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86parseError (char *format,...)
1117N/A{
1117N/A va_list ap;
1117N/A
1117N/A xf86printErrorF("Parse error on line %d of section %s in file %s\n\t",
1117N/A configLineNo, configSection, configPath);
1117N/A va_start (ap, format);
1117N/A VErrorF (format, ap);
1117N/A va_end (ap);
1117N/A
1117N/A ErrorF ("\n");
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86parseWarning (char *format,...)
1117N/A{
1117N/A va_list ap;
1117N/A
1117N/A xf86printErrorF("Parse warning on line %d of section %s in file %s\n\t",
1117N/A configLineNo, configSection, configPath);
1117N/A va_start (ap, format);
1117N/A VErrorF (format, ap);
1117N/A va_end (ap);
1117N/A
1117N/A ErrorF ("\n");
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86validationError (char *format, ...)
1117N/A{
1117N/A va_list ap;
1117N/A
1117N/A xf86printErrorF("Error in config file, %s\n\t", configPath);
1117N/A va_start (ap, format);
1117N/A VErrorF (format, ap);
1117N/A va_end (ap);
1117N/A
1117N/A ErrorF ("\n");
1117N/A}
1117N/A
1117N/Avoid
1117N/Axf86setSection (char *section)
1117N/A{
1117N/A if (configSection)
1117N/A xf86conffree(configSection);
1117N/A configSection = xf86confmalloc(strlen (section) + 1);
1117N/A strcpy (configSection, section);
1117N/A}
1117N/A
1117N/A/*
1117N/A * xf86getToken --
1117N/A * Lookup a string if it is actually a token in disguise.
1117N/A */
1117N/Aint
1117N/Axf86getStringToken (xf86ConfigSymTabRec * tab)
1117N/A{
1117N/A return StringToToken (val.str, tab);
1117N/A}
1117N/A
1117N/Astatic int
1117N/AStringToToken (char *str, xf86ConfigSymTabRec * tab)
1117N/A{
1117N/A int i;
1117N/A
1117N/A for (i = 0; tab[i].token != -1; i++)
1117N/A {
1117N/A if (!xf86nameCompare (tab[i].name, str))
1117N/A return tab[i].token;
1117N/A }
1117N/A return (ERROR_TOKEN);
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86nameCompareResumable()
1117N/A *
1117N/A * Compare two name-like strings pointed to by s1 and s2. Ignore
1117N/A * alphabetic case and the characters, '_', ' ', and '\t'. If s2
1117N/A * matches the initial characters of s1 then return a pointer to the
1117N/A * next character of s1 via s1resume (where further comparison could
1117N/A * be resumed). Otherwise return NULL via s1resume. Return the
1117N/A * conventional negative, zero, or positive value to indicate the
1117N/A * result of the basic comparison.
1117N/A */
1117N/Astatic int
1117N/Axf86nameCompareResumable(
1117N/A const char *s1, const char *s2, const char **s1resume)
1117N/A{
1117N/A int c1; /* Normalized character from s1 */
1117N/A int c2; /* Normalized character from s2 */
1117N/A
1117N/A *s1resume = NULL; /* Comparison has no resumption point yet */
1117N/A
1117N/A if ((s1 == NULL) && (s2 == NULL)) {
1117N/A return (0);
1117N/A }
1117N/A if (s1 == NULL) {
1117N/A return (-1); /* Behave as if NULL < non-NULL */
1117N/A }
1117N/A if (s2 == NULL) {
1117N/A return (1); /* Behave as if non-NULL > NULL */
1117N/A }
1117N/A
1117N/A do {
1117N/A while ((*s1 == '_') || (*s1 == ' ') || (*s1 == '\t')) {
1117N/A s1 += 1;
1117N/A }
1117N/A while ((*s2 == '_') || (*s2 == ' ') || (*s2 == '\t')) {
1117N/A s2 += 1;
1117N/A }
1117N/A if (*s2 == '\0') {
1117N/A /* s1 matches s2 or contains s2 as a prefix */
1117N/A *s1resume = s1;
1117N/A return (0);
1117N/A }
1117N/A c1 = tolower(*s1);
1117N/A c2 = tolower(*s2);
1117N/A s1++;
1117N/A s2++;
1117N/A
1117N/A }
1117N/A while (c1 == c2);
1117N/A
1117N/A /*
1117N/A * The strings don't match
1117N/A */
1117N/A return (c1 - c2);
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86nameCompare()
1117N/A *
1117N/A * Compare two name-like strings pointed to by s1 and s2. Ignore
1117N/A * alphabetic case and the characters, '_', ' ', and '\t'. Return
1117N/A * the conventional negative, zero, or positive value to indicate the
1117N/A * result of the comparison.
1117N/A */
1117N/Aint
1117N/Axf86nameCompare(const char *s1, const char *s2)
1117N/A{
1117N/A int result; /* Name comparison result */
1117N/A const char *s1resume; /* Comparison resumption point */
1117N/A
1117N/A /*
1117N/A * Compare the name strings, s1 and s2
1117N/A */
1117N/A result = xf86nameCompareResumable(s1, s2, &s1resume);
1117N/A if (result == 0) {
1117N/A /*
1117N/A * Determine whether s2 matches all of or just part of s1
1117N/A *
1117N/A * Note that s1resume will not be NULL if result is
1117N/A * zero.
1117N/A */
1117N/A result = *s1resume - '\0';
1117N/A }
1117N/A
1117N/A /*
1117N/A * Return the final result of the comparison
1117N/A */
1117N/A return (result);
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86lookupBoolOption()
1117N/A *
1117N/A * Look up an option name in an array of known Boolean option names.
1117N/A * Note that a Boolean option name can have a "No" prefix. If found,
1117N/A * return the array subscript of the Boolean option name. Otherwise
1117N/A * return -1.
1117N/A */
1117N/Astatic int
1117N/Axf86lookupBoolOption(
1117N/A const char *const bool_option_names[], const char *opt_name)
1117N/A{
1117N/A int i; /* Index into option name array */
1117N/A const char *s1resume; /* Comparison resumption point */
1117N/A
1117N/A /*
1117N/A * Look up the option name, which can be negated using a "No" prefix
1117N/A */
1117N/A for (i = 0; bool_option_names[i] != NULL; i += 1) {
1117N/A /*
1117N/A * See whether this is a plain instance of the option name
1117N/A */
1117N/A if (xf86nameCompare(bool_option_names[i], opt_name) == 0) {
1117N/A return (i); /* Have a match */
1117N/A }
1117N/A
1117N/A /*
1117N/A * See whether this is a negated instance of the option name
1117N/A */
1117N/A (void) xf86nameCompareResumable(opt_name, "No", &s1resume);
1117N/A if (s1resume == NULL) {
1117N/A s1resume = opt_name; /* Doesn't have a "No" prefix */
1117N/A }
1117N/A if (xf86nameCompare(bool_option_names[i], s1resume) == 0) {
1117N/A return (i); /* Have a match */
1117N/A }
1117N/A }
1117N/A
1117N/A /*
1117N/A * Not the name of a known Boolean option
1117N/A */
1117N/A return (-1);
1117N/A}
1117N/A
1117N/A
1117N/A/*
1117N/A * xf86optionNameCompare()
1117N/A *
1117N/A * Compare two option names pointed to by s1 and s2. Ignore
1117N/A * alphabetic case and the characters, '_', ' ', and '\t'. For names
1117N/A * of known Boolean options (provided via bool_option_names[]), any
1117N/A * "No" prefix is ignored. Return the usual negative, zero, or
1117N/A * positive values to indicate the results of the comparison.
1117N/A *
1117N/A * To see why we want a list of known Boolean option names, consider
1117N/A * these ponderables:
1117N/A * * Can we tell from this hypothetical example whether "Tables"
1117N/A * is the name of a Boolean option, which could be negated?
1117N/A * Option "Tables" 1
1117N/A * * Can we tell whether "Notables" is the opposite of "Tables"?
1117N/A * * Is the opposite of the documented Boolean option,
1117N/A * "NoTrapSignals", intended to be "NoNoTrapSignals" or
1117N/A * "TrapSignals"? Ditto for "NoPM" and "NoInt10".
1117N/A */
1117N/Aint
1117N/Axf86optionNameCompare(
1117N/A const char *const bool_option_names[], const char *s1, const char *s2)
1117N/A{
1117N/A int i; /* Index of option name, else -1 */
1117N/A
1117N/A i = xf86lookupBoolOption(bool_option_names, s1);
1117N/A if ((i != -1) && (i == xf86lookupBoolOption(bool_option_names, s2))) {
1117N/A return (0); /* Known Boolean option names match */
1117N/A }
1117N/A return (xf86nameCompare(s1, s2));
1117N/A}
1117N/A
1117N/A
1117N/Achar *
1117N/Axf86addComment(char *cur, char *add)
1117N/A{
1117N/A char *str;
1117N/A int len, curlen, iscomment, hasnewline = 0, endnewline;
1117N/A
1117N/A if (add == NULL || add[0] == '\0')
1117N/A return (cur);
1117N/A
1117N/A if (cur) {
1117N/A curlen = strlen(cur);
1117N/A if (curlen)
1117N/A hasnewline = cur[curlen - 1] == '\n';
1117N/A eol_seen = 0;
1117N/A }
1117N/A else
1117N/A curlen = 0;
1117N/A
1117N/A str = add;
1117N/A iscomment = 0;
1117N/A while (*str) {
1117N/A if (*str != ' ' && *str != '\t')
1117N/A break;
1117N/A ++str;
1117N/A }
1117N/A iscomment = (*str == '#');
1117N/A
1117N/A len = strlen(add);
1117N/A endnewline = add[len - 1] == '\n';
1117N/A len += 1 + iscomment + (!hasnewline) + (!endnewline) + eol_seen;
1117N/A
1117N/A if ((str = xf86confrealloc(cur, len + curlen)) == NULL)
1117N/A return (cur);
1117N/A
1117N/A cur = str;
1117N/A
1117N/A if (eol_seen || (curlen && !hasnewline))
1117N/A cur[curlen++] = '\n';
1117N/A if (!iscomment)
1117N/A cur[curlen++] = '#';
1117N/A strcpy(cur + curlen, add);
1117N/A if (!endnewline)
1117N/A strcat(cur, "\n");
1117N/A
1117N/A return (cur);
1117N/A}
1117N/A