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