diff --git a/src/util/xmlconfig.c b/src/util/xmlconfig.c index b00ae109eb7..5e6c49d2a96 100644 --- a/src/util/xmlconfig.c +++ b/src/util/xmlconfig.c @@ -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, - "\n" \ - "\n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - "]>" \ - "\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, " \n"); - - ralloc_asprintf_append(&str, - "
\n" - " \n", - opt->desc); - - in_section = true; - continue; - } - - ralloc_asprintf_append(&str, - " \n"); - } - - assert(in_section); - ralloc_asprintf_append(&str, "
\n"); - - ralloc_asprintf_append(&str, "
\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, + "\n" \ + "\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + "]>" \ + "\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, " \n"); + + ralloc_asprintf_append(&str, + "
\n" + " \n", + opt->desc); + + in_section = true; + continue; + } + + ralloc_asprintf_append(&str, + " \n"); + } + + assert(in_section); + ralloc_asprintf_append(&str, "
\n"); + + ralloc_asprintf_append(&str, "
\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)