Merge branch '7.8'
[mesa.git] / src / mesa / drivers / dri / common / xmlconfig.c
index 887f720f0d9344fd573ef724c1fc4617678f7736..738b1ae97fd374d0caeeb2196becc861245d0dad 100644 (file)
@@ -27,7 +27,7 @@
  * \author Felix Kuehling
  */
 
-#include "glheader.h"
+#include "main/glheader.h"
 
 #include <string.h>
 #include <assert.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
-#include "imports.h"
-#include "dri_util.h"
+#include "main/imports.h"
+#include "utils.h"
 #include "xmlconfig.h"
 
-/*
- * OS dependent ways of getting the name of the running program
- */
-#if (defined(__unix__) || defined(unix)) && !defined(USG)
-#include <sys/param.h>
-#endif
-
 #undef GET_PROGRAM_NAME
 
-#if defined(__GNU_LIBRARY__) || defined(__GLIBC__)
+#if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__)
+#    if !defined(__GLIBC__) || (__GLIBC__ < 2)
+/* These aren't declared in any libc5 header */
+extern char *program_invocation_name, *program_invocation_short_name;
+#    endif
 #    define GET_PROGRAM_NAME() program_invocation_short_name
 #elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
 #    include <osreldate.h>
 #elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)
 #    include <stdlib.h>
 #    define GET_PROGRAM_NAME() getprogname()
+#elif defined(__sun)
+/* Solaris has getexecname() which returns the full path - return just
+   the basename to match BSD getprogname() */
+#    include <stdlib.h>
+#    include <libgen.h>
+#    define GET_PROGRAM_NAME() basename(getexecname())
 #endif
 
 #if !defined(GET_PROGRAM_NAME)
-#    if defined(OpenBSD) || defined(NetBSD)
-/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU. It's
+#    if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__)
+/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU.
+ * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's
  * used as a last resort, if there is no documented facility available. */
 static const char *__getProgramName () {
     extern const char *__progname;
-    return progname;
+    char * arg = strrchr(__progname, '/');
+    if (arg)
+        return arg+1;
+    else
+        return __progname;
 }
 #        define GET_PROGRAM_NAME() __getProgramName()
 #    else
 #        define GET_PROGRAM_NAME() ""
-#        warning "Per application configuration won't with your OS version work."
+#        warning "Per application configuration won't work with your OS version."
 #    endif
 #endif
 
@@ -137,10 +145,140 @@ static GLuint bsearchStr (const XML_Char *name,
        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 GLint strToI (const XML_Char *string, const XML_Char **tail, int base) {
+    GLint radix = base == 0 ? 10 : base;
+    GLint result = 0;
+    GLint sign = 1;
+    GLboolean numberFound = GL_FALSE;
+    const XML_Char *start = string;
+
+    assert (radix >= 2 && radix <= 36);
+
+    if (*string == '-') {
+       sign = -1;
+       string++;
+    } else if (*string == '+')
+       string++;
+    if (base == 0 && *string == '0') {
+       numberFound = GL_TRUE; 
+       if (*(string+1) == 'x' || *(string+1) == 'X') {
+           radix = 16;
+           string += 2;
+       } else {
+           radix = 8;
+           string++;
+       }
+    }
+    do {
+       GLint 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 = GL_TRUE;
+           result = radix*result + digit;
+           string++;
+       } else
+           break;
+    } while (GL_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 occor 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 GLfloat strToF (const XML_Char *string, const XML_Char **tail) {
+    GLint nDigits = 0, pointPos, exponent;
+    GLfloat sign = 1.0f, result = 0.0f, scale;
+    const XML_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 XML_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 * (GLfloat)pow (10.0, (GLdouble)(pointPos-1 + exponent));
+
+    /* second pass: parse digits */
+    do {
+       if (*string != '.') {
+           assert (*string >= '0' && *string <= '9');
+           result += scale * (GLfloat)(*string - '0');
+           scale *= 0.1f;
+           nDigits--;
+       }
+       string++;
+    } while (nDigits > 0);
+
+    return result;
+}
+
 /** \brief Parse a value of a given type. */
 static GLboolean parseValue (driOptionValue *v, driOptionType type,
                             const XML_Char *string) {
-    const XML_Char *tail;
+    const XML_Char *tail = NULL;
   /* skip leading white-space */
     string += strspn (string, " \f\n\r\t\v");
     switch (type) {
@@ -157,10 +295,10 @@ static GLboolean parseValue (driOptionValue *v, driOptionType type,
        break;
       case DRI_ENUM: /* enum is just a special integer */
       case DRI_INT:
-       v->_int = strtol (string, (char **)&tail, 0);
+       v->_int = strToI (string, &tail, 0);
        break;
       case DRI_FLOAT:
-       v->_float = strtod (string, (char **)&tail);
+       v->_float = strToF (string, &tail);
        break;
     }
 
@@ -264,40 +402,40 @@ static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info)
 /** \brief Output a warning message. */
 #define XML_WARNING1(msg) do {\
     __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
-                      XML_GetCurrentLineNumber(data->parser), \
-                      XML_GetCurrentColumnNumber(data->parser)); \
+                      (int) XML_GetCurrentLineNumber(data->parser), \
+                      (int) XML_GetCurrentColumnNumber(data->parser)); \
 } while (0)
 #define XML_WARNING(msg,args...) do { \
     __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \
-                      XML_GetCurrentLineNumber(data->parser), \
-                      XML_GetCurrentColumnNumber(data->parser), \
+                      (int) XML_GetCurrentLineNumber(data->parser), \
+                      (int) XML_GetCurrentColumnNumber(data->parser), \
                       args); \
 } while (0)
 /** \brief Output an error message. */
 #define XML_ERROR1(msg) do { \
     __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
-                      XML_GetCurrentLineNumber(data->parser), \
-                      XML_GetCurrentColumnNumber(data->parser)); \
+                      (int) XML_GetCurrentLineNumber(data->parser), \
+                      (int) XML_GetCurrentColumnNumber(data->parser)); \
 } while (0)
 #define XML_ERROR(msg,args...) do { \
     __driUtilMessage ("Error in %s line %d, column %d: "msg, data->name, \
-                      XML_GetCurrentLineNumber(data->parser), \
-                      XML_GetCurrentColumnNumber(data->parser), \
+                      (int) XML_GetCurrentLineNumber(data->parser), \
+                      (int) XML_GetCurrentColumnNumber(data->parser), \
                       args); \
 } while (0)
 /** \brief Output a fatal error message and abort. */
 #define XML_FATAL1(msg) do { \
     fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
              data->name, \
-             XML_GetCurrentLineNumber(data->parser), \
-             XML_GetCurrentColumnNumber(data->parser)); \
+             (int) XML_GetCurrentLineNumber(data->parser),     \
+             (int) XML_GetCurrentColumnNumber(data->parser)); \
     abort();\
 } while (0)
 #define XML_FATAL(msg,args...) do { \
     fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
              data->name, \
-             XML_GetCurrentLineNumber(data->parser), \
-             XML_GetCurrentColumnNumber(data->parser), \
+             (int) XML_GetCurrentLineNumber(data->parser),     \
+             (int) XML_GetCurrentColumnNumber(data->parser),           \
              args); \
     abort();\
 } while (0)
@@ -512,13 +650,17 @@ void driParseOptionInfo (driOptionCache *info,
     struct OptInfoData *data = &userData;
     GLuint realNoptions;
 
-  /* determine hash table size and allocate memory */
+  /* determine hash table size and allocate memory:
+   * 3/2 of the number of options, rounded up, so there remains always
+   * at least one free entry. This is needed for detecting undefined
+   * options in configuration files without getting a hash table overflow.
+   * Round this up to a power of two. */
+    GLuint minSize = (nConfigOptions*3 + 1) / 2;
     GLuint size, log2size;
-    for (size = 1, log2size = 0; size < nConfigOptions*3/2;
-        size <<= 1, ++log2size);
+    for (size = 1, log2size = 0; size < minSize; size <<= 1, ++log2size);
     info->tableSize = log2size;
     info->info = CALLOC (size * sizeof (driOptionInfo));
-    info->values = CALLOC (size * sizeof (driOptionInfo));
+    info->values = CALLOC (size * sizeof (driOptionValue));
     if (info->info == NULL || info->values == NULL) {
        fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
        abort();
@@ -707,7 +849,7 @@ static void optConfEndElem (void *userData, const XML_Char *name) {
 }
 
 /** \brief Initialize an option cache based on info */
-static void initOptionCache (driOptionCache *cache, driOptionCache *info) {
+static void initOptionCache (driOptionCache *cache, const driOptionCache *info) {
     cache->info = info->info;
     cache->tableSize = info->tableSize;
     cache->values = MALLOC ((1<<info->tableSize) * sizeof (driOptionValue));
@@ -758,7 +900,7 @@ static void parseOneConfigFile (XML_Parser p) {
 #undef BUF_SIZE
 }
 
-void driParseConfigFiles (driOptionCache *cache, driOptionCache *info,
+void driParseConfigFiles (driOptionCache *cache, const driOptionCache *info,
                          GLint screenNum, const char *driverName) {
     char *filenames[2] = {"/etc/drirc", NULL};
     char *home;
@@ -770,11 +912,7 @@ void driParseConfigFiles (driOptionCache *cache, driOptionCache *info,
     userData.cache = cache;
     userData.screenNum = screenNum;
     userData.driverName = driverName;
-#ifndef _SOLO    
     userData.execName = GET_PROGRAM_NAME();
-#else
-    userData.execName = "Solo";
-#endif    
 
     if ((home = getenv ("HOME"))) {
        GLuint len = strlen (home);