2
* XML DRI client-side driver configuration
3
* Copyright (C) 2003 Felix Kuehling
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:
12
* The above copyright notice and this permission notice shall be included
13
* in all copies or substantial portions of the Software.
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.
26
* \brief Driver-independent client-side part of the XML configuration
27
* \author Felix Kuehling
30
#include "xmlconfig.h"
48
#define REG_EXTENDED 0
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) {}
60
#include "u_process.h"
63
/* For systems like Hurd */
71
const char *s = getenv("MESA_DEBUG");
75
return strstr(s, "silent") == NULL;
78
/** \brief Locale-independent integer parser.
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. */
88
strToI(const char *string, const char **tail, int base)
90
int radix = base == 0 ? 10 : base;
93
bool numberFound = false;
94
const char *start = string;
96
assert(radix >= 2 && radix <= 36);
101
} else if (*string == '+')
103
if (base == 0 && *string == '0') {
105
if (*(string+1) == 'x' || *(string+1) == 'X') {
116
if (*string >= '0' && *string < '0' + radix)
117
digit = *string - '0';
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;
128
result = radix*result + digit;
133
*tail = numberFound ? string : start;
134
return sign * result;
137
/** \brief Locale-independent floating-point parser.
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.
148
* Uses two passes for maximum accuracy. */
150
strToF(const char *string, const char **tail)
152
int nDigits = 0, pointPos, exponent;
153
float sign = 1.0f, result = 0.0f, scale;
154
const char *start = string, *numStart;
157
if (*string == '-') {
160
} else if (*string == '+')
163
/* first pass: determine position of decimal point, number of
164
* digits, exponent and the end of the number. */
166
while (*string >= '0' && *string <= '9') {
171
if (*string == '.') {
173
while (*string >= '0' && *string <= '9') {
179
/* no digits, no number */
184
if (*string == 'e' || *string == 'E') {
186
exponent = strToI(string+1, &expTail, 10);
187
if (expTail == string+1)
195
/* scale of the first digit */
196
scale = sign * (float)pow(10.0, (double)(pointPos-1 + exponent));
198
/* second pass: parse digits */
200
if (*string != '.') {
201
assert(*string >= '0' && *string <= '9');
202
result += scale * (float)(*string - '0');
207
} while (nDigits > 0);
212
/** \brief Parse a value of a given type. */
214
parseValue(driOptionValue *v, driOptionType type, const char *string)
216
const char *tail = NULL;
217
/* skip leading white-space */
218
string += strspn(string, " \f\n\r\t\v");
221
if (!strcmp(string, "false")) {
224
} else if (!strcmp(string, "true")) {
231
case DRI_ENUM: /* enum is just a special integer */
233
v->_int = strToI(string, &tail, 0);
236
v->_float = strToF(string, &tail);
240
v->_string = strndup(string, STRING_CONF_MAXLEN);
243
unreachable("shouldn't be parsing values in section declarations");
247
return false; /* empty string (or containing only white-space) */
248
/* skip trailing white space */
250
tail += strspn(tail, " \f\n\r\t\v");
252
return false; /* something left over that is not part of value */
257
/** \brief Find an option in an option cache with the name as key */
259
findOption(const driOptionCache *cache, const char *name)
261
uint32_t len = strlen(name);
262
uint32_t size = 1 << cache->tableSize, mask = size - 1;
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;
270
hash = (hash >> (16-cache->tableSize/2)) & mask;
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)
277
else if (!strcmp(name, cache->info[hash].name))
280
/* this assertion fails if the hash table is full */
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__); \
294
/** \brief Check if a value is in info->range. */
296
checkValue(const driOptionValue *v, const driOptionInfo *info)
298
switch (info->type) {
299
case DRI_ENUM: /* enum is just a special integer */
301
return (info->range.start._int == info->range.end._int ||
302
(v->_int >= info->range.start._int &&
303
v->_int <= info->range.end._int));
306
return (info->range.start._float == info->range.end._float ||
307
(v->_float >= info->range.start._float &&
308
v->_float <= info->range.end._float));
316
driParseOptionInfo(driOptionCache *info,
317
const driOptionDescription *configOptions,
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.
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__);
331
UNUSED bool in_section = false;
332
for (int o = 0; o < numOptions; o++) {
333
const driOptionDescription *opt = &configOptions[o];
335
if (opt->info.type == DRI_SECTION) {
340
/* for driconf xml generation, options must always be preceded by a
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];
350
assert(!optinfo->name); /* No duplicate options in your list. */
352
optinfo->type = opt->info.type;
353
optinfo->range = opt->info.range;
354
XSTRDUP(optinfo->name, name);
356
switch (opt->info.type) {
358
optval->_bool = opt->value._bool;
363
optval->_int = opt->value._int;
367
optval->_float = opt->value._float;
371
XSTRDUP(optval->_string, opt->value._string);
375
unreachable("handled above");
378
/* Built-in default values should always be valid. */
379
assert(checkValue(optval, optinfo));
381
char *envVal = getenv(name);
382
if (envVal != NULL) {
385
/* make sure the value is initialized to something sensible */
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! */
393
"ATTENTION: default value of option %s overridden by environment.\n",
398
fprintf(stderr, "illegal environment value for %s: \"%s\". Ignoring.\n",
406
driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
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" \
427
bool in_section = false;
428
for (int o = 0; o < numOptions; o++) {
429
const driOptionDescription *opt = &configOptions[o];
431
const char *name = opt->info.name;
432
const char *types[] = {
435
[DRI_FLOAT] = "float",
437
[DRI_STRING] = "string",
440
if (opt->info.type == DRI_SECTION) {
442
ralloc_asprintf_append(&str, " </section>\n");
444
ralloc_asprintf_append(&str,
446
" <description lang=\"en\" text=\"%s\"/>\n",
453
ralloc_asprintf_append(&str,
454
" <option name=\"%s\" type=\"%s\" default=\"",
456
types[opt->info.type]);
458
switch (opt->info.type) {
460
ralloc_asprintf_append(&str, opt->value._bool ? "true" : "false");
465
ralloc_asprintf_append(&str, "%d", opt->value._int);
469
ralloc_asprintf_append(&str, "%f", opt->value._float);
473
ralloc_asprintf_append(&str, "%s", opt->value._string);
477
unreachable("handled above");
480
ralloc_asprintf_append(&str, "\"");
483
switch (opt->info.type) {
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);
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);
505
ralloc_asprintf_append(&str, ">\n"); /* end of <option> */
508
ralloc_asprintf_append(&str, " <description lang=\"en\" text=\"%s\"%s>\n",
509
opt->desc, opt->info.type != DRI_ENUM ? "/" : "");
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);
516
ralloc_asprintf_append(&str, " </description>\n");
519
ralloc_asprintf_append(&str, " </option>\n");
523
ralloc_asprintf_append(&str, " </section>\n");
525
ralloc_asprintf_append(&str, "</driinfo>\n");
527
char *output = strdup(str);
534
* Print message to \c stderr if the \c LIBGL_DEBUG environment variable
537
* Is called from the drivers.
539
* \param f \c printf like format string.
542
__driUtilMessage(const char *f, ...)
545
const char *libgl_debug;
547
libgl_debug=getenv("LIBGL_DEBUG");
548
if (libgl_debug && !strstr(libgl_debug, "quiet")) {
549
fprintf(stderr, "libGL: ");
551
vfprintf(stderr, f, args);
553
fprintf(stderr, "\n");
557
/* We don't have real line/column # info in static-config case: */
559
# define XML_GetCurrentLineNumber(p) -1
560
# define XML_GetCurrentColumnNumber(p) -1
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)); \
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), \
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)); \
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), \
588
/** \brief Parser context for configuration files. */
594
driOptionCache *cache;
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;
611
/** \brief Parse a list of ranges of type info->type. */
613
parseRange(driOptionInfo *info, const char *string)
620
sep = strchr(cp, ':');
627
if (!parseValue(&info->range.start, info->type, cp) ||
628
!parseValue(&info->range.end, info->type, sep+1)) {
632
if (info->type == DRI_INT &&
633
info->range.start._int >= info->range.end._int) {
637
if (info->type == DRI_FLOAT &&
638
info->range.start._float >= info->range.end._float) {
647
/** \brief Parse attributes of a device element. */
649
parseDeviceAttr(struct OptConfData *data, const char **attr)
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]);
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;
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;
677
/** \brief Parse attributes of an application element. */
679
parseAppAttr(struct OptConfData *data, const char **attr)
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 = {
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]);
702
if (exec && strcmp(exec, data->execName)) {
703
data->ignoringApp = data->inApp;
704
} else if (exec_regexp) {
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;
712
XML_WARNING("Invalid executable_regexp=\"%s\".", exec_regexp);
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;
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);
730
if (strcmp(sha1, sha1s)) {
731
data->ignoringApp = data->inApp;
734
data->ignoringApp = data->inApp;
737
} else if (application_name_match) {
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;
745
XML_WARNING("Invalid application_name_match=\"%s\".", application_name_match);
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;
753
XML_WARNING("Failed to parse application_versions range=\"%s\".",
754
application_versions);
759
/** \brief Parse attributes of an application element. */
761
parseEngineAttr(struct OptConfData *data, const char **attr)
764
const char *engine_name_match = NULL, *engine_versions = NULL;
765
driOptionInfo version_range = {
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]);
774
if (engine_name_match) {
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;
782
XML_WARNING("Invalid engine_name_match=\"%s\".", engine_name_match);
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;
790
XML_WARNING("Failed to parse engine_versions range=\"%s\".",
796
/** \brief Parse attributes of an option element. */
798
parseOptConfAttr(struct OptConfData *data, const char **attr)
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]);
807
if (!name) XML_WARNING1("name attribute missing in option.");
808
if (!value) XML_WARNING1("value attribute missing in option.");
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 */
816
else if (getenv(cache->info[opt].name)) {
817
/* don't use XML_WARNING, we want the user to see this! */
820
"ATTENTION: option value of option %s ignored.\n",
821
cache->info[opt].name);
823
} else if (!parseValue(&cache->values[opt], cache->info[opt].type, value))
824
XML_WARNING("illegal option value: %s.", value);
830
/** \brief Elements in configuration files. */
832
OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_ENGINE, OC_OPTION, OC_COUNT
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",
842
static int compare(const void *a, const void *b) {
843
return strcmp(*(char *const*)a, *(char *const*)b);
845
/** \brief Binary search in a string array. */
847
bsearchStr(const char *name, const char *elems[], uint32_t count)
850
found = bsearch(&name, elems, count, sizeof(char *), compare);
852
return found - elems;
857
/** \brief Handler for start element events. */
859
optConfStartElem(void *userData, const char *name,
862
struct OptConfData *data = (struct OptConfData *)userData;
863
enum OptConfElem elem = bsearchStr(name, OptConfElems, OC_COUNT);
867
XML_WARNING1("nested <driconf> elements.");
869
XML_WARNING1("attributes specified on <driconf> element.");
873
if (!data->inDriConf)
874
XML_WARNING1("<device> should be inside <driconf>.");
876
XML_WARNING1("nested <device> elements.");
878
if (!data->ignoringDevice && !data->ignoringApp)
879
parseDeviceAttr(data, attr);
883
XML_WARNING1("<application> should be inside <device>.");
885
XML_WARNING1("nested <application> or <engine> elements.");
887
if (!data->ignoringDevice && !data->ignoringApp)
888
parseAppAttr(data, attr);
892
XML_WARNING1("<engine> should be inside <device>.");
894
XML_WARNING1("nested <application> or <engine> elements.");
896
if (!data->ignoringDevice && !data->ignoringApp)
897
parseEngineAttr(data, attr);
901
XML_WARNING1("<option> should be inside <application>.");
903
XML_WARNING1("nested <option> elements.");
905
if (!data->ignoringDevice && !data->ignoringApp)
906
parseOptConfAttr(data, attr);
909
XML_WARNING("unknown element: %s.", name);
913
/** \brief Handler for end element events. */
915
optConfEndElem(void *userData, const char *name)
917
struct OptConfData *data = (struct OptConfData *)userData;
918
enum OptConfElem elem = bsearchStr(name, OptConfElems, OC_COUNT);
924
if (data->inDevice-- == data->ignoringDevice)
925
data->ignoringDevice = 0;
929
if (data->inApp-- == data->ignoringApp)
930
data->ignoringApp = 0;
936
/* unknown element, warning was produced on start tag */;
941
_parseOneConfigFile(XML_Parser p)
943
#define BUF_SIZE 0x1000
944
struct OptConfData *data = (struct OptConfData *)XML_GetUserData(p);
948
if ((fd = open(data->name, O_RDONLY)) == -1) {
949
__driUtilMessage("Can't open configuration file %s: %s.",
950
data->name, strerror(errno));
956
void *buffer = XML_GetBuffer(p, BUF_SIZE);
958
__driUtilMessage("Can't allocate parser buffer.");
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));
967
status = XML_ParseBuffer(p, bytesRead, bytesRead == 0);
969
XML_ERROR("%s.", XML_ErrorString(XML_GetErrorCode(p)));
980
/** \brief Parse the named configuration file */
982
parseOneConfigFile(struct OptConfData *data, const char *filename)
986
p = XML_ParserCreate(NULL); /* use encoding specified by file */
987
XML_SetElementHandler(p, optConfStartElem, optConfEndElem);
988
XML_SetUserData(p, data);
990
data->name = filename;
991
data->ignoringDevice = 0;
992
data->ignoringApp = 0;
998
_parseOneConfigFile(p);
1003
scandir_filter(const struct dirent *ent)
1005
#ifndef DT_REG /* systems without d_type in dirent results */
1008
if ((lstat(ent->d_name, &st) != 0) ||
1009
(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)))
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
1015
if (ent->d_type != DT_REG && ent->d_type != DT_LNK && ent->d_type != DT_UNKNOWN)
1019
int len = strlen(ent->d_name);
1020
if (len <= 5 || strcmp(ent->d_name + len - 5, ".conf"))
1026
/** \brief Parse configuration files in a directory */
1028
parseConfigDir(struct OptConfData *data, const char *dirname)
1031
struct dirent **entries = NULL;
1033
count = scandir(dirname, &entries, scandir_filter, alphasort);
1037
for (i = 0; i < count; i++) {
1038
char filename[PATH_MAX];
1040
unsigned char d_type = entries[i]->d_type;
1043
snprintf(filename, PATH_MAX, "%s/%s", dirname, entries[i]->d_name);
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
1050
if (d_type == DT_UNKNOWN) {
1052
if (stat(filename, &st) != 0 ||
1053
!S_ISREG(st.st_mode)) {
1059
parseOneConfigFile(data, filename);
1065
# include "driconf_static.h"
1068
parseStaticOptions(struct OptConfData *data, const struct driconf_option *options,
1069
unsigned num_options)
1071
if (data->ignoringDevice || data->ignoringApp)
1073
for (unsigned i = 0; i < num_options; i++) {
1074
const char *optattr[] = {
1075
"name", options[i].name,
1076
"value", options[i].value,
1079
parseOptConfAttr(data, optattr);
1084
parseStaticConfig(struct OptConfData *data)
1086
data->ignoringDevice = 0;
1087
data->ignoringApp = 0;
1088
data->inDriConf = 0;
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,
1101
data->ignoringDevice = 0;
1103
parseDeviceAttr(data, devattr);
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,
1116
data->ignoringApp = 0;
1117
parseEngineAttr(data, engattr);
1118
parseStaticOptions(data, e->options, e->num_options);
1121
for (unsigned j = 0; j < d->num_applications; j++) {
1122
const struct driconf_application *a = &d->applications[j];
1123
const char *appattr[] = {
1125
"executable", a->executable,
1126
"executable_regexp", a->executable_regexp,
1128
"application_name_match", a->application_name_match,
1129
"application_versions", a->application_versions,
1133
data->ignoringApp = 0;
1134
parseAppAttr(data, appattr);
1135
parseStaticOptions(data, a->options, a->num_options);
1141
#endif /* WITH_XMLCONFIG */
1143
/** \brief Initialize an option cache based on info */
1145
initOptionCache(driOptionCache *cache, const driOptionCache *info)
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__);
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);
1164
#define SYSCONFDIR "/etc"
1168
#define DATADIR "/usr/share"
1171
static const char *datadir = DATADIR "/drirc.d";
1172
static const char *execname;
1175
driInjectDataDir(const char *dir)
1181
driInjectExecName(const char *exec)
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)
1194
initOptionCache(cache, info);
1195
struct OptConfData userData;
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();
1211
parseConfigDir(&userData, datadir);
1212
parseOneConfigFile(&userData, SYSCONFDIR "/drirc");
1214
if ((home = getenv("HOME"))) {
1215
char filename[PATH_MAX];
1217
snprintf(filename, PATH_MAX, "%s/.drirc", home);
1218
parseOneConfigFile(&userData, filename);
1221
parseStaticConfig(&userData);
1222
#endif /* WITH_XMLCONFIG */
1226
driDestroyOptionInfo(driOptionCache *info)
1228
driDestroyOptionCache(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);
1241
driDestroyOptionCache(driOptionCache *cache)
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);
1250
free(cache->values);
1254
driCheckOption(const driOptionCache *cache, const char *name,
1257
uint32_t i = findOption(cache, name);
1258
return cache->info[i].name != NULL && cache->info[i].type == type;
1262
driQueryOptionb(const driOptionCache *cache, const char *name)
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;
1272
driQueryOptioni(const driOptionCache *cache, const char *name)
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;
1282
driQueryOptionf(const driOptionCache *cache, const char *name)
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;
1292
driQueryOptionstr(const driOptionCache *cache, const char *name)
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;