From ffb525800b0397ea8b0de581ac670bb236227ffd Mon Sep 17 00:00:00 2001 From: Seg Date: Sat, 23 Jul 2022 21:44:46 -0600 Subject: [PATCH] Implement XDG Base Directory Specification --- BasiliskII/src/Unix/prefs_unix.cpp | 93 +++++++++++++++++++------- BasiliskII/src/Unix/xpram_unix.cpp | 59 +++++----------- SheepShaver/src/Unix/prefs_unix.cpp | 100 ++++++++++++++++++++-------- 3 files changed, 158 insertions(+), 94 deletions(-) diff --git a/BasiliskII/src/Unix/prefs_unix.cpp b/BasiliskII/src/Unix/prefs_unix.cpp index 4f2aa7ee..59dec302 100644 --- a/BasiliskII/src/Unix/prefs_unix.cpp +++ b/BasiliskII/src/Unix/prefs_unix.cpp @@ -20,15 +20,13 @@ #include "sysdeps.h" -#include -#include +#include #include using std::string; #include "prefs.h" - // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"fbdevicefile", TYPE_STRING, false, "path of frame buffer device specification file"}, @@ -41,24 +39,37 @@ prefs_desc platform_prefs_items[] = { {NULL, TYPE_END, false, NULL} // End of list }; - // Prefs file name and path -const char PREFS_FILE_NAME[] = ".basilisk_ii_prefs"; +static const char PREFS_FILE_NAME[] = "/prefs"; string UserPrefsPath; static string prefs_path; - +static string prefs_name; +extern string xpram_name; /* * Load preferences from settings file */ -void LoadPrefs(const char *vmdir) -{ - if (vmdir) { - prefs_path = string(vmdir) + '/' + string("prefs"); - FILE *prefs = fopen(prefs_path.c_str(), "r"); +// Comply with XDG Base Directory Specification +// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html +static void get_prefs_path_from_env(void){ + char* env; + if(env=getenv("XDG_CONFIG_HOME")){ + prefs_path = string(env); + return; + } + if(env=getenv("HOME")){ + prefs_path = string(env) + "/.config"; + } +} + +void LoadPrefs(const char* vmdir){ + if(vmdir){ + prefs_path = string(vmdir); + prefs_name = prefs_path + PREFS_FILE_NAME; + FILE *prefs = fopen(prefs_name.c_str(), "r"); if (!prefs) { - printf("No file at %s found.\n", prefs_path.c_str()); + printf("No file at %s found.\n", prefs_name.c_str()); exit(1); } LoadPrefsFromStream(prefs); @@ -67,16 +78,20 @@ void LoadPrefs(const char *vmdir) } // Construct prefs path - if (UserPrefsPath.empty()) { - char *home = getenv("HOME"); - if (home) - prefs_path = string(home) + '/'; - prefs_path += PREFS_FILE_NAME; - } else - prefs_path = UserPrefsPath; + get_prefs_path_from_env(); + if(!prefs_path.empty()){ + prefs_path += "/BasiliskII"; + prefs_name = prefs_path + PREFS_FILE_NAME; + } + xpram_name = prefs_path + "/xpram"; + + // --config was specified + if(!UserPrefsPath.empty()){ + prefs_name = UserPrefsPath; + } // Read preferences from settings file - FILE *f = fopen(prefs_path.c_str(), "r"); + FILE *f = fopen(prefs_name.c_str(), "r"); if (f != NULL) { // Prefs file found, load settings @@ -92,21 +107,51 @@ void LoadPrefs(const char *vmdir) } } +static bool is_dir(const std::string& path){ + struct stat info; + if(stat(path.c_str(), &info) != 0){ + return false; + } + return (info.st_mode & S_IFDIR) != 0; +} + +static bool create_directories(const std::string& path,mode_t mode){ + if(mkdir(path.c_str(),mode)==0) + return true; + + switch (errno){ + case ENOENT: + { + int pos = path.find_last_of('/'); + if (pos == std::string::npos) + return false; + if (!create_directories(path.substr(0,pos),mode)) + return false; + } + return 0 == mkdir(path.c_str(),mode); + + case EEXIST: + return is_dir(path); + default: + return false; + } +} /* * Save preferences to settings file */ -void SavePrefs(void) -{ +void SavePrefs(void){ FILE *f; - if ((f = fopen(prefs_path.c_str(), "w")) != NULL) { + if(!prefs_path.empty()&&!is_dir(prefs_path)){ + create_directories(prefs_path,0700); + } + if ((f = fopen(prefs_name.c_str(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } - /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() diff --git a/BasiliskII/src/Unix/xpram_unix.cpp b/BasiliskII/src/Unix/xpram_unix.cpp index 3037b02d..e0bca701 100644 --- a/BasiliskII/src/Unix/xpram_unix.cpp +++ b/BasiliskII/src/Unix/xpram_unix.cpp @@ -20,81 +20,54 @@ #include "sysdeps.h" -#include +#include +using std::string; #include "xpram.h" - -// XPRAM file name and path -#if POWERPC_ROM -const char XPRAM_FILE_NAME[] = ".sheepshaver_nvram"; -#else -const char XPRAM_FILE_NAME[] = ".basilisk_ii_xpram"; -#endif -static char xpram_path[1024]; - +// XPRAM file name, set by LoadPrefs() in prefs_unix.cpp +string xpram_name; /* * Load XPRAM from settings file */ -void LoadXPRAM(const char *vmdir) -{ - if (vmdir) { +void LoadXPRAM(const char* vmdir){ + if(vmdir){ #if POWERPC_ROM - snprintf(xpram_path, sizeof(xpram_path), "%s/nvram", vmdir); + xpram_name = string(vmdir) + "/nvram"; #else - snprintf(xpram_path, sizeof(xpram_path), "%s/xpram", vmdir); + xpram_name = string(vmdir) + "/xpram"; #endif - } else { - // Construct XPRAM path - xpram_path[0] = 0; - char *home = getenv("HOME"); - if (home != NULL && strlen(home) < 1000) { - strncpy(xpram_path, home, 1000); - strcat(xpram_path, "/"); - } - strcat(xpram_path, XPRAM_FILE_NAME); } - // Load XPRAM from settings file + assert(!xpram_name.empty()); int fd; - if ((fd = open(xpram_path, O_RDONLY)) >= 0) { + if ((fd = open(xpram_name.c_str(), O_RDONLY)) >= 0) { read(fd, XPRAM, XPRAM_SIZE); close(fd); } } - /* * Save XPRAM to settings file */ -void SaveXPRAM(void) -{ +void SaveXPRAM(void){ + assert(!xpram_name.empty()); int fd; - if ((fd = open(xpram_path, O_WRONLY | O_CREAT, 0666)) >= 0) { + if ((fd = open(xpram_name.c_str(), O_WRONLY | O_CREAT, 0666)) >= 0) { write(fd, XPRAM, XPRAM_SIZE); close(fd); } } - /* * Delete PRAM file */ -void ZapPRAM(void) -{ - // Construct PRAM path - xpram_path[0] = 0; - char *home = getenv("HOME"); - if (home != NULL && strlen(home) < 1000) { - strncpy(xpram_path, home, 1000); - strcat(xpram_path, "/"); - } - strcat(xpram_path, XPRAM_FILE_NAME); - +void ZapPRAM(void){ // Delete file - unlink(xpram_path); + assert(!xpram_name.empty()); + unlink(xpram_name.c_str()); } diff --git a/SheepShaver/src/Unix/prefs_unix.cpp b/SheepShaver/src/Unix/prefs_unix.cpp index 7ac92cbd..df496512 100644 --- a/SheepShaver/src/Unix/prefs_unix.cpp +++ b/SheepShaver/src/Unix/prefs_unix.cpp @@ -20,14 +20,14 @@ #include "sysdeps.h" -#include -#include -#include +#include +#include + #include +using std::string; #include "prefs.h" - // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"ether", TYPE_STRING, false, "device name of Mac ethernet adapter"}, @@ -47,8 +47,10 @@ prefs_desc platform_prefs_items[] = { // Prefs file name and path -const char PREFS_FILE_NAME[] = ".sheepshaver_prefs"; -static char prefs_path[1024]; +static const char PREFS_FILE_NAME[] = "/prefs"; +static string prefs_path; +static string prefs_name; +extern string xpram_name; std::string UserPrefsPath; @@ -56,13 +58,26 @@ std::string UserPrefsPath; * Load preferences from settings file */ -void LoadPrefs(const char *vmdir) -{ - if (vmdir) { - snprintf(prefs_path, sizeof(prefs_path), "%s/prefs", vmdir); - FILE *prefs = fopen(prefs_path, "r"); +// Comply with XDG Base Directory Specification +// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html +static void get_prefs_path_from_env(void){ + char* env; + if(env=getenv("XDG_CONFIG_HOME")){ + prefs_path = string(env); + return; + } + if(env=getenv("HOME")){ + prefs_path = string(env) + "/.config"; + } +} + +void LoadPrefs(const char* vmdir){ + if(vmdir){ + prefs_path = string(vmdir); + prefs_name = prefs_path + PREFS_FILE_NAME; + FILE *prefs = fopen(prefs_name.c_str(), "r"); if (!prefs) { - printf("No file at %s found.\n", prefs_path); + printf("No file at %s found.\n", prefs_name.c_str()); exit(1); } LoadPrefsFromStream(prefs); @@ -70,20 +85,21 @@ void LoadPrefs(const char *vmdir) return; } - if (!UserPrefsPath.empty()) strncpy(prefs_path, UserPrefsPath.c_str(), 1000); - else { - // Construct prefs path - prefs_path[0] = 0; - char *home = getenv("HOME"); - if (home != NULL && strlen(home) < 1000) { - strncpy(prefs_path, home, 1000); - strcat(prefs_path, "/"); - } - strcat(prefs_path, PREFS_FILE_NAME); + // Construct prefs path + get_prefs_path_from_env(); + if(!prefs_path.empty()){ + prefs_path += "/SheepShaver"; + prefs_name = prefs_path + PREFS_FILE_NAME; + } + xpram_name = prefs_path + "/nvram"; + + // --config was specified + if(!UserPrefsPath.empty()){ + prefs_name = UserPrefsPath; } // Read preferences from settings file - FILE *f = fopen(prefs_path, "r"); + FILE *f = fopen(prefs_name.c_str(), "r"); if (f != NULL) { // Prefs file found, load settings @@ -99,21 +115,51 @@ void LoadPrefs(const char *vmdir) } } +static bool is_dir(const std::string& path){ + struct stat info; + if(stat(path.c_str(), &info) != 0){ + return false; + } + return (info.st_mode & S_IFDIR) != 0; +} + +static bool create_directories(const std::string& path,mode_t mode){ + if(mkdir(path.c_str(),mode)==0) + return true; + + switch (errno){ + case ENOENT: + { + int pos = path.find_last_of('/'); + if (pos == std::string::npos) + return false; + if (!create_directories(path.substr(0,pos),mode)) + return false; + } + return 0 == mkdir(path.c_str(),mode); + + case EEXIST: + return is_dir(path); + default: + return false; + } +} /* * Save preferences to settings file */ -void SavePrefs(void) -{ +void SavePrefs(void){ FILE *f; - if ((f = fopen(prefs_path, "w")) != NULL) { + if(!prefs_path.empty()&&!is_dir(prefs_path)){ + create_directories(prefs_path,0700); + } + if ((f = fopen(prefs_name.c_str(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } - /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit()