58d0e0656505382a7def892d0fd1c7ed15025b20
[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 <string.h>
31 #include <assert.h>
32 #include <expat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include "main/imports.h"
37 #include "utils.h"
38 #include "xmlconfig.h"
39
40 #undef GET_PROGRAM_NAME
41
42 #if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__)
43 # if !defined(__GLIBC__) || (__GLIBC__ < 2)
44 /* These aren't declared in any libc5 header */
45 extern char *program_invocation_name, *program_invocation_short_name;
46 # endif
47 # define GET_PROGRAM_NAME() program_invocation_short_name
48 #elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
49 # include <osreldate.h>
50 # if (__FreeBSD_version >= 440000)
51 # include <stdlib.h>
52 # define GET_PROGRAM_NAME() getprogname()
53 # endif
54 #elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)
55 # include <stdlib.h>
56 # define GET_PROGRAM_NAME() getprogname()
57 #elif defined(__APPLE__)
58 # include <stdlib.h>
59 # define GET_PROGRAM_NAME() getprogname()
60 #elif defined(__sun)
61 /* Solaris has getexecname() which returns the full path - return just
62 the basename to match BSD getprogname() */
63 # include <stdlib.h>
64 # include <libgen.h>
65
66 static const char *__getProgramName () {
67 static const char *progname;
68
69 if (progname == NULL) {
70 const char *e = getexecname();
71 if (e != NULL) {
72 /* Have to make a copy since getexecname can return a readonly
73 string, but basename expects to be able to modify its arg. */
74 char *n = strdup(e);
75 if (n != NULL) {
76 progname = basename(n);
77 }
78 }
79 }
80 return progname;
81 }
82
83 # define GET_PROGRAM_NAME() __getProgramName()
84 #endif
85
86 #if !defined(GET_PROGRAM_NAME)
87 # if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__) || defined(ANDROID)
88 /* This is a hack. It's said to work on OpenBSD, NetBSD and GNU.
89 * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's
90 * used as a last resort, if there is no documented facility available. */
91 static const char *__getProgramName () {
92 extern const char *__progname;
93 char * arg = strrchr(__progname, '/');
94 if (arg)
95 return arg+1;
96 else
97 return __progname;
98 }
99 # define GET_PROGRAM_NAME() __getProgramName()
100 # else
101 # define GET_PROGRAM_NAME() ""
102 # warning "Per application configuration won't work with your OS version."
103 # endif
104 #endif
105
106 /** \brief Find an option in an option cache with the name as key */
107 static uint32_t findOption (const driOptionCache *cache, const char *name) {
108 uint32_t len = strlen (name);
109 uint32_t size = 1 << cache->tableSize, mask = size - 1;
110 uint32_t hash = 0;
111 uint32_t i, shift;
112
113 /* compute a hash from the variable length name */
114 for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
115 hash += (uint32_t)name[i] << shift;
116 hash *= hash;
117 hash = (hash >> (16-cache->tableSize/2)) & mask;
118
119 /* this is just the starting point of the linear search for the option */
120 for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
121 /* if we hit an empty entry then the option is not defined (yet) */
122 if (cache->info[hash].name == 0)
123 break;
124 else if (!strcmp (name, cache->info[hash].name))
125 break;
126 }
127 /* this assertion fails if the hash table is full */
128 assert (i < size);
129
130 return hash;
131 }
132
133 /** \brief Like strdup but using malloc and with error checking. */
134 #define XSTRDUP(dest,source) do { \
135 uint32_t len = strlen (source); \
136 if (!(dest = malloc(len+1))) { \
137 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
138 abort(); \
139 } \
140 memcpy (dest, source, len+1); \
141 } while (0)
142
143 static int compare (const void *a, const void *b) {
144 return strcmp (*(char *const*)a, *(char *const*)b);
145 }
146 /** \brief Binary search in a string array. */
147 static uint32_t bsearchStr (const XML_Char *name,
148 const XML_Char *elems[], uint32_t count) {
149 const XML_Char **found;
150 found = bsearch (&name, elems, count, sizeof (XML_Char *), compare);
151 if (found)
152 return found - elems;
153 else
154 return count;
155 }
156
157 /** \brief Locale-independent integer parser.
158 *
159 * Works similar to strtol. Leading space is NOT skipped. The input
160 * number may have an optional sign. Radix is specified by base. If
161 * base is 0 then decimal is assumed unless the input number is
162 * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
163 * returning tail points to the first character that is not part of
164 * the integer number. If no number was found then tail points to the
165 * start of the input string. */
166 static int strToI (const XML_Char *string, const XML_Char **tail, int base) {
167 int radix = base == 0 ? 10 : base;
168 int result = 0;
169 int sign = 1;
170 bool numberFound = false;
171 const XML_Char *start = string;
172
173 assert (radix >= 2 && radix <= 36);
174
175 if (*string == '-') {
176 sign = -1;
177 string++;
178 } else if (*string == '+')
179 string++;
180 if (base == 0 && *string == '0') {
181 numberFound = true;
182 if (*(string+1) == 'x' || *(string+1) == 'X') {
183 radix = 16;
184 string += 2;
185 } else {
186 radix = 8;
187 string++;
188 }
189 }
190 do {
191 int digit = -1;
192 if (radix <= 10) {
193 if (*string >= '0' && *string < '0' + radix)
194 digit = *string - '0';
195 } else {
196 if (*string >= '0' && *string <= '9')
197 digit = *string - '0';
198 else if (*string >= 'a' && *string < 'a' + radix - 10)
199 digit = *string - 'a' + 10;
200 else if (*string >= 'A' && *string < 'A' + radix - 10)
201 digit = *string - 'A' + 10;
202 }
203 if (digit != -1) {
204 numberFound = true;
205 result = radix*result + digit;
206 string++;
207 } else
208 break;
209 } while (true);
210 *tail = numberFound ? string : start;
211 return sign * result;
212 }
213
214 /** \brief Locale-independent floating-point parser.
215 *
216 * Works similar to strtod. Leading space is NOT skipped. The input
217 * number may have an optional sign. '.' is interpreted as decimal
218 * point and may occur at most once. Optionally the number may end in
219 * [eE]<exponent>, where <exponent> is an integer as recognized by
220 * strToI. In that case the result is number * 10^exponent. After
221 * returning tail points to the first character that is not part of
222 * the floating point number. If no number was found then tail points
223 * to the start of the input string.
224 *
225 * Uses two passes for maximum accuracy. */
226 static float strToF (const XML_Char *string, const XML_Char **tail) {
227 int nDigits = 0, pointPos, exponent;
228 float sign = 1.0f, result = 0.0f, scale;
229 const XML_Char *start = string, *numStart;
230
231 /* sign */
232 if (*string == '-') {
233 sign = -1.0f;
234 string++;
235 } else if (*string == '+')
236 string++;
237
238 /* first pass: determine position of decimal point, number of
239 * digits, exponent and the end of the number. */
240 numStart = string;
241 while (*string >= '0' && *string <= '9') {
242 string++;
243 nDigits++;
244 }
245 pointPos = nDigits;
246 if (*string == '.') {
247 string++;
248 while (*string >= '0' && *string <= '9') {
249 string++;
250 nDigits++;
251 }
252 }
253 if (nDigits == 0) {
254 /* no digits, no number */
255 *tail = start;
256 return 0.0f;
257 }
258 *tail = string;
259 if (*string == 'e' || *string == 'E') {
260 const XML_Char *expTail;
261 exponent = strToI (string+1, &expTail, 10);
262 if (expTail == string+1)
263 exponent = 0;
264 else
265 *tail = expTail;
266 } else
267 exponent = 0;
268 string = numStart;
269
270 /* scale of the first digit */
271 scale = sign * (float)pow (10.0, (double)(pointPos-1 + exponent));
272
273 /* second pass: parse digits */
274 do {
275 if (*string != '.') {
276 assert (*string >= '0' && *string <= '9');
277 result += scale * (float)(*string - '0');
278 scale *= 0.1f;
279 nDigits--;
280 }
281 string++;
282 } while (nDigits > 0);
283
284 return result;
285 }
286
287 /** \brief Parse a value of a given type. */
288 static unsigned char parseValue (driOptionValue *v, driOptionType type,
289 const XML_Char *string) {
290 const XML_Char *tail = NULL;
291 /* skip leading white-space */
292 string += strspn (string, " \f\n\r\t\v");
293 switch (type) {
294 case DRI_BOOL:
295 if (!strcmp (string, "false")) {
296 v->_bool = false;
297 tail = string + 5;
298 } else if (!strcmp (string, "true")) {
299 v->_bool = true;
300 tail = string + 4;
301 }
302 else
303 return false;
304 break;
305 case DRI_ENUM: /* enum is just a special integer */
306 case DRI_INT:
307 v->_int = strToI (string, &tail, 0);
308 break;
309 case DRI_FLOAT:
310 v->_float = strToF (string, &tail);
311 break;
312 case DRI_STRING:
313 if (v->_string)
314 free (v->_string);
315 v->_string = strndup(string, STRING_CONF_MAXLEN);
316 return GL_TRUE;
317 }
318
319 if (tail == string)
320 return false; /* empty string (or containing only white-space) */
321 /* skip trailing white space */
322 if (*tail)
323 tail += strspn (tail, " \f\n\r\t\v");
324 if (*tail)
325 return false; /* something left over that is not part of value */
326
327 return true;
328 }
329
330 /** \brief Parse a list of ranges of type info->type. */
331 static unsigned char parseRanges (driOptionInfo *info, const XML_Char *string) {
332 XML_Char *cp, *range;
333 uint32_t nRanges, i;
334 driOptionRange *ranges;
335
336 XSTRDUP (cp, string);
337 /* pass 1: determine the number of ranges (number of commas + 1) */
338 range = cp;
339 for (nRanges = 1; *range; ++range)
340 if (*range == ',')
341 ++nRanges;
342
343 if ((ranges = malloc(nRanges*sizeof(driOptionRange))) == NULL) {
344 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
345 abort();
346 }
347
348 /* pass 2: parse all ranges into preallocated array */
349 range = cp;
350 for (i = 0; i < nRanges; ++i) {
351 XML_Char *end, *sep;
352 assert (range);
353 end = strchr (range, ',');
354 if (end)
355 *end = '\0';
356 sep = strchr (range, ':');
357 if (sep) { /* non-empty interval */
358 *sep = '\0';
359 if (!parseValue (&ranges[i].start, info->type, range) ||
360 !parseValue (&ranges[i].end, info->type, sep+1))
361 break;
362 if (info->type == DRI_INT &&
363 ranges[i].start._int > ranges[i].end._int)
364 break;
365 if (info->type == DRI_FLOAT &&
366 ranges[i].start._float > ranges[i].end._float)
367 break;
368 } else { /* empty interval */
369 if (!parseValue (&ranges[i].start, info->type, range))
370 break;
371 ranges[i].end = ranges[i].start;
372 }
373 if (end)
374 range = end+1;
375 else
376 range = NULL;
377 }
378 free(cp);
379 if (i < nRanges) {
380 free(ranges);
381 return false;
382 } else
383 assert (range == NULL);
384
385 info->nRanges = nRanges;
386 info->ranges = ranges;
387 return true;
388 }
389
390 /** \brief Check if a value is in one of info->ranges. */
391 static bool checkValue (const driOptionValue *v, const driOptionInfo *info) {
392 uint32_t i;
393 assert (info->type != DRI_BOOL); /* should be caught by the parser */
394 if (info->nRanges == 0)
395 return true;
396 switch (info->type) {
397 case DRI_ENUM: /* enum is just a special integer */
398 case DRI_INT:
399 for (i = 0; i < info->nRanges; ++i)
400 if (v->_int >= info->ranges[i].start._int &&
401 v->_int <= info->ranges[i].end._int)
402 return true;
403 break;
404 case DRI_FLOAT:
405 for (i = 0; i < info->nRanges; ++i)
406 if (v->_float >= info->ranges[i].start._float &&
407 v->_float <= info->ranges[i].end._float)
408 return true;
409 break;
410 case DRI_STRING:
411 break;
412 default:
413 assert (0); /* should never happen */
414 }
415 return false;
416 }
417
418 /**
419 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
420 * is set.
421 *
422 * Is called from the drivers.
423 *
424 * \param f \c printf like format string.
425 */
426 static void
427 __driUtilMessage(const char *f, ...)
428 {
429 va_list args;
430
431 if (getenv("LIBGL_DEBUG")) {
432 fprintf(stderr, "libGL: ");
433 va_start(args, f);
434 vfprintf(stderr, f, args);
435 va_end(args);
436 fprintf(stderr, "\n");
437 }
438 }
439
440 /** \brief Output a warning message. */
441 #define XML_WARNING1(msg) do {\
442 __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
443 (int) XML_GetCurrentLineNumber(data->parser), \
444 (int) XML_GetCurrentColumnNumber(data->parser)); \
445 } while (0)
446 #define XML_WARNING(msg,args...) do { \
447 __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
448 (int) XML_GetCurrentLineNumber(data->parser), \
449 (int) XML_GetCurrentColumnNumber(data->parser), \
450 args); \
451 } while (0)
452 /** \brief Output an error message. */
453 #define XML_ERROR1(msg) do { \
454 __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
455 (int) XML_GetCurrentLineNumber(data->parser), \
456 (int) XML_GetCurrentColumnNumber(data->parser)); \
457 } while (0)
458 #define XML_ERROR(msg,args...) do { \
459 __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
460 (int) XML_GetCurrentLineNumber(data->parser), \
461 (int) XML_GetCurrentColumnNumber(data->parser), \
462 args); \
463 } while (0)
464 /** \brief Output a fatal error message and abort. */
465 #define XML_FATAL1(msg) do { \
466 fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
467 data->name, \
468 (int) XML_GetCurrentLineNumber(data->parser), \
469 (int) XML_GetCurrentColumnNumber(data->parser)); \
470 abort();\
471 } while (0)
472 #define XML_FATAL(msg,args...) do { \
473 fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
474 data->name, \
475 (int) XML_GetCurrentLineNumber(data->parser), \
476 (int) XML_GetCurrentColumnNumber(data->parser), \
477 args); \
478 abort();\
479 } while (0)
480
481 /** \brief Parser context for __driConfigOptions. */
482 struct OptInfoData {
483 const char *name;
484 XML_Parser parser;
485 driOptionCache *cache;
486 bool inDriInfo;
487 bool inSection;
488 bool inDesc;
489 bool inOption;
490 bool inEnum;
491 int curOption;
492 };
493
494 /** \brief Elements in __driConfigOptions. */
495 enum OptInfoElem {
496 OI_DESCRIPTION = 0, OI_DRIINFO, OI_ENUM, OI_OPTION, OI_SECTION, OI_COUNT
497 };
498 static const XML_Char *OptInfoElems[] = {
499 "description", "driinfo", "enum", "option", "section"
500 };
501
502 /** \brief Parse attributes of an enum element.
503 *
504 * We're not actually interested in the data. Just make sure this is ok
505 * for external configuration tools.
506 */
507 static void parseEnumAttr (struct OptInfoData *data, const XML_Char **attr) {
508 uint32_t i;
509 const XML_Char *value = NULL, *text = NULL;
510 driOptionValue v;
511 uint32_t opt = data->curOption;
512 for (i = 0; attr[i]; i += 2) {
513 if (!strcmp (attr[i], "value")) value = attr[i+1];
514 else if (!strcmp (attr[i], "text")) text = attr[i+1];
515 else XML_FATAL("illegal enum attribute: %s.", attr[i]);
516 }
517 if (!value) XML_FATAL1 ("value attribute missing in enum.");
518 if (!text) XML_FATAL1 ("text attribute missing in enum.");
519 if (!parseValue (&v, data->cache->info[opt].type, value))
520 XML_FATAL ("illegal enum value: %s.", value);
521 if (!checkValue (&v, &data->cache->info[opt]))
522 XML_FATAL ("enum value out of valid range: %s.", value);
523 }
524
525 /** \brief Parse attributes of a description element.
526 *
527 * We're not actually interested in the data. Just make sure this is ok
528 * for external configuration tools.
529 */
530 static void parseDescAttr (struct OptInfoData *data, const XML_Char **attr) {
531 uint32_t i;
532 const XML_Char *lang = NULL, *text = NULL;
533 for (i = 0; attr[i]; i += 2) {
534 if (!strcmp (attr[i], "lang")) lang = attr[i+1];
535 else if (!strcmp (attr[i], "text")) text = attr[i+1];
536 else XML_FATAL("illegal description attribute: %s.", attr[i]);
537 }
538 if (!lang) XML_FATAL1 ("lang attribute missing in description.");
539 if (!text) XML_FATAL1 ("text attribute missing in description.");
540 }
541
542 /** \brief Parse attributes of an option element. */
543 static void parseOptInfoAttr (struct OptInfoData *data, const XML_Char **attr) {
544 enum OptAttr {OA_DEFAULT = 0, OA_NAME, OA_TYPE, OA_VALID, OA_COUNT};
545 static const XML_Char *optAttr[] = {"default", "name", "type", "valid"};
546 const XML_Char *attrVal[OA_COUNT] = {NULL, NULL, NULL, NULL};
547 const char *defaultVal;
548 driOptionCache *cache = data->cache;
549 uint32_t opt, i;
550 for (i = 0; attr[i]; i += 2) {
551 uint32_t attrName = bsearchStr (attr[i], optAttr, OA_COUNT);
552 if (attrName >= OA_COUNT)
553 XML_FATAL ("illegal option attribute: %s", attr[i]);
554 attrVal[attrName] = attr[i+1];
555 }
556 if (!attrVal[OA_NAME]) XML_FATAL1 ("name attribute missing in option.");
557 if (!attrVal[OA_TYPE]) XML_FATAL1 ("type attribute missing in option.");
558 if (!attrVal[OA_DEFAULT]) XML_FATAL1 ("default attribute missing in option.");
559
560 opt = findOption (cache, attrVal[OA_NAME]);
561 if (cache->info[opt].name)
562 XML_FATAL ("option %s redefined.", attrVal[OA_NAME]);
563 data->curOption = opt;
564
565 XSTRDUP (cache->info[opt].name, attrVal[OA_NAME]);
566
567 if (!strcmp (attrVal[OA_TYPE], "bool"))
568 cache->info[opt].type = DRI_BOOL;
569 else if (!strcmp (attrVal[OA_TYPE], "enum"))
570 cache->info[opt].type = DRI_ENUM;
571 else if (!strcmp (attrVal[OA_TYPE], "int"))
572 cache->info[opt].type = DRI_INT;
573 else if (!strcmp (attrVal[OA_TYPE], "float"))
574 cache->info[opt].type = DRI_FLOAT;
575 else if (!strcmp (attrVal[OA_TYPE], "string"))
576 cache->info[opt].type = DRI_STRING;
577 else
578 XML_FATAL ("illegal type in option: %s.", attrVal[OA_TYPE]);
579
580 defaultVal = getenv (cache->info[opt].name);
581 if (defaultVal != NULL) {
582 /* don't use XML_WARNING, we want the user to see this! */
583 fprintf (stderr,
584 "ATTENTION: default value of option %s overridden by environment.\n",
585 cache->info[opt].name);
586 } else
587 defaultVal = attrVal[OA_DEFAULT];
588 if (!parseValue (&cache->values[opt], cache->info[opt].type, defaultVal))
589 XML_FATAL ("illegal default value for %s: %s.", cache->info[opt].name, defaultVal);
590
591 if (attrVal[OA_VALID]) {
592 if (cache->info[opt].type == DRI_BOOL)
593 XML_FATAL1 ("boolean option with valid attribute.");
594 if (!parseRanges (&cache->info[opt], attrVal[OA_VALID]))
595 XML_FATAL ("illegal valid attribute: %s.", attrVal[OA_VALID]);
596 if (!checkValue (&cache->values[opt], &cache->info[opt]))
597 XML_FATAL ("default value out of valid range '%s': %s.",
598 attrVal[OA_VALID], defaultVal);
599 } else if (cache->info[opt].type == DRI_ENUM) {
600 XML_FATAL1 ("valid attribute missing in option (mandatory for enums).");
601 } else {
602 cache->info[opt].nRanges = 0;
603 cache->info[opt].ranges = NULL;
604 }
605 }
606
607 /** \brief Handler for start element events. */
608 static void optInfoStartElem (void *userData, const XML_Char *name,
609 const XML_Char **attr) {
610 struct OptInfoData *data = (struct OptInfoData *)userData;
611 enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
612 switch (elem) {
613 case OI_DRIINFO:
614 if (data->inDriInfo)
615 XML_FATAL1 ("nested <driinfo> elements.");
616 if (attr[0])
617 XML_FATAL1 ("attributes specified on <driinfo> element.");
618 data->inDriInfo = true;
619 break;
620 case OI_SECTION:
621 if (!data->inDriInfo)
622 XML_FATAL1 ("<section> must be inside <driinfo>.");
623 if (data->inSection)
624 XML_FATAL1 ("nested <section> elements.");
625 if (attr[0])
626 XML_FATAL1 ("attributes specified on <section> element.");
627 data->inSection = true;
628 break;
629 case OI_DESCRIPTION:
630 if (!data->inSection && !data->inOption)
631 XML_FATAL1 ("<description> must be inside <description> or <option.");
632 if (data->inDesc)
633 XML_FATAL1 ("nested <description> elements.");
634 data->inDesc = true;
635 parseDescAttr (data, attr);
636 break;
637 case OI_OPTION:
638 if (!data->inSection)
639 XML_FATAL1 ("<option> must be inside <section>.");
640 if (data->inDesc)
641 XML_FATAL1 ("<option> nested in <description> element.");
642 if (data->inOption)
643 XML_FATAL1 ("nested <option> elements.");
644 data->inOption = true;
645 parseOptInfoAttr (data, attr);
646 break;
647 case OI_ENUM:
648 if (!(data->inOption && data->inDesc))
649 XML_FATAL1 ("<enum> must be inside <option> and <description>.");
650 if (data->inEnum)
651 XML_FATAL1 ("nested <enum> elements.");
652 data->inEnum = true;
653 parseEnumAttr (data, attr);
654 break;
655 default:
656 XML_FATAL ("unknown element: %s.", name);
657 }
658 }
659
660 /** \brief Handler for end element events. */
661 static void optInfoEndElem (void *userData, const XML_Char *name) {
662 struct OptInfoData *data = (struct OptInfoData *)userData;
663 enum OptInfoElem elem = bsearchStr (name, OptInfoElems, OI_COUNT);
664 switch (elem) {
665 case OI_DRIINFO:
666 data->inDriInfo = false;
667 break;
668 case OI_SECTION:
669 data->inSection = false;
670 break;
671 case OI_DESCRIPTION:
672 data->inDesc = false;
673 break;
674 case OI_OPTION:
675 data->inOption = false;
676 break;
677 case OI_ENUM:
678 data->inEnum = false;
679 break;
680 default:
681 assert (0); /* should have been caught by StartElem */
682 }
683 }
684
685 void driParseOptionInfo (driOptionCache *info, const char *configOptions) {
686 XML_Parser p;
687 int status;
688 struct OptInfoData userData;
689 struct OptInfoData *data = &userData;
690
691 /* Make the hash table big enough to fit more than the maximum number of
692 * config options we've ever seen in a driver.
693 */
694 info->tableSize = 6;
695 info->info = calloc(1 << info->tableSize, sizeof (driOptionInfo));
696 info->values = calloc(1 << info->tableSize, sizeof (driOptionValue));
697 if (info->info == NULL || info->values == NULL) {
698 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
699 abort();
700 }
701
702 p = XML_ParserCreate ("UTF-8"); /* always UTF-8 */
703 XML_SetElementHandler (p, optInfoStartElem, optInfoEndElem);
704 XML_SetUserData (p, data);
705
706 userData.name = "__driConfigOptions";
707 userData.parser = p;
708 userData.cache = info;
709 userData.inDriInfo = false;
710 userData.inSection = false;
711 userData.inDesc = false;
712 userData.inOption = false;
713 userData.inEnum = false;
714 userData.curOption = -1;
715
716 status = XML_Parse (p, configOptions, strlen (configOptions), 1);
717 if (!status)
718 XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
719
720 XML_ParserFree (p);
721 }
722
723 /** \brief Parser context for configuration files. */
724 struct OptConfData {
725 const char *name;
726 XML_Parser parser;
727 driOptionCache *cache;
728 int screenNum;
729 const char *driverName, *execName;
730 uint32_t ignoringDevice;
731 uint32_t ignoringApp;
732 uint32_t inDriConf;
733 uint32_t inDevice;
734 uint32_t inApp;
735 uint32_t inOption;
736 };
737
738 /** \brief Elements in configuration files. */
739 enum OptConfElem {
740 OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_OPTION, OC_COUNT
741 };
742 static const XML_Char *OptConfElems[] = {
743 "application", "device", "driconf", "option"
744 };
745
746 /** \brief Parse attributes of a device element. */
747 static void parseDeviceAttr (struct OptConfData *data, const XML_Char **attr) {
748 uint32_t i;
749 const XML_Char *driver = NULL, *screen = NULL;
750 for (i = 0; attr[i]; i += 2) {
751 if (!strcmp (attr[i], "driver")) driver = attr[i+1];
752 else if (!strcmp (attr[i], "screen")) screen = attr[i+1];
753 else XML_WARNING("unknown device attribute: %s.", attr[i]);
754 }
755 if (driver && strcmp (driver, data->driverName))
756 data->ignoringDevice = data->inDevice;
757 else if (screen) {
758 driOptionValue screenNum;
759 if (!parseValue (&screenNum, DRI_INT, screen))
760 XML_WARNING("illegal screen number: %s.", screen);
761 else if (screenNum._int != data->screenNum)
762 data->ignoringDevice = data->inDevice;
763 }
764 }
765
766 /** \brief Parse attributes of an application element. */
767 static void parseAppAttr (struct OptConfData *data, const XML_Char **attr) {
768 uint32_t i;
769 const XML_Char *exec = NULL;
770 for (i = 0; attr[i]; i += 2) {
771 if (!strcmp (attr[i], "name")) /* not needed here */;
772 else if (!strcmp (attr[i], "executable")) exec = attr[i+1];
773 else XML_WARNING("unknown application attribute: %s.", attr[i]);
774 }
775 if (exec && strcmp (exec, data->execName))
776 data->ignoringApp = data->inApp;
777 }
778
779 /** \brief Parse attributes of an option element. */
780 static void parseOptConfAttr (struct OptConfData *data, const XML_Char **attr) {
781 uint32_t i;
782 const XML_Char *name = NULL, *value = NULL;
783 for (i = 0; attr[i]; i += 2) {
784 if (!strcmp (attr[i], "name")) name = attr[i+1];
785 else if (!strcmp (attr[i], "value")) value = attr[i+1];
786 else XML_WARNING("unknown option attribute: %s.", attr[i]);
787 }
788 if (!name) XML_WARNING1 ("name attribute missing in option.");
789 if (!value) XML_WARNING1 ("value attribute missing in option.");
790 if (name && value) {
791 driOptionCache *cache = data->cache;
792 uint32_t opt = findOption (cache, name);
793 if (cache->info[opt].name == NULL)
794 /* don't use XML_WARNING, drirc defines options for all drivers,
795 * but not all drivers support them */
796 return;
797 else if (getenv (cache->info[opt].name))
798 /* don't use XML_WARNING, we want the user to see this! */
799 fprintf (stderr, "ATTENTION: option value of option %s ignored.\n",
800 cache->info[opt].name);
801 else if (!parseValue (&cache->values[opt], cache->info[opt].type, value))
802 XML_WARNING ("illegal option value: %s.", value);
803 }
804 }
805
806 /** \brief Handler for start element events. */
807 static void optConfStartElem (void *userData, const XML_Char *name,
808 const XML_Char **attr) {
809 struct OptConfData *data = (struct OptConfData *)userData;
810 enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
811 switch (elem) {
812 case OC_DRICONF:
813 if (data->inDriConf)
814 XML_WARNING1 ("nested <driconf> elements.");
815 if (attr[0])
816 XML_WARNING1 ("attributes specified on <driconf> element.");
817 data->inDriConf++;
818 break;
819 case OC_DEVICE:
820 if (!data->inDriConf)
821 XML_WARNING1 ("<device> should be inside <driconf>.");
822 if (data->inDevice)
823 XML_WARNING1 ("nested <device> elements.");
824 data->inDevice++;
825 if (!data->ignoringDevice && !data->ignoringApp)
826 parseDeviceAttr (data, attr);
827 break;
828 case OC_APPLICATION:
829 if (!data->inDevice)
830 XML_WARNING1 ("<application> should be inside <device>.");
831 if (data->inApp)
832 XML_WARNING1 ("nested <application> elements.");
833 data->inApp++;
834 if (!data->ignoringDevice && !data->ignoringApp)
835 parseAppAttr (data, attr);
836 break;
837 case OC_OPTION:
838 if (!data->inApp)
839 XML_WARNING1 ("<option> should be inside <application>.");
840 if (data->inOption)
841 XML_WARNING1 ("nested <option> elements.");
842 data->inOption++;
843 if (!data->ignoringDevice && !data->ignoringApp)
844 parseOptConfAttr (data, attr);
845 break;
846 default:
847 XML_WARNING ("unknown element: %s.", name);
848 }
849 }
850
851 /** \brief Handler for end element events. */
852 static void optConfEndElem (void *userData, const XML_Char *name) {
853 struct OptConfData *data = (struct OptConfData *)userData;
854 enum OptConfElem elem = bsearchStr (name, OptConfElems, OC_COUNT);
855 switch (elem) {
856 case OC_DRICONF:
857 data->inDriConf--;
858 break;
859 case OC_DEVICE:
860 if (data->inDevice-- == data->ignoringDevice)
861 data->ignoringDevice = 0;
862 break;
863 case OC_APPLICATION:
864 if (data->inApp-- == data->ignoringApp)
865 data->ignoringApp = 0;
866 break;
867 case OC_OPTION:
868 data->inOption--;
869 break;
870 default:
871 /* unknown element, warning was produced on start tag */;
872 }
873 }
874
875 /** \brief Initialize an option cache based on info */
876 static void initOptionCache (driOptionCache *cache, const driOptionCache *info) {
877 GLuint i, size = 1 << info->tableSize;
878 cache->info = info->info;
879 cache->tableSize = info->tableSize;
880 cache->values = malloc((1<<info->tableSize) * sizeof (driOptionValue));
881 if (cache->values == NULL) {
882 fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
883 abort();
884 }
885 memcpy (cache->values, info->values,
886 (1<<info->tableSize) * sizeof (driOptionValue));
887 for (i = 0; i < size; ++i) {
888 if (cache->info[i].type == DRI_STRING)
889 XSTRDUP(cache->values[i]._string, info->values[i]._string);
890 }
891 }
892
893 /** \brief Parse the named configuration file */
894 static void parseOneConfigFile (XML_Parser p) {
895 #define BUF_SIZE 0x1000
896 struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p);
897 int status;
898 int fd;
899
900 if ((fd = open (data->name, O_RDONLY)) == -1) {
901 __driUtilMessage ("Can't open configuration file %s: %s.",
902 data->name, strerror (errno));
903 return;
904 }
905
906 while (1) {
907 int bytesRead;
908 void *buffer = XML_GetBuffer (p, BUF_SIZE);
909 if (!buffer) {
910 __driUtilMessage ("Can't allocate parser buffer.");
911 break;
912 }
913 bytesRead = read (fd, buffer, BUF_SIZE);
914 if (bytesRead == -1) {
915 __driUtilMessage ("Error reading from configuration file %s: %s.",
916 data->name, strerror (errno));
917 break;
918 }
919 status = XML_ParseBuffer (p, bytesRead, bytesRead == 0);
920 if (!status) {
921 XML_ERROR ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
922 break;
923 }
924 if (bytesRead == 0)
925 break;
926 }
927
928 close (fd);
929 #undef BUF_SIZE
930 }
931
932 void driParseConfigFiles (driOptionCache *cache, const driOptionCache *info,
933 int screenNum, const char *driverName) {
934 char *filenames[2] = {"/etc/drirc", NULL};
935 char *home;
936 uint32_t i;
937 struct OptConfData userData;
938
939 initOptionCache (cache, info);
940
941 userData.cache = cache;
942 userData.screenNum = screenNum;
943 userData.driverName = driverName;
944 userData.execName = GET_PROGRAM_NAME();
945
946 if ((home = getenv ("HOME"))) {
947 uint32_t len = strlen (home);
948 filenames[1] = malloc(len + 7+1);
949 if (filenames[1] == NULL)
950 __driUtilMessage ("Can't allocate memory for %s/.drirc.", home);
951 else {
952 memcpy (filenames[1], home, len);
953 memcpy (filenames[1] + len, "/.drirc", 7+1);
954 }
955 }
956
957 for (i = 0; i < 2; ++i) {
958 XML_Parser p;
959 if (filenames[i] == NULL)
960 continue;
961
962 p = XML_ParserCreate (NULL); /* use encoding specified by file */
963 XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
964 XML_SetUserData (p, &userData);
965 userData.parser = p;
966 userData.name = filenames[i];
967 userData.ignoringDevice = 0;
968 userData.ignoringApp = 0;
969 userData.inDriConf = 0;
970 userData.inDevice = 0;
971 userData.inApp = 0;
972 userData.inOption = 0;
973
974 parseOneConfigFile (p);
975 XML_ParserFree (p);
976 }
977
978 free(filenames[1]);
979 }
980
981 void driDestroyOptionInfo (driOptionCache *info) {
982 driDestroyOptionCache (info);
983 if (info->info) {
984 uint32_t i, size = 1 << info->tableSize;
985 for (i = 0; i < size; ++i) {
986 if (info->info[i].name) {
987 free(info->info[i].name);
988 free(info->info[i].ranges);
989 }
990 }
991 free(info->info);
992 }
993 }
994
995 void driDestroyOptionCache (driOptionCache *cache) {
996 if (cache->info) {
997 GLuint i, size = 1 << cache->tableSize;
998 for (i = 0; i < size; ++i) {
999 if (cache->info[i].type == DRI_STRING)
1000 free(cache->values[i]._string);
1001 }
1002 }
1003 free(cache->values);
1004 }
1005
1006 unsigned char driCheckOption (const driOptionCache *cache, const char *name,
1007 driOptionType type) {
1008 uint32_t i = findOption (cache, name);
1009 return cache->info[i].name != NULL && cache->info[i].type == type;
1010 }
1011
1012 unsigned char driQueryOptionb (const driOptionCache *cache, const char *name) {
1013 uint32_t i = findOption (cache, name);
1014 /* make sure the option is defined and has the correct type */
1015 assert (cache->info[i].name != NULL);
1016 assert (cache->info[i].type == DRI_BOOL);
1017 return cache->values[i]._bool;
1018 }
1019
1020 int driQueryOptioni (const driOptionCache *cache, const char *name) {
1021 uint32_t i = findOption (cache, name);
1022 /* make sure the option is defined and has the correct type */
1023 assert (cache->info[i].name != NULL);
1024 assert (cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM);
1025 return cache->values[i]._int;
1026 }
1027
1028 float driQueryOptionf (const driOptionCache *cache, const char *name) {
1029 uint32_t i = findOption (cache, name);
1030 /* make sure the option is defined and has the correct type */
1031 assert (cache->info[i].name != NULL);
1032 assert (cache->info[i].type == DRI_FLOAT);
1033 return cache->values[i]._float;
1034 }
1035
1036 char *driQueryOptionstr (const driOptionCache *cache, const char *name) {
1037 GLuint i = findOption (cache, name);
1038 /* make sure the option is defined and has the correct type */
1039 assert (cache->info[i].name != NULL);
1040 assert (cache->info[i].type == DRI_STRING);
1041 return cache->values[i]._string;
1042 }