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