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