~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/util/xmlconfig.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 "xmlconfig.h"
31
 
#include <limits.h>
32
 
#include <stdarg.h>
33
 
#include <stdbool.h>
34
 
#include <stdint.h>
35
 
#include <stdio.h>
36
 
#include <stdlib.h>
37
 
#include <string.h>
38
 
#include <assert.h>
39
 
#if WITH_XMLCONFIG
40
 
#include <expat.h>
41
 
#include <unistd.h>
42
 
#include <errno.h>
43
 
#include <dirent.h>
44
 
#include <sys/stat.h>
45
 
#endif
46
 
#ifdef NO_REGEX
47
 
typedef int regex_t;
48
 
#define REG_EXTENDED 0
49
 
#define REG_NOSUB 0
50
 
#define REG_NOMATCH 1
51
 
static inline int regcomp(regex_t *r, const char *s, int f) { return 0; }
52
 
static inline int regexec(regex_t *r, const char *s, int n, void *p, int f) { return REG_NOMATCH; }
53
 
static inline void regfree(regex_t* r) {}
54
 
#else
55
 
#include <regex.h>
56
 
#endif
57
 
#include <fcntl.h>
58
 
#include <math.h>
59
 
#include "strndup.h"
60
 
#include "u_process.h"
61
 
#include "os_file.h"
62
 
 
63
 
/* For systems like Hurd */
64
 
#ifndef PATH_MAX
65
 
#define PATH_MAX 4096
66
 
#endif
67
 
 
68
 
static bool
69
 
be_verbose(void)
70
 
{
71
 
   const char *s = getenv("MESA_DEBUG");
72
 
   if (!s)
73
 
      return true;
74
 
 
75
 
   return strstr(s, "silent") == NULL;
76
 
}
77
 
 
78
 
/** \brief Locale-independent integer parser.
79
 
 *
80
 
 * Works similar to strtol. Leading space is NOT skipped. The input
81
 
 * number may have an optional sign. Radix is specified by base. If
82
 
 * base is 0 then decimal is assumed unless the input number is
83
 
 * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
84
 
 * returning tail points to the first character that is not part of
85
 
 * the integer number. If no number was found then tail points to the
86
 
 * start of the input string. */
87
 
static int
88
 
strToI(const char *string, const char **tail, int base)
89
 
{
90
 
   int radix = base == 0 ? 10 : base;
91
 
   int result = 0;
92
 
   int sign = 1;
93
 
   bool numberFound = false;
94
 
   const char *start = string;
95
 
 
96
 
   assert(radix >= 2 && radix <= 36);
97
 
 
98
 
   if (*string == '-') {
99
 
      sign = -1;
100
 
      string++;
101
 
   } else if (*string == '+')
102
 
      string++;
103
 
   if (base == 0 && *string == '0') {
104
 
      numberFound = true;
105
 
      if (*(string+1) == 'x' || *(string+1) == 'X') {
106
 
         radix = 16;
107
 
         string += 2;
108
 
      } else {
109
 
         radix = 8;
110
 
         string++;
111
 
      }
112
 
   }
113
 
   do {
114
 
      int digit = -1;
115
 
      if (radix <= 10) {
116
 
         if (*string >= '0' && *string < '0' + radix)
117
 
            digit = *string - '0';
118
 
      } else {
119
 
         if (*string >= '0' && *string <= '9')
120
 
            digit = *string - '0';
121
 
         else if (*string >= 'a' && *string < 'a' + radix - 10)
122
 
            digit = *string - 'a' + 10;
123
 
         else if (*string >= 'A' && *string < 'A' + radix - 10)
124
 
            digit = *string - 'A' + 10;
125
 
      }
126
 
      if (digit != -1) {
127
 
         numberFound = true;
128
 
         result = radix*result + digit;
129
 
         string++;
130
 
      } else
131
 
         break;
132
 
   } while (true);
133
 
   *tail = numberFound ? string : start;
134
 
   return sign * result;
135
 
}
136
 
 
137
 
/** \brief Locale-independent floating-point parser.
138
 
 *
139
 
 * Works similar to strtod. Leading space is NOT skipped. The input
140
 
 * number may have an optional sign. '.' is interpreted as decimal
141
 
 * point and may occur at most once. Optionally the number may end in
142
 
 * [eE]<exponent>, where <exponent> is an integer as recognized by
143
 
 * strToI. In that case the result is number * 10^exponent. After
144
 
 * returning tail points to the first character that is not part of
145
 
 * the floating point number. If no number was found then tail points
146
 
 * to the start of the input string.
147
 
 *
148
 
 * Uses two passes for maximum accuracy. */
149
 
static float
150
 
strToF(const char *string, const char **tail)
151
 
{
152
 
   int nDigits = 0, pointPos, exponent;
153
 
   float sign = 1.0f, result = 0.0f, scale;
154
 
   const char *start = string, *numStart;
155
 
 
156
 
   /* sign */
157
 
   if (*string == '-') {
158
 
      sign = -1.0f;
159
 
      string++;
160
 
   } else if (*string == '+')
161
 
      string++;
162
 
 
163
 
   /* first pass: determine position of decimal point, number of
164
 
    * digits, exponent and the end of the number. */
165
 
   numStart = string;
166
 
   while (*string >= '0' && *string <= '9') {
167
 
      string++;
168
 
      nDigits++;
169
 
   }
170
 
   pointPos = nDigits;
171
 
   if (*string == '.') {
172
 
      string++;
173
 
      while (*string >= '0' && *string <= '9') {
174
 
         string++;
175
 
         nDigits++;
176
 
      }
177
 
   }
178
 
   if (nDigits == 0) {
179
 
      /* no digits, no number */
180
 
      *tail = start;
181
 
      return 0.0f;
182
 
   }
183
 
   *tail = string;
184
 
   if (*string == 'e' || *string == 'E') {
185
 
      const char *expTail;
186
 
      exponent = strToI(string+1, &expTail, 10);
187
 
      if (expTail == string+1)
188
 
         exponent = 0;
189
 
      else
190
 
         *tail = expTail;
191
 
   } else
192
 
      exponent = 0;
193
 
   string = numStart;
194
 
 
195
 
   /* scale of the first digit */
196
 
   scale = sign * (float)pow(10.0, (double)(pointPos-1 + exponent));
197
 
 
198
 
   /* second pass: parse digits */
199
 
   do {
200
 
      if (*string != '.') {
201
 
         assert(*string >= '0' && *string <= '9');
202
 
         result += scale * (float)(*string - '0');
203
 
         scale *= 0.1f;
204
 
         nDigits--;
205
 
      }
206
 
      string++;
207
 
   } while (nDigits > 0);
208
 
 
209
 
   return result;
210
 
}
211
 
 
212
 
/** \brief Parse a value of a given type. */
213
 
static unsigned char
214
 
parseValue(driOptionValue *v, driOptionType type, const char *string)
215
 
{
216
 
   const char *tail = NULL;
217
 
   /* skip leading white-space */
218
 
   string += strspn(string, " \f\n\r\t\v");
219
 
   switch (type) {
220
 
   case DRI_BOOL:
221
 
      if (!strcmp(string, "false")) {
222
 
         v->_bool = false;
223
 
         tail = string + 5;
224
 
      } else if (!strcmp(string, "true")) {
225
 
         v->_bool = true;
226
 
         tail = string + 4;
227
 
      }
228
 
      else
229
 
         return false;
230
 
      break;
231
 
   case DRI_ENUM: /* enum is just a special integer */
232
 
   case DRI_INT:
233
 
      v->_int = strToI(string, &tail, 0);
234
 
      break;
235
 
   case DRI_FLOAT:
236
 
      v->_float = strToF(string, &tail);
237
 
      break;
238
 
   case DRI_STRING:
239
 
      free(v->_string);
240
 
      v->_string = strndup(string, STRING_CONF_MAXLEN);
241
 
      return true;
242
 
   case DRI_SECTION:
243
 
      unreachable("shouldn't be parsing values in section declarations");
244
 
   }
245
 
 
246
 
   if (tail == string)
247
 
      return false; /* empty string (or containing only white-space) */
248
 
   /* skip trailing white space */
249
 
   if (*tail)
250
 
      tail += strspn(tail, " \f\n\r\t\v");
251
 
   if (*tail)
252
 
      return false; /* something left over that is not part of value */
253
 
 
254
 
   return true;
255
 
}
256
 
 
257
 
/** \brief Find an option in an option cache with the name as key */
258
 
static uint32_t
259
 
findOption(const driOptionCache *cache, const char *name)
260
 
{
261
 
   uint32_t len = strlen(name);
262
 
   uint32_t size = 1 << cache->tableSize, mask = size - 1;
263
 
   uint32_t hash = 0;
264
 
   uint32_t i, shift;
265
 
 
266
 
   /* compute a hash from the variable length name */
267
 
   for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
268
 
      hash += (uint32_t)name[i] << shift;
269
 
   hash *= hash;
270
 
   hash = (hash >> (16-cache->tableSize/2)) & mask;
271
 
 
272
 
   /* this is just the starting point of the linear search for the option */
273
 
   for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
274
 
      /* if we hit an empty entry then the option is not defined (yet) */
275
 
      if (cache->info[hash].name == NULL)
276
 
         break;
277
 
      else if (!strcmp(name, cache->info[hash].name))
278
 
         break;
279
 
   }
280
 
   /* this assertion fails if the hash table is full */
281
 
   assert (i < size);
282
 
 
283
 
   return hash;
284
 
}
285
 
 
286
 
/** \brief Like strdup with error checking. */
287
 
#define XSTRDUP(dest,source) do {                                       \
288
 
      if (!(dest = strdup(source))) {                                   \
289
 
         fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
290
 
         abort();                                                       \
291
 
      }                                                                 \
292
 
   } while (0)
293
 
 
294
 
/** \brief Check if a value is in info->range. */
295
 
UNUSED static bool
296
 
checkValue(const driOptionValue *v, const driOptionInfo *info)
297
 
{
298
 
   switch (info->type) {
299
 
   case DRI_ENUM: /* enum is just a special integer */
300
 
   case DRI_INT:
301
 
      return (info->range.start._int == info->range.end._int ||
302
 
              (v->_int >= info->range.start._int &&
303
 
               v->_int <= info->range.end._int));
304
 
 
305
 
   case DRI_FLOAT:
306
 
      return (info->range.start._float == info->range.end._float ||
307
 
              (v->_float >= info->range.start._float &&
308
 
               v->_float <= info->range.end._float));
309
 
 
310
 
   default:
311
 
      return true;
312
 
   }
313
 
}
314
 
 
315
 
void
316
 
driParseOptionInfo(driOptionCache *info,
317
 
                   const driOptionDescription *configOptions,
318
 
                   unsigned numOptions)
319
 
{
320
 
   /* Make the hash table big enough to fit more than the maximum number of
321
 
    * config options we've ever seen in a driver.
322
 
    */
323
 
   info->tableSize = 7;
324
 
   info->info = calloc((size_t)1 << info->tableSize, sizeof(driOptionInfo));
325
 
   info->values = calloc((size_t)1 << info->tableSize, sizeof(driOptionValue));
326
 
   if (info->info == NULL || info->values == NULL) {
327
 
      fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
328
 
      abort();
329
 
   }
330
 
 
331
 
   UNUSED bool in_section = false;
332
 
   for (int o = 0; o < numOptions; o++) {
333
 
      const driOptionDescription *opt = &configOptions[o];
334
 
 
335
 
      if (opt->info.type == DRI_SECTION) {
336
 
         in_section = true;
337
 
         continue;
338
 
      }
339
 
 
340
 
      /* for driconf xml generation, options must always be preceded by a
341
 
       * DRI_CONF_SECTION
342
 
       */
343
 
      assert(in_section);
344
 
 
345
 
      const char *name = opt->info.name;
346
 
      int i = findOption(info, name);
347
 
      driOptionInfo *optinfo = &info->info[i];
348
 
      driOptionValue *optval = &info->values[i];
349
 
 
350
 
      assert(!optinfo->name); /* No duplicate options in your list. */
351
 
 
352
 
      optinfo->type = opt->info.type;
353
 
      optinfo->range = opt->info.range;
354
 
      XSTRDUP(optinfo->name, name);
355
 
 
356
 
      switch (opt->info.type) {
357
 
      case DRI_BOOL:
358
 
         optval->_bool = opt->value._bool;
359
 
         break;
360
 
 
361
 
      case DRI_INT:
362
 
      case DRI_ENUM:
363
 
         optval->_int = opt->value._int;
364
 
         break;
365
 
 
366
 
      case DRI_FLOAT:
367
 
         optval->_float = opt->value._float;
368
 
         break;
369
 
 
370
 
      case DRI_STRING:
371
 
         XSTRDUP(optval->_string, opt->value._string);
372
 
         break;
373
 
 
374
 
      case DRI_SECTION:
375
 
         unreachable("handled above");
376
 
      }
377
 
 
378
 
      /* Built-in default values should always be valid. */
379
 
      assert(checkValue(optval, optinfo));
380
 
 
381
 
      char *envVal = getenv(name);
382
 
      if (envVal != NULL) {
383
 
         driOptionValue v;
384
 
 
385
 
         /* make sure the value is initialized to something sensible */
386
 
         v._string = NULL;
387
 
 
388
 
         if (parseValue(&v, opt->info.type, envVal) &&
389
 
             checkValue(&v, optinfo)) {
390
 
            /* don't use XML_WARNING, we want the user to see this! */
391
 
            if (be_verbose()) {
392
 
               fprintf(stderr,
393
 
                       "ATTENTION: default value of option %s overridden by environment.\n",
394
 
                       name);
395
 
            }
396
 
            *optval = v;
397
 
         } else {
398
 
            fprintf(stderr, "illegal environment value for %s: \"%s\".  Ignoring.\n",
399
 
                    name, envVal);
400
 
         }
401
 
      }
402
 
   }
403
 
}
404
 
 
405
 
char *
406
 
driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
407
 
{
408
 
   char *str = ralloc_strdup(NULL,
409
 
      "<?xml version=\"1.0\" standalone=\"yes\"?>\n" \
410
 
      "<!DOCTYPE driinfo [\n" \
411
 
      "   <!ELEMENT driinfo      (section*)>\n" \
412
 
      "   <!ELEMENT section      (description+, option+)>\n" \
413
 
      "   <!ELEMENT description  (enum*)>\n" \
414
 
      "   <!ATTLIST description  lang CDATA #FIXED \"en\"\n" \
415
 
      "                          text CDATA #REQUIRED>\n" \
416
 
      "   <!ELEMENT option       (description+)>\n" \
417
 
      "   <!ATTLIST option       name CDATA #REQUIRED\n" \
418
 
      "                          type (bool|enum|int|float) #REQUIRED\n" \
419
 
      "                          default CDATA #REQUIRED\n" \
420
 
      "                          valid CDATA #IMPLIED>\n" \
421
 
      "   <!ELEMENT enum         EMPTY>\n" \
422
 
      "   <!ATTLIST enum         value CDATA #REQUIRED\n" \
423
 
      "                          text CDATA #REQUIRED>\n" \
424
 
      "]>" \
425
 
      "<driinfo>\n");
426
 
 
427
 
   bool in_section = false;
428
 
   for (int o = 0; o < numOptions; o++) {
429
 
      const driOptionDescription *opt = &configOptions[o];
430
 
 
431
 
      const char *name = opt->info.name;
432
 
      const char *types[] = {
433
 
         [DRI_BOOL] = "bool",
434
 
         [DRI_INT] = "int",
435
 
         [DRI_FLOAT] = "float",
436
 
         [DRI_ENUM] = "enum",
437
 
         [DRI_STRING] = "string",
438
 
      };
439
 
 
440
 
      if (opt->info.type == DRI_SECTION) {
441
 
         if (in_section)
442
 
            ralloc_asprintf_append(&str, "  </section>\n");
443
 
 
444
 
         ralloc_asprintf_append(&str,
445
 
                                "  <section>\n"
446
 
                                "    <description lang=\"en\" text=\"%s\"/>\n",
447
 
                                opt->desc);
448
 
 
449
 
         in_section = true;
450
 
         continue;
451
 
      }
452
 
 
453
 
      ralloc_asprintf_append(&str,
454
 
                             "      <option name=\"%s\" type=\"%s\" default=\"",
455
 
                             name,
456
 
                             types[opt->info.type]);
457
 
 
458
 
      switch (opt->info.type) {
459
 
      case DRI_BOOL:
460
 
         ralloc_asprintf_append(&str, opt->value._bool ? "true" : "false");
461
 
         break;
462
 
 
463
 
      case DRI_INT:
464
 
      case DRI_ENUM:
465
 
         ralloc_asprintf_append(&str, "%d", opt->value._int);
466
 
         break;
467
 
 
468
 
      case DRI_FLOAT:
469
 
         ralloc_asprintf_append(&str, "%f", opt->value._float);
470
 
         break;
471
 
 
472
 
      case DRI_STRING:
473
 
         ralloc_asprintf_append(&str, "%s", opt->value._string);
474
 
         break;
475
 
 
476
 
      case DRI_SECTION:
477
 
         unreachable("handled above");
478
 
         break;
479
 
      }
480
 
      ralloc_asprintf_append(&str, "\"");
481
 
 
482
 
 
483
 
      switch (opt->info.type) {
484
 
      case DRI_INT:
485
 
      case DRI_ENUM:
486
 
         if (opt->info.range.start._int < opt->info.range.end._int) {
487
 
            ralloc_asprintf_append(&str, " valid=\"%d:%d\"",
488
 
                                   opt->info.range.start._int,
489
 
                                   opt->info.range.end._int);
490
 
         }
491
 
         break;
492
 
 
493
 
      case DRI_FLOAT:
494
 
         if (opt->info.range.start._float < opt->info.range.end._float) {
495
 
            ralloc_asprintf_append(&str, " valid=\"%f:%f\"",
496
 
                                   opt->info.range.start._float,
497
 
                                   opt->info.range.end._float);
498
 
         }
499
 
         break;
500
 
 
501
 
      default:
502
 
         break;
503
 
      }
504
 
 
505
 
      ralloc_asprintf_append(&str, ">\n"); /* end of <option> */
506
 
 
507
 
 
508
 
      ralloc_asprintf_append(&str, "        <description lang=\"en\" text=\"%s\"%s>\n",
509
 
                             opt->desc, opt->info.type != DRI_ENUM ? "/" : "");
510
 
 
511
 
      if (opt->info.type == DRI_ENUM) {
512
 
         for (int i = 0; i < ARRAY_SIZE(opt->enums) && opt->enums[i].desc; i++) {
513
 
            ralloc_asprintf_append(&str, "          <enum value=\"%d\" text=\"%s\"/>\n",
514
 
                                   opt->enums[i].value, opt->enums[i].desc);
515
 
         }
516
 
         ralloc_asprintf_append(&str, "        </description>\n");
517
 
      }
518
 
 
519
 
      ralloc_asprintf_append(&str, "      </option>\n");
520
 
   }
521
 
 
522
 
   assert(in_section);
523
 
   ralloc_asprintf_append(&str, "  </section>\n");
524
 
 
525
 
   ralloc_asprintf_append(&str, "</driinfo>\n");
526
 
 
527
 
   char *output = strdup(str);
528
 
   ralloc_free(str);
529
 
 
530
 
   return output;
531
 
}
532
 
 
533
 
/**
534
 
 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
535
 
 * is set.
536
 
 *
537
 
 * Is called from the drivers.
538
 
 *
539
 
 * \param f \c printf like format string.
540
 
 */
541
 
static void
542
 
__driUtilMessage(const char *f, ...)
543
 
{
544
 
   va_list args;
545
 
   const char *libgl_debug;
546
 
 
547
 
   libgl_debug=getenv("LIBGL_DEBUG");
548
 
   if (libgl_debug && !strstr(libgl_debug, "quiet")) {
549
 
      fprintf(stderr, "libGL: ");
550
 
      va_start(args, f);
551
 
      vfprintf(stderr, f, args);
552
 
      va_end(args);
553
 
      fprintf(stderr, "\n");
554
 
   }
555
 
}
556
 
 
557
 
/* We don't have real line/column # info in static-config case: */
558
 
#if !WITH_XML_CONFIG
559
 
#  define XML_GetCurrentLineNumber(p) -1
560
 
#  define XML_GetCurrentColumnNumber(p) -1
561
 
#endif
562
 
 
563
 
/** \brief Output a warning message. */
564
 
#define XML_WARNING1(msg) do {                                          \
565
 
      __driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
566
 
                        (int) XML_GetCurrentLineNumber(data->parser),   \
567
 
                        (int) XML_GetCurrentColumnNumber(data->parser)); \
568
 
   } while (0)
569
 
#define XML_WARNING(msg, ...) do {                                      \
570
 
      __driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
571
 
                        (int) XML_GetCurrentLineNumber(data->parser),   \
572
 
                        (int) XML_GetCurrentColumnNumber(data->parser), \
573
 
                        ##__VA_ARGS__);                                 \
574
 
   } while (0)
575
 
/** \brief Output an error message. */
576
 
#define XML_ERROR1(msg) do {                                            \
577
 
      __driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
578
 
                        (int) XML_GetCurrentLineNumber(data->parser),   \
579
 
                        (int) XML_GetCurrentColumnNumber(data->parser)); \
580
 
   } while (0)
581
 
#define XML_ERROR(msg, ...) do {                                        \
582
 
      __driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
583
 
                        (int) XML_GetCurrentLineNumber(data->parser),   \
584
 
                        (int) XML_GetCurrentColumnNumber(data->parser), \
585
 
                        ##__VA_ARGS__);                                 \
586
 
   } while (0)
587
 
 
588
 
/** \brief Parser context for configuration files. */
589
 
struct OptConfData {
590
 
   const char *name;
591
 
#if WITH_XMLCONFIG
592
 
   XML_Parser parser;
593
 
#endif
594
 
   driOptionCache *cache;
595
 
   int screenNum;
596
 
   const char *driverName, *execName;
597
 
   const char *kernelDriverName;
598
 
   const char *deviceName;
599
 
   const char *engineName;
600
 
   const char *applicationName;
601
 
   uint32_t engineVersion;
602
 
   uint32_t applicationVersion;
603
 
   uint32_t ignoringDevice;
604
 
   uint32_t ignoringApp;
605
 
   uint32_t inDriConf;
606
 
   uint32_t inDevice;
607
 
   uint32_t inApp;
608
 
   uint32_t inOption;
609
 
};
610
 
 
611
 
/** \brief Parse a list of ranges of type info->type. */
612
 
static unsigned char
613
 
parseRange(driOptionInfo *info, const char *string)
614
 
{
615
 
   char *cp;
616
 
 
617
 
   XSTRDUP(cp, string);
618
 
 
619
 
   char *sep;
620
 
   sep = strchr(cp, ':');
621
 
   if (!sep) {
622
 
      free(cp);
623
 
      return false;
624
 
   }
625
 
 
626
 
   *sep = '\0';
627
 
   if (!parseValue(&info->range.start, info->type, cp) ||
628
 
       !parseValue(&info->range.end, info->type, sep+1)) {
629
 
      free(cp);
630
 
      return false;
631
 
   }
632
 
   if (info->type == DRI_INT &&
633
 
       info->range.start._int >= info->range.end._int) {
634
 
      free(cp);
635
 
      return false;
636
 
   }
637
 
   if (info->type == DRI_FLOAT &&
638
 
       info->range.start._float >= info->range.end._float) {
639
 
      free(cp);
640
 
      return false;
641
 
   }
642
 
 
643
 
   free(cp);
644
 
   return true;
645
 
}
646
 
 
647
 
/** \brief Parse attributes of a device element. */
648
 
static void
649
 
parseDeviceAttr(struct OptConfData *data, const char **attr)
650
 
{
651
 
   uint32_t i;
652
 
   const char *driver = NULL, *screen = NULL, *kernel = NULL, *device = NULL;
653
 
   for (i = 0; attr[i]; i += 2) {
654
 
      if (!strcmp(attr[i], "driver")) driver = attr[i+1];
655
 
      else if (!strcmp(attr[i], "screen")) screen = attr[i+1];
656
 
      else if (!strcmp(attr[i], "kernel_driver")) kernel = attr[i+1];
657
 
      else if (!strcmp(attr[i], "device")) device = attr[i+1];
658
 
      else XML_WARNING("unknown device attribute: %s.", attr[i]);
659
 
   }
660
 
   if (driver && strcmp(driver, data->driverName))
661
 
      data->ignoringDevice = data->inDevice;
662
 
   else if (kernel && (!data->kernelDriverName ||
663
 
                       strcmp(kernel, data->kernelDriverName)))
664
 
      data->ignoringDevice = data->inDevice;
665
 
   else if (device && (!data->deviceName ||
666
 
                       strcmp(device, data->deviceName)))
667
 
      data->ignoringDevice = data->inDevice;
668
 
   else if (screen) {
669
 
      driOptionValue screenNum;
670
 
      if (!parseValue(&screenNum, DRI_INT, screen))
671
 
         XML_WARNING("illegal screen number: %s.", screen);
672
 
      else if (screenNum._int != data->screenNum)
673
 
         data->ignoringDevice = data->inDevice;
674
 
   }
675
 
}
676
 
 
677
 
/** \brief Parse attributes of an application element. */
678
 
static void
679
 
parseAppAttr(struct OptConfData *data, const char **attr)
680
 
{
681
 
   uint32_t i;
682
 
   const char *exec = NULL;
683
 
   const char *sha1 = NULL;
684
 
   const char *exec_regexp = NULL;
685
 
   const char *application_name_match = NULL;
686
 
   const char *application_versions = NULL;
687
 
   driOptionInfo version_range = {
688
 
      .type = DRI_INT,
689
 
   };
690
 
 
691
 
   for (i = 0; attr[i]; i += 2) {
692
 
      if (!strcmp(attr[i], "name")) /* not needed here */;
693
 
      else if (!strcmp(attr[i], "executable")) exec = attr[i+1];
694
 
      else if (!strcmp(attr[i], "executable_regexp")) exec_regexp = attr[i+1];
695
 
      else if (!strcmp(attr[i], "sha1")) sha1 = attr[i+1];
696
 
      else if (!strcmp(attr[i], "application_name_match"))
697
 
         application_name_match = attr[i+1];
698
 
      else if (!strcmp(attr[i], "application_versions"))
699
 
         application_versions = attr[i+1];
700
 
      else XML_WARNING("unknown application attribute: %s.", attr[i]);
701
 
   }
702
 
   if (exec && strcmp(exec, data->execName)) {
703
 
      data->ignoringApp = data->inApp;
704
 
   } else if (exec_regexp) {
705
 
      regex_t re;
706
 
 
707
 
      if (regcomp(&re, exec_regexp, REG_EXTENDED|REG_NOSUB) == 0) {
708
 
         if (regexec(&re, data->execName, 0, NULL, 0) == REG_NOMATCH)
709
 
            data->ignoringApp = data->inApp;
710
 
         regfree(&re);
711
 
      } else
712
 
         XML_WARNING("Invalid executable_regexp=\"%s\".", exec_regexp);
713
 
   } else if (sha1) {
714
 
      /* SHA1_DIGEST_STRING_LENGTH includes terminating null byte */
715
 
      if (strlen(sha1) != (SHA1_DIGEST_STRING_LENGTH - 1)) {
716
 
         XML_WARNING("Incorrect sha1 application attribute");
717
 
         data->ignoringApp = data->inApp;
718
 
      } else {
719
 
         size_t len;
720
 
         char* content;
721
 
         char path[PATH_MAX];
722
 
         if (util_get_process_exec_path(path, ARRAY_SIZE(path)) > 0 &&
723
 
             (content = os_read_file(path, &len))) {
724
 
            uint8_t sha1x[SHA1_DIGEST_LENGTH];
725
 
            char sha1s[SHA1_DIGEST_STRING_LENGTH];
726
 
            _mesa_sha1_compute(content, len, sha1x);
727
 
            _mesa_sha1_format((char*) sha1s, sha1x);
728
 
            free(content);
729
 
 
730
 
            if (strcmp(sha1, sha1s)) {
731
 
               data->ignoringApp = data->inApp;
732
 
            }
733
 
         } else {
734
 
            data->ignoringApp = data->inApp;
735
 
         }
736
 
      }
737
 
   } else if (application_name_match) {
738
 
      regex_t re;
739
 
 
740
 
      if (regcomp(&re, application_name_match, REG_EXTENDED|REG_NOSUB) == 0) {
741
 
         if (regexec(&re, data->applicationName, 0, NULL, 0) == REG_NOMATCH)
742
 
            data->ignoringApp = data->inApp;
743
 
         regfree(&re);
744
 
      } else
745
 
         XML_WARNING("Invalid application_name_match=\"%s\".", application_name_match);
746
 
   }
747
 
   if (application_versions) {
748
 
      driOptionValue v = { ._int = data->applicationVersion };
749
 
      if (parseRange(&version_range, application_versions)) {
750
 
         if (!checkValue(&v, &version_range))
751
 
            data->ignoringApp = data->inApp;
752
 
      } else {
753
 
         XML_WARNING("Failed to parse application_versions range=\"%s\".",
754
 
                     application_versions);
755
 
      }
756
 
   }
757
 
}
758
 
 
759
 
/** \brief Parse attributes of an application element. */
760
 
static void
761
 
parseEngineAttr(struct OptConfData *data, const char **attr)
762
 
{
763
 
   uint32_t i;
764
 
   const char *engine_name_match = NULL, *engine_versions = NULL;
765
 
   driOptionInfo version_range = {
766
 
      .type = DRI_INT,
767
 
   };
768
 
   for (i = 0; attr[i]; i += 2) {
769
 
      if (!strcmp(attr[i], "name")) /* not needed here */;
770
 
      else if (!strcmp(attr[i], "engine_name_match")) engine_name_match = attr[i+1];
771
 
      else if (!strcmp(attr[i], "engine_versions")) engine_versions = attr[i+1];
772
 
      else XML_WARNING("unknown application attribute: %s.", attr[i]);
773
 
   }
774
 
   if (engine_name_match) {
775
 
      regex_t re;
776
 
 
777
 
      if (regcomp(&re, engine_name_match, REG_EXTENDED|REG_NOSUB) == 0) {
778
 
         if (regexec(&re, data->engineName, 0, NULL, 0) == REG_NOMATCH)
779
 
            data->ignoringApp = data->inApp;
780
 
         regfree(&re);
781
 
      } else
782
 
         XML_WARNING("Invalid engine_name_match=\"%s\".", engine_name_match);
783
 
   }
784
 
   if (engine_versions) {
785
 
      driOptionValue v = { ._int = data->engineVersion };
786
 
      if (parseRange(&version_range, engine_versions)) {
787
 
         if (!checkValue(&v, &version_range))
788
 
            data->ignoringApp = data->inApp;
789
 
      } else {
790
 
         XML_WARNING("Failed to parse engine_versions range=\"%s\".",
791
 
                     engine_versions);
792
 
      }
793
 
   }
794
 
}
795
 
 
796
 
/** \brief Parse attributes of an option element. */
797
 
static void
798
 
parseOptConfAttr(struct OptConfData *data, const char **attr)
799
 
{
800
 
   uint32_t i;
801
 
   const char *name = NULL, *value = NULL;
802
 
   for (i = 0; attr[i]; i += 2) {
803
 
      if (!strcmp(attr[i], "name")) name = attr[i+1];
804
 
      else if (!strcmp(attr[i], "value")) value = attr[i+1];
805
 
      else XML_WARNING("unknown option attribute: %s.", attr[i]);
806
 
   }
807
 
   if (!name) XML_WARNING1("name attribute missing in option.");
808
 
   if (!value) XML_WARNING1("value attribute missing in option.");
809
 
   if (name && value) {
810
 
      driOptionCache *cache = data->cache;
811
 
      uint32_t opt = findOption(cache, name);
812
 
      if (cache->info[opt].name == NULL)
813
 
         /* don't use XML_WARNING, drirc defines options for all drivers,
814
 
          * but not all drivers support them */
815
 
         return;
816
 
      else if (getenv(cache->info[opt].name)) {
817
 
         /* don't use XML_WARNING, we want the user to see this! */
818
 
         if (be_verbose()) {
819
 
            fprintf(stderr,
820
 
                    "ATTENTION: option value of option %s ignored.\n",
821
 
                    cache->info[opt].name);
822
 
         }
823
 
      } else if (!parseValue(&cache->values[opt], cache->info[opt].type, value))
824
 
         XML_WARNING("illegal option value: %s.", value);
825
 
   }
826
 
}
827
 
 
828
 
#if WITH_XMLCONFIG
829
 
 
830
 
/** \brief Elements in configuration files. */
831
 
enum OptConfElem {
832
 
   OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_ENGINE, OC_OPTION, OC_COUNT
833
 
};
834
 
static const char *OptConfElems[] = {
835
 
   [OC_APPLICATION]  = "application",
836
 
   [OC_DEVICE] = "device",
837
 
   [OC_DRICONF] = "driconf",
838
 
   [OC_ENGINE]  = "engine",
839
 
   [OC_OPTION] = "option",
840
 
};
841
 
 
842
 
static int compare(const void *a, const void *b) {
843
 
   return strcmp(*(char *const*)a, *(char *const*)b);
844
 
}
845
 
/** \brief Binary search in a string array. */
846
 
static uint32_t
847
 
bsearchStr(const char *name, const char *elems[], uint32_t count)
848
 
{
849
 
   const char **found;
850
 
   found = bsearch(&name, elems, count, sizeof(char *), compare);
851
 
   if (found)
852
 
      return found - elems;
853
 
   else
854
 
      return count;
855
 
}
856
 
 
857
 
/** \brief Handler for start element events. */
858
 
static void
859
 
optConfStartElem(void *userData, const char *name,
860
 
                 const char **attr)
861
 
{
862
 
   struct OptConfData *data = (struct OptConfData *)userData;
863
 
   enum OptConfElem elem = bsearchStr(name, OptConfElems, OC_COUNT);
864
 
   switch (elem) {
865
 
   case OC_DRICONF:
866
 
      if (data->inDriConf)
867
 
         XML_WARNING1("nested <driconf> elements.");
868
 
      if (attr[0])
869
 
         XML_WARNING1("attributes specified on <driconf> element.");
870
 
      data->inDriConf++;
871
 
      break;
872
 
   case OC_DEVICE:
873
 
      if (!data->inDriConf)
874
 
         XML_WARNING1("<device> should be inside <driconf>.");
875
 
      if (data->inDevice)
876
 
         XML_WARNING1("nested <device> elements.");
877
 
      data->inDevice++;
878
 
      if (!data->ignoringDevice && !data->ignoringApp)
879
 
         parseDeviceAttr(data, attr);
880
 
      break;
881
 
   case OC_APPLICATION:
882
 
      if (!data->inDevice)
883
 
         XML_WARNING1("<application> should be inside <device>.");
884
 
      if (data->inApp)
885
 
         XML_WARNING1("nested <application> or <engine> elements.");
886
 
      data->inApp++;
887
 
      if (!data->ignoringDevice && !data->ignoringApp)
888
 
         parseAppAttr(data, attr);
889
 
      break;
890
 
   case OC_ENGINE:
891
 
      if (!data->inDevice)
892
 
         XML_WARNING1("<engine> should be inside <device>.");
893
 
      if (data->inApp)
894
 
         XML_WARNING1("nested <application> or <engine> elements.");
895
 
      data->inApp++;
896
 
      if (!data->ignoringDevice && !data->ignoringApp)
897
 
         parseEngineAttr(data, attr);
898
 
      break;
899
 
   case OC_OPTION:
900
 
      if (!data->inApp)
901
 
         XML_WARNING1("<option> should be inside <application>.");
902
 
      if (data->inOption)
903
 
         XML_WARNING1("nested <option> elements.");
904
 
      data->inOption++;
905
 
      if (!data->ignoringDevice && !data->ignoringApp)
906
 
         parseOptConfAttr(data, attr);
907
 
      break;
908
 
   default:
909
 
      XML_WARNING("unknown element: %s.", name);
910
 
   }
911
 
}
912
 
 
913
 
/** \brief Handler for end element events. */
914
 
static void
915
 
optConfEndElem(void *userData, const char *name)
916
 
{
917
 
   struct OptConfData *data = (struct OptConfData *)userData;
918
 
   enum OptConfElem elem = bsearchStr(name, OptConfElems, OC_COUNT);
919
 
   switch (elem) {
920
 
   case OC_DRICONF:
921
 
      data->inDriConf--;
922
 
      break;
923
 
   case OC_DEVICE:
924
 
      if (data->inDevice-- == data->ignoringDevice)
925
 
         data->ignoringDevice = 0;
926
 
      break;
927
 
   case OC_APPLICATION:
928
 
   case OC_ENGINE:
929
 
      if (data->inApp-- == data->ignoringApp)
930
 
         data->ignoringApp = 0;
931
 
      break;
932
 
   case OC_OPTION:
933
 
      data->inOption--;
934
 
      break;
935
 
   default:
936
 
      /* unknown element, warning was produced on start tag */;
937
 
   }
938
 
}
939
 
 
940
 
static void
941
 
_parseOneConfigFile(XML_Parser p)
942
 
{
943
 
#define BUF_SIZE 0x1000
944
 
   struct OptConfData *data = (struct OptConfData *)XML_GetUserData(p);
945
 
   int status;
946
 
   int fd;
947
 
 
948
 
   if ((fd = open(data->name, O_RDONLY)) == -1) {
949
 
      __driUtilMessage("Can't open configuration file %s: %s.",
950
 
                       data->name, strerror(errno));
951
 
      return;
952
 
   }
953
 
 
954
 
   while (1) {
955
 
      int bytesRead;
956
 
      void *buffer = XML_GetBuffer(p, BUF_SIZE);
957
 
      if (!buffer) {
958
 
         __driUtilMessage("Can't allocate parser buffer.");
959
 
         break;
960
 
      }
961
 
      bytesRead = read(fd, buffer, BUF_SIZE);
962
 
      if (bytesRead == -1) {
963
 
         __driUtilMessage("Error reading from configuration file %s: %s.",
964
 
                          data->name, strerror(errno));
965
 
         break;
966
 
      }
967
 
      status = XML_ParseBuffer(p, bytesRead, bytesRead == 0);
968
 
      if (!status) {
969
 
         XML_ERROR("%s.", XML_ErrorString(XML_GetErrorCode(p)));
970
 
         break;
971
 
      }
972
 
      if (bytesRead == 0)
973
 
         break;
974
 
   }
975
 
 
976
 
   close(fd);
977
 
#undef BUF_SIZE
978
 
}
979
 
 
980
 
/** \brief Parse the named configuration file */
981
 
static void
982
 
parseOneConfigFile(struct OptConfData *data, const char *filename)
983
 
{
984
 
   XML_Parser p;
985
 
 
986
 
   p = XML_ParserCreate(NULL); /* use encoding specified by file */
987
 
   XML_SetElementHandler(p, optConfStartElem, optConfEndElem);
988
 
   XML_SetUserData(p, data);
989
 
   data->parser = p;
990
 
   data->name = filename;
991
 
   data->ignoringDevice = 0;
992
 
   data->ignoringApp = 0;
993
 
   data->inDriConf = 0;
994
 
   data->inDevice = 0;
995
 
   data->inApp = 0;
996
 
   data->inOption = 0;
997
 
 
998
 
   _parseOneConfigFile(p);
999
 
   XML_ParserFree(p);
1000
 
}
1001
 
 
1002
 
static int
1003
 
scandir_filter(const struct dirent *ent)
1004
 
{
1005
 
#ifndef DT_REG /* systems without d_type in dirent results */
1006
 
   struct stat st;
1007
 
 
1008
 
   if ((lstat(ent->d_name, &st) != 0) ||
1009
 
       (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)))
1010
 
      return 0;
1011
 
#else
1012
 
   /* Allow through unknown file types for filesystems that don't support d_type
1013
 
    * The full filepath isn't available here to stat the file
1014
 
    */
1015
 
   if (ent->d_type != DT_REG && ent->d_type != DT_LNK && ent->d_type != DT_UNKNOWN)
1016
 
      return 0;
1017
 
#endif
1018
 
 
1019
 
   int len = strlen(ent->d_name);
1020
 
   if (len <= 5 || strcmp(ent->d_name + len - 5, ".conf"))
1021
 
      return 0;
1022
 
 
1023
 
   return 1;
1024
 
}
1025
 
 
1026
 
/** \brief Parse configuration files in a directory */
1027
 
static void
1028
 
parseConfigDir(struct OptConfData *data, const char *dirname)
1029
 
{
1030
 
   int i, count;
1031
 
   struct dirent **entries = NULL;
1032
 
 
1033
 
   count = scandir(dirname, &entries, scandir_filter, alphasort);
1034
 
   if (count < 0)
1035
 
      return;
1036
 
 
1037
 
   for (i = 0; i < count; i++) {
1038
 
      char filename[PATH_MAX];
1039
 
#ifdef DT_REG
1040
 
      unsigned char d_type = entries[i]->d_type;
1041
 
#endif
1042
 
 
1043
 
      snprintf(filename, PATH_MAX, "%s/%s", dirname, entries[i]->d_name);
1044
 
      free(entries[i]);
1045
 
 
1046
 
#ifdef DT_REG
1047
 
      /* In the case of unknown d_type, ensure it is a regular file
1048
 
       * This can be accomplished with stat on the full filepath
1049
 
       */
1050
 
      if (d_type == DT_UNKNOWN) {
1051
 
         struct stat st;
1052
 
         if (stat(filename, &st) != 0 ||
1053
 
             !S_ISREG(st.st_mode)) {
1054
 
            continue;
1055
 
         }
1056
 
      }
1057
 
#endif
1058
 
 
1059
 
      parseOneConfigFile(data, filename);
1060
 
   }
1061
 
 
1062
 
   free(entries);
1063
 
}
1064
 
#else
1065
 
#  include "driconf_static.h"
1066
 
 
1067
 
static void
1068
 
parseStaticOptions(struct OptConfData *data, const struct driconf_option *options,
1069
 
                   unsigned num_options)
1070
 
{
1071
 
   if (data->ignoringDevice || data->ignoringApp)
1072
 
      return;
1073
 
   for (unsigned i = 0; i < num_options; i++) {
1074
 
      const char *optattr[] = {
1075
 
         "name", options[i].name,
1076
 
         "value", options[i].value,
1077
 
         NULL
1078
 
      };
1079
 
      parseOptConfAttr(data, optattr);
1080
 
   }
1081
 
}
1082
 
 
1083
 
static void
1084
 
parseStaticConfig(struct OptConfData *data)
1085
 
{
1086
 
   data->ignoringDevice = 0;
1087
 
   data->ignoringApp = 0;
1088
 
   data->inDriConf = 0;
1089
 
   data->inDevice = 0;
1090
 
   data->inApp = 0;
1091
 
   data->inOption = 0;
1092
 
 
1093
 
   for (unsigned i = 0; i < ARRAY_SIZE(driconf); i++) {
1094
 
      const struct driconf_device *d = driconf[i];
1095
 
      const char *devattr[] = {
1096
 
         "driver", d->driver,
1097
 
         "device", d->device,
1098
 
         NULL
1099
 
      };
1100
 
 
1101
 
      data->ignoringDevice = 0;
1102
 
      data->inDevice++;
1103
 
      parseDeviceAttr(data, devattr);
1104
 
      data->inDevice--;
1105
 
 
1106
 
      data->inApp++;
1107
 
 
1108
 
      for (unsigned j = 0; j < d->num_engines; j++) {
1109
 
         const struct driconf_engine *e = &d->engines[j];
1110
 
         const char *engattr[] = {
1111
 
            "engine_name_match", e->engine_name_match,
1112
 
            "engine_versions", e->engine_versions,
1113
 
            NULL
1114
 
         };
1115
 
 
1116
 
         data->ignoringApp = 0;
1117
 
         parseEngineAttr(data, engattr);
1118
 
         parseStaticOptions(data, e->options, e->num_options);
1119
 
      }
1120
 
 
1121
 
      for (unsigned j = 0; j < d->num_applications; j++) {
1122
 
         const struct driconf_application *a = &d->applications[j];
1123
 
         const char *appattr[] = {
1124
 
            "name", a->name,
1125
 
            "executable", a->executable,
1126
 
            "executable_regexp", a->executable_regexp,
1127
 
            "sha1", a->sha1,
1128
 
            "application_name_match", a->application_name_match,
1129
 
            "application_versions", a->application_versions,
1130
 
            NULL
1131
 
         };
1132
 
 
1133
 
         data->ignoringApp = 0;
1134
 
         parseAppAttr(data, appattr);
1135
 
         parseStaticOptions(data, a->options, a->num_options);
1136
 
      }
1137
 
 
1138
 
      data->inApp--;
1139
 
   }
1140
 
}
1141
 
#endif /* WITH_XMLCONFIG */
1142
 
 
1143
 
/** \brief Initialize an option cache based on info */
1144
 
static void
1145
 
initOptionCache(driOptionCache *cache, const driOptionCache *info)
1146
 
{
1147
 
   unsigned i, size = 1 << info->tableSize;
1148
 
   cache->info = info->info;
1149
 
   cache->tableSize = info->tableSize;
1150
 
   cache->values = malloc(((size_t)1 << info->tableSize) * sizeof(driOptionValue));
1151
 
   if (cache->values == NULL) {
1152
 
      fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
1153
 
      abort();
1154
 
   }
1155
 
   memcpy(cache->values, info->values,
1156
 
           ((size_t)1 << info->tableSize) * sizeof(driOptionValue));
1157
 
   for (i = 0; i < size; ++i) {
1158
 
      if (cache->info[i].type == DRI_STRING)
1159
 
         XSTRDUP(cache->values[i]._string, info->values[i]._string);
1160
 
   }
1161
 
}
1162
 
 
1163
 
#ifndef SYSCONFDIR
1164
 
#define SYSCONFDIR "/etc"
1165
 
#endif
1166
 
 
1167
 
#ifndef DATADIR
1168
 
#define DATADIR "/usr/share"
1169
 
#endif
1170
 
 
1171
 
static const char *datadir = DATADIR "/drirc.d";
1172
 
static const char *execname;
1173
 
 
1174
 
void
1175
 
driInjectDataDir(const char *dir)
1176
 
{
1177
 
   datadir = dir;
1178
 
}
1179
 
 
1180
 
void
1181
 
driInjectExecName(const char *exec)
1182
 
{
1183
 
   execname = exec;
1184
 
}
1185
 
 
1186
 
void
1187
 
driParseConfigFiles(driOptionCache *cache, const driOptionCache *info,
1188
 
                    int screenNum, const char *driverName,
1189
 
                    const char *kernelDriverName,
1190
 
                    const char *deviceName,
1191
 
                    const char *applicationName, uint32_t applicationVersion,
1192
 
                    const char *engineName, uint32_t engineVersion)
1193
 
{
1194
 
   initOptionCache(cache, info);
1195
 
   struct OptConfData userData;
1196
 
 
1197
 
   userData.cache = cache;
1198
 
   userData.screenNum = screenNum;
1199
 
   userData.driverName = driverName;
1200
 
   userData.kernelDriverName = kernelDriverName;
1201
 
   userData.deviceName = deviceName;
1202
 
   userData.applicationName = applicationName ? applicationName : "";
1203
 
   userData.applicationVersion = applicationVersion;
1204
 
   userData.engineName = engineName ? engineName : "";
1205
 
   userData.engineVersion = engineVersion;
1206
 
   userData.execName = execname ? execname : util_get_process_name();
1207
 
 
1208
 
#if WITH_XMLCONFIG
1209
 
   char *home;
1210
 
 
1211
 
   parseConfigDir(&userData, datadir);
1212
 
   parseOneConfigFile(&userData, SYSCONFDIR "/drirc");
1213
 
 
1214
 
   if ((home = getenv("HOME"))) {
1215
 
      char filename[PATH_MAX];
1216
 
 
1217
 
      snprintf(filename, PATH_MAX, "%s/.drirc", home);
1218
 
      parseOneConfigFile(&userData, filename);
1219
 
   }
1220
 
#else
1221
 
   parseStaticConfig(&userData);
1222
 
#endif /* WITH_XMLCONFIG */
1223
 
}
1224
 
 
1225
 
void
1226
 
driDestroyOptionInfo(driOptionCache *info)
1227
 
{
1228
 
   driDestroyOptionCache(info);
1229
 
   if (info->info) {
1230
 
      uint32_t i, size = 1 << info->tableSize;
1231
 
      for (i = 0; i < size; ++i) {
1232
 
         if (info->info[i].name) {
1233
 
            free(info->info[i].name);
1234
 
         }
1235
 
      }
1236
 
      free(info->info);
1237
 
   }
1238
 
}
1239
 
 
1240
 
void
1241
 
driDestroyOptionCache(driOptionCache *cache)
1242
 
{
1243
 
   if (cache->info) {
1244
 
      unsigned i, size = 1 << cache->tableSize;
1245
 
      for (i = 0; i < size; ++i) {
1246
 
         if (cache->info[i].type == DRI_STRING)
1247
 
            free(cache->values[i]._string);
1248
 
      }
1249
 
   }
1250
 
   free(cache->values);
1251
 
}
1252
 
 
1253
 
unsigned char
1254
 
driCheckOption(const driOptionCache *cache, const char *name,
1255
 
               driOptionType type)
1256
 
{
1257
 
   uint32_t i = findOption(cache, name);
1258
 
   return cache->info[i].name != NULL && cache->info[i].type == type;
1259
 
}
1260
 
 
1261
 
unsigned char
1262
 
driQueryOptionb(const driOptionCache *cache, const char *name)
1263
 
{
1264
 
   uint32_t i = findOption(cache, name);
1265
 
   /* make sure the option is defined and has the correct type */
1266
 
   assert(cache->info[i].name != NULL);
1267
 
   assert(cache->info[i].type == DRI_BOOL);
1268
 
   return cache->values[i]._bool;
1269
 
}
1270
 
 
1271
 
int
1272
 
driQueryOptioni(const driOptionCache *cache, const char *name)
1273
 
{
1274
 
   uint32_t i = findOption(cache, name);
1275
 
   /* make sure the option is defined and has the correct type */
1276
 
   assert(cache->info[i].name != NULL);
1277
 
   assert(cache->info[i].type == DRI_INT || cache->info[i].type == DRI_ENUM);
1278
 
   return cache->values[i]._int;
1279
 
}
1280
 
 
1281
 
float
1282
 
driQueryOptionf(const driOptionCache *cache, const char *name)
1283
 
{
1284
 
   uint32_t i = findOption(cache, name);
1285
 
   /* make sure the option is defined and has the correct type */
1286
 
   assert(cache->info[i].name != NULL);
1287
 
   assert(cache->info[i].type == DRI_FLOAT);
1288
 
   return cache->values[i]._float;
1289
 
}
1290
 
 
1291
 
char *
1292
 
driQueryOptionstr(const driOptionCache *cache, const char *name)
1293
 
{
1294
 
   uint32_t i = findOption(cache, name);
1295
 
   /* make sure the option is defined and has the correct type */
1296
 
   assert(cache->info[i].name != NULL);
1297
 
   assert(cache->info[i].type == DRI_STRING);
1298
 
   return cache->values[i]._string;
1299
 
}