driconf: Restore the ability to override driconf with the environment.
I distinctly remember testing this during development, yet clearly deleted
the code.
I pulled the parseValue code back up to the top where it used to be since
we have to use it, rather than just adding a prototype.
Fixes: 8a05d6ffc6
("driconf: Make the driver's declarations be structs instead of XML.")
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7012>
This commit is contained in:
parent
455bfecdff
commit
7fb4ab9ec1
|
@ -61,262 +61,6 @@
|
|||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
/** \brief Find an option in an option cache with the name as key */
|
||||
static uint32_t
|
||||
findOption(const driOptionCache *cache, const char *name)
|
||||
{
|
||||
uint32_t len = strlen(name);
|
||||
uint32_t size = 1 << cache->tableSize, mask = size - 1;
|
||||
uint32_t hash = 0;
|
||||
uint32_t i, shift;
|
||||
|
||||
/* compute a hash from the variable length name */
|
||||
for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
|
||||
hash += (uint32_t)name[i] << shift;
|
||||
hash *= hash;
|
||||
hash = (hash >> (16-cache->tableSize/2)) & mask;
|
||||
|
||||
/* this is just the starting point of the linear search for the option */
|
||||
for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
|
||||
/* if we hit an empty entry then the option is not defined (yet) */
|
||||
if (cache->info[hash].name == 0)
|
||||
break;
|
||||
else if (!strcmp(name, cache->info[hash].name))
|
||||
break;
|
||||
}
|
||||
/* this assertion fails if the hash table is full */
|
||||
assert (i < size);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** \brief Like strdup with error checking. */
|
||||
#define XSTRDUP(dest,source) do { \
|
||||
if (!(dest = strdup(source))) { \
|
||||
fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** \brief Check if a value is in info->range. */
|
||||
UNUSED static bool
|
||||
checkValue(const driOptionValue *v, const driOptionInfo *info)
|
||||
{
|
||||
switch (info->type) {
|
||||
case DRI_ENUM: /* enum is just a special integer */
|
||||
case DRI_INT:
|
||||
return (info->range.start._int == info->range.end._int ||
|
||||
(v->_int >= info->range.start._int &&
|
||||
v->_int <= info->range.end._int));
|
||||
|
||||
case DRI_FLOAT:
|
||||
return (info->range.start._float == info->range.end._float ||
|
||||
(v->_float >= info->range.start._float &&
|
||||
v->_float <= info->range.end._float));
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
driParseOptionInfo(driOptionCache *info,
|
||||
const driOptionDescription *configOptions,
|
||||
unsigned numOptions)
|
||||
{
|
||||
/* Make the hash table big enough to fit more than the maximum number of
|
||||
* config options we've ever seen in a driver.
|
||||
*/
|
||||
info->tableSize = 6;
|
||||
info->info = calloc(1 << info->tableSize, sizeof(driOptionInfo));
|
||||
info->values = calloc(1 << info->tableSize, sizeof(driOptionValue));
|
||||
if (info->info == NULL || info->values == NULL) {
|
||||
fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
|
||||
abort();
|
||||
}
|
||||
|
||||
UNUSED bool in_section = false;
|
||||
for (int o = 0; o < numOptions; o++) {
|
||||
const driOptionDescription *opt = &configOptions[o];
|
||||
|
||||
if (opt->info.type == DRI_SECTION) {
|
||||
in_section = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* for driconf xml generation, options must always be preceded by a
|
||||
* DRI_CONF_SECTION
|
||||
*/
|
||||
assert(in_section);
|
||||
|
||||
const char *name = opt->info.name;
|
||||
int i = findOption(info, name);
|
||||
driOptionInfo *optinfo = &info->info[i];
|
||||
driOptionValue *optval = &info->values[i];
|
||||
|
||||
assert(!optinfo->name); /* No duplicate options in your list. */
|
||||
|
||||
optinfo->type = opt->info.type;
|
||||
optinfo->range = opt->info.range;
|
||||
XSTRDUP(optinfo->name, name);
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_BOOL:
|
||||
optval->_bool = opt->value._bool;
|
||||
break;
|
||||
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
optval->_int = opt->value._int;
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
optval->_float = opt->value._float;
|
||||
break;
|
||||
|
||||
case DRI_STRING:
|
||||
XSTRDUP(optval->_string, opt->value._string);
|
||||
break;
|
||||
|
||||
case DRI_SECTION:
|
||||
unreachable("handled above");
|
||||
}
|
||||
|
||||
/* Built-in default values should always be valid. */
|
||||
assert(checkValue(optval, optinfo));
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
|
||||
{
|
||||
char *str = ralloc_strdup(NULL,
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n" \
|
||||
"<!DOCTYPE driinfo [\n" \
|
||||
" <!ELEMENT driinfo (section*)>\n" \
|
||||
" <!ELEMENT section (description+, option+)>\n" \
|
||||
" <!ELEMENT description (enum*)>\n" \
|
||||
" <!ATTLIST description lang CDATA #FIXED \"en\"\n" \
|
||||
" text CDATA #REQUIRED>\n" \
|
||||
" <!ELEMENT option (description+)>\n" \
|
||||
" <!ATTLIST option name CDATA #REQUIRED\n" \
|
||||
" type (bool|enum|int|float) #REQUIRED\n" \
|
||||
" default CDATA #REQUIRED\n" \
|
||||
" valid CDATA #IMPLIED>\n" \
|
||||
" <!ELEMENT enum EMPTY>\n" \
|
||||
" <!ATTLIST enum value CDATA #REQUIRED\n" \
|
||||
" text CDATA #REQUIRED>\n" \
|
||||
"]>" \
|
||||
"<driinfo>\n");
|
||||
|
||||
bool in_section = false;
|
||||
for (int o = 0; o < numOptions; o++) {
|
||||
const driOptionDescription *opt = &configOptions[o];
|
||||
|
||||
const char *name = opt->info.name;
|
||||
const char *types[] = {
|
||||
[DRI_BOOL] = "bool",
|
||||
[DRI_INT] = "int",
|
||||
[DRI_FLOAT] = "float",
|
||||
[DRI_ENUM] = "enum",
|
||||
[DRI_STRING] = "string",
|
||||
};
|
||||
|
||||
if (opt->info.type == DRI_SECTION) {
|
||||
if (in_section)
|
||||
ralloc_asprintf_append(&str, " </section>\n");
|
||||
|
||||
ralloc_asprintf_append(&str,
|
||||
" <section>\n"
|
||||
" <description lang=\"en\" text=\"%s\"/>\n",
|
||||
opt->desc);
|
||||
|
||||
in_section = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str,
|
||||
" <option name=\"%s\" type=\"%s\" default=\"",
|
||||
name,
|
||||
types[opt->info.type]);
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_BOOL:
|
||||
ralloc_asprintf_append(&str, opt->value._bool ? "true" : "false");
|
||||
break;
|
||||
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
ralloc_asprintf_append(&str, "%d", opt->value._int);
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
ralloc_asprintf_append(&str, "%f", opt->value._float);
|
||||
break;
|
||||
|
||||
case DRI_STRING:
|
||||
ralloc_asprintf_append(&str, "%s", opt->value._string);
|
||||
break;
|
||||
|
||||
case DRI_SECTION:
|
||||
unreachable("handled above");
|
||||
break;
|
||||
}
|
||||
ralloc_asprintf_append(&str, "\"");
|
||||
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
if (opt->info.range.start._int < opt->info.range.end._int) {
|
||||
ralloc_asprintf_append(&str, " valid=\"%d:%d\"",
|
||||
opt->info.range.start._int,
|
||||
opt->info.range.end._int);
|
||||
}
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
if (opt->info.range.start._float < opt->info.range.end._float) {
|
||||
ralloc_asprintf_append(&str, " valid=\"%f:%f\"",
|
||||
opt->info.range.start._float,
|
||||
opt->info.range.end._float);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str, ">\n"); /* end of <option> */
|
||||
|
||||
|
||||
ralloc_asprintf_append(&str, " <description lang=\"en\" text=\"%s\"%s>\n",
|
||||
opt->desc, opt->info.type != DRI_ENUM ? "/" : "");
|
||||
|
||||
if (opt->info.type == DRI_ENUM) {
|
||||
for (int i = 0; i < ARRAY_SIZE(opt->enums) && opt->enums[i].desc; i++) {
|
||||
ralloc_asprintf_append(&str, " <enum value=\"%d\" text=\"%s\"/>\n",
|
||||
opt->enums[i].value, opt->enums[i].desc);
|
||||
}
|
||||
ralloc_asprintf_append(&str, " </description>\n");
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str, " </option>\n");
|
||||
}
|
||||
|
||||
assert(in_section);
|
||||
ralloc_asprintf_append(&str, " </section>\n");
|
||||
|
||||
ralloc_asprintf_append(&str, "</driinfo>\n");
|
||||
|
||||
char *output = strdup(str);
|
||||
ralloc_free(str);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if WITH_XMLCONFIG
|
||||
|
||||
static bool
|
||||
be_verbose(void)
|
||||
{
|
||||
|
@ -327,102 +71,6 @@ be_verbose(void)
|
|||
return strstr(s, "silent") == NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print message to \c stderr if the \c LIBGL_DEBUG environment variable
|
||||
* is set.
|
||||
*
|
||||
* Is called from the drivers.
|
||||
*
|
||||
* \param f \c printf like format string.
|
||||
*/
|
||||
static void
|
||||
__driUtilMessage(const char *f, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char *libgl_debug;
|
||||
|
||||
libgl_debug=getenv("LIBGL_DEBUG");
|
||||
if (libgl_debug && !strstr(libgl_debug, "quiet")) {
|
||||
fprintf(stderr, "libGL: ");
|
||||
va_start(args, f);
|
||||
vfprintf(stderr, f, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Output a warning message. */
|
||||
#define XML_WARNING1(msg) do { \
|
||||
__driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser)); \
|
||||
} while (0)
|
||||
#define XML_WARNING(msg, ...) do { \
|
||||
__driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
/** \brief Output an error message. */
|
||||
#define XML_ERROR1(msg) do { \
|
||||
__driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser)); \
|
||||
} while (0)
|
||||
#define XML_ERROR(msg, ...) do { \
|
||||
__driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/** \brief Parser context for configuration files. */
|
||||
struct OptConfData {
|
||||
const char *name;
|
||||
XML_Parser parser;
|
||||
driOptionCache *cache;
|
||||
int screenNum;
|
||||
const char *driverName, *execName;
|
||||
const char *kernelDriverName;
|
||||
const char *engineName;
|
||||
const char *applicationName;
|
||||
uint32_t engineVersion;
|
||||
uint32_t applicationVersion;
|
||||
uint32_t ignoringDevice;
|
||||
uint32_t ignoringApp;
|
||||
uint32_t inDriConf;
|
||||
uint32_t inDevice;
|
||||
uint32_t inApp;
|
||||
uint32_t inOption;
|
||||
};
|
||||
|
||||
/** \brief Elements in configuration files. */
|
||||
enum OptConfElem {
|
||||
OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_ENGINE, OC_OPTION, OC_COUNT
|
||||
};
|
||||
static const char *OptConfElems[] = {
|
||||
[OC_APPLICATION] = "application",
|
||||
[OC_DEVICE] = "device",
|
||||
[OC_DRICONF] = "driconf",
|
||||
[OC_ENGINE] = "engine",
|
||||
[OC_OPTION] = "option",
|
||||
};
|
||||
|
||||
static int compare(const void *a, const void *b) {
|
||||
return strcmp(*(char *const*)a, *(char *const*)b);
|
||||
}
|
||||
/** \brief Binary search in a string array. */
|
||||
static uint32_t
|
||||
bsearchStr(const char *name, const char *elems[], uint32_t count)
|
||||
{
|
||||
const char **found;
|
||||
found = bsearch(&name, elems, count, sizeof(char *), compare);
|
||||
if (found)
|
||||
return found - elems;
|
||||
else
|
||||
return count;
|
||||
}
|
||||
|
||||
/** \brief Locale-independent integer parser.
|
||||
*
|
||||
* Works similar to strtol. Leading space is NOT skipped. The input
|
||||
|
@ -602,6 +250,376 @@ parseValue(driOptionValue *v, driOptionType type, const char *string)
|
|||
return true;
|
||||
}
|
||||
|
||||
/** \brief Find an option in an option cache with the name as key */
|
||||
static uint32_t
|
||||
findOption(const driOptionCache *cache, const char *name)
|
||||
{
|
||||
uint32_t len = strlen(name);
|
||||
uint32_t size = 1 << cache->tableSize, mask = size - 1;
|
||||
uint32_t hash = 0;
|
||||
uint32_t i, shift;
|
||||
|
||||
/* compute a hash from the variable length name */
|
||||
for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31)
|
||||
hash += (uint32_t)name[i] << shift;
|
||||
hash *= hash;
|
||||
hash = (hash >> (16-cache->tableSize/2)) & mask;
|
||||
|
||||
/* this is just the starting point of the linear search for the option */
|
||||
for (i = 0; i < size; ++i, hash = (hash+1) & mask) {
|
||||
/* if we hit an empty entry then the option is not defined (yet) */
|
||||
if (cache->info[hash].name == 0)
|
||||
break;
|
||||
else if (!strcmp(name, cache->info[hash].name))
|
||||
break;
|
||||
}
|
||||
/* this assertion fails if the hash table is full */
|
||||
assert (i < size);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** \brief Like strdup with error checking. */
|
||||
#define XSTRDUP(dest,source) do { \
|
||||
if (!(dest = strdup(source))) { \
|
||||
fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** \brief Check if a value is in info->range. */
|
||||
UNUSED static bool
|
||||
checkValue(const driOptionValue *v, const driOptionInfo *info)
|
||||
{
|
||||
switch (info->type) {
|
||||
case DRI_ENUM: /* enum is just a special integer */
|
||||
case DRI_INT:
|
||||
return (info->range.start._int == info->range.end._int ||
|
||||
(v->_int >= info->range.start._int &&
|
||||
v->_int <= info->range.end._int));
|
||||
|
||||
case DRI_FLOAT:
|
||||
return (info->range.start._float == info->range.end._float ||
|
||||
(v->_float >= info->range.start._float &&
|
||||
v->_float <= info->range.end._float));
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
driParseOptionInfo(driOptionCache *info,
|
||||
const driOptionDescription *configOptions,
|
||||
unsigned numOptions)
|
||||
{
|
||||
/* Make the hash table big enough to fit more than the maximum number of
|
||||
* config options we've ever seen in a driver.
|
||||
*/
|
||||
info->tableSize = 6;
|
||||
info->info = calloc(1 << info->tableSize, sizeof(driOptionInfo));
|
||||
info->values = calloc(1 << info->tableSize, sizeof(driOptionValue));
|
||||
if (info->info == NULL || info->values == NULL) {
|
||||
fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
|
||||
abort();
|
||||
}
|
||||
|
||||
UNUSED bool in_section = false;
|
||||
for (int o = 0; o < numOptions; o++) {
|
||||
const driOptionDescription *opt = &configOptions[o];
|
||||
|
||||
if (opt->info.type == DRI_SECTION) {
|
||||
in_section = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* for driconf xml generation, options must always be preceded by a
|
||||
* DRI_CONF_SECTION
|
||||
*/
|
||||
assert(in_section);
|
||||
|
||||
const char *name = opt->info.name;
|
||||
int i = findOption(info, name);
|
||||
driOptionInfo *optinfo = &info->info[i];
|
||||
driOptionValue *optval = &info->values[i];
|
||||
|
||||
assert(!optinfo->name); /* No duplicate options in your list. */
|
||||
|
||||
optinfo->type = opt->info.type;
|
||||
optinfo->range = opt->info.range;
|
||||
XSTRDUP(optinfo->name, name);
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_BOOL:
|
||||
optval->_bool = opt->value._bool;
|
||||
break;
|
||||
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
optval->_int = opt->value._int;
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
optval->_float = opt->value._float;
|
||||
break;
|
||||
|
||||
case DRI_STRING:
|
||||
XSTRDUP(optval->_string, opt->value._string);
|
||||
break;
|
||||
|
||||
case DRI_SECTION:
|
||||
unreachable("handled above");
|
||||
}
|
||||
|
||||
/* Built-in default values should always be valid. */
|
||||
assert(checkValue(optval, optinfo));
|
||||
|
||||
char *envVal = getenv(name);
|
||||
if (envVal != NULL) {
|
||||
driOptionValue v;
|
||||
if (parseValue(&v, opt->info.type, envVal) &&
|
||||
checkValue(&v, optinfo)) {
|
||||
/* don't use XML_WARNING, we want the user to see this! */
|
||||
if (be_verbose()) {
|
||||
fprintf(stderr,
|
||||
"ATTENTION: default value of option %s overridden by environment.\n",
|
||||
name);
|
||||
}
|
||||
*optval = v;
|
||||
} else {
|
||||
fprintf(stderr, "illegal environment value for %s: \"%s\". Ignoring.\n",
|
||||
name, envVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
|
||||
{
|
||||
char *str = ralloc_strdup(NULL,
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n" \
|
||||
"<!DOCTYPE driinfo [\n" \
|
||||
" <!ELEMENT driinfo (section*)>\n" \
|
||||
" <!ELEMENT section (description+, option+)>\n" \
|
||||
" <!ELEMENT description (enum*)>\n" \
|
||||
" <!ATTLIST description lang CDATA #FIXED \"en\"\n" \
|
||||
" text CDATA #REQUIRED>\n" \
|
||||
" <!ELEMENT option (description+)>\n" \
|
||||
" <!ATTLIST option name CDATA #REQUIRED\n" \
|
||||
" type (bool|enum|int|float) #REQUIRED\n" \
|
||||
" default CDATA #REQUIRED\n" \
|
||||
" valid CDATA #IMPLIED>\n" \
|
||||
" <!ELEMENT enum EMPTY>\n" \
|
||||
" <!ATTLIST enum value CDATA #REQUIRED\n" \
|
||||
" text CDATA #REQUIRED>\n" \
|
||||
"]>" \
|
||||
"<driinfo>\n");
|
||||
|
||||
bool in_section = false;
|
||||
for (int o = 0; o < numOptions; o++) {
|
||||
const driOptionDescription *opt = &configOptions[o];
|
||||
|
||||
const char *name = opt->info.name;
|
||||
const char *types[] = {
|
||||
[DRI_BOOL] = "bool",
|
||||
[DRI_INT] = "int",
|
||||
[DRI_FLOAT] = "float",
|
||||
[DRI_ENUM] = "enum",
|
||||
[DRI_STRING] = "string",
|
||||
};
|
||||
|
||||
if (opt->info.type == DRI_SECTION) {
|
||||
if (in_section)
|
||||
ralloc_asprintf_append(&str, " </section>\n");
|
||||
|
||||
ralloc_asprintf_append(&str,
|
||||
" <section>\n"
|
||||
" <description lang=\"en\" text=\"%s\"/>\n",
|
||||
opt->desc);
|
||||
|
||||
in_section = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str,
|
||||
" <option name=\"%s\" type=\"%s\" default=\"",
|
||||
name,
|
||||
types[opt->info.type]);
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_BOOL:
|
||||
ralloc_asprintf_append(&str, opt->value._bool ? "true" : "false");
|
||||
break;
|
||||
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
ralloc_asprintf_append(&str, "%d", opt->value._int);
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
ralloc_asprintf_append(&str, "%f", opt->value._float);
|
||||
break;
|
||||
|
||||
case DRI_STRING:
|
||||
ralloc_asprintf_append(&str, "%s", opt->value._string);
|
||||
break;
|
||||
|
||||
case DRI_SECTION:
|
||||
unreachable("handled above");
|
||||
break;
|
||||
}
|
||||
ralloc_asprintf_append(&str, "\"");
|
||||
|
||||
|
||||
switch (opt->info.type) {
|
||||
case DRI_INT:
|
||||
case DRI_ENUM:
|
||||
if (opt->info.range.start._int < opt->info.range.end._int) {
|
||||
ralloc_asprintf_append(&str, " valid=\"%d:%d\"",
|
||||
opt->info.range.start._int,
|
||||
opt->info.range.end._int);
|
||||
}
|
||||
break;
|
||||
|
||||
case DRI_FLOAT:
|
||||
if (opt->info.range.start._float < opt->info.range.end._float) {
|
||||
ralloc_asprintf_append(&str, " valid=\"%f:%f\"",
|
||||
opt->info.range.start._float,
|
||||
opt->info.range.end._float);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str, ">\n"); /* end of <option> */
|
||||
|
||||
|
||||
ralloc_asprintf_append(&str, " <description lang=\"en\" text=\"%s\"%s>\n",
|
||||
opt->desc, opt->info.type != DRI_ENUM ? "/" : "");
|
||||
|
||||
if (opt->info.type == DRI_ENUM) {
|
||||
for (int i = 0; i < ARRAY_SIZE(opt->enums) && opt->enums[i].desc; i++) {
|
||||
ralloc_asprintf_append(&str, " <enum value=\"%d\" text=\"%s\"/>\n",
|
||||
opt->enums[i].value, opt->enums[i].desc);
|
||||
}
|
||||
ralloc_asprintf_append(&str, " </description>\n");
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&str, " </option>\n");
|
||||
}
|
||||
|
||||
assert(in_section);
|
||||
ralloc_asprintf_append(&str, " </section>\n");
|
||||
|
||||
ralloc_asprintf_append(&str, "</driinfo>\n");
|
||||
|
||||
char *output = strdup(str);
|
||||
ralloc_free(str);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#if WITH_XMLCONFIG
|
||||
|
||||
/**
|
||||
* Print message to \c stderr if the \c LIBGL_DEBUG environment variable
|
||||
* is set.
|
||||
*
|
||||
* Is called from the drivers.
|
||||
*
|
||||
* \param f \c printf like format string.
|
||||
*/
|
||||
static void
|
||||
__driUtilMessage(const char *f, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char *libgl_debug;
|
||||
|
||||
libgl_debug=getenv("LIBGL_DEBUG");
|
||||
if (libgl_debug && !strstr(libgl_debug, "quiet")) {
|
||||
fprintf(stderr, "libGL: ");
|
||||
va_start(args, f);
|
||||
vfprintf(stderr, f, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Output a warning message. */
|
||||
#define XML_WARNING1(msg) do { \
|
||||
__driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser)); \
|
||||
} while (0)
|
||||
#define XML_WARNING(msg, ...) do { \
|
||||
__driUtilMessage("Warning in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
/** \brief Output an error message. */
|
||||
#define XML_ERROR1(msg) do { \
|
||||
__driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser)); \
|
||||
} while (0)
|
||||
#define XML_ERROR(msg, ...) do { \
|
||||
__driUtilMessage("Error in %s line %d, column %d: "msg, data->name, \
|
||||
(int) XML_GetCurrentLineNumber(data->parser), \
|
||||
(int) XML_GetCurrentColumnNumber(data->parser), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/** \brief Parser context for configuration files. */
|
||||
struct OptConfData {
|
||||
const char *name;
|
||||
XML_Parser parser;
|
||||
driOptionCache *cache;
|
||||
int screenNum;
|
||||
const char *driverName, *execName;
|
||||
const char *kernelDriverName;
|
||||
const char *engineName;
|
||||
const char *applicationName;
|
||||
uint32_t engineVersion;
|
||||
uint32_t applicationVersion;
|
||||
uint32_t ignoringDevice;
|
||||
uint32_t ignoringApp;
|
||||
uint32_t inDriConf;
|
||||
uint32_t inDevice;
|
||||
uint32_t inApp;
|
||||
uint32_t inOption;
|
||||
};
|
||||
|
||||
/** \brief Elements in configuration files. */
|
||||
enum OptConfElem {
|
||||
OC_APPLICATION = 0, OC_DEVICE, OC_DRICONF, OC_ENGINE, OC_OPTION, OC_COUNT
|
||||
};
|
||||
static const char *OptConfElems[] = {
|
||||
[OC_APPLICATION] = "application",
|
||||
[OC_DEVICE] = "device",
|
||||
[OC_DRICONF] = "driconf",
|
||||
[OC_ENGINE] = "engine",
|
||||
[OC_OPTION] = "option",
|
||||
};
|
||||
|
||||
static int compare(const void *a, const void *b) {
|
||||
return strcmp(*(char *const*)a, *(char *const*)b);
|
||||
}
|
||||
/** \brief Binary search in a string array. */
|
||||
static uint32_t
|
||||
bsearchStr(const char *name, const char *elems[], uint32_t count)
|
||||
{
|
||||
const char **found;
|
||||
found = bsearch(&name, elems, count, sizeof(char *), compare);
|
||||
if (found)
|
||||
return found - elems;
|
||||
else
|
||||
return count;
|
||||
}
|
||||
|
||||
/** \brief Parse a list of ranges of type info->type. */
|
||||
static unsigned char
|
||||
parseRange(driOptionInfo *info, const char *string)
|
||||
|
|
Loading…
Reference in New Issue