xmlconfig: read more config files from drirc.d/
[mesa.git] / src / util / xmlconfig.c
index d3f47ecda0c1738d9d050d9bae1d27df349df82d..68ce5cee921aa4e80322b8d7dac0efcf9f5ac299 100644 (file)
@@ -27,6 +27,7 @@
  * \author Felix Kuehling
  */
 
+#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 #include <unistd.h>
 #include <errno.h>
+#include <dirent.h>
+#include <fnmatch.h>
 #include "xmlconfig.h"
+#include "u_process.h"
 
-#undef GET_PROGRAM_NAME
-
-#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(__CYGWIN__)
-#    define GET_PROGRAM_NAME() program_invocation_short_name
-#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
-#    include <osreldate.h>
-#    if (__FreeBSD_version >= 440000)
-#        include <stdlib.h>
-#        define GET_PROGRAM_NAME() getprogname()
-#    endif
-#elif defined(__NetBSD__) && defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000100)
-#    include <stdlib.h>
-#    define GET_PROGRAM_NAME() getprogname()
-#elif defined(__DragonFly__)
-#    include <stdlib.h>
-#    define GET_PROGRAM_NAME() getprogname()
-#elif defined(__APPLE__)
-#    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>
-
-static const char *
-__getProgramName()
-{
-    static const char *progname;
-
-    if (progname == NULL) {
-        const char *e = getexecname();
-        if (e != NULL) {
-            /* Have to make a copy since getexecname can return a readonly
-               string, but basename expects to be able to modify its arg. */
-            char *n = strdup(e);
-            if (n != NULL) {
-                progname = basename(n);
-            }
-        }
-    }
-    return progname;
-}
-
-#    define GET_PROGRAM_NAME() __getProgramName()
-#endif
-
-#if !defined(GET_PROGRAM_NAME)
-#    if defined(__OpenBSD__) || defined(NetBSD) || defined(__UCLIBC__) || defined(ANDROID)
-/* 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;
-    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 work with your OS version."
-#    endif
-#endif
 
 /** \brief Find an option in an option cache with the name as key */
 static uint32_t
@@ -466,11 +396,11 @@ __driUtilMessage(const char *f, ...)
                       (int) XML_GetCurrentLineNumber(data->parser), \
                       (int) XML_GetCurrentColumnNumber(data->parser)); \
 } while (0)
-#define XML_WARNING(msg,args...) do { \
+#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), \
-                      args); \
+                      ##__VA_ARGS__); \
 } while (0)
 /** \brief Output an error message. */
 #define XML_ERROR1(msg) do { \
@@ -478,11 +408,11 @@ __driUtilMessage(const char *f, ...)
                       (int) XML_GetCurrentLineNumber(data->parser), \
                       (int) XML_GetCurrentColumnNumber(data->parser)); \
 } while (0)
-#define XML_ERROR(msg,args...) do { \
+#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), \
-                      args); \
+                      ##__VA_ARGS__); \
 } while (0)
 /** \brief Output a fatal error message and abort. */
 #define XML_FATAL1(msg) do { \
@@ -492,12 +422,12 @@ __driUtilMessage(const char *f, ...)
              (int) XML_GetCurrentColumnNumber(data->parser)); \
     abort();\
 } while (0)
-#define XML_FATAL(msg,args...) do { \
+#define XML_FATAL(msg, ...) do { \
     fprintf (stderr, "Fatal error in %s line %d, column %d: "msg"\n", \
              data->name, \
              (int) XML_GetCurrentLineNumber(data->parser), \
              (int) XML_GetCurrentColumnNumber(data->parser), \
-             args); \
+             ##__VA_ARGS__); \
     abort();\
 } while (0)
 
@@ -939,9 +869,8 @@ initOptionCache(driOptionCache *cache, const driOptionCache *info)
     }
 }
 
-/** \brief Parse the named configuration file */
 static void
-parseOneConfigFile(XML_Parser p)
+_parseOneConfigFile(XML_Parser p)
 {
 #define BUF_SIZE 0x1000
     struct OptConfData *data = (struct OptConfData *)XML_GetUserData (p);
@@ -980,17 +909,76 @@ parseOneConfigFile(XML_Parser p)
 #undef BUF_SIZE
 }
 
+/** \brief Parse the named configuration file */
+static void
+parseOneConfigFile(struct OptConfData *data, const char *filename)
+{
+    XML_Parser p;
+
+    p = XML_ParserCreate (NULL); /* use encoding specified by file */
+    XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
+    XML_SetUserData (p, data);
+    data->parser = p;
+    data->name = filename;
+    data->ignoringDevice = 0;
+    data->ignoringApp = 0;
+    data->inDriConf = 0;
+    data->inDevice = 0;
+    data->inApp = 0;
+    data->inOption = 0;
+
+    _parseOneConfigFile (p);
+    XML_ParserFree (p);
+}
+
+static int
+scandir_filter(const struct dirent *ent)
+{
+    if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
+       return 0;
+
+    if (fnmatch("*.conf", ent->d_name, 0))
+       return 0;
+
+    return 1;
+}
+
+/** \brief Parse configuration files in a directory */
+static void
+parseConfigDir(struct OptConfData *data, const char *dirname)
+{
+    int i, count;
+    struct dirent **entries = NULL;
+
+    count = scandir(dirname, &entries, scandir_filter, alphasort);
+    if (count < 0)
+        return;
+
+    for (i = 0; i < count; i++) {
+        char filename[PATH_MAX];
+
+        snprintf(filename, PATH_MAX, "%s/%s", dirname, entries[i]->d_name);
+        free(entries[i]);
+
+        parseOneConfigFile(data, filename);
+    }
+
+    free(entries);
+}
+
 #ifndef SYSCONFDIR
 #define SYSCONFDIR "/etc"
 #endif
 
+#ifndef DATADIR
+#define DATADIR "/usr/share"
+#endif
+
 void
 driParseConfigFiles(driOptionCache *cache, const driOptionCache *info,
                     int screenNum, const char *driverName)
 {
-    char *filenames[2] = { SYSCONFDIR "/drirc", NULL};
     char *home;
-    uint32_t i;
     struct OptConfData userData;
 
     initOptionCache (cache, info);
@@ -998,41 +986,17 @@ driParseConfigFiles(driOptionCache *cache, const driOptionCache *info,
     userData.cache = cache;
     userData.screenNum = screenNum;
     userData.driverName = driverName;
-    userData.execName = GET_PROGRAM_NAME();
+    userData.execName = util_get_process_name();
+
+    parseConfigDir(&userData, DATADIR "/drirc.d");
+    parseOneConfigFile(&userData, SYSCONFDIR "/drirc");
 
     if ((home = getenv ("HOME"))) {
-        uint32_t len = strlen (home);
-        filenames[1] = malloc(len + 7+1);
-        if (filenames[1] == NULL)
-            __driUtilMessage ("Can't allocate memory for %s/.drirc.", home);
-        else {
-            memcpy (filenames[1], home, len);
-            memcpy (filenames[1] + len, "/.drirc", 7+1);
-        }
-    }
+        char filename[PATH_MAX];
 
-    for (i = 0; i < 2; ++i) {
-        XML_Parser p;
-        if (filenames[i] == NULL)
-            continue;
-
-        p = XML_ParserCreate (NULL); /* use encoding specified by file */
-        XML_SetElementHandler (p, optConfStartElem, optConfEndElem);
-        XML_SetUserData (p, &userData);
-        userData.parser = p;
-        userData.name = filenames[i];
-        userData.ignoringDevice = 0;
-        userData.ignoringApp = 0;
-        userData.inDriConf = 0;
-        userData.inDevice = 0;
-        userData.inApp = 0;
-        userData.inOption = 0;
-
-        parseOneConfigFile (p);
-        XML_ParserFree (p);
+        snprintf(filename, PATH_MAX, "%s/.drirc", home);
+        parseOneConfigFile(&userData, filename);
     }
-
-    free(filenames[1]);
 }
 
 void