From 64772850b51fe2c3fc4aa4e33bd8f86ba593864a Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Thu, 16 Apr 2020 02:18:30 +0200 Subject: [PATCH] Respect XDG spec for dosbox main .conf file Windows and macOS config files are left as they were, this change affects mostly Linux users. Users are not forced to migrate, but visible warning is being issued if they aren't. Majority of users probably won't notice it, as the stable release should generate newly named .conf file. --- include/cross.h | 2 + src/gui/sdlmain.cpp | 2 + src/misc/cross.cpp | 113 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/include/cross.h b/include/cross.h index 6cbb0c81..0c4e89ac 100644 --- a/include/cross.h +++ b/include/cross.h @@ -76,6 +76,8 @@ static inline float powf (float x, float y) { return (float) pow (x,y); } #endif +void CROSS_DetermineConfigPaths(); + class Cross { public: static void GetPlatformConfigDir(std::string& in); diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index c90f4b05..1f3b0091 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -3163,6 +3163,8 @@ int main(int argc, char* argv[]) { sdl.num_joysticks=SDL_NumJoysticks(); + CROSS_DetermineConfigPaths(); + /* Parse configuration files */ std::string config_file, config_path, config_combined; Cross::GetPlatformConfigDir(config_path); diff --git a/src/misc/cross.cpp b/src/misc/cross.cpp index 017b92b3..fb0c2d49 100644 --- a/src/misc/cross.cpp +++ b/src/misc/cross.cpp @@ -16,26 +16,108 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "dosbox.h" #include "cross.h" -#include "support.h" + #include +#include + #include #include +#include +#include #ifdef WIN32 #ifndef _WIN32_IE #define _WIN32_IE 0x0400 #endif #include +#else +#include #endif -#if defined HAVE_SYS_TYPES_H && defined HAVE_PWD_H -#include +#if defined HAVE_PWD_H #include #endif +#include "support.h" + +#ifndef WIN32 + +std::string cached_conf_path; + +static bool CreateDirectories(const std::string &path) +{ + struct stat sb; + if (stat(path.c_str(), &sb) == 0) { + const bool is_dir = ((sb.st_mode & S_IFMT) == S_IFDIR); + return is_dir; + } + + std::vector tmp(path.begin(), path.end()); + std::string dname = dirname(tmp.data()); + + // Create parent directories recursively + if (!CreateDirectories(dname)) + return false; + + return (mkdir(path.c_str(), 0700) == 0); +} + +static std::string GetConfigName() +{ + std::string file_name; + Cross::GetPlatformConfigName(file_name); + return file_name; +} + +static std::string ResolveHome(std::string tilde_path) +{ + Cross::ResolveHomedir(tilde_path); + return tilde_path; +} + +static bool PathExists(const std::string &path) +{ + return (access(path.c_str(), F_OK) == 0); +} + +static std::string DetermineConfigPath() +{ + const char *xdg_conf_home = getenv("XDG_CONFIG_HOME"); + const std::string conf_home = xdg_conf_home ? xdg_conf_home : "~/.config"; + const std::string conf_path = ResolveHome(conf_home + "/dosbox"); + const std::string old_conf_path = ResolveHome("~/.dosbox"); + + if (PathExists(conf_path + "/" + GetConfigName())) { + return conf_path; + } + + if (PathExists(old_conf_path + "/" + GetConfigName())) { + LOG_MSG("WARNING: Config file found in deprecated path! (~/.dosbox)\n" + "Backup/remove this dir and restart to generate updated config file.\n" + "---"); + return old_conf_path; + } + + if (!CreateDirectories(conf_path)) { + LOG_MSG("ERROR: Directory '%s' cannot be created", + conf_path.c_str()); + return old_conf_path; + } + + return conf_path; +} + +#endif // !WIN32 + +void CROSS_DetermineConfigPaths() +{ +#if !defined(WIN32) && !defined(MACOSX) + if (cached_conf_path.empty()) + cached_conf_path = DetermineConfigPath(); +#endif +} + #ifdef WIN32 static void W32_ConfDir(std::string& in,bool create) { int c = create?1:0; @@ -63,10 +145,11 @@ void Cross::GetPlatformConfigDir(std::string& in) { in = "~/Library/Preferences"; ResolveHomedir(in); #else - in = "~/.dosbox"; - ResolveHomedir(in); + assert(!cached_conf_path.empty()); + in = cached_conf_path; #endif - in += CROSS_FILESPLIT; + if (in.back() != CROSS_FILESPLIT) + in += CROSS_FILESPLIT; } void Cross::GetPlatformConfigName(std::string& in) { @@ -80,7 +163,8 @@ void Cross::GetPlatformConfigName(std::string& in) { in = DEFAULT_CONFIG_FILE; } -void Cross::CreatePlatformConfigDir(std::string& in) { +void Cross::CreatePlatformConfigDir(std::string &in) +{ #ifdef WIN32 W32_ConfDir(in,true); in += "\\DOSBox"; @@ -90,11 +174,12 @@ void Cross::CreatePlatformConfigDir(std::string& in) { ResolveHomedir(in); //Don't create it. Assume it exists #else - in = "~/.dosbox"; - ResolveHomedir(in); - mkdir(in.c_str(),0700); + assert(!cached_conf_path.empty()); + in = cached_conf_path.c_str(); + mkdir(in.c_str(), 0700); #endif - in += CROSS_FILESPLIT; + if (in.back() != CROSS_FILESPLIT) + in += CROSS_FILESPLIT; } void Cross::ResolveHomedir(std::string & temp_line) { @@ -300,5 +385,3 @@ FILE *fopen_wrap(const char *path, const char *mode) { return fopen(path,mode); } - -