foxygit / doom Log in
commit d1d65f2567d4943e2103414e793b0e445e6365d5
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Sun Aug 23 16:08:58 2015 -0400
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Sun Aug 23 16:08:58 2015 -0400

    Make IWAD search paths compliant with XDG spec.

    The XDG Base Directory Specification defines standard directories
    that are searched for data files via the XDG_DATA_HOME and
    XDG_DATA_DIRS environment variables:
    http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

    To make Chocolate Doom a good citizen, use these directories to
    determine some of the locations in which to look for IWAD files. This
    includes /usr/share/games/doom, which is absorbed under the default
    value of the XDG_DATA_DIRS variable. We also now support the alternative
    ~/.local/share/games/doom as a user-writeable path in the user's home
    directory that doesn't require root privileges.

    This is part of #597 (thanks to @chungy for the suggestion).
---
 src/d_iwad.c | 128 ++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 82 insertions(+), 46 deletions(-)

diff --git a/src/d_iwad.c b/src/d_iwad.c
index 2d6460bc..3777bab6 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -509,55 +509,96 @@ static GameMission_t IdentifyIWADByName(char *name, int mask)
     return mission;
 }

-//
-// Add directories from the list in the DOOMWADPATH environment variable.
-//
-
-static void AddDoomWadPath(void)
+// Add IWAD directories parsed from splitting a path string containing
+// paths separated by PATH_SEPARATOR. 'suffix' is a string to concatenate
+// to the end of the paths before adding them.
+static void AddIWADPath(char *path, char *suffix)
 {
-    char *doomwadpath;
-    char *p;
-
-    // Check the DOOMWADPATH environment variable.
-
-    doomwadpath = getenv("DOOMWADPATH");
-
-    if (doomwadpath == NULL)
-    {
-        return;
-    }
+    char *left, *p;

-    doomwadpath = M_StringDuplicate(doomwadpath);
-
-    // Add the initial directory
-
-    AddIWADDir(doomwadpath);
+    path = M_StringDuplicate(path);

     // Split into individual dirs within the list.
-
-    p = doomwadpath;
+    left = path;

     for (;;)
     {
-        p = strchr(p, PATH_SEPARATOR);
-
+        p = strchr(left, PATH_SEPARATOR);
         if (p != NULL)
         {
-            // Break at the separator and store the right hand side
+            // Break at the separator and use the left hand side
             // as another iwad dir
-
             *p = '\0';
-            p += 1;

-            AddIWADDir(p);
+            AddIWADDir(M_StringJoin(left, suffix, NULL));
+            left = p + 1;
         }
         else
         {
             break;
         }
     }
+
+    AddIWADDir(M_StringJoin(left, suffix, NULL));
+
+    free(path);
 }

+// Add standard directories where IWADs are located on Unix systems.
+// To respect the freedesktop.org specification we support overriding
+// using standard environment variables. See the XDG Base Directory
+// Specification:
+// <http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>
+static void AddXdgDirs(void)
+{
+    char *env, *tmp_env;
+
+    // Quote:
+    // > $XDG_DATA_HOME defines the base directory relative to which
+    // > user specific data files should be stored. If $XDG_DATA_HOME
+    // > is either not set or empty, a default equal to
+    // > $HOME/.local/share should be used.
+    env = getenv("XDG_DATA_HOME");
+    tmp_env = NULL;
+
+    if (env == NULL)
+    {
+        char *homedir = getenv("HOME");
+        if (homedir == NULL)
+        {
+            homedir = "/";
+        }
+
+        tmp_env = M_StringJoin(homedir, "/.local/share", NULL);
+        env = tmp_env;
+    }
+
+    // We support $XDG_DATA_HOME/games/doom (which will usually be
+    // ~/.local/share/games/doom) as a user-writeable extension to
+    // the usual /usr/share/games/doom location.
+    AddIWADDir(M_StringJoin(env, "/games/doom", NULL));
+    free(tmp_env);
+
+    // Quote:
+    // > $XDG_DATA_DIRS defines the preference-ordered set of base
+    // > directories to search for data files in addition to the
+    // > $XDG_DATA_HOME base directory. The directories in $XDG_DATA_DIRS
+    // > should be seperated with a colon ':'.
+    // >
+    // > If $XDG_DATA_DIRS is either not set or empty, a value equal to
+    // > /usr/local/share/:/usr/share/ should be used.
+    env = getenv("XDG_DATA_DIRS");
+    if (env == NULL)
+    {
+        // (Trailing / omitted from paths, as it is added below)
+        env = "/usr/local/share:/usr/share";
+    }
+
+    // The "standard" location for IWADs on Unix that is supported by most
+    // source ports is /usr/share/games/doom - we support this through the
+    // XDG_DATA_DIRS mechanism, through which it can be overridden.
+    AddIWADPath(env, "/games/doom");
+}

 //
 // Build a list of IWAD files
@@ -565,7 +606,7 @@ static void AddDoomWadPath(void)

 static void BuildIWADDirList(void)
 {
-    char *doomwaddir;
+    char *env;

     if (iwad_dirs_built)
     {
@@ -573,21 +614,21 @@ static void BuildIWADDirList(void)
     }

     // Look in the current directory.  Doom always does this.
-
     AddIWADDir(".");

     // Add DOOMWADDIR if it is in the environment
-
-    doomwaddir = getenv("DOOMWADDIR");
-
-    if (doomwaddir != NULL)
+    env = getenv("DOOMWADDIR");
+    if (env != NULL)
     {
-        AddIWADDir(doomwaddir);
-    }
-
-    // Add dirs from DOOMWADPATH
+        AddIWADDir(env);
+    }

-    AddDoomWadPath();
+    // Add dirs from DOOMWADPATH:
+    env = getenv("DOOMWADPATH");
+    if (env != NULL)
+    {
+        AddIWADPath(env, "");
+    }

 #ifdef _WIN32

@@ -603,12 +644,7 @@ static void BuildIWADDirList(void)
     CheckSteamGUSPatches();

 #else
-
-    // Standard places where IWAD files are installed under Unix.
-
-    AddIWADDir("/usr/share/games/doom");
-    AddIWADDir("/usr/local/share/games/doom");
-
+    AddXdgDirs();
 #endif

     // Don't run this function again.