Просмотр исходного кода

Common: Switch to the XDG Base Directory Specification for directory selection.

This allows for easily movable and independent configuration and data directories, using standardized paths.
Emmanuel Gil Peyrot 11 лет назад
Родитель
Сommit
129ad721c1
2 измененных файлов с 69 добавлено и 10 удалено
  1. 1 1
      src/common/common_paths.h
  2. 68 9
      src/common/file_util.cpp

+ 1 - 1
src/common/common_paths.h

@@ -25,7 +25,7 @@
     #ifdef USER_DIR
         #define EMU_DATA_DIR USER_DIR
     #else
-        #define EMU_DATA_DIR ".citra-emu"
+        #define EMU_DATA_DIR "citra-emu"
     #endif
 #endif
 

+ 68 - 9
src/common/file_util.cpp

@@ -16,7 +16,10 @@
 #include <tchar.h>
 #else
 #include <sys/param.h>
+#include <sys/types.h>
 #include <dirent.h>
+#include <pwd.h>
+#include <unistd.h>
 #endif
 
 #if defined(__APPLE__)
@@ -632,6 +635,55 @@ std::string& GetExeDirectory()
     }
     return exe_path;
 }
+#else
+/**
+ * @return The user’s home directory on POSIX systems
+ */
+static const std::string& GetHomeDirectory() {
+    static std::string home_path;
+    if (home_path.empty()) {
+        const char* envvar = getenv("HOME");
+        if (envvar) {
+            home_path = envvar;
+        } else {
+            auto pw = getpwuid(getuid());
+            ASSERT_MSG(pw, "$HOME isn’t defined, and the current user can’t be found in /etc/passwd.");
+            home_path = pw->pw_dir;
+        }
+    }
+    return home_path;
+}
+
+/**
+ * Follows the XDG Base Directory Specification to get a directory path
+ * @param envvar The XDG environment variable to get the value from
+ * @return The directory path
+ * @sa http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ */
+static const std::string GetUserDirectory(const std::string& envvar) {
+    const char* directory = getenv(envvar.c_str());
+
+    std::string user_dir;
+    if (directory) {
+        user_dir = directory;
+    } else {
+        std::string subdirectory;
+        if (envvar == "XDG_DATA_HOME")
+            subdirectory = DIR_SEP ".local" DIR_SEP "share";
+        else if (envvar == "XDG_CONFIG_HOME")
+            subdirectory = DIR_SEP ".config";
+        else if (envvar == "XDG_CACHE_HOME")
+            subdirectory = DIR_SEP ".cache";
+        else
+            ASSERT_MSG(false, "Unknown XDG variable %s.", envvar.c_str());
+        user_dir = GetHomeDirectory() + subdirectory;
+    }
+
+    ASSERT_MSG(!user_dir.empty(), "User directory %s musn’t be empty.", envvar.c_str());
+    ASSERT_MSG(user_dir[0] == '/', "User directory %s must be absolute.", envvar.c_str());
+
+    return user_dir;
+}
 #endif
 
 std::string GetSysDirectory()
@@ -661,20 +713,27 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
     if (paths[D_USER_IDX].empty())
     {
 #ifdef _WIN32
-        paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
+        paths[D_USER_IDX]   = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
+        paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
+        paths[D_CACHE_IDX]  = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
 #else
-        if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
-            paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
-        else
-            paths[D_USER_IDX] = std::string(getenv("HOME") ?
-                getenv("HOME") : getenv("PWD") ?
-                getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP;
+        if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
+            paths[D_USER_IDX]   = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
+            paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
+            paths[D_CACHE_IDX]  = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+        } else {
+            std::string data_dir   = GetUserDirectory("XDG_DATA_HOME");
+            std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
+            std::string cache_dir  = GetUserDirectory("XDG_CACHE_HOME");
+
+            paths[D_USER_IDX]   = data_dir   + DIR_SEP EMU_DATA_DIR DIR_SEP;
+            paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
+            paths[D_CACHE_IDX]  = cache_dir  + DIR_SEP EMU_DATA_DIR DIR_SEP;
+        }
 #endif
 
-        paths[D_CONFIG_IDX]         = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
         paths[D_GAMECONFIG_IDX]     = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
         paths[D_MAPS_IDX]           = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
-        paths[D_CACHE_IDX]          = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
         paths[D_SDMC_IDX]           = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
         paths[D_NAND_IDX]           = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
         paths[D_SYSDATA_IDX]        = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;