1bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/*
2bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * XML DRI client-side driver configuration
3bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * Copyright (C) 2003 Felix Kuehling
4bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
5bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * Permission is hereby granted, free of charge, to any person obtaining a
6bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * copy of this software and associated documentation files (the "Software"),
7bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * to deal in the Software without restriction, including without limitation
8bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * and/or sell copies of the Software, and to permit persons to whom the
10bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * Software is furnished to do so, subject to the following conditions:
11bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
12bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * The above copyright notice and this permission notice shall be included
13bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * in all copies or substantial portions of the Software.
14bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
15bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
19bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
23bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl */
24bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/**
25bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * \file xmlconfig.c
26bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * \brief Driver-independent client-side part of the XML configuration
27bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * \author Felix Kuehling
28bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl */
29bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
30ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "main/glheader.h"
31bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
32bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <string.h>
33bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <assert.h>
34bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <expat.h>
35bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <fcntl.h>
36bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <unistd.h>
37bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include <errno.h>
38ecadb51bbcb972a79f3ed79e65a7986b9396e757Brian Paul#include "main/imports.h"
39631a1a9ac8b97dec172205e13e33ef51f28bb1c0George Sapountzis#include "utils.h"
40bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#include "xmlconfig.h"
41bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
42bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#undef GET_PROGRAM_NAME
43bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
44486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling#if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__)
4522ae633d1ea636e0e07ba044a0f8fa2195c83bc6Alan Hourihane#    if !defined(__GLIBC__) || (__GLIBC__ < 2)
4622ae633d1ea636e0e07ba044a0f8fa2195c83bc6Alan Hourihane/* These aren't declared in any libc5 header */
4722ae633d1ea636e0e07ba044a0f8fa2195c83bc6Alan Hourihaneextern char *program_invocation_name, *program_invocation_short_name;
4822ae633d1ea636e0e07ba044a0f8fa2195c83bc6Alan Hourihane#    endif
49bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    define GET_PROGRAM_NAME() program_invocation_short_name
50bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
51bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    include <osreldate.h>
52bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    if (__FreeBSD_version >= 440000)
53bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#        include <stdlib.h>
54bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#        define GET_PROGRAM_NAME() getprogname()
55bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    endif
56bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)
57bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    include <stdlib.h>
58bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    define GET_PROGRAM_NAME() getprogname()
5979d56577700a4f4b8628b3b61098763d019f17d4Vinson Lee#elif defined(__APPLE__)
6079d56577700a4f4b8628b3b61098763d019f17d4Vinson Lee#    include <stdlib.h>
6179d56577700a4f4b8628b3b61098763d019f17d4Vinson Lee#    define GET_PROGRAM_NAME() getprogname()
62e1f9adc27445ea3381af1f71cfec0317298be5b1Alan Coopersmith#elif defined(__sun)
63e1f9adc27445ea3381af1f71cfec0317298be5b1Alan Coopersmith/* Solaris has getexecname() which returns the full path - return just
64e1f9adc27445ea3381af1f71cfec0317298be5b1Alan Coopersmith   the basename to match BSD getprogname() */
65e1f9adc27445ea3381af1f71cfec0317298be5b1Alan Coopersmith#    include <stdlib.h>
66e1f9adc27445ea3381af1f71cfec0317298be5b1Alan Coopersmith#    include <libgen.h>
6764ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith
6864ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmithstatic const char *__getProgramName () {
6964ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith    static const char *progname;
7064ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith
7164ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith    if (progname == NULL) {
7264ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	const char *e = getexecname();
7364ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	if (e != NULL) {
7464ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	    /* Have to make a copy since getexecname can return a readonly
7564ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	       string, but basename expects to be able to modify its arg. */
7664ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	    char *n = strdup(e);
7764ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	    if (n != NULL) {
7864ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith		progname = basename(n);
7964ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	    }
8064ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith	}
8164ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith    }
8264ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith    return progname;
8364ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith}
8464ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith
8564ce3933f59f71ac78d83b8b3db813b6d2619382Alan Coopersmith#    define GET_PROGRAM_NAME() __getProgramName()
86bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#endif
87bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
88bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#if !defined(GET_PROGRAM_NAME)
898cffec495c73f104819deab2bc5631abc1b36429Tapani Pälli#    if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__) || defined(ANDROID)
90486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU.
91486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's
92bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * used as a last resort, if there is no documented facility available. */
93bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic const char *__getProgramName () {
94bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    extern const char *__progname;
95486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling    char * arg = strrchr(__progname, '/');
96486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling    if (arg)
97486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling        return arg+1;
98486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling    else
99486e5c26dc3164493b4f045b533fc1b9e1847581Felix Kuehling        return __progname;
100bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
101bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#        define GET_PROGRAM_NAME() __getProgramName()
102bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    else
103bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#        define GET_PROGRAM_NAME() ""
104fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling#        warning "Per application configuration won't work with your OS version."
105bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#    endif
106bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#endif
107bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
108bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Find an option in an option cache with the name as key */
109bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLuint findOption (const driOptionCache *cache, const char *name) {
110bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint len = strlen (name);
111bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint size = 1 << cache->tableSize, mask = size - 1;
112bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint hash = 0;
113bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i, shift;
114bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
115bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* compute a hash from the variable length name */
116bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
117bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	hash += (GLuint)name[i] << shift;
118bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    hash *= hash;
119bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    hash = (hash >> (16-cache->tableSize/2)) & mask;
120bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
121bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* this is just the starting point of the linear search for the option */
122bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
123bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      /* if we hit an empty entry then the option is not defined (yet) */
124bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (cache->info[hash].name == 0)
125bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
126bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (name, cache->info[hash].name))
127bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
128bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
129bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* this assertion fails if the hash table is full */
130bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (i < size);
131bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
132bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return hash;
133bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
134bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
135bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Count the real number of options in an option cache */
136bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLuint countOptions (const driOptionCache *cache) {
137bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint size = 1 << cache->tableSize;
138bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i, count = 0;
139bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; i < size; ++i)
140bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (cache->info[i].name)
141bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    count++;
142bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return count;
143bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
144bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
145bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Like strdup but using MALLOC and with error checking. */
146bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XSTRDUP(dest,source) do { \
147bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint len = strlen (source); \
148bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!(dest = MALLOC (len+1))) { \
149bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
150bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	abort(); \
151bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    } \
152bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    memcpy (dest, source, len+1); \
153bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
154bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
155bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic int compare (const void *a, const void *b) {
156bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return strcmp (*(char *const*)a, *(char *const*)b);
157bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
158bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Binary search in a string array. */
159bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLuint bsearchStr (const XML_Char *name,
160bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			  const XML_Char *elems[], GLuint count) {
161bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char **found;
162bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    found = bsearch (&name, elems, count, sizeof (XML_Char *), compare);
163bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (found)
164bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return found - elems;
165bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else
166bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return count;
167bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
168bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
16994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling/** \brief Locale-independent integer parser.
17094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling *
17194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * Works similar to strtol. Leading space is NOT skipped. The input
17294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * number may have an optional sign. Radix is specified by base. If
17394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * base is 0 then decimal is assumed unless the input number is
17494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
17594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * returning tail points to the first character that is not part of
17694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * the integer number. If no number was found then tail points to the
17794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * start of the input string. */
17894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehlingstatic GLint strToI (const XML_Char *string, const XML_Char **tail, int base) {
17994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLint radix = base == 0 ? 10 : base;
18094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLint result = 0;
18194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLint sign = 1;
18294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLboolean numberFound = GL_FALSE;
18394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    const XML_Char *start = string;
18494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
18594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    assert (radix >= 2 && radix <= 36);
18694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
18794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (*string == '-') {
18894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	sign = -1;
18994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
19094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    } else if (*string == '+')
19194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
19294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (base == 0 && *string == '0') {
19394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	numberFound = GL_TRUE;
19494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	if (*(string+1) == 'x' || *(string+1) == 'X') {
19594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    radix = 16;
19694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    string += 2;
19794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	} else {
19894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    radix = 8;
19994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    string++;
20094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	}
20194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    }
20294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    do {
20394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	GLint digit = -1;
20494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	if (radix <= 10) {
20594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    if (*string >= '0' && *string < '0' + radix)
20694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling		digit = *string - '0';
20794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	} else {
20894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    if (*string >= '0' && *string <= '9')
20994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling		digit = *string - '0';
21094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    else if (*string >= 'a' && *string < 'a' + radix - 10)
21194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling		digit = *string - 'a' + 10;
21294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    else if (*string >= 'A' && *string < 'A' + radix - 10)
21394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling		digit = *string - 'A' + 10;
21494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	}
21594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	if (digit != -1) {
21694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    numberFound = GL_TRUE;
21794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    result = radix*result + digit;
21894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    string++;
21994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	} else
22094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    break;
22194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    } while (GL_TRUE);
22294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    *tail = numberFound ? string : start;
22394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    return sign * result;
22494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling}
22594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
22694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling/** \brief Locale-independent floating-point parser.
22794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling *
22894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * Works similar to strtod. Leading space is NOT skipped. The input
22994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * number may have an optional sign. '.' is interpreted as decimal
23099907303f6a1e9abe02977664ad8457c122213ceTimo Wiren * point and may occur at most once. Optionally the number may end in
23194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * [eE]<exponent>, where <exponent> is an integer as recognized by
23294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * strToI. In that case the result is number * 10^exponent. After
23394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * returning tail points to the first character that is not part of
23494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * the floating point number. If no number was found then tail points
23594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * to the start of the input string.
23694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling *
23794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling * Uses two passes for maximum accuracy. */
23894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehlingstatic GLfloat strToF (const XML_Char *string, const XML_Char **tail) {
23994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLint nDigits = 0, pointPos, exponent;
24094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    GLfloat sign = 1.0f, result = 0.0f, scale;
24194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    const XML_Char *start = string, *numStart;
24294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
24394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    /* sign */
24494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (*string == '-') {
24594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	sign = -1.0f;
24694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
24794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    } else if (*string == '+')
24894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
24994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
25094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    /* first pass: determine position of decimal point, number of
25194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling     * digits, exponent and the end of the number. */
25294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    numStart = string;
25394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    while (*string >= '0' && *string <= '9') {
25494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
25594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	nDigits++;
25694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    }
25794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    pointPos = nDigits;
25894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (*string == '.') {
25994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
26094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	while (*string >= '0' && *string <= '9') {
26194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    string++;
26294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    nDigits++;
26394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	}
26494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    }
26594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (nDigits == 0) {
26694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	/* no digits, no number */
26794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	*tail = start;
26894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	return 0.0f;
26994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    }
27094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    *tail = string;
27194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    if (*string == 'e' || *string == 'E') {
27294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	const XML_Char *expTail;
27394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	exponent = strToI (string+1, &expTail, 10);
27494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	if (expTail == string+1)
27594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    exponent = 0;
27694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	else
27794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    *tail = expTail;
27894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    } else
27994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	exponent = 0;
28094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    string = numStart;
28194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
28294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    /* scale of the first digit */
28322ae633d1ea636e0e07ba044a0f8fa2195c83bc6Alan Hourihane    scale = sign * (GLfloat)pow (10.0, (GLdouble)(pointPos-1 + exponent));
28494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
28594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    /* second pass: parse digits */
28694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    do {
28794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	if (*string != '.') {
28894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    assert (*string >= '0' && *string <= '9');
28994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    result += scale * (GLfloat)(*string - '0');
29094de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    scale *= 0.1f;
29194de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	    nDigits--;
29294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	}
29394de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	string++;
29494de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    } while (nDigits > 0);
29594de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
29694de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling    return result;
29794de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling}
29894de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling
299bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse a value of a given type. */
300bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLboolean parseValue (driOptionValue *v, driOptionType type,
301bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			     const XML_Char *string) {
302118de7a01369977d13f40bab2ad591320cc7f7ffAlan Hourihane    const XML_Char *tail = NULL;
303bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* skip leading white-space */
304bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    string += strspn (string, " \f\n\r\t\v");
305bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (type) {
306bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_BOOL:
307bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!strcmp (string, "false")) {
308bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    v->_bool = GL_FALSE;
309bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    tail = string + 5;
310bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	} else if (!strcmp (string, "true")) {
311bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    v->_bool = GL_TRUE;
312bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    tail = string + 4;
313bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
314bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else
315bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    return GL_FALSE;
316bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
317bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_ENUM: /* enum is just a special integer */
318bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_INT:
31994de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	v->_int = strToI (string, &tail, 0);
320bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
321bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_FLOAT:
32294de418fd053a2a970d1a1312765f14be7aeb6f6Felix Kuehling	v->_float = strToF (string, &tail);
323bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
324bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
325bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
326bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (tail == string)
327bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return GL_FALSE; /* empty string (or containing only white-space) */
328bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* skip trailing white space */
329bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (*tail)
330bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	tail += strspn (tail, " \f\n\r\t\v");
331bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (*tail)
332bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return GL_FALSE; /* something left over that is not part of value */
333bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
334bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return GL_TRUE;
335bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
336bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
337bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse a list of ranges of type info->type. */
338bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) {
339bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_Char *cp, *range;
340bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint nRanges, i;
341bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driOptionRange *ranges;
342bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
343bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XSTRDUP (cp, string);
344bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* pass 1: determine the number of ranges (number of commas + 1) */
345bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    range = cp;
346bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (nRanges = 1; *range; ++range)
347bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (*range == ',')
348bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    ++nRanges;
349bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
350bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) {
351bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
352bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	abort();
353bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
354bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
355bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* pass 2: parse all ranges into preallocated array */
356bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    range = cp;
357bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; i < nRanges; ++i) {
358bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_Char *end, *sep;
359bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	assert (range);
360bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	end = strchr (range, ',');
361bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (end)
362bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    *end = '\0';
363bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	sep = strchr (range, ':');
364bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (sep) { /* non-empty interval */
365bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    *sep = '\0';
366bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (!parseValue (&ranges[i].start, info->type, range) ||
367bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		!parseValue (&ranges[i].end, info->type, sep+1))
368bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	        break;
369bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (info->type == DRI_INT &&
370bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		ranges[i].start._int > ranges[i].end._int)
371bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		break;
372bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (info->type == DRI_FLOAT &&
373bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		ranges[i].start._float > ranges[i].end._float)
374bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		break;
375bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	} else { /* empty interval */
376bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (!parseValue (&ranges[i].start, info->type, range))
377bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		break;
378bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    ranges[i].end = ranges[i].start;
379bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
380bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (end)
381bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    range = end+1;
382bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else
383bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    range = NULL;
384bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
385bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    FREE (cp);
386bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (i < nRanges) {
387bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	FREE (ranges);
388bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return GL_FALSE;
389bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    } else
390bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	assert (range == NULL);
391bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
392bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    info->nRanges = nRanges;
393bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    info->ranges = ranges;
394bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return GL_TRUE;
395bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
396bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
397bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Check if a value is in one of info->ranges. */
398bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) {
399bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
400bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (info->type != DRI_BOOL); /* should be caught by the parser */
401bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (info->nRanges == 0)
402bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return GL_TRUE;
403bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (info->type) {
404bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_ENUM: /* enum is just a special integer */
405bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_INT:
406bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	for (i = 0; i < info->nRanges; ++i)
407bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (v->_int >= info->ranges[i].start._int &&
408bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		v->_int <= info->ranges[i].end._int)
409bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		return GL_TRUE;
410bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
411bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case DRI_FLOAT:
412bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	for (i = 0; i < info->nRanges; ++i)
413bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (v->_float >= info->ranges[i].start._float &&
414bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		v->_float <= info->ranges[i].end._float)
415bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		return GL_TRUE;
416bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
417bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      default:
418bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	assert (0); /* should never happen */
419bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
420bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return GL_FALSE;
421bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
422bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
423ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis/**
424ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
425ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis * is set.
426ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis *
427ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis * Is called from the drivers.
428ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis *
429ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis * \param f \c printf like format string.
430ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis */
431ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzisstatic void
432ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis__driUtilMessage(const char *f, ...)
433ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis{
434ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis    va_list args;
435ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis
436ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis    if (getenv("LIBGL_DEBUG")) {
437ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis        fprintf(stderr, "libGL: ");
438ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis        va_start(args, f);
439ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis        vfprintf(stderr, f, args);
440ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis        va_end(args);
441ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis        fprintf(stderr, "\n");
442ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis    }
443ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis}
444ceda4da8573cca85e02d0e7c2db41f9151683321George Sapountzis
445bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Output a warning message. */
446bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_WARNING1(msg) do {\
447bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
4482f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentLineNumber(data->parser), \
4492f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentColumnNumber(data->parser)); \
450bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
451bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_WARNING(msg,args...) do { \
452bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
4532f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentLineNumber(data->parser), \
4542f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentColumnNumber(data->parser), \
455bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl                      args); \
456bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
457bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Output an error message. */
458bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_ERROR1(msg) do { \
459bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
4602f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentLineNumber(data->parser), \
4612f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentColumnNumber(data->parser)); \
462bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
463bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_ERROR(msg,args...) do { \
464bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
4652f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentLineNumber(data->parser), \
4662f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg                      (int) XML_GetCurrentColumnNumber(data->parser), \
467bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl                      args); \
468bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
469bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Output a fatal error message and abort. */
470bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_FATAL1(msg) do { \
471bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
472bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl             data->name, \
4732f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg             (int) XML_GetCurrentLineNumber(data->parser),	\
4742f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg             (int) XML_GetCurrentColumnNumber(data->parser)); \
475bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    abort();\
476bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
477bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define XML_FATAL(msg,args...) do { \
478bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
479bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl             data->name, \
4802f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg             (int) XML_GetCurrentLineNumber(data->parser),	\
4812f3e939ae719f522fc26bfd62997fa8b7940c8edKristian Høgsberg             (int) XML_GetCurrentColumnNumber(data->parser),		\
482bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl             args); \
483bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    abort();\
484bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl} while (0)
485bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
486bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parser context for __driConfigOptions. */
487bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstruct OptInfoData {
488bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const char *name;
489bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_Parser parser;
490bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driOptionCache *cache;
491bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLboolean inDriInfo;
492bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLboolean inSection;
493bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLboolean inDesc;
494bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLboolean inOption;
495bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLboolean inEnum;
496bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    int curOption;
497bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
498bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
499bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Elements in __driConfigOptions. */
500bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlenum OptInfoElem {
501bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT
502bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
503bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic const XML_Char *OptInfoElems[] = {
504bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    "description", "driinfo", "enum", "option", "section"
505bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
506bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
507bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of an enum element.
508bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
509bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * We're not actually interested in the data. Just make sure this is ok
510bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * for external configuration tools.
511bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl */
512bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) {
513bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
514bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char *value = NULL, *text = NULL;
515bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driOptionValue v;
516bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint opt = data->curOption;
517bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
518bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!strcmp (attr[i], "value")) value = attr[i+1];
519bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (attr[i], "text")) text = attr[i+1];
520bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else XML_FATAL("illegal enum attribute: %s.", attr[i]);
521bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
522bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!value) XML_FATAL1 ("value attribute missing in enum.");
523bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!text) XML_FATAL1 ("text attribute missing in enum.");
524bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl     if (!parseValue (&v, data->cache->info[opt].type, value))
525bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("illegal enum value: %s.", value);
526bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!checkValue (&v, &data->cache->info[opt]))
527bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("enum value out of valid range: %s.", value);
528bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
529bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
530bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of a description element.
531bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl *
532bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * We're not actually interested in the data. Just make sure this is ok
533bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl * for external configuration tools.
534bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl */
535bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) {
536bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
537bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char *lang = NULL, *text = NULL;
538bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
539bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!strcmp (attr[i], "lang")) lang = attr[i+1];
540bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (attr[i], "text")) text = attr[i+1];
541bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else XML_FATAL("illegal description attribute: %s.", attr[i]);
542bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
543bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!lang) XML_FATAL1 ("lang attribute missing in description.");
544bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!text) XML_FATAL1 ("text attribute missing in description.");
545bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
546bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
547bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of an option element. */
548bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) {
549bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT};
550bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    static const XML_Char *optAttr[] = {"default", "name", "type", "valid"};
551bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL};
552bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const char *defaultVal;
553bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driOptionCache *cache = data->cache;
554bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint opt, i;
555bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
556bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	GLuint attrName = bsearchStr (attr[i], optAttr, OA_COUNT);
557bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (attrName >= OA_COUNT)
558bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL ("illegal option attribute: %s", attr[i]);
559bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	attrVal[attrName] = attr[i+1];
560bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
561bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option.");
562bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option.");
563bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option.");
564bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
565bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    opt = findOption (cache, attrVal[OA_NAME]);
566bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (cache->info[opt].name)
567bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("option %s redefined.", attrVal[OA_NAME]);
568bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    data->curOption = opt;
569bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
570bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]);
571bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
572bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!strcmp (attrVal[OA_TYPE], "bool"))
573bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].type = DRI_BOOL;
574bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else if (!strcmp (attrVal[OA_TYPE], "enum"))
575bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].type = DRI_ENUM;
576bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else if (!strcmp (attrVal[OA_TYPE], "int"))
577bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].type = DRI_INT;
578bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else if (!strcmp (attrVal[OA_TYPE], "float"))
579bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].type = DRI_FLOAT;
580bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else
581bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]);
582bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
583bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    defaultVal = getenv (cache->info[opt].name);
584bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (defaultVal != NULL) {
585bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      /* don't use XML_WARNING, we want the user to see this! */
586bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr,
587bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		 "ATTENTION: default value of option %s overridden by environment.\n",
588bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		 cache->info[opt].name);
589bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    } else
590bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	defaultVal = attrVal[OA_DEFAULT];
591bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal))
592b629d5ba24f76ed6af35455a874d351fde1e5bbeLauri Kasanen	XML_FATAL ("illegal default value for %s: %s.", cache->info[opt].name, defaultVal);
593bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
594bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (attrVal[OA_VALID]) {
595bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (cache->info[opt].type == DRI_BOOL)
596bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("boolean option with valid attribute.");
597bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!parseRanges (&cache->info[opt], attrVal[OA_VALID]))
598bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]);
599bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!checkValue (&cache->values[opt], &cache->info[opt]))
600bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL ("default value out of valid range '%s': %s.",
601bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		       attrVal[OA_VALID], defaultVal);
602bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    } else if (cache->info[opt].type == DRI_ENUM) {
603bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL1 ("valid attribute missing in option (mandatory for enums).");
604bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    } else {
605bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].nRanges = 0;
606bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	cache->info[opt].ranges = NULL;
607bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
608bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
609bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
610bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Handler for start element events. */
611bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void optInfoStartElem (void *userData, const XML_Char *name,
612bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			      const XML_Char **attr) {
613bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptInfoData *data = (struct OptInfoData *)userData;
614bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
615bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (elem) {
616bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_DRIINFO:
617bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDriInfo)
618bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("nested <driinfo> elements.");
619bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (attr[0])
620bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("attributes specified on <driinfo> element.");
621bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDriInfo = GL_TRUE;
622bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
623bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_SECTION:
624bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inDriInfo)
625bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("<section> must be inside <driinfo>.");
626bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inSection)
627bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("nested <section> elements.");
628bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (attr[0])
629bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("attributes specified on <section> element.");
630bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inSection = GL_TRUE;
631bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
632bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_DESCRIPTION:
633bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inSection && !data->inOption)
634bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("<description> must be inside <description> or <option.");
635bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDesc)
636bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("nested <description> elements.");
637bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDesc = GL_TRUE;
638bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	parseDescAttr (data, attr);
639bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
640bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_OPTION:
641bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inSection)
642bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("<option> must be inside <section>.");
643bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDesc)
644bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("<option> nested in <description> element.");
645bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inOption)
646bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("nested <option> elements.");
647bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inOption = GL_TRUE;
648bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	parseOptInfoAttr (data, attr);
649bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
650bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_ENUM:
651bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!(data->inOption && data->inDesc))
652bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("<enum> must be inside <option> and <description>.");
653bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inEnum)
654bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_FATAL1 ("nested <enum> elements.");
655bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inEnum = GL_TRUE;
656bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	parseEnumAttr (data, attr);
657bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
658bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      default:
659bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("unknown element: %s.", name);
660bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
661bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
662bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
663bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Handler for end element events. */
664bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void optInfoEndElem (void *userData, const XML_Char *name) {
665bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptInfoData *data = (struct OptInfoData *)userData;
666bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
667bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (elem) {
668bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_DRIINFO:
669bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDriInfo = GL_FALSE;
670bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
671bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_SECTION:
672bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inSection = GL_FALSE;
673bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
674bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_DESCRIPTION:
675bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDesc = GL_FALSE;
676bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
677bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_OPTION:
678bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inOption = GL_FALSE;
679bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
680bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OI_ENUM:
681bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inEnum = GL_FALSE;
682bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
683bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      default:
684bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	assert (0); /* should have been caught by StartElem */
685bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
686bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
687bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
688d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paulvoid driParseOptionInfo (driOptionCache *info,
689d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul			 const char *configOptions, GLuint nConfigOptions) {
690bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_Parser p;
691bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    int status;
692bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptInfoData userData;
693bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptInfoData *data = &userData;
694d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul    GLuint realNoptions;
695bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
696fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling  /* determine hash table size and allocate memory:
697fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling   * 3/2 of the number of options, rounded up, so there remains always
698fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling   * at least one free entry. This is needed for detecting undefined
699fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling   * options in configuration files without getting a hash table overflow.
700fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling   * Round this up to a power of two. */
701fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling    GLuint minSize = (nConfigOptions*3 + 1) / 2;
702bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint size, log2size;
703fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling    for (size = 1, log2size = 0; size < minSize; size <<= 1, ++log2size);
704bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    info->tableSize = log2size;
705bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    info->info = CALLOC (size * sizeof (driOptionInfo));
706fff87eecbe94ca3ac4ca0e7e8647ee7cae7fae56Felix Kuehling    info->values = CALLOC (size * sizeof (driOptionValue));
707bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (info->info == NULL || info->values == NULL) {
708bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
709bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	abort();
710bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
711bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
712bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    p = XML_ParserCreate ("UTF-8"); /* always UTF-8 */
713bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_SetElementHandler (p, optInfoStartElem, optInfoEndElem);
714bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_SetUserData (p, data);
715bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
716bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.name = "__driConfigOptions";
717bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.parser = p;
718bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.cache = info;
719bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.inDriInfo = GL_FALSE;
720bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.inSection = GL_FALSE;
721bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.inDesc = GL_FALSE;
722bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.inOption = GL_FALSE;
723bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.inEnum = GL_FALSE;
724bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.curOption = -1;
725bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
726d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul    status = XML_Parse (p, configOptions, strlen (configOptions), 1);
727bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!status)
728bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
729bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
730bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_ParserFree (p);
731bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
732d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul  /* Check if the actual number of options matches nConfigOptions.
733bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl   * A mismatch is not fatal (a hash table overflow would be) but we
734bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl   * want the driver developer's attention anyway. */
735d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul    realNoptions = countOptions (info);
736d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul    if (realNoptions != nConfigOptions) {
737bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr,
738d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul		 "Error: nConfigOptions (%u) does not match the actual number of options in\n"
739bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		 "       __driConfigOptions (%u).\n",
740d450d0b0e228e5b16c04b2a1acb9ea549aa690f2Brian Paul		 nConfigOptions, realNoptions);
741bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
742bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
743bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
744bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parser context for configuration files. */
745bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstruct OptConfData {
746bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const char *name;
747bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    XML_Parser parser;
748bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driOptionCache *cache;
749bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLint screenNum;
750bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const char *driverName, *execName;
751bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint ignoringDevice;
752bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint ignoringApp;
753bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint inDriConf;
754bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint inDevice;
755bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint inApp;
756bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint inOption;
757bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
758bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
759bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Elements in configuration files. */
760bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlenum OptConfElem {
761bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_OPTION, OC_COUNT
762bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
763bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic const XML_Char *OptConfElems[] = {
764bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    "application", "device", "driconf", "option"
765bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl};
766bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
767bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of a device element. */
768bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseDeviceAttr (struct OptConfData *data, const XML_Char **attr) {
769bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
770bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char *driver = NULL, *screen = NULL;
771bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
772bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!strcmp (attr[i], "driver")) driver = attr[i+1];
773bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (attr[i], "screen")) screen = attr[i+1];
77499907303f6a1e9abe02977664ad8457c122213ceTimo Wiren	else XML_WARNING("unknown device attribute: %s.", attr[i]);
775bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
776bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (driver && strcmp (driver, data->driverName))
777bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->ignoringDevice = data->inDevice;
778bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    else if (screen) {
779bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	driOptionValue screenNum;
780bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!parseValue (&screenNum, DRI_INT, screen))
781bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING("illegal screen number: %s.", screen);
782bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (screenNum._int != data->screenNum)
783bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    data->ignoringDevice = data->inDevice;
784bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
785bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
786bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
787bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of an application element. */
788bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseAppAttr (struct OptConfData *data, const XML_Char **attr) {
789bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
7907854b8cb166e513300085f8798b3fd05ae6a492eMarek Olšák    const XML_Char *exec = NULL;
791bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
7927854b8cb166e513300085f8798b3fd05ae6a492eMarek Olšák	if (!strcmp (attr[i], "name")) /* not needed here */;
793bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (attr[i], "executable")) exec = attr[i+1];
79499907303f6a1e9abe02977664ad8457c122213ceTimo Wiren	else XML_WARNING("unknown application attribute: %s.", attr[i]);
795bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
796bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (exec && strcmp (exec, data->execName))
797bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->ignoringApp = data->inApp;
798bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
799bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
800bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse attributes of an option element. */
801bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseOptConfAttr (struct OptConfData *data, const XML_Char **attr) {
802bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
803bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    const XML_Char *name = NULL, *value = NULL;
804bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; attr[i]; i += 2) {
805bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!strcmp (attr[i], "name")) name = attr[i+1];
806bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!strcmp (attr[i], "value")) value = attr[i+1];
80799907303f6a1e9abe02977664ad8457c122213ceTimo Wiren	else XML_WARNING("unknown option attribute: %s.", attr[i]);
808bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
809bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!name) XML_WARNING1 ("name attribute missing in option.");
810bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (!value) XML_WARNING1 ("value attribute missing in option.");
811bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (name && value) {
812bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	driOptionCache *cache = data->cache;
813bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	GLuint opt = findOption (cache, name);
814bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (cache->info[opt].name == NULL)
815bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING ("undefined option: %s.", name);
816bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (getenv (cache->info[opt].name))
817bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	  /* don't use XML_WARNING, we want the user to see this! */
818bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    fprintf (stderr, "ATTENTION: option value of option %s ignored.\n",
819bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		     cache->info[opt].name);
820bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else if (!parseValue (&cache->values[opt], cache->info[opt].type, value))
821bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING ("illegal option value: %s.", value);
822bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
823bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
824bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
825bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Handler for start element events. */
826bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void optConfStartElem (void *userData, const XML_Char *name,
827bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			      const XML_Char **attr) {
828bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptConfData *data = (struct OptConfData *)userData;
829bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
830bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (elem) {
831bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_DRICONF:
832bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDriConf)
833bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("nested <driconf> elements.");
834bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (attr[0])
835bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("attributes specified on <driconf> element.");
836bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDriConf++;
837bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
838bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_DEVICE:
839bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inDriConf)
840bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("<device> should be inside <driconf>.");
841bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDevice)
842bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("nested <device> elements.");
843bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDevice++;
844bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->ignoringDevice && !data->ignoringApp)
845bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    parseDeviceAttr (data, attr);
846bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
847bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_APPLICATION:
848bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inDevice)
849bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("<application> should be inside <device>.");
850bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inApp)
851bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("nested <application> elements.");
852bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inApp++;
853bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->ignoringDevice && !data->ignoringApp)
854bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    parseAppAttr (data, attr);
855bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
856bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_OPTION:
857bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->inApp)
858bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("<option> should be inside <application>.");
859bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inOption)
860bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_WARNING1 ("nested <option> elements.");
861bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inOption++;
862bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!data->ignoringDevice && !data->ignoringApp)
863bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    parseOptConfAttr (data, attr);
864bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
865bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      default:
866bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_WARNING ("unknown element: %s.", name);
867bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
868bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
869bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
870bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Handler for end element events. */
871bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void optConfEndElem (void *userData, const XML_Char *name) {
872bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptConfData *data = (struct OptConfData *)userData;
873bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
874bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    switch (elem) {
875bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_DRICONF:
876bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inDriConf--;
877bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
878bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_DEVICE:
879bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inDevice-- == data->ignoringDevice)
880bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    data->ignoringDevice = 0;
881bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
882bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_APPLICATION:
883bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (data->inApp-- == data->ignoringApp)
884bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    data->ignoringApp = 0;
885bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
886bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      case OC_OPTION:
887bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	data->inOption--;
888bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	break;
889bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl      default:
890bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	/* unknown element, warning was produced on start tag */;
891bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
892bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
893bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
894bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Initialize an option cache based on info */
89597fcc0e77b55f2d11a4fe34fbe71605d0550e6c8Brian Paulstatic void initOptionCache (driOptionCache *cache, const driOptionCache *info) {
896bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    cache->info = info->info;
897bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    cache->tableSize = info->tableSize;
898bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    cache->values = MALLOC ((1<<info->tableSize) * sizeof (driOptionValue));
899bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (cache->values == NULL) {
900bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
901bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	abort();
902bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
903bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    memcpy (cache->values, info->values,
904bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    (1<<info->tableSize) * sizeof (driOptionValue));
905bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
906bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
907bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl/** \brief Parse the named configuration file */
908bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlstatic void parseOneConfigFile (XML_Parser p) {
909bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#define BUF_SIZE 0x1000
910bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p);
911bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    int status;
912bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    int fd;
913bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
914bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if ((fd = open (data->name, O_RDONLY)) == -1) {
915bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	__driUtilMessage ("Can't open configuration file %s: %s.",
916bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			  data->name, strerror (errno));
917bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	return;
918bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
919bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
920bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    while (1) {
921bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	int bytesRead;
922bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	void *buffer = XML_GetBuffer (p, BUF_SIZE);
923bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!buffer) {
924bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    __driUtilMessage ("Can't allocate parser buffer.");
925bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
926bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
927bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	bytesRead = read (fd, buffer, BUF_SIZE);
928bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (bytesRead == -1) {
929bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    __driUtilMessage ("Error reading from configuration file %s: %s.",
930bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			      data->name, strerror (errno));
931bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
932bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
933bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	status = XML_ParseBuffer (p, bytesRead, bytesRead == 0);
934bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (!status) {
935bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    XML_ERROR ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
936bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
937bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
938bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (bytesRead == 0)
939bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    break;
940bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
941bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
942bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    close (fd);
943bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl#undef BUF_SIZE
944bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
945bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
94697fcc0e77b55f2d11a4fe34fbe71605d0550e6c8Brian Paulvoid driParseConfigFiles (driOptionCache *cache, const driOptionCache *info,
947bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			  GLint screenNum, const char *driverName) {
948bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    char *filenames[2] = {"/etc/drirc", NULL};
949bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    char *home;
950bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i;
951bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    struct OptConfData userData;
952bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
953bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    initOptionCache (cache, info);
954bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
955bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.cache = cache;
956bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.screenNum = screenNum;
957bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.driverName = driverName;
958bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    userData.execName = GET_PROGRAM_NAME();
959bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
960bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if ((home = getenv ("HOME"))) {
961bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	GLuint len = strlen (home);
962bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	filenames[1] = MALLOC (len + 7+1);
963bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (filenames[1] == NULL)
964bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    __driUtilMessage ("Can't allocate memory for %s/.drirc.", home);
965bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	else {
966bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    memcpy (filenames[1], home, len);
967bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    memcpy (filenames[1] + len, "/.drirc", 7+1);
968bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
969bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
970bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
971bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    for (i = 0; i < 2; ++i) {
972bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_Parser p;
973bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	if (filenames[i] == NULL)
974bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    continue;
975bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
976bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	p = XML_ParserCreate (NULL); /* use encoding specified by file */
977bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
978bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_SetUserData (p, &userData);
979bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.parser = p;
980bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.name = filenames[i];
981bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.ignoringDevice = 0;
982bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.ignoringApp = 0;
983bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.inDriConf = 0;
984bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.inDevice = 0;
985bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.inApp = 0;
986bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	userData.inOption = 0;
987bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
988bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	parseOneConfigFile (p);
989bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	XML_ParserFree (p);
990bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
991bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
992bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (filenames[1])
993bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	FREE (filenames[1]);
994bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
995bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
996bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlvoid driDestroyOptionInfo (driOptionCache *info) {
997bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    driDestroyOptionCache (info);
998bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (info->info) {
999bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	GLuint i, size = 1 << info->tableSize;
1000bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	for (i = 0; i < size; ++i) {
1001bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    if (info->info[i].name) {
1002bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		FREE (info->info[i].name);
1003bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		if (info->info[i].ranges)
1004bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl		    FREE (info->info[i].ranges);
1005bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	    }
1006bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	}
1007bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	FREE (info->info);
1008bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    }
1009bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1010bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
1011bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirlvoid driDestroyOptionCache (driOptionCache *cache) {
1012bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    if (cache->values)
1013bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl	FREE (cache->values);
1014bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1015bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
1016bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon SmirlGLboolean driCheckOption (const driOptionCache *cache, const char *name,
1017bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl			  driOptionType type) {
1018bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i = findOption (cache, name);
1019bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return cache->info[i].name != NULL && cache->info[i].type == type;
1020bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1021bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
1022bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon SmirlGLboolean driQueryOptionb (const driOptionCache *cache, const char *name) {
1023bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i = findOption (cache, name);
1024bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* make sure the option is defined and has the correct type */
1025bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].name != NULL);
1026bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].type == DRI_BOOL);
1027bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return cache->values[i]._bool;
1028bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1029bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
1030bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon SmirlGLint driQueryOptioni (const driOptionCache *cache, const char *name) {
1031bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i = findOption (cache, name);
1032bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* make sure the option is defined and has the correct type */
1033bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].name != NULL);
1034bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM);
1035bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return cache->values[i]._int;
1036bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1037bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl
1038bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon SmirlGLfloat driQueryOptionf (const driOptionCache *cache, const char *name) {
1039bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    GLuint i = findOption (cache, name);
1040bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl  /* make sure the option is defined and has the correct type */
1041bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].name != NULL);
1042bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    assert (cache->info[i].type == DRI_FLOAT);
1043bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl    return cache->values[i]._float;
1044bcc6eddd335e97d49ed2ef3a1440f94d58dce12dJon Smirl}
1045