XDG Base Dir Spec followup #383

* Add XDG Base Dir Spec for other Unix alike platform.

* Add XDG Base Dir support for the fallback on SDL port.

* Add migration for Unix configuration file.
We migrate from 'vbam.conf' to 'vbam.ini' automatically.

* Refactor code for portability of dir creation functions.

* Fix for MacOS compilation directive.
This commit is contained in:
Edênis Freindorfer Azevedo 2019-03-06 20:38:57 -03:00 committed by Rafael Kitover
parent 39fd3f6580
commit 36453885fc
6 changed files with 115 additions and 47 deletions

View File

@ -64,6 +64,66 @@ bool FileExists(const char *filename)
#endif
}
// Get user-specific config dir manually.
// apple: ~/Library/Application Support/
// windows: %APPDATA%
// unix: ${XDG_CONFIG_HOME:-~/.config}
std::string get_xdg_user_config_home()
{
std::string path;
#ifdef __APPLE__
std::string home(getenv("HOME"));
path = home + "/Library/Application Support/";
#elif _WIN32
std::string app_data(getenv("LOCALAPPDATA"));
path = app_data + '\\';
#else // Unix
char *xdg_var = getenv("XDG_CONFIG_HOME");
if (!xdg_var || !*xdg_var)
{
std::string xdg_default(getenv("HOME"));
xdg_default += "/.config";
path = xdg_default;
}
else
{
path = xdg_var;
}
path += '/';
#endif
return path;
}
// Get user-specific data dir manually.
// apple: ~/Library/Application Support/
// windows: %APPDATA%
// unix: ${XDG_DATA_HOME:-~/.local/share}
std::string get_xdg_user_data_home()
{
std::string path;
#ifdef __APPLE__
std::string home(getenv("HOME"));
path = home + "/Library/Application Support/";
#elif _WIN32
std::string app_data(getenv("LOCALAPPDATA"));
path = app_data + '\\';
#else // Unix
char *xdg_var = getenv("XDG_DATA_HOME");
if (!xdg_var || !*xdg_var)
{
std::string xdg_default(getenv("HOME"));
xdg_default += "/.local/share";
path = xdg_default;
}
else
{
path = xdg_var;
}
path += '/';
#endif
return path;
}
void utilReadScreenPixels(uint8_t *dest, int w, int h)
{
uint8_t *b = dest;

View File

@ -1,6 +1,7 @@
#ifndef UTIL_H
#define UTIL_H
#include <string>
#include "System.h"
enum IMAGE_TYPE { IMAGE_UNKNOWN = -1, IMAGE_GBA = 0, IMAGE_GB = 1 };
@ -13,6 +14,9 @@ typedef struct {
bool FileExists(const char *filename);
std::string get_xdg_user_config_home();
std::string get_xdg_user_data_home();
void utilReadScreenPixels(uint8_t *dest, int w, int h);
bool utilWritePNGFile(const char *, int, int, uint8_t *);
bool utilWriteBMPFile(const char *, int, int, uint8_t *);

View File

@ -38,6 +38,9 @@ extern "C" {
#include <direct.h>
#define GETCWD _getcwd
#define snprintf sprintf
#define stat _stat
#define mkdir(X,Y) (_mkdir(X))
#define S_ISDIR _S_IFDIR
#endif // _WIN32
#ifndef __GNUC__
@ -647,7 +650,7 @@ const char* FindConfigFile(const char *name)
}
if (homeDir) {
sprintf(path, "%s%c%s%c%s", homeDir, FILE_SEP, DOT_DIR, FILE_SEP, name);
sprintf(path, "%s%c%s", homeDir, FILE_SEP, name);
if (FileExists(path))
{
return path;
@ -717,11 +720,11 @@ const char* FindConfigFile(const char *name)
void LoadConfigFile()
{
#if !defined(_WIN32) && !defined(__APPLE__)
homeDir = getenv("HOME");
#else
homeDir = 0;
#endif
struct stat s;
std::string homeDirTmp = get_xdg_user_config_home() + FILE_SEP + DOT_DIR;
homeDir = (char *)homeDirTmp.c_str();
if (stat(homeDir, &s) == -1 || !S_ISDIR(s.st_mode))
mkdir(homeDir, 0755);
if (preferences == NULL)
{
@ -738,11 +741,11 @@ void LoadConfigFile()
void SaveConfigFile()
{
#if !defined(_WIN32) && !defined(__APPLE__)
homeDir = getenv("HOME");
#else
homeDir = 0;
#endif
struct stat s;
std::string homeDirTmp = get_xdg_user_config_home() + FILE_SEP + DOT_DIR;
homeDir = (char *)homeDirTmp.c_str();
if (stat(homeDir, &s) == -1 || !S_ISDIR(s.st_mode))
mkdir(homeDir, 0755);
const char* configFile = FindConfigFile("vbam.ini");

View File

@ -164,7 +164,7 @@ extern const char *saveDir;
extern const char *batteryDir;
// Directory within homedir to use for default save location.
#define DOT_DIR ".vbam"
#define DOT_DIR "visualboyadvance-m"
void SetHome(char *_arg0);
void SaveConfigFile();

View File

@ -71,6 +71,9 @@
#include <direct.h>
#define GETCWD _getcwd
#define snprintf sprintf
#define stat _stat
#define mkdir(X,Y) (_mkdir(X))
#define S_ISDIR _S_IFDIR
#endif // _WIN32
#ifndef __GNUC__
@ -202,6 +205,7 @@ int sdlMirroringEnable = 1;
void systemConsoleMessage(const char*);
char* home;
char homeDataDir[2048];
char screenMessageBuffer[21];
uint32_t screenMessageTime = 0;
@ -246,7 +250,7 @@ void StartLirc(void)
fprintf(stdout, "Success\n");
//read the config file
char LIRCConfigLoc[2048];
sprintf(LIRCConfigLoc, "%s/%s/%s", homeDir, DOT_DIR, "lircrc");
sprintf(LIRCConfigLoc, "%s/%s", homeDataDir, "lircrc");
fprintf(stdout, "LIRC Config file:");
if (lirc_readconfig(LIRCConfigLoc, &LIRCConfigInfo, NULL) == 0) {
//check vbam dir for lircrc
@ -366,8 +370,8 @@ FILE* sdlFindFile(const char* name)
}
if (homeDir) {
fprintf(stdout, "Searching home directory: %s%c%s\n", homeDir, FILE_SEP, DOT_DIR);
sprintf(path, "%s%c%s%c%s", homeDir, FILE_SEP, DOT_DIR, FILE_SEP, name);
fprintf(stdout, "Searching home directory: %s\n", homeDataDir);
sprintf(path, "%s%c%s", homeDataDir, FILE_SEP, name);
f = fopen(path, "r");
if (f != NULL)
return f;
@ -659,7 +663,7 @@ static char* sdlStateName(int num)
sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
num + 1);
else if (homeDir)
sprintf(stateName, "%s/%s/%s%d.sgm", homeDir, DOT_DIR, sdlGetFilename(filename), num + 1);
sprintf(stateName, "%s/%s%d.sgm", homeDataDir, sdlGetFilename(filename), num + 1);
else
sprintf(stateName, "%s%d.sgm", filename, num + 1);
@ -758,7 +762,7 @@ void sdlWriteBattery()
if (batteryDir)
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
else if (homeDir)
sprintf(buffer, "%s/%s/%s.sav", homeDir, DOT_DIR, sdlGetFilename(filename));
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
else
sprintf(buffer, "%s.sav", filename);
@ -774,7 +778,7 @@ void sdlReadBattery()
if (batteryDir)
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
else if (homeDir)
sprintf(buffer, "%s/%s/%s.sav", homeDir, DOT_DIR, sdlGetFilename(filename));
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
else
sprintf(buffer, "%s.sav", filename);
@ -1637,12 +1641,21 @@ void handleRewinds()
}
}
void SetHomeDataDir()
{
sprintf(homeDataDir, "%s%s", get_xdg_user_data_home().c_str(), DOT_DIR);
struct stat s;
if (stat(homeDataDir, &s) == -1 || !S_ISDIR(s.st_mode))
mkdir(homeDataDir, 0755);
}
int main(int argc, char** argv)
{
fprintf(stdout, "%s\n", VBA_NAME_AND_SUBVERSION);
home = argv[0];
SetHome(home);
SetHomeDataDir();
frameSkip = 2;
gbBorderOn = 0;
@ -2213,7 +2226,7 @@ void systemScreenCapture(int a)
if (screenShotDir)
sprintf(buffer, "%s/%s%02d.bmp", screenShotDir, sdlGetFilename(filename), a);
else if (homeDir)
sprintf(buffer, "%s/%s/%s%02d.bmp", homeDir, DOT_DIR, sdlGetFilename(filename), a);
sprintf(buffer, "%s/%s%02d.bmp", homeDataDir, sdlGetFilename(filename), a);
else
sprintf(buffer, "%s%02d.bmp", filename, a);
@ -2222,7 +2235,7 @@ void systemScreenCapture(int a)
if (screenShotDir)
sprintf(buffer, "%s/%s%02d.png", screenShotDir, sdlGetFilename(filename), a);
else if (homeDir)
sprintf(buffer, "%s/%s/%s%02d.png", homeDir, DOT_DIR, sdlGetFilename(filename), a);
sprintf(buffer, "%s/%s%02d.png", homeDataDir, sdlGetFilename(filename), a);
else
sprintf(buffer, "%s%02d.png", filename, a);
emulator.emuWritePNG(buffer);

View File

@ -32,26 +32,6 @@
IMPLEMENT_APP(wxvbamApp)
IMPLEMENT_DYNAMIC_CLASS(MainFrame, wxFrame)
// Get XDG_CONFIG_HOME dir manually
// only native support for XDG config when wxWidgets >= 3.1
static wxString get_xdg_user_config_home()
{
wxString path;
char *xdg_config_home = getenv("XDG_CONFIG_HOME");
// Default for XDG_CONFIG_HOME is '$HOME/.config'
if (!xdg_config_home || !*xdg_config_home)
{
wxString xdg_default(getenv("HOME"));
xdg_default += "/.config";
path = xdg_default;
}
else
{
path = xdg_config_home;
}
return path + "/";
}
// generate config file path
static void get_config_path(wxPathList& path, bool exists = true)
{
@ -79,7 +59,7 @@ static void get_config_path(wxPathList& path, bool exists = true)
wxLogDebug(wxT("GetDataDir(): %s"), stdp.GetDataDir().mb_str());
wxLogDebug(wxT("GetLocalDataDir(): %s"), stdp.GetLocalDataDir().mb_str());
wxLogDebug(wxT("GetPluginsDir(): %s"), stdp.GetPluginsDir().mb_str());
#if defined(__LINUX__)
#if defined(__WXGTK__)
wxLogDebug(wxT("XdgConfigDir: %s"), get_xdg_user_config_home() + current_app_name);
#endif
debug_dumped = true;
@ -87,11 +67,11 @@ static void get_config_path(wxPathList& path, bool exists = true)
// When native support for XDG dirs is available (wxWidgets >= 3.1),
// this will be no longer necessary
#if defined(__LINUX__)
#if defined(__WXGTK__)
// XDG spec manual support
// ${XDG_CONFIG_HOME:-$HOME/.config}/`appname`
wxString old_config = wxString(getenv("HOME")) + "/.vbam";
wxString new_config = get_xdg_user_config_home();
wxString new_config(get_xdg_user_config_home());
if (!wxDirExists(old_config) && wxIsWritable(new_config))
{
path.Add(new_config + current_app_name);
@ -253,12 +233,20 @@ bool wxvbamApp::OnInit()
// this needs to be in a subdir to support other config as well
// but subdir flag behaves differently 2.8 vs. 2.9. Oh well.
// NOTE: this does not support XDG (freedesktop.org) paths
#if defined(__WXMSW__) || defined(__APPLE__)
wxString confname("vbam.ini");
#else
wxString confname("vbam.conf");
#endif
wxFileName vbamconf(GetConfigurationPath(), confname);
// /MIGRATION
// migrate from 'vbam.conf' to 'vbam.ini' to manage a single config
// file for all platforms.
#if !defined(__WXMSW__) && !defined(__APPLE__)
wxString oldConf(GetConfigurationPath() + "/vbam.conf");
wxString newConf(GetConfigurationPath() + "/vbam.ini");
if (wxFileExists(oldConf))
{
wxRenameFile(oldConf, newConf, false);
}
#endif
// /END_MIGRATION
cfg = new wxFileConfig(wxT("vbam"), wxEmptyString,
vbamconf.GetFullPath(),
wxEmptyString, wxCONFIG_USE_LOCAL_FILE);