Update DRI drivers to current DRI CVS and make them work.
[mesa.git] / src / mesa / drivers / dri / common / xmlconfig.c
1 /*
2 * XML DRI client-side driver configuration
3 * Copyright (C) 2003 Felix Kuehling
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24 /**
25 * \file xmlconfig.c
26 * \brief Driver-independent client-side part of the XML configuration
27 * \author Felix Kuehling
28 */
29
30 #include "glheader.h"
31
32 #include <string.h>
33 #include <assert.h>
34 #include <expat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include "imports.h"
39 #include "dri_util.h"
40 #include "xmlconfig.h"
41
42 /*
43 * OS dependent ways of getting the name of the running program
44 */
45 #if (defined(__unix__) || defined(unix)) && !defined(USG)
46 #include <sys/param.h>
47 #endif
48
49 #undef GET_PROGRAM_NAME
50
51 #if defined(__GNU_LIBRARY__) || defined(__GLIBC__)
52 # define GET_PROGRAM_NAME() program_invocation_short_name
53 #elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
54 # include <osreldate.h>
55 # if (__FreeBSD_version >= 440000)
56 # include <stdlib.h>
57 # define GET_PROGRAM_NAME() getprogname()
58 # endif
59 #elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)
60 # include <stdlib.h>
61 # define GET_PROGRAM_NAME() getprogname()
62 #endif
63
64 #if !defined(GET_PROGRAM_NAME)
65 # if defined(OpenBSD) || defined(NetBSD)
66 /* This is a hack. It's said to work on OpenBSD, NetBSD and GNU. It's
67 * used as a last resort, if there is no documented facility available. */
68 static const char *__getProgramName () {
69 extern const char *__progname;
70 return progname;
71 }
72 # define GET_PROGRAM_NAME() __getProgramName()
73 # else
74 # define GET_PROGRAM_NAME() ""
75 # warning "Per application configuration won't with your OS version work."
76 # endif
77 #endif
78
79 /** \brief Find an option in an option cache with the name as key */
80 static GLuint findOption (const driOptionCache *cache, const char *name) {
81 GLuint len = strlen (name);
82 GLuint size = 1 << cache->tableSize, mask = size - 1;
83 GLuint hash = 0;
84 GLuint i, shift;
85
86 /* compute a hash from the variable length name */
87 for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
88 hash += (GLuint)name[i] << shift;
89 hash *= hash;
90 hash = (hash >> (16-cache->tableSize/2)) & mask;
91
92 /* this is just the starting point of the linear search for the option */
93 for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
94 /* if we hit an empty entry then the option is not defined (yet) */
95 if (cache->info[hash].name == 0)
96 break;
97 else if (!strcmp (name, cache->info[hash].name))
98 break;
99 }
100 /* this assertion fails if the hash table is full */
101 assert (i < size);
102
103 return hash;
104 }
105
106 /** \brief Count the real number of options in an option cache */
107 static GLuint countOptions (const driOptionCache *cache) {
108 GLuint size = 1 << cache->tableSize;
109 GLuint i, count = 0;
110 for (i = 0; i < size; ++i)
111 if (cache->info[i].name)
112 count++;
113 return count;
114 }
115
116 /** \brief Like strdup but using MALLOC and with error checking. */
117 #define XSTRDUP(dest,source) do { \
118 GLuint len = strlen (source); \
119 if (!(dest = MALLOC (len+1))) { \
120 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
121 abort(); \
122 } \
123 memcpy (dest, source, len+1); \
124 } while (0)
125
126 static int compare (const void *a, const void *b) {
127 return strcmp (*(char *const*)a, *(char *const*)b);
128 }
129 /** \brief Binary search in a string array. */
130 static GLuint bsearchStr (const XML_Char *name,
131 const XML_Char *elems[], GLuint count) {
132 const XML_Char **found;
133 found = bsearch (&name, elems, count, sizeof (XML_Char *), compare);
134 if (found)
135 return found - elems;
136 else
137 return count;
138 }
139
140 /** \brief Parse a value of a given type. */
141 static GLboolean parseValue (driOptionValue *v, driOptionType type,
142 const XML_Char *string) {
143 const XML_Char *tail;
144 /* skip leading white-space */
145 string += strspn (string, " \f\n\r\t\v");
146 switch (type) {
147 case DRI_BOOL:
148 if (!strcmp (string, "false")) {
149 v->_bool = GL_FALSE;
150 tail = string + 5;
151 } else if (!strcmp (string, "true")) {
152 v->_bool = GL_TRUE;
153 tail = string + 4;
154 }
155 else
156 return GL_FALSE;
157 break;
158 case DRI_ENUM: /* enum is just a special integer */
159 case DRI_INT:
160 v->_int = strtol (string, (char **)&tail, 0);
161 break;
162 case DRI_FLOAT:
163 v->_float = strtod (string, (char **)&tail);
164 break;
165 }
166
167 if (tail == string)
168 return GL_FALSE; /* empty string (or containing only white-space) */
169 /* skip trailing white space */
170 if (*tail)
171 tail += strspn (tail, " \f\n\r\t\v");
172 if (*tail)
173 return GL_FALSE; /* something left over that is not part of value */
174
175 return GL_TRUE;
176 }
177
178 /** \brief Parse a list of ranges of type info->type. */
179 static GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) {
180 XML_Char *cp, *range;
181 GLuint nRanges, i;
182 driOptionRange *ranges;
183
184 XSTRDUP (cp, string);
185 /* pass 1: determine the number of ranges (number of commas + 1) */
186 range = cp;
187 for (nRanges = 1; *range; ++range)
188 if (*range == ',')
189 ++nRanges;
190
191 if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) {
192 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
193 abort();
194 }
195
196 /* pass 2: parse all ranges into preallocated array */
197 range = cp;
198 for (i = 0; i < nRanges; ++i) {
199 XML_Char *end, *sep;
200 assert (range);
201 end = strchr (range, ',');
202 if (end)
203 *end = '\0';
204 sep = strchr (range, ':');
205 if (sep) { /* non-empty interval */
206 *sep = '\0';
207 if (!parseValue (&ranges[i].start, info->type, range) ||
208 !parseValue (&ranges[i].end, info->type, sep+1))
209 break;
210 if (info->type == DRI_INT &&
211 ranges[i].start._int > ranges[i].end._int)
212 break;
213 if (info->type == DRI_FLOAT &&
214 ranges[i].start._float > ranges[i].end._float)
215 break;
216 } else { /* empty interval */
217 if (!parseValue (&ranges[i].start, info->type, range))
218 break;
219 ranges[i].end = ranges[i].start;
220 }
221 if (end)
222 range = end+1;
223 else
224 range = NULL;
225 }
226 FREE (cp);
227 if (i < nRanges) {
228 FREE (ranges);
229 return GL_FALSE;
230 } else
231 assert (range == NULL);
232
233 info->nRanges = nRanges;
234 info->ranges = ranges;
235 return GL_TRUE;
236 }
237
238 /** \brief Check if a value is in one of info->ranges. */
239 static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) {
240 GLuint i;
241 assert (info->type != DRI_BOOL); /* should be caught by the parser */
242 if (info->nRanges == 0)
243 return GL_TRUE;
244 switch (info->type) {
245 case DRI_ENUM: /* enum is just a special integer */
246 case DRI_INT:
247 for (i = 0; i < info->nRanges; ++i)
248 if (v->_int >= info->ranges[i].start._int &&
249 v->_int <= info->ranges[i].end._int)
250 return GL_TRUE;
251 break;
252 case DRI_FLOAT:
253 for (i = 0; i < info->nRanges; ++i)
254 if (v->_float >= info->ranges[i].start._float &&
255 v->_float <= info->ranges[i].end._float)
256 return GL_TRUE;
257 break;
258 default:
259 assert (0); /* should never happen */
260 }
261 return GL_FALSE;
262 }
263
264 /** \brief Output a warning message. */
265 #define XML_WARNING1(msg) do {\
266 __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
267 XML_GetCurrentLineNumber(data->parser), \
268 XML_GetCurrentColumnNumber(data->parser)); \
269 } while (0)
270 #define XML_WARNING(msg,args...) do { \
271 __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
272 XML_GetCurrentLineNumber(data->parser), \
273 XML_GetCurrentColumnNumber(data->parser), \
274 args); \
275 } while (0)
276 /** \brief Output an error message. */
277 #define XML_ERROR1(msg) do { \
278 __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
279 XML_GetCurrentLineNumber(data->parser), \
280 XML_GetCurrentColumnNumber(data->parser)); \
281 } while (0)
282 #define XML_ERROR(msg,args...) do { \
283 __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
284 XML_GetCurrentLineNumber(data->parser), \
285 XML_GetCurrentColumnNumber(data->parser), \
286 args); \
287 } while (0)
288 /** \brief Output a fatal error message and abort. */
289 #define XML_FATAL1(msg) do { \
290 fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
291 data->name, \
292 XML_GetCurrentLineNumber(data->parser), \
293 XML_GetCurrentColumnNumber(data->parser)); \
294 abort();\
295 } while (0)
296 #define XML_FATAL(msg,args...) do { \
297 fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
298 data->name, \
299 XML_GetCurrentLineNumber(data->parser), \
300 XML_GetCurrentColumnNumber(data->parser), \
301 args); \
302 abort();\
303 } while (0)
304
305 /** \brief Parser context for __driConfigOptions. */
306 struct OptInfoData {
307 const char *name;
308 XML_Parser parser;
309 driOptionCache *cache;
310 GLboolean inDriInfo;
311 GLboolean inSection;
312 GLboolean inDesc;
313 GLboolean inOption;
314 GLboolean inEnum;
315 int curOption;
316 };
317
318 /** \brief Elements in __driConfigOptions. */
319 enum OptInfoElem {
320 OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT
321 };
322 static const XML_Char *OptInfoElems[] = {
323 "description", "driinfo", "enum", "option", "section"
324 };
325
326 /** \brief Parse attributes of an enum element.
327 *
328 * We're not actually interested in the data. Just make sure this is ok
329 * for external configuration tools.
330 */
331 static void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) {
332 GLuint i;
333 const XML_Char *value = NULL, *text = NULL;
334 driOptionValue v;
335 GLuint opt = data->curOption;
336 for (i = 0; attr[i]; i += 2) {
337 if (!strcmp (attr[i], "value")) value = attr[i+1];
338 else if (!strcmp (attr[i], "text")) text = attr[i+1];
339 else XML_FATAL("illegal enum attribute: %s.", attr[i]);
340 }
341 if (!value) XML_FATAL1 ("value attribute missing in enum.");
342 if (!text) XML_FATAL1 ("text attribute missing in enum.");
343 if (!parseValue (&v, data->cache->info[opt].type, value))
344 XML_FATAL ("illegal enum value: %s.", value);
345 if (!checkValue (&v, &data->cache->info[opt]))
346 XML_FATAL ("enum value out of valid range: %s.", value);
347 }
348
349 /** \brief Parse attributes of a description element.
350 *
351 * We're not actually interested in the data. Just make sure this is ok
352 * for external configuration tools.
353 */
354 static void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) {
355 GLuint i;
356 const XML_Char *lang = NULL, *text = NULL;
357 for (i = 0; attr[i]; i += 2) {
358 if (!strcmp (attr[i], "lang")) lang = attr[i+1];
359 else if (!strcmp (attr[i], "text")) text = attr[i+1];
360 else XML_FATAL("illegal description attribute: %s.", attr[i]);
361 }
362 if (!lang) XML_FATAL1 ("lang attribute missing in description.");
363 if (!text) XML_FATAL1 ("text attribute missing in description.");
364 }
365
366 /** \brief Parse attributes of an option element. */
367 static void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) {
368 enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT};
369 static const XML_Char *optAttr[] = {"default", "name", "type", "valid"};
370 const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL};
371 const char *defaultVal;
372 driOptionCache *cache = data->cache;
373 GLuint opt, i;
374 for (i = 0; attr[i]; i += 2) {
375 GLuint attrName = bsearchStr (attr[i], optAttr, OA_COUNT);
376 if (attrName >= OA_COUNT)
377 XML_FATAL ("illegal option attribute: %s", attr[i]);
378 attrVal[attrName] = attr[i+1];
379 }
380 if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option.");
381 if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option.");
382 if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option.");
383
384 opt = findOption (cache, attrVal[OA_NAME]);
385 if (cache->info[opt].name)
386 XML_FATAL ("option %s redefined.", attrVal[OA_NAME]);
387 data->curOption = opt;
388
389 XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]);
390
391 if (!strcmp (attrVal[OA_TYPE], "bool"))
392 cache->info[opt].type = DRI_BOOL;
393 else if (!strcmp (attrVal[OA_TYPE], "enum"))
394 cache->info[opt].type = DRI_ENUM;
395 else if (!strcmp (attrVal[OA_TYPE], "int"))
396 cache->info[opt].type = DRI_INT;
397 else if (!strcmp (attrVal[OA_TYPE], "float"))
398 cache->info[opt].type = DRI_FLOAT;
399 else
400 XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]);
401
402 defaultVal = getenv (cache->info[opt].name);
403 if (defaultVal != NULL) {
404 /* don't use XML_WARNING, we want the user to see this! */
405 fprintf (stderr,
406 "ATTENTION: default value of option %s overridden by environment.\n",
407 cache->info[opt].name);
408 } else
409 defaultVal = attrVal[OA_DEFAULT];
410 if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal))
411 XML_FATAL ("illegal default value: %s.", defaultVal);
412
413 if (attrVal[OA_VALID]) {
414 if (cache->info[opt].type == DRI_BOOL)
415 XML_FATAL1 ("boolean option with valid attribute.");
416 if (!parseRanges (&cache->info[opt], attrVal[OA_VALID]))
417 XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]);
418 if (!checkValue (&cache->values[opt], &cache->info[opt]))
419 XML_FATAL ("default value out of valid range '%s': %s.",
420 attrVal[OA_VALID], defaultVal);
421 } else if (cache->info[opt].type == DRI_ENUM) {
422 XML_FATAL1 ("valid attribute missing in option (mandatory for enums).");
423 } else {
424 cache->info[opt].nRanges = 0;
425 cache->info[opt].ranges = NULL;
426 }
427 }
428
429 /** \brief Handler for start element events. */
430 static void optInfoStartElem (void *userData, const XML_Char *name,
431 const XML_Char **attr) {
432 struct OptInfoData *data = (struct OptInfoData *)userData;
433 enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
434 switch (elem) {
435 case OI_DRIINFO:
436 if (data->inDriInfo)
437 XML_FATAL1 ("nested <driinfo> elements.");
438 if (attr[0])
439 XML_FATAL1 ("attributes specified on <driinfo> element.");
440 data->inDriInfo = GL_TRUE;
441 break;
442 case OI_SECTION:
443 if (!data->inDriInfo)
444 XML_FATAL1 ("<section> must be inside <driinfo>.");
445 if (data->inSection)
446 XML_FATAL1 ("nested <section> elements.");
447 if (attr[0])
448 XML_FATAL1 ("attributes specified on <section> element.");
449 data->inSection = GL_TRUE;
450 break;
451 case OI_DESCRIPTION:
452 if (!data->inSection && !data->inOption)
453 XML_FATAL1 ("<description> must be inside <description> or <option.");
454 if (data->inDesc)
455 XML_FATAL1 ("nested <description> elements.");
456 data->inDesc = GL_TRUE;
457 parseDescAttr (data, attr);
458 break;
459 case OI_OPTION:
460 if (!data->inSection)
461 XML_FATAL1 ("<option> must be inside <section>.");
462 if (data->inDesc)
463 XML_FATAL1 ("<option> nested in <description> element.");
464 if (data->inOption)
465 XML_FATAL1 ("nested <option> elements.");
466 data->inOption = GL_TRUE;
467 parseOptInfoAttr (data, attr);
468 break;
469 case OI_ENUM:
470 if (!(data->inOption && data->inDesc))
471 XML_FATAL1 ("<enum> must be inside <option> and <description>.");
472 if (data->inEnum)
473 XML_FATAL1 ("nested <enum> elements.");
474 data->inEnum = GL_TRUE;
475 parseEnumAttr (data, attr);
476 break;
477 default:
478 XML_FATAL ("unknown element: %s.", name);
479 }
480 }
481
482 /** \brief Handler for end element events. */
483 static void optInfoEndElem (void *userData, const XML_Char *name) {
484 struct OptInfoData *data = (struct OptInfoData *)userData;
485 enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
486 switch (elem) {
487 case OI_DRIINFO:
488 data->inDriInfo = GL_FALSE;
489 break;
490 case OI_SECTION:
491 data->inSection = GL_FALSE;
492 break;
493 case OI_DESCRIPTION:
494 data->inDesc = GL_FALSE;
495 break;
496 case OI_OPTION:
497 data->inOption = GL_FALSE;
498 break;
499 case OI_ENUM:
500 data->inEnum = GL_FALSE;
501 break;
502 default:
503 assert (0); /* should have been caught by StartElem */
504 }
505 }
506
507 void driParseOptionInfo (driOptionCache *info) {
508 XML_Parser p;
509 int status;
510 struct OptInfoData userData;
511 struct OptInfoData *data = &userData;
512 GLuint nOptions;
513
514 /* determine hash table size and allocate memory */
515 GLuint size, log2size;
516 for (size = 1, log2size = 0; size < __driNConfigOptions*3/2;
517 size <<= 1, ++log2size);
518 info->tableSize = log2size;
519 info->info = CALLOC (size * sizeof (driOptionInfo));
520 info->values = CALLOC (size * sizeof (driOptionInfo));
521 if (info->info == NULL || info->values == NULL) {
522 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
523 abort();
524 }
525
526 p = XML_ParserCreate ("UTF-8"); /* always UTF-8 */
527 XML_SetElementHandler (p, optInfoStartElem, optInfoEndElem);
528 XML_SetUserData (p, data);
529
530 userData.name = "__driConfigOptions";
531 userData.parser = p;
532 userData.cache = info;
533 userData.inDriInfo = GL_FALSE;
534 userData.inSection = GL_FALSE;
535 userData.inDesc = GL_FALSE;
536 userData.inOption = GL_FALSE;
537 userData.inEnum = GL_FALSE;
538 userData.curOption = -1;
539
540 status = XML_Parse (p, __driConfigOptions, strlen (__driConfigOptions), 1);
541 if (!status)
542 XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
543
544 XML_ParserFree (p);
545
546 /* Check if the actual number of options matches __driNConfigOptions.
547 * A mismatch is not fatal (a hash table overflow would be) but we
548 * want the driver developer's attention anyway. */
549 nOptions = countOptions (info);
550 if (nOptions != __driNConfigOptions) {
551 fprintf (stderr,
552 "Error: __driNConfigOptions (%u) does not match the actual number of options in\n"
553 " __driConfigOptions (%u).\n",
554 __driNConfigOptions, nOptions);
555 }
556 }
557
558 /** \brief Parser context for configuration files. */
559 struct OptConfData {
560 const char *name;
561 XML_Parser parser;
562 driOptionCache *cache;
563 GLint screenNum;
564 const char *driverName, *execName;
565 GLuint ignoringDevice;
566 GLuint ignoringApp;
567 GLuint inDriConf;
568 GLuint inDevice;
569 GLuint inApp;
570 GLuint inOption;
571 };
572
573 /** \brief Elements in configuration files. */
574 enum OptConfElem {
575 OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_OPTION, OC_COUNT
576 };
577 static const XML_Char *OptConfElems[] = {
578 "application", "device", "driconf", "option"
579 };
580
581 /** \brief Parse attributes of a device element. */
582 static void parseDeviceAttr (struct OptConfData *data, const XML_Char **attr) {
583 GLuint i;
584 const XML_Char *driver = NULL, *screen = NULL;
585 for (i = 0; attr[i]; i += 2) {
586 if (!strcmp (attr[i], "driver")) driver = attr[i+1];
587 else if (!strcmp (attr[i], "screen")) screen = attr[i+1];
588 else XML_WARNING("unkown device attribute: %s.", attr[i]);
589 }
590 if (driver && strcmp (driver, data->driverName))
591 data->ignoringDevice = data->inDevice;
592 else if (screen) {
593 driOptionValue screenNum;
594 if (!parseValue (&screenNum, DRI_INT, screen))
595 XML_WARNING("illegal screen number: %s.", screen);
596 else if (screenNum._int != data->screenNum)
597 data->ignoringDevice = data->inDevice;
598 }
599 }
600
601 /** \brief Parse attributes of an application element. */
602 static void parseAppAttr (struct OptConfData *data, const XML_Char **attr) {
603 GLuint i;
604 const XML_Char *name = NULL, *exec = NULL;
605 for (i = 0; attr[i]; i += 2) {
606 if (!strcmp (attr[i], "name")) name = attr[i+1];
607 else if (!strcmp (attr[i], "executable")) exec = attr[i+1];
608 else XML_WARNING("unkown application attribute: %s.", attr[i]);
609 }
610 if (exec && strcmp (exec, data->execName))
611 data->ignoringApp = data->inApp;
612 }
613
614 /** \brief Parse attributes of an option element. */
615 static void parseOptConfAttr (struct OptConfData *data, const XML_Char **attr) {
616 GLuint i;
617 const XML_Char *name = NULL, *value = NULL;
618 for (i = 0; attr[i]; i += 2) {
619 if (!strcmp (attr[i], "name")) name = attr[i+1];
620 else if (!strcmp (attr[i], "value")) value = attr[i+1];
621 else XML_WARNING("unkown option attribute: %s.", attr[i]);
622 }
623 if (!name) XML_WARNING1 ("name attribute missing in option.");
624 if (!value) XML_WARNING1 ("value attribute missing in option.");
625 if (name && value) {
626 driOptionCache *cache = data->cache;
627 GLuint opt = findOption (cache, name);
628 if (cache->info[opt].name == NULL)
629 XML_WARNING ("undefined option: %s.", name);
630 else if (getenv (cache->info[opt].name))
631 /* don't use XML_WARNING, we want the user to see this! */
632 fprintf (stderr, "ATTENTION: option value of option %s ignored.\n",
633 cache->info[opt].name);
634 else if (!parseValue (&cache->values[opt], cache->info[opt].type, value))
635 XML_WARNING ("illegal option value: %s.", value);
636 }
637 }
638
639 /** \brief Handler for start element events. */
640 static void optConfStartElem (void *userData, const XML_Char *name,
641 const XML_Char **attr) {
642 struct OptConfData *data = (struct OptConfData *)userData;
643 enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
644 switch (elem) {
645 case OC_DRICONF:
646 if (data->inDriConf)
647 XML_WARNING1 ("nested <driconf> elements.");
648 if (attr[0])
649 XML_WARNING1 ("attributes specified on <driconf> element.");
650 data->inDriConf++;
651 break;
652 case OC_DEVICE:
653 if (!data->inDriConf)
654 XML_WARNING1 ("<device> should be inside <driconf>.");
655 if (data->inDevice)
656 XML_WARNING1 ("nested <device> elements.");
657 data->inDevice++;
658 if (!data->ignoringDevice && !data->ignoringApp)
659 parseDeviceAttr (data, attr);
660 break;
661 case OC_APPLICATION:
662 if (!data->inDevice)
663 XML_WARNING1 ("<application> should be inside <device>.");
664 if (data->inApp)
665 XML_WARNING1 ("nested <application> elements.");
666 data->inApp++;
667 if (!data->ignoringDevice && !data->ignoringApp)
668 parseAppAttr (data, attr);
669 break;
670 case OC_OPTION:
671 if (!data->inApp)
672 XML_WARNING1 ("<option> should be inside <application>.");
673 if (data->inOption)
674 XML_WARNING1 ("nested <option> elements.");
675 data->inOption++;
676 if (!data->ignoringDevice && !data->ignoringApp)
677 parseOptConfAttr (data, attr);
678 break;
679 default:
680 XML_WARNING ("unknown element: %s.", name);
681 }
682 }
683
684 /** \brief Handler for end element events. */
685 static void optConfEndElem (void *userData, const XML_Char *name) {
686 struct OptConfData *data = (struct OptConfData *)userData;
687 enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
688 switch (elem) {
689 case OC_DRICONF:
690 data->inDriConf--;
691 break;
692 case OC_DEVICE:
693 if (data->inDevice-- == data->ignoringDevice)
694 data->ignoringDevice = 0;
695 break;
696 case OC_APPLICATION:
697 if (data->inApp-- == data->ignoringApp)
698 data->ignoringApp = 0;
699 break;
700 case OC_OPTION:
701 data->inOption--;
702 break;
703 default:
704 /* unknown element, warning was produced on start tag */;
705 }
706 }
707
708 /** \brief Initialize an option cache based on info */
709 static void initOptionCache (driOptionCache *cache, driOptionCache *info) {
710 cache->info = info->info;
711 cache->tableSize = info->tableSize;
712 cache->values = MALLOC ((1<<info->tableSize) * sizeof (driOptionValue));
713 if (cache->values == NULL) {
714 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
715 abort();
716 }
717 memcpy (cache->values, info->values,
718 (1<<info->tableSize) * sizeof (driOptionValue));
719 }
720
721 /** \brief Parse the named configuration file */
722 static void parseOneConfigFile (XML_Parser p) {
723 #define BUF_SIZE 0x1000
724 struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p);
725 int status;
726 int fd;
727
728 if ((fd = open (data->name, O_RDONLY)) == -1) {
729 __driUtilMessage ("Can't open configuration file %s: %s.",
730 data->name, strerror (errno));
731 return;
732 }
733
734 while (1) {
735 int bytesRead;
736 void *buffer = XML_GetBuffer (p, BUF_SIZE);
737 if (!buffer) {
738 __driUtilMessage ("Can't allocate parser buffer.");
739 break;
740 }
741 bytesRead = read (fd, buffer, BUF_SIZE);
742 if (bytesRead == -1) {
743 __driUtilMessage ("Error reading from configuration file %s: %s.",
744 data->name, strerror (errno));
745 break;
746 }
747 status = XML_ParseBuffer (p, bytesRead, bytesRead == 0);
748 if (!status) {
749 XML_ERROR ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
750 break;
751 }
752 if (bytesRead == 0)
753 break;
754 }
755
756 close (fd);
757 #undef BUF_SIZE
758 }
759
760 void driParseConfigFiles (driOptionCache *cache, driOptionCache *info,
761 GLint screenNum, const char *driverName) {
762 char *filenames[2] = {"/etc/drirc", NULL};
763 char *home;
764 GLuint i;
765 struct OptConfData userData;
766
767 initOptionCache (cache, info);
768
769 userData.cache = cache;
770 userData.screenNum = screenNum;
771 userData.driverName = driverName;
772 #ifndef _SOLO
773 userData.execName = GET_PROGRAM_NAME();
774 #else
775 userData.execName = "Solo";
776 #endif
777
778 if ((home = getenv ("HOME"))) {
779 GLuint len = strlen (home);
780 filenames[1] = MALLOC (len + 7+1);
781 if (filenames[1] == NULL)
782 __driUtilMessage ("Can't allocate memory for %s/.drirc.", home);
783 else {
784 memcpy (filenames[1], home, len);
785 memcpy (filenames[1] + len, "/.drirc", 7+1);
786 }
787 }
788
789 for (i = 0; i < 2; ++i) {
790 XML_Parser p;
791 if (filenames[i] == NULL)
792 continue;
793
794 p = XML_ParserCreate (NULL); /* use encoding specified by file */
795 XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
796 XML_SetUserData (p, &userData);
797 userData.parser = p;
798 userData.name = filenames[i];
799 userData.ignoringDevice = 0;
800 userData.ignoringApp = 0;
801 userData.inDriConf = 0;
802 userData.inDevice = 0;
803 userData.inApp = 0;
804 userData.inOption = 0;
805
806 parseOneConfigFile (p);
807 XML_ParserFree (p);
808 }
809
810 if (filenames[1])
811 FREE (filenames[1]);
812 }
813
814 void driDestroyOptionInfo (driOptionCache *info) {
815 driDestroyOptionCache (info);
816 if (info->info) {
817 GLuint i, size = 1 << info->tableSize;
818 for (i = 0; i < size; ++i) {
819 if (info->info[i].name) {
820 FREE (info->info[i].name);
821 if (info->info[i].ranges)
822 FREE (info->info[i].ranges);
823 }
824 }
825 FREE (info->info);
826 }
827 }
828
829 void driDestroyOptionCache (driOptionCache *cache) {
830 if (cache->values)
831 FREE (cache->values);
832 }
833
834 GLboolean driCheckOption (const driOptionCache *cache, const char *name,
835 driOptionType type) {
836 GLuint i = findOption (cache, name);
837 return cache->info[i].name != NULL && cache->info[i].type == type;
838 }
839
840 GLboolean driQueryOptionb (const driOptionCache *cache, const char *name) {
841 GLuint i = findOption (cache, name);
842 /* make sure the option is defined and has the correct type */
843 assert (cache->info[i].name != NULL);
844 assert (cache->info[i].type == DRI_BOOL);
845 return cache->values[i]._bool;
846 }
847
848 GLint driQueryOptioni (const driOptionCache *cache, const char *name) {
849 GLuint i = findOption (cache, name);
850 /* make sure the option is defined and has the correct type */
851 assert (cache->info[i].name != NULL);
852 assert (cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM);
853 return cache->values[i]._int;
854 }
855
856 GLfloat driQueryOptionf (const driOptionCache *cache, const char *name) {
857 GLuint i = findOption (cache, name);
858 /* make sure the option is defined and has the correct type */
859 assert (cache->info[i].name != NULL);
860 assert (cache->info[i].type == DRI_FLOAT);
861 return cache->values[i]._float;
862 }