android: Disable the user XML config parsing.
authorEric Anholt <eric@anholt.net>
Tue, 29 Sep 2020 16:37:50 +0000 (09:37 -0700)
committerMarge Bot <eric+marge@anholt.net>
Fri, 2 Oct 2020 23:59:52 +0000 (23:59 +0000)
The android platform is not interested in this feature of Mesa.  There are
currently workarounds for apps on Android, and no support for it in the
xmlconfig code.  Even if there we do need workarounds eventually, we'll
want to bake them in as structs rather than have this awkward external
dependency for parsing user-readable data installed by Mesa for
Mesa-internal details.

This gets rid of the expat dependency in the turnip driver.

Note that rather than have more #ifdefs in the file, I've opted to move
the code to have more logical locations since the structs refactor had
left less-used helpers scattered across the file.

Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6916>

src/util/meson.build
src/util/xmlconfig.c

index 3174c85..e1a820c 100644 (file)
@@ -196,11 +196,16 @@ idep_mesautil = declare_dependency(
   dependencies : [dep_zlib, dep_clock, dep_thread, dep_atomic, dep_m],
 )
 
+xmlconfig_deps = []
+if not with_platform_android
+  xmlconfig_deps += dep_expat
+endif
+
 _libxmlconfig = static_library(
   'xmlconfig',
   files_xmlconfig,
   include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux],
-  dependencies : [idep_mesautil, dep_expat, dep_m],
+  dependencies : [idep_mesautil, dep_m, xmlconfig_deps],
   c_args : [
     c_msvc_compat_args,
     '-DSYSCONFDIR="@0@"'.format(
@@ -215,7 +220,7 @@ _libxmlconfig = static_library(
 )
 
 idep_xmlconfig = declare_dependency(
-  dependencies : dep_expat,
+  dependencies : xmlconfig_deps,
   link_with : _libxmlconfig,
 )
 
index 9cbbf2c..b54fd10 100644 (file)
  * \author Felix Kuehling
  */
 
+#ifdef ANDROID
+#define WITH_XMLCONFIG 0
+#else
+#define WITH_XMLCONFIG 1
+#endif
+
 #include <limits.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -35,7 +41,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#if WITH_XMLCONFIG
 #include <expat.h>
+#endif
 #include <fcntl.h>
 #include <math.h>
 #include <unistd.h>
 #define PATH_MAX 4096
 #endif
 
-static bool
-be_verbose(void)
-{
-   const char *s = getenv("MESA_DEBUG");
-   if (!s)
-      return true;
-
-   return strstr(s, "silent") == NULL;
-}
-
 /** \brief Find an option in an option cache with the name as key */
 static uint32_t
 findOption(const driOptionCache *cache, const char *name)
@@ -100,230 +98,6 @@ findOption(const driOptionCache *cache, const char *name)
       }                                                                 \
    } while (0)
 
-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
- * number may have an optional sign. Radix is specified by base. If
- * base is 0 then decimal is assumed unless the input number is
- * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
- * returning tail points to the first character that is not part of
- * the integer number. If no number was found then tail points to the
- * start of the input string. */
-static int
-strToI(const char *string, const char **tail, int base)
-{
-   int radix = base == 0 ? 10 : base;
-   int result = 0;
-   int sign = 1;
-   bool numberFound = false;
-   const char *start = string;
-
-   assert(radix >= 2 && radix <= 36);
-
-   if (*string == '-') {
-      sign = -1;
-      string++;
-   } else if (*string == '+')
-      string++;
-   if (base == 0 && *string == '0') {
-      numberFound = true;
-      if (*(string+1) == 'x' || *(string+1) == 'X') {
-         radix = 16;
-         string += 2;
-      } else {
-         radix = 8;
-         string++;
-      }
-   }
-   do {
-      int digit = -1;
-      if (radix <= 10) {
-         if (*string >= '0' && *string < '0' + radix)
-            digit = *string - '0';
-      } else {
-         if (*string >= '0' && *string <= '9')
-            digit = *string - '0';
-         else if (*string >= 'a' && *string < 'a' + radix - 10)
-            digit = *string - 'a' + 10;
-         else if (*string >= 'A' && *string < 'A' + radix - 10)
-            digit = *string - 'A' + 10;
-      }
-      if (digit != -1) {
-         numberFound = true;
-         result = radix*result + digit;
-         string++;
-      } else
-         break;
-   } while (true);
-   *tail = numberFound ? string : start;
-   return sign * result;
-}
-
-/** \brief Locale-independent floating-point parser.
- *
- * Works similar to strtod. Leading space is NOT skipped. The input
- * number may have an optional sign. '.' is interpreted as decimal
- * point and may occur at most once. Optionally the number may end in
- * [eE]<exponent>, where <exponent> is an integer as recognized by
- * strToI. In that case the result is number * 10^exponent. After
- * returning tail points to the first character that is not part of
- * the floating point number. If no number was found then tail points
- * to the start of the input string.
- *
- * Uses two passes for maximum accuracy. */
-static float
-strToF(const char *string, const char **tail)
-{
-   int nDigits = 0, pointPos, exponent;
-   float sign = 1.0f, result = 0.0f, scale;
-   const char *start = string, *numStart;
-
-   /* sign */
-   if (*string == '-') {
-      sign = -1.0f;
-      string++;
-   } else if (*string == '+')
-      string++;
-
-   /* first pass: determine position of decimal point, number of
-    * digits, exponent and the end of the number. */
-   numStart = string;
-   while (*string >= '0' && *string <= '9') {
-      string++;
-      nDigits++;
-   }
-   pointPos = nDigits;
-   if (*string == '.') {
-      string++;
-      while (*string >= '0' && *string <= '9') {
-         string++;
-         nDigits++;
-      }
-   }
-   if (nDigits == 0) {
-      /* no digits, no number */
-      *tail = start;
-      return 0.0f;
-   }
-   *tail = string;
-   if (*string == 'e' || *string == 'E') {
-      const char *expTail;
-      exponent = strToI(string+1, &expTail, 10);
-      if (expTail == string+1)
-         exponent = 0;
-      else
-         *tail = expTail;
-   } else
-      exponent = 0;
-   string = numStart;
-
-   /* scale of the first digit */
-   scale = sign * (float)pow(10.0, (double)(pointPos-1 + exponent));
-
-   /* second pass: parse digits */
-   do {
-      if (*string != '.') {
-         assert(*string >= '0' && *string <= '9');
-         result += scale * (float)(*string - '0');
-         scale *= 0.1f;
-         nDigits--;
-      }
-      string++;
-   } while (nDigits > 0);
-
-   return result;
-}
-
-/** \brief Parse a value of a given type. */
-static unsigned char
-parseValue(driOptionValue *v, driOptionType type, const char *string)
-{
-   const char *tail = NULL;
-   /* skip leading white-space */
-   string += strspn(string, " \f\n\r\t\v");
-   switch (type) {
-   case DRI_BOOL:
-      if (!strcmp(string, "false")) {
-         v->_bool = false;
-         tail = string + 5;
-      } else if (!strcmp(string, "true")) {
-         v->_bool = true;
-         tail = string + 4;
-      }
-      else
-         return false;
-      break;
-   case DRI_ENUM: /* enum is just a special integer */
-   case DRI_INT:
-      v->_int = strToI(string, &tail, 0);
-      break;
-   case DRI_FLOAT:
-      v->_float = strToF(string, &tail);
-      break;
-   case DRI_STRING:
-      free(v->_string);
-      v->_string = strndup(string, STRING_CONF_MAXLEN);
-      return true;
-   case DRI_SECTION:
-      unreachable("shouldn't be parsing values in section declarations");
-   }
-
-   if (tail == string)
-      return false; /* empty string (or containing only white-space) */
-   /* skip trailing white space */
-   if (*tail)
-      tail += strspn(tail, " \f\n\r\t\v");
-   if (*tail)
-      return false; /* something left over that is not part of value */
-
-   return true;
-}
-
-/** \brief Parse a list of ranges of type info->type. */
-static unsigned char
-parseRange(driOptionInfo *info, const char *string)
-{
-   char *cp;
-
-   XSTRDUP(cp, string);
-
-   char *sep;
-   sep = strchr(cp, ':');
-   if (!sep) {
-      free(cp);
-      return false;
-   }
-
-   *sep = '\0';
-   if (!parseValue(&info->range.start, info->type, cp) ||
-       !parseValue(&info->range.end, info->type, sep+1))
-      return false;
-   if (info->type == DRI_INT &&
-       info->range.start._int >= info->range.end._int)
-      return false;
-   if (info->type == DRI_FLOAT &&
-       info->range.start._float >= info->range.end._float)
-      return false;
-
-   free(cp);
-   return true;
-}
-
 /** \brief Check if a value is in info->range. */
 UNUSED static bool
 checkValue(const driOptionValue *v, const driOptionInfo *info)
@@ -341,59 +115,10 @@ checkValue(const driOptionValue *v, const driOptionInfo *info)
                v->_float <= info->range.end._float));
 
    default:
-      return true;
-   }
-}
-
-/**
- * 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");
+      return true;
    }
 }
 
-/** \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)
-
 void
 driParseOptionInfo(driOptionCache *info,
                    const driOptionDescription *configOptions,
@@ -523,103 +248,388 @@ driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
          ralloc_asprintf_append(&str, "%d", opt->value._int);
          break;
 
-      case DRI_FLOAT:
-         ralloc_asprintf_append(&str, "%f", opt->value._float);
-         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)
+{
+   const char *s = getenv("MESA_DEBUG");
+   if (!s)
+      return true;
+
+   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
+ * number may have an optional sign. Radix is specified by base. If
+ * base is 0 then decimal is assumed unless the input number is
+ * prefixed by 0x or 0X for hexadecimal or 0 for octal. After
+ * returning tail points to the first character that is not part of
+ * the integer number. If no number was found then tail points to the
+ * start of the input string. */
+static int
+strToI(const char *string, const char **tail, int base)
+{
+   int radix = base == 0 ? 10 : base;
+   int result = 0;
+   int sign = 1;
+   bool numberFound = false;
+   const char *start = string;
+
+   assert(radix >= 2 && radix <= 36);
+
+   if (*string == '-') {
+      sign = -1;
+      string++;
+   } else if (*string == '+')
+      string++;
+   if (base == 0 && *string == '0') {
+      numberFound = true;
+      if (*(string+1) == 'x' || *(string+1) == 'X') {
+         radix = 16;
+         string += 2;
+      } else {
+         radix = 8;
+         string++;
+      }
+   }
+   do {
+      int digit = -1;
+      if (radix <= 10) {
+         if (*string >= '0' && *string < '0' + radix)
+            digit = *string - '0';
+      } else {
+         if (*string >= '0' && *string <= '9')
+            digit = *string - '0';
+         else if (*string >= 'a' && *string < 'a' + radix - 10)
+            digit = *string - 'a' + 10;
+         else if (*string >= 'A' && *string < 'A' + radix - 10)
+            digit = *string - 'A' + 10;
+      }
+      if (digit != -1) {
+         numberFound = true;
+         result = radix*result + digit;
+         string++;
+      } else
+         break;
+   } while (true);
+   *tail = numberFound ? string : start;
+   return sign * result;
+}
+
+/** \brief Locale-independent floating-point parser.
+ *
+ * Works similar to strtod. Leading space is NOT skipped. The input
+ * number may have an optional sign. '.' is interpreted as decimal
+ * point and may occur at most once. Optionally the number may end in
+ * [eE]<exponent>, where <exponent> is an integer as recognized by
+ * strToI. In that case the result is number * 10^exponent. After
+ * returning tail points to the first character that is not part of
+ * the floating point number. If no number was found then tail points
+ * to the start of the input string.
+ *
+ * Uses two passes for maximum accuracy. */
+static float
+strToF(const char *string, const char **tail)
+{
+   int nDigits = 0, pointPos, exponent;
+   float sign = 1.0f, result = 0.0f, scale;
+   const char *start = string, *numStart;
 
-      case DRI_STRING:
-         ralloc_asprintf_append(&str, "%s", opt->value._string);
-         break;
+   /* sign */
+   if (*string == '-') {
+      sign = -1.0f;
+      string++;
+   } else if (*string == '+')
+      string++;
 
-      case DRI_SECTION:
-         unreachable("handled above");
-         break;
+   /* first pass: determine position of decimal point, number of
+    * digits, exponent and the end of the number. */
+   numStart = string;
+   while (*string >= '0' && *string <= '9') {
+      string++;
+      nDigits++;
+   }
+   pointPos = nDigits;
+   if (*string == '.') {
+      string++;
+      while (*string >= '0' && *string <= '9') {
+         string++;
+         nDigits++;
       }
-      ralloc_asprintf_append(&str, "\"");
+   }
+   if (nDigits == 0) {
+      /* no digits, no number */
+      *tail = start;
+      return 0.0f;
+   }
+   *tail = string;
+   if (*string == 'e' || *string == 'E') {
+      const char *expTail;
+      exponent = strToI(string+1, &expTail, 10);
+      if (expTail == string+1)
+         exponent = 0;
+      else
+         *tail = expTail;
+   } else
+      exponent = 0;
+   string = numStart;
 
+   /* scale of the first digit */
+   scale = sign * (float)pow(10.0, (double)(pointPos-1 + exponent));
 
-      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;
+   /* second pass: parse digits */
+   do {
+      if (*string != '.') {
+         assert(*string >= '0' && *string <= '9');
+         result += scale * (float)(*string - '0');
+         scale *= 0.1f;
+         nDigits--;
+      }
+      string++;
+   } while (nDigits > 0);
 
-      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;
+   return result;
+}
 
-      default:
-         break;
+/** \brief Parse a value of a given type. */
+static unsigned char
+parseValue(driOptionValue *v, driOptionType type, const char *string)
+{
+   const char *tail = NULL;
+   /* skip leading white-space */
+   string += strspn(string, " \f\n\r\t\v");
+   switch (type) {
+   case DRI_BOOL:
+      if (!strcmp(string, "false")) {
+         v->_bool = false;
+         tail = string + 5;
+      } else if (!strcmp(string, "true")) {
+         v->_bool = true;
+         tail = string + 4;
       }
+      else
+         return false;
+      break;
+   case DRI_ENUM: /* enum is just a special integer */
+   case DRI_INT:
+      v->_int = strToI(string, &tail, 0);
+      break;
+   case DRI_FLOAT:
+      v->_float = strToF(string, &tail);
+      break;
+   case DRI_STRING:
+      free(v->_string);
+      v->_string = strndup(string, STRING_CONF_MAXLEN);
+      return true;
+   case DRI_SECTION:
+      unreachable("shouldn't be parsing values in section declarations");
+   }
 
-      ralloc_asprintf_append(&str, ">\n"); /* end of <option> */
+   if (tail == string)
+      return false; /* empty string (or containing only white-space) */
+   /* skip trailing white space */
+   if (*tail)
+      tail += strspn(tail, " \f\n\r\t\v");
+   if (*tail)
+      return false; /* something left over that is not part of value */
 
+   return true;
+}
 
-      ralloc_asprintf_append(&str, "        <description lang=\"en\" text=\"%s\"%s>\n",
-                             opt->desc, opt->info.type != DRI_ENUM ? "/" : "");
+/** \brief Parse a list of ranges of type info->type. */
+static unsigned char
+parseRange(driOptionInfo *info, const char *string)
+{
+   char *cp;
 
-      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");
-      }
+   XSTRDUP(cp, string);
 
-      ralloc_asprintf_append(&str, "      </option>\n");
+   char *sep;
+   sep = strchr(cp, ':');
+   if (!sep) {
+      free(cp);
+      return false;
    }
 
-   assert(in_section);
-   ralloc_asprintf_append(&str, "  </section>\n");
-
-   ralloc_asprintf_append(&str, "</driinfo>\n");
-
-   char *output = strdup(str);
-   ralloc_free(str);
+   *sep = '\0';
+   if (!parseValue(&info->range.start, info->type, cp) ||
+       !parseValue(&info->range.end, info->type, sep+1))
+      return false;
+   if (info->type == DRI_INT &&
+       info->range.start._int >= info->range.end._int)
+      return false;
+   if (info->type == DRI_FLOAT &&
+       info->range.start._float >= info->range.end._float)
+      return false;
 
-   return output;
+   free(cp);
+   return true;
 }
 
-/** \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",
-};
-
 /** \brief Parse attributes of a device element. */
 static void
 parseDeviceAttr(struct OptConfData *data, const char **attr)
@@ -861,26 +871,6 @@ optConfEndElem(void *userData, const char *name)
    }
 }
 
-/** \brief Initialize an option cache based on info */
-static void
-initOptionCache(driOptionCache *cache, const driOptionCache *info)
-{
-   unsigned i, size = 1 << info->tableSize;
-   cache->info = info->info;
-   cache->tableSize = info->tableSize;
-   cache->values = malloc((1<<info->tableSize) * sizeof(driOptionValue));
-   if (cache->values == NULL) {
-      fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
-      abort();
-   }
-   memcpy(cache->values, info->values,
-           (1<<info->tableSize) * sizeof(driOptionValue));
-   for (i = 0; i < size; ++i) {
-      if (cache->info[i].type == DRI_STRING)
-         XSTRDUP(cache->values[i]._string, info->values[i]._string);
-   }
-}
-
 static void
 _parseOneConfigFile(XML_Parser p)
 {
@@ -986,6 +976,27 @@ parseConfigDir(struct OptConfData *data, const char *dirname)
 
    free(entries);
 }
+#endif /* WITH_XMLCONFIG */
+
+/** \brief Initialize an option cache based on info */
+static void
+initOptionCache(driOptionCache *cache, const driOptionCache *info)
+{
+   unsigned i, size = 1 << info->tableSize;
+   cache->info = info->info;
+   cache->tableSize = info->tableSize;
+   cache->values = malloc((1<<info->tableSize) * sizeof(driOptionValue));
+   if (cache->values == NULL) {
+      fprintf(stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
+      abort();
+   }
+   memcpy(cache->values, info->values,
+           (1<<info->tableSize) * sizeof(driOptionValue));
+   for (i = 0; i < size; ++i) {
+      if (cache->info[i].type == DRI_STRING)
+         XSTRDUP(cache->values[i]._string, info->values[i]._string);
+   }
+}
 
 #ifndef SYSCONFDIR
 #define SYSCONFDIR "/etc"
@@ -1002,11 +1013,12 @@ driParseConfigFiles(driOptionCache *cache, const driOptionCache *info,
                     const char *applicationName, uint32_t applicationVersion,
                     const char *engineName, uint32_t engineVersion)
 {
+   initOptionCache(cache, info);
+
+#if WITH_XMLCONFIG
    char *home;
    struct OptConfData userData;
 
-   initOptionCache(cache, info);
-
    userData.cache = cache;
    userData.screenNum = screenNum;
    userData.driverName = driverName;
@@ -1026,6 +1038,7 @@ driParseConfigFiles(driOptionCache *cache, const driOptionCache *info,
       snprintf(filename, PATH_MAX, "%s/.drirc", home);
       parseOneConfigFile(&userData, filename);
    }
+#endif /* WITH_XMLCONFIG */
 }
 
 void